How a JSON or JSON-like language enables the next generation of safe human and AI-generated UIs Haku Haku , Waxaan ka mid ahay in ka mid ah macluumaadka macluumaadka ee macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluuma iyo a (CAD) oo ka mid ah (JPRX if), sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale sidoo kale. Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka A2 Home Qalabka Qalabka JSON Pointer Waxaa sidoo kale loo isticmaali karaa in ka mid ah xawaaraha waxaa loo isticmaali karaa si ay u isticmaali karaa macluumaadka iyo dhismaha oo ka mid ah macluumaadka. cCOM iyo JPRX waxaa loo isticmaali karaa; waxay isticmaali karaa dhismaha iyo dhismaha ka mid ah JSON Pointers, JSON Schema, iyo XPath. Sida loo yaabaa in la soo bandhigay sida cDOM iyo JPRX waxaa loo isticmaali karaa, waxaan loo isticmaali karaa mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid ah mid ah mid ka mid Qalabka waa in ay ku yaal ah: Shuruudaha dhismaha: Waxaad ka mid ah in la soo saarka dhismaha cusub ama in la soo saarka dhismaha ugu horeysay? Qiimeeyo: Waxaad ka mid ah in aad ka mid ah '+' oo ka mid ah '-' oo ka mid ah '*' oo ka mid ah ugu badan? DRY Logic: Sida loo isticmaali kartaa codka mid ka mid ah codka mid ka mid ah 10 macluumaadka for buttons 0-9? Sidaas, waxaan ku yidhi Claude Opus si ay u baabuurta, macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka macluumaadka. - Dhammaan cDOM iyo JPRX. zero custom JavaScript functions Marka loo yaqaan 'AI' waxay ka soo saarka qalabka dhismaha oo ka mid ah qalabka dhismaha, waxaa loo yaqaan 'cDOM' iyo 'JPRX' waa mid ka mid ah dhismaha dhismaha cusub. codka Marka aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan tahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay in aad u baahan yahay. { div: { class: "calculator", // A calculator feels stateless, but it's actually a strict state machine. // You're never just "typing a number"; you're either entering the first operand, // waiting for an operator, or entering the next operand. onmount: =state({ display: "0", // What you see on the screen expr: "", // History string, (e.g. "8 + 5 =") prev: "", // value stored before an operation op: "", // the active operator waiting: false // true when expecting a new number vs operator },{ name: "c", // the root name of our state, so we can express things like: /c/display schema: "polymorphic", // allow type changes, e.g. "0" or 0 scope: $this // scope the path to the current element }), children: [ // Display area { div: { class: "display", children: [ { div: { class: "expression",children[=/c/expr] }}, { div: { class: "result",children[=/c/display] }} ] } }, // Button grid { div: { class: "buttons", children: [ // Row 1: AC, ±, %, ÷ { button: { class: "btn btn-clear", onclick: =/c = { display: "0", expr: "", prev: "", op: "", waiting: false }, children: ["AC"] } }, { button: { class: "btn btn-function", onclick: =/c = { display: negate(/c/display), waiting: true, expr: "" }, children: ["±"] } }, { button: { class: "btn btn-function", onclick: =/c = { display: toPercent(/c/display), waiting: true, expr: "" }, children: ["%"] } }, // Divison is our first operator. This is where it gets tricky. // When you click `+`, you can't just link `prev` to `display`. // If you did, `prev` would update every time you selected a new digit for the**second**number, // breaking the math. We need a snapshot of the value at that exact moment. // Excel solves this with INDIRECT, effectively dereferencing a cell. JPRX borrows the same concept: { button: { class: "btn btn-operator", onclick: =/c = { prev: indirect(/c/display), // Capture the value right now expr: concat(/c/display, " ÷"), op: "/", waiting: true }, children: ["÷"] } }, // Row 2: 7, 8, 9, × // I have 10 number buttons. Do I write 10 handlers? Do I write a loop? In React or Vue, // you'd probably map over an array. With JPRX, the DOM is the data key and although map is available, // I represent the calculator using literals in this example. In a future article I will cover map. // By giving each button an `id` (e.g., `id: "7"`), we write a uniform logic expression that adapts // to whichever element triggered it. We just reference $this.id in JPRX and use an xpath to get the text // content for the child node, #../@id. In cDOM (not JPRX) '#' delimits the start of an xpath expression { button: { id: "7", class: "btn btn-number", onclick: =/c = { display: if(/c/waiting, $this.id, if(/c/display==0, $this.id, concat(/c/display, $this.id))), waiting: false }, children: [#../@id] // use xpath (starting char #) to get the text for the button from parent id } }, // Here's what is happening: // Waiting for input? (e.g., just hit `+`) → Replace the display with the button's ID. // Displaying "0"? → Replace it (avoids "07"). // Otherwise: → Append the button's ID. // This is replicated identically for every number button. No loops, no external helper functions. { button: { id: "8", class: "btn btn-number", onclick: =/c = { display: if(/c/waiting, $this.id, if(/c/display==0), $this.id, concat(/c/display, $this.id))), waiting: false }, children: [#../@id] } }, { button: { id: "9", class: "btn btn-number", onclick: =/c = { display: if(/c/waiting, $this.id, if(/c/display==0, $this.id, concat(/c/display, $this.id))), waiting: false }, children: [#../@id] } }, { button: { class: "btn btn-operator", onclick: =/c = { prev: indirect(/c/display), expr: concat(/c/display, " ×"), op: "*", waiting: true }, children: ["×"] } }, // Row 3: 4, 5, 6, − { button: { id: "4", class: "btn btn-number", onclick: =/c = { display: if(/c/waiting, $this.id, if(/c/display==0, $this.id, concat(/c/display, $this.id))), waiting: false }, children: [#../@id] } }, { button: { id: "5", class: "btn btn-number", onclick: =/c = { display: if(/c/waiting, $this.id, if(/c/display==0, $this.id, concat(/c/display, $this.id))), waiting: false }, children: [#../@id] } }, { button: { id: "6", class: "btn btn-number", onclick: =/c = { display: if(/c/waiting, $this.id, if(/c/display==0, $this.id, concat(/c/display, $this.id))), waiting: false }, children: [#../@id] } }, { button: { class: "btn btn-operator", onclick: =/c = { prev: indirect(/c/display), expr: concat(/c/display, " −"), op: "-", waiting: true }, children: ["−"] } }, // Row 4: 1, 2, 3, +, use set and eq just to demonstrate equivalence with = and == // the buttons below use 'set' in place of the infix operator '=', just to show a different way of doing things { button: { id: "1", class: "btn btn-number", onclick: =set(/c, { display: if(/c/waiting, $this.id, if(eq(/c/display, "0"), $this.id, concat(/c/display, $this.id))), waiting: false }), children: [#../@id] } }, { button: { id: "2", class: "btn btn-number", onclick: =set(/c, { display: if(/c/waiting, $this.id, if(eq(/c/display, "0"), $this.id, concat(/c/display, $this.id))), waiting: false }), children: [#../@id] } }, { button: { id: "3", class: "btn btn-number", onclick: =set(/c, { display: if(/c/waiting, $this.id, if(eq(/c/display, "0"), $this.id, concat(/c/display, $this.id))), waiting: false }), children: [#../@id] } }, { button: { class: "btn btn-operator", onclick: =set(/c, { prev: indirect(/c/display), expr: concat(/c/display, " +"), op: "+", waiting: true }), children: ["+"] } }, // Row 5: 0, ., = { button: { id: "0", class: "btn btn-number btn-wide", onclick: =set(/c, { display: if(/c/waiting, $this.id, if(eq(/c/display, "0"), "0", concat(/c/display, $this.id))), waiting: false }), children: [#../@id] } }, { button: { class: "btn btn-number", onclick: =set(/c, { display: if(/c/waiting, "0.", if(contains(/c/display, "."), /c/display, concat(/c/display, "."))), waiting: false }), children: ["."] } }, // Finally, the math. We need to say: // 1. Take the snapshot we stored // 2. Apply the current operator // 3. combine it with what's on screen now // This is the job of calc(). If prev == 8 and op == * and display = 5, then calc would be evaluated as calc("8 * 5") // To keep the syntax a little cleaner we also use $(<path>) as a shorthand for indirect. { button: { class: "btn btn-equals", onclick: =set(/c, { display: if(eq(/c/op, ""), /c/display, calc(concat("$('/c/prev') ", /c/op, " $('/c/display')"))), expr: concat(/c/expr, " ", /c/display, " ="), prev: "", op: "", waiting: true }), children: ["="] } } ] } }, // Branding { div: { class: "branding", children: [ { span: { children: [ "Built with ", { a: { href: "https://github.com/anywhichway/lightview", target: "_blank", children: ["Lightview"] } }, " cDOM • No custom JS!" ] } } ] } } ] } } Soo dejisan cDOM via Lightview Hypermedia Lightview waxaa loo isticmaali karaa kharashka hypermedia sida Sida loo isticmaali karaa Qalabka dhismaha ugu badan oo dhan. HTMX src Nala soo xiriir a Filter oo loo isticmaali karaa : cDOM src <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content="A beautiful calculator built with Lightview cDOM and JPRX reactive expressions - no custom JavaScript!"> <title>Calculator | Lightview cDOM</title> <link rel="stylesheet" href="calculator.css"> <!-- Load Lightview scripts --> <script src="/lightview.js"></script> <!-- DOM as JSON and reactivity support --> <script src="/lightview-x.js"></script> <!-- hypermedia support --> <script src="/lightview-cdom.js"></script> <-- cDOM/JPRX support --> </head> <body> <!-- The calculator cDOM is loaded via Lightview's hypermedia src attribute --> <div id="app" src="./calculator.cdomc"></div> </body> </html> EE.UU Qalabka ugu horeysay ee HTML Marka Tag - Lightview waxaa loo isticmaali karaa file, parseeeyo, oo ku yaalaa content reactive ee element target. src <img> <script> .cdomc Markaas ka mid ah loo yaabaa this way? Ma waxaad ka mid ahay Waxa uu ku yidhi: concat("$('/c/prev') ...") Why in the world you't just write parseFloat(prev) + parseFloat(curr) ? Waxaad ka mid ah ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah mid ka mid ah. Sida loo yaqaan 'Infrastructure for Sida loo yaqaan 'JSON-based path', waxaa loo isticmaali karaa in ay ka mid ah macluumaadka codsiga ah: AI Agents Sandboxing: Waxa uu soo saarka in ay ku yaalaa in ay soo saarka soo saarka ah. Logic waxay ka heli karaa 'windows', si ay u soo saarka global, ama si ay u soo saarka codsiga sekundaar. Xirfad: Xirfadka ugu badan ee UI-ka - logic iyo oo dhan - waa mid ka mid ah dhismaha. Waxaa laga yaabaa in la xira, waxaa laga yaabaa in dhismaha, ama waxaa laga yaabaa in ka mid ah model AI. Model Mental: Waxaad ku dhigi karaa xawaaraha qiyaasta oo ka mid ah shuruudaha dhismaha iyo dhismaha dhismaha, oo waa mid ka mid ah LLMs dhismaha ugu fiican. Sida loo yaqaan "declarative" waxay ka mid ah "dumb" iyo "primitive" waxay ka mid ah "state", "conditionals" iyo "path-based referencing" waxay ka mid ah "declarative" oo ka mid ah "dumb". Qalabka ugu badan Waxa uu ka mid ah wax soo saarka ah oo ka mid ah wax soo saarka iyo wax soo saarka iyo wax soo saarka. Haku , waxaan soo baxsanay xafiisyada in la yaqaan 'LLM's' in la xiriyaa scripts raw iyo ku yaala "Data as UI" philosophy. Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka Qalabka In this article, waxaan soo bandhigay in "Data as UI" waxay ka mid ah "dumb UI." Waxaan soo bandhigay status, kontekst, data snapshots, math, iyo navigation DOM la 'xpath' oo ka mid ah in la taabto mid ka mid ah kala duwan ee JavaScript. JPRX waxaa loo yaqaan "reactivity without the compilation" iyo "UI without the security risks". Waayo, si aad u Calculator waxaa laga heli karaa at: Demo Live: https://lightview.dev/docs/calculator.html Sida loo yaabaa in aad Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada Cudarada https://lightview.dev/docs/calculator.html https://github.com/anywhichway/lightview/blob/main/docs/calculator.html