Inline

examples/webview/inline.ts — a self-contained desktop app: an inline-HTML UI whose buttons call straight into native KlainMainLang code. Two native bindings: a counter kept in native state, and a directory listing read with fs.readdirSync. Native pushes results back into the page with eval.

Build: klainmain examples/webview/inline.ts && ./examples/webview/inline Windows: klainmain examples/webview/inline.ts && examples/webview/inline.exe (WebView2; see README) (macOS: zero extra deps; Linux: WebKitGTK dev packages — see README.)

import { Webview } from 'klain:webview'
import { readdirSync } from 'fs'

let count = 0

const w = new Webview({ title: "Klain Desktop", width: 640, height: 480, debug: true })

// Native counter: page calls window.bump(), gets the new value back as JSON.
w.bind("bump", (args: string): string => {
  count = count + 1
  return JSON.stringify({ count: count })
})

// Native file browser: page calls window.listDir(JSON.stringify([path])),
// native reads the directory and returns the entries as a JSON array.
w.bind("listDir", (args: string): string => {
  const parsed: string[] = JSON.parse(args)
  const path = parsed[0]
  const entries = readdirSync(path)
  return JSON.stringify(entries)
})

w.html(`<!doctype html>
<html>
<head><meta charset="utf-8"><title>Klain Desktop</title>
<style>
  body { font-family: -apple-system, system-ui, sans-serif; margin: 2rem; }
  button { font-size: 1rem; padding: .5rem 1rem; margin-right: .5rem; }
  #count { font-size: 2rem; font-weight: 600; }
  ul { max-height: 12rem; overflow: auto; border: 1px solid #ccc; padding: .5rem 1.5rem; }
</style></head>
<body>
  <h1>Counter</h1>
  <p><span id="count">0</span></p>
  <button onclick="bump()">Increment (native)</button>

  <h1>Directory</h1>
  <input id="path" value="." style="width: 60%; padding: .4rem;">
  <button onclick="browse()">List (native fs)</button>
  <ul id="entries"></ul>

  <script>
    async function bump() {
      const r = await window.bump()
      document.getElementById('count').textContent = r.count
    }
    async function browse() {
      const path = document.getElementById('path').value
      const entries = await window.listDir(JSON.stringify([path]))
      const ul = document.getElementById('entries')
      ul.innerHTML = ''
      for (const name of entries) {
        const li = document.createElement('li')
        li.textContent = name
        ul.appendChild(li)
      }
    }
  </script>
</body>
</html>`)

// Native → page push: set an initial status line after the window is up.
w.init("window.addEventListener('load', () => console.log('inline app loaded'))")

w.run()
console.log("window closed")
View source on GitHubexamples/webview/inline.ts