{"_id":"@audinue/ooui","name":"@audinue/ooui","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@audinue/ooui","version":"0.1.0","description":"TypeScript/Bun port of Ooui (https://github.com/praeclarum/ooui) — server-side DOM synced to the browser over WebSocket.","keywords":["ooui","websocket","server-side-dom","bun","ssr"],"publishConfig":{"access":"public"},"type":"module","main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","default":"./dist/index.js"},"./package.json":"./package.json"},"engines":{"bun":">=1.3.0"},"scripts":{"example":"bun run examples/app.ts","test":"bun test","typecheck":"tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.tests.json","format":"prettier --write .","build":"bunup","prepublishOnly":"bun run typecheck && bun run test && bun run build"},"devDependencies":{"@types/bun":"^1.3.14","bunup":"^0.16.32","playwright":"^1.62.1","prettier":"^3.9.6","typescript":"^7.0.2"},"gitHead":"85f458c68267b0db6ee394d6920b5948dc1f33b7","_id":"@audinue/ooui@0.1.0","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-Du0ud+EVmo7BhORByveUpdIQyHZ3yorMp7G9oyUd9TJByzvgKurkR7PcTMYeJcz8PAQcVGdlHgMgylXtuhRiuQ==","shasum":"1fdb0d5a6eb207a7eeac4fb628f79923b492d58f","tarball":"https://registry.npmjs.org/@audinue/ooui/-/ooui-0.1.0.tgz","fileCount":5,"unpackedSize":164797,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCcFSzPu5iWLyTo4Wus+iSM7js8GFJoY8qm+jKjDy7IUgIhAIFVez72gUeF0pqt0X08X7P0MWW0AOG1RIhbD9KS9IWt"}]},"_npmUser":{"name":"audinue","email":"audinue@gmail.com"},"directories":{},"maintainers":[{"name":"audinue","email":"audinue@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ooui_0.1.0_1786834826062_0.7867859578494183"},"_hasShrinkwrap":false}},"time":{"created":"2026-08-15T23:00:25.943Z","0.1.0":"2026-08-15T23:00:26.214Z","modified":"2026-08-15T23:00:26.388Z"},"maintainers":[{"name":"audinue","email":"audinue@gmail.com"}],"description":"TypeScript/Bun port of Ooui (https://github.com/praeclarum/ooui) — server-side DOM synced to the browser over WebSocket.","keywords":["ooui","websocket","server-side-dom","bun","ssr"],"readme":"# ooui-ts\n\nTypeScript/Bun port of [Ooui](https://github.com/praeclarum/ooui): build a UI as\na server-side DOM tree, and Ooui keeps a real browser DOM in sync with it over\na WebSocket. All app logic and state live on the server; the client is a thin\n~250-line script that applies patch messages and reports back events.\n\nPorted: the core element model (`Node`/`Element`/`Document`/`Window`/`Body`),\nthe full message protocol (`create`/`set`/`setAttr`/`remAttr`/`call`/`listen`/`event`),\ninline styles, a `classList` (`TokenList`, DOMTokenList-alike), and the common\nHTML elements (`Div`, `Span`, `Paragraph`, `Heading`, `Anchor`, `Label`,\n`Image`, `List`/`ListItem`, `Form`, `Button`, `Input`, `TextArea`,\n`Select`/`Option`). Not ported: `Ooui.Forms` (Xamarin.Forms renderers) and\n`Ooui.Wasm` (Mono/WebAssembly client) — neither has a TS/browser equivalent.\n\nThe example app pulls in [Tailwind's Play CDN](https://tailwindcss.com/docs/installation/play-cdn)\nby default (`UI.headHtml`) for zero-build styling — fine for a demo, swap it\nfor a real stylesheet (`UI.setHeadHtml(...)`) before shipping anything real.\n\n## Run the example\n\n```sh\nbun install\nbun run example\n```\n\nThen open:\n\n- `http://localhost:8080/` — index\n- `http://localhost:8080/button` — shared click counter\n- `http://localhost:8080/todo` — shared todo list\n\n## Usage\n\n```ts\nimport { UI, Div, Button } from './src/index'\n\nfunction makeApp() {\n  const button = new Button('Click me!')\n  let count = 0\n  button.onClick(() => {\n    count++\n    button.text = `Clicked ${count} times`\n  })\n  return button\n}\n\nUI.publish('/button', makeApp)\nawait UI.start()\n```\n\nEvery connected browser tab gets its own `WebSocketSession`; if you publish a\nshared element instance (like the C# sample's `UI.Publish(path, element)`\noverload) rather than a factory, all tabs share the same state.\n\n`classList` works like the browser's, and stays in sync with `className`:\n\n```ts\nbutton.classList.add('bg-blue-600', 'text-white', 'rounded')\nbutton.classList.toggle('opacity-50', isDisabled)\n```\n","readmeFilename":"README.md","_rev":"1-dc1c82f484e544693cf7c3682ae7c2a7"}