{"_id":"@angerenage/jtx","_rev":"7-94bd93899dc937525c97ab08b83f1dc0","name":"@angerenage/jtx","dist-tags":{"latest":"1.1.1"},"versions":{"1.0.1":{"name":"@angerenage/jtx","version":"1.0.1","keywords":["reactive","frontend","html","json","jtx"],"author":{"name":"Ange Rollet"},"license":"MIT","_id":"@angerenage/jtx@1.0.1","maintainers":[{"name":"angerenage","email":"ange.renage@gmail.com"}],"dist":{"shasum":"3379205769aa5e4175d02c23bc202d9a1c91d138","tarball":"https://registry.npmjs.org/@angerenage/jtx/-/jtx-1.0.1.tgz","fileCount":7,"integrity":"sha512-PvUheZSEPzkpMJcXIYzF5i6E0BHvgCu+qlkHYvKUcINF+YF/KnycLxU96VIA1uObyloyxki1BqlZi9mF4Pq1FA==","signatures":[{"sig":"MEQCIAtzEeOlr5HudxSsreVpg4g2LWkg6YZADjLn9K9SkbQJAiAzWiqe4hccZq6UqT9vcQw6ETouhT3vhghSLKvEaXs4ww==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":201919},"main":"dist/jtx.umd.js","unpkg":"dist/jtx.umd.js","module":"dist/jtx.esm.js","gitHead":"93761842896577e7ecbace8307e0d6d73424820c","scripts":{"lint":"eslint src","build":"esbuild src/index.js --bundle --format=esm --outfile=dist/jtx.esm.js --minify --sourcemap && esbuild src/index.js --bundle --format=iife --global-name=JTX --outfile=dist/jtx.umd.js --minify --sourcemap","prepublishOnly":"npm run lint && npm run build"},"_npmUser":{"name":"angerenage","email":"ange.renage@gmail.com"},"_npmVersion":"10.8.2","description":"Tiny, build-free library that adds reactive, JSON-driven interactivity to server-rendered HTML using simple tags and attributes.","directories":{},"_nodeVersion":"20.19.5","_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.35.0","esbuild":"^0.25.9"},"_npmOperationalInternal":{"tmp":"tmp/jtx_1.0.1_1757613142981_0.3873618258162488","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@angerenage/jtx","version":"1.0.2","keywords":["reactive","frontend","html","json","jtx"],"author":{"name":"Ange Rollet"},"license":"MIT","_id":"@angerenage/jtx@1.0.2","maintainers":[{"name":"angerenage","email":"ange.renage@gmail.com"}],"dist":{"shasum":"104e245b1ce487d2d1e6453df64d6335ef22e10b","tarball":"https://registry.npmjs.org/@angerenage/jtx/-/jtx-1.0.2.tgz","fileCount":8,"integrity":"sha512-tzMKd7h+ocVKKEc8njXfeT/VscvEX5ollDtW0o9vBHGdam0sV/FiKVwM1Y4xxXtVEg8RdtKorOWDHQDQ/A3DMg==","signatures":[{"sig":"MEUCICmBuM2XSNBU48P/Uav7OMRtYZVEz64PRmNYQ46aHSdCAiEAzDiq5gCOjgwVmZx9+vlSSFw6GkGwLnUwjhN1Lhu3NWs=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":224876},"main":"dist/jtx.umd.js","unpkg":"dist/jtx.umd.js","module":"dist/jtx.esm.js","gitHead":"73d2d2342211994db50b5c91ddfd0ebe63339a76","scripts":{"lint":"eslint src","build":"esbuild src/index.js --bundle --format=esm --outfile=dist/jtx.esm.js --minify --sourcemap && esbuild src/index.js --bundle --format=iife --global-name=JTX --outfile=dist/jtx.umd.js --minify --sourcemap","prepublishOnly":"npm run lint && npm run build"},"_npmUser":{"name":"angerenage","email":"ange.renage@gmail.com"},"_npmVersion":"10.8.2","description":"Tiny, build-free library that adds reactive, JSON-driven interactivity to server-rendered HTML using simple tags and attributes.","directories":{},"_nodeVersion":"20.19.5","_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.35.0","esbuild":"^0.25.9"},"_npmOperationalInternal":{"tmp":"tmp/jtx_1.0.2_1757614311564_0.3365368500815282","host":"s3://npm-registry-packages-npm-production"}},"1.1.0":{"name":"@angerenage/jtx","version":"1.1.0","keywords":["reactive","frontend","html","json","jtx"],"author":{"name":"Ange Rollet"},"license":"MIT","_id":"@angerenage/jtx@1.1.0","maintainers":[{"name":"angerenage","email":"ange.renage@gmail.com"}],"dist":{"shasum":"4806736806006694ab85ee172114d0bc55bf5d2d","tarball":"https://registry.npmjs.org/@angerenage/jtx/-/jtx-1.1.0.tgz","fileCount":8,"integrity":"sha512-fZIIzSezz7N++MdespSGAyg2Jb2OPhrT8xwsBoHG0pWyBO7Y9QMPgcz4gDAG4Zv+XsMtSSukkg+jYTOYhu2esw==","signatures":[{"sig":"MEUCICOPM/a87CPiL9wV7++R3X4R5kGuLugVvzGaec9Sn6OHAiEAw0KWiY5o9jmaguCPqtjIJB8KsBUmcycGgGrovOQ597w=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":314311},"main":"dist/jtx.umd.js","unpkg":"dist/jtx.umd.js","module":"dist/jtx.esm.js","gitHead":"757e393ef7f61007bb0c087c95178af89e12f5da","scripts":{"lint":"eslint src","build":"esbuild src/index.js --bundle --format=esm --outfile=dist/jtx.esm.js --minify --sourcemap && esbuild src/index.js --bundle --format=iife --global-name=JTX --outfile=dist/jtx.umd.js --minify --sourcemap","prepublishOnly":"npm run lint && npm run build"},"_npmUser":{"name":"angerenage","email":"ange.renage@gmail.com"},"_npmVersion":"10.8.2","description":"Tiny, build-free library that adds reactive, JSON-driven interactivity to server-rendered HTML using simple tags and attributes.","directories":{},"_nodeVersion":"20.19.5","_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.35.0","esbuild":"^0.25.9"},"_npmOperationalInternal":{"tmp":"tmp/jtx_1.1.0_1757741324523_0.7137233200041644","host":"s3://npm-registry-packages-npm-production"}},"1.1.1":{"name":"@angerenage/jtx","version":"1.1.1","main":"dist/jtx.umd.js","type":"module","module":"dist/jtx.esm.js","unpkg":"dist/jtx.umd.js","scripts":{"lint":"eslint src","build":"esbuild src/index.js --bundle --format=esm --outfile=dist/jtx.esm.js --minify --sourcemap && esbuild src/index.js --bundle --format=iife --global-name=JTX --outfile=dist/jtx.umd.js --minify --sourcemap","prepublishOnly":"npm run lint && npm run build","test":"node --test \"test/*.test.mjs\"","manual:test":"node test/manual/api/server.mjs"},"keywords":["reactive","frontend","html","json","jtx"],"author":{"name":"Ange Rollet"},"license":"MIT","description":"Tiny, build-free library that adds reactive, JSON-driven interactivity to server-rendered HTML using simple tags and attributes.","devDependencies":{"esbuild":"^0.25.9","eslint":"^9.35.0","jsdom":"^25.0.1","ws":"^8.18.0"},"repository":{"type":"git","url":"git+https://github.com/angerenage/jtx.git"},"homepage":"https://github.com/angerenage/jtx#readme","bugs":{"url":"https://github.com/angerenage/jtx/issues"},"_id":"@angerenage/jtx@1.1.1","gitHead":"91e32d537e0720c52b2433fff09f974839b7b39c","_nodeVersion":"22.19.0","_npmVersion":"11.6.0","dist":{"integrity":"sha512-cqmPcXAooN+VRHXsUtH47q2cA6doAxFa8jj/qft/1ugMQF5t0Pjp4OdLuO8ieLv+g9DxJN729q4QdngXtxsHXQ==","shasum":"da1ca1b11414d6fe5d102cab26a0612aa0e91a31","tarball":"https://registry.npmjs.org/@angerenage/jtx/-/jtx-1.1.1.tgz","fileCount":8,"unpackedSize":352625,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIGEqsX9dleRCRQkGGvox0NuHxZWqxag/IVGj1qoV7zF8AiEA70TwIPWkjNAeoDwYzViYFlLnZV0xf7tC0rHfB7u90Sc="}]},"_npmUser":{"name":"angerenage","email":"ange.renage@gmail.com"},"directories":{},"maintainers":[{"name":"angerenage","email":"ange.renage@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/jtx_1.1.1_1759532834203_0.6450682975145663"},"_hasShrinkwrap":false}},"time":{"created":"2025-09-11T17:52:22.911Z","modified":"2025-10-03T23:07:14.578Z","1.0.0":"2025-09-08T00:09:19.833Z","1.0.1":"2025-09-11T17:52:23.168Z","1.0.2":"2025-09-11T18:11:51.840Z","1.1.0":"2025-09-13T05:28:44.753Z","1.1.1":"2025-10-03T23:07:14.404Z"},"author":{"name":"Ange Rollet"},"license":"MIT","keywords":["reactive","frontend","html","json","jtx"],"description":"Tiny, build-free library that adds reactive, JSON-driven interactivity to server-rendered HTML using simple tags and attributes.","maintainers":[{"name":"angerenage","email":"ange.renage@gmail.com"}],"readme":"# JTX — Add interactivity to HTML, no framework required\r\n\r\nJTX is a tiny library that makes a server‑rendered page feel alive. Keep writing normal HTML on the server; sprinkle a few small tags and attributes in your markup; JTX binds your JSON data to the page so it updates reactively — without a build step or a virtual DOM.\r\n\r\nFor the full, precise specification, see [SPEC.md](SPEC.md). This README is a practical \"how to\".\r\n\r\n**What JTX is**\r\n- A lightweight layer on top of your existing HTML.\r\n- Driven by JSON from HTTP/SSE/WebSocket sources or local state.\r\n- Declarative: add attributes/tags; JTX updates the DOM for you.\r\n- Build‑free: include a script and you’re done.\r\n\r\n**Why use it**\r\n- Keep SSR and progressively enhance with minimal client code.\r\n- Great for lists, text, toggles, and live feeds.\r\n- Stays close to the platform — just HTML + a few helpers.\r\n\r\n## Quick Start\r\n- NPM: `npm install @angerenage/jtx`\r\n- CDN: `<script src=\"https://unpkg.com/@angerenage/jtx\"></script>`\r\n\r\nJTX auto‑initializes on `DOMContentLoaded`. If you append HTML later, call `JTX.init(subtreeElement)`.\r\n\r\n## Core Concepts\r\n- `@name.path`: read values from a state or source.\r\n- Expressions are plain JS (in attribute values).\r\n- Event handlers use `jtx-on=\"event: code\"`.\r\n\r\nHelpers available in expressions and handlers:\r\n- `emit(name, detail)`: dispatch a custom event on the current element.\r\n- `refresh('srcName')` or `@src.refresh()`: re‑fetch a source.\r\n- `get/post/put/patch/del(url, [bodyOrHeaders], [headers])`: thin `fetch` helpers.\r\n- `$event`: current event in `jtx-on`.\r\n- `$el`: current element.\r\n\r\n## jtx‑state — Local, Mutable State\r\nDeclare a state and expose keys as data to descendants.\r\n\r\n```html\r\n<jtx-state name=\"ui\" counter=\"0\" theme=\"'light'\" persist=\"theme\" persist-url=\"counter\">\r\n  <button jtx-on=\"click: @ui.counter++\">+</button>\r\n  <span jtx-text=\"@ui.counter\"></span>\r\n</jtx-state>\r\n```\r\n\r\n- `name` (required): unique id.\r\n- Any other attribute becomes a key (evaluated once at init).\r\n- `persist`: comma‑separated keys saved to `localStorage`.\r\n- `persist-url`: comma‑separated keys synced to query string.\r\n\r\nEvents you can listen to (they bubble):\r\n- `init`: `{ name, value }` when created.\r\n- `update`: `{ name, keys, value }` after batched changes.\r\n\r\nTwo‑way binding with form elements via `jtx-model`:\r\n\r\n```html\r\n<jtx-state name=\"form\" email=\"''\">\r\n  <input type=\"email\" jtx-model=\"@form.email\">\r\n  <p jtx-text=\"@form.email\"></p>\r\n</jtx-state>\r\n```\r\n\r\nNotes:\r\n- States are scoped: a `<jtx-state>` inside a template/section shadows outer states of the same name.\r\n\r\n## jtx‑src — Remote or Streaming Data\r\nFetch JSON over HTTP or stream JSON via SSE/WebSocket. Use child content to render the value.\r\n\r\n```html\r\n<!-- HTTP example: fetch on load and every 30s -->\r\n<jtx-src name=\"orders\" url=\"/api/orders\" fetch=\"onload, every 30s\" select=\"items\">\r\n  <jtx-loading>Loading…</jtx-loading>\r\n  <jtx-error>Could not load orders.</jtx-error>\r\n  <jtx-empty>No orders yet.</jtx-empty>\r\n\r\n  <ul>\r\n    <jtx-insert for=\"o in @orders\">\r\n      <jtx-template>\r\n        <li>\r\n          <span jtx-text=\"o.id\"></span> — <span jtx-text=\"o.title\"></span>\r\n        </li>\r\n      </jtx-template>\r\n    </jtx-insert>\r\n  </ul>\r\n</jtx-src>\r\n```\r\n\r\n```html\r\n<!-- SSE example: stream events; optionally filter with sse-event -->\r\n<jtx-src name=\"feed\" url=\"sse:/events\" sse-event=\"tick\">\r\n  <p jtx-text=\"@feed.$status\"></p>\r\n</jtx-src>\r\n\r\n<!-- WebSocket example -->\r\n<jtx-src name=\"chat\" url=\"wss:/ws/chat\"></jtx-src>\r\n```\r\n\r\nAttributes:\r\n- `name` (required): unique id.\r\n- `url` (required): HTTP (`/api` or `https://…`), SSE (`sse:/path`), WS (`ws:/…` or `wss:/…`).\r\n- `fetch`: when to fetch (HTTP only): `onload` (default), `idle`, `visible`, `every 5s`, or `manual` for manual control.\r\n- `headers`: JSON or expression for request headers, e.g. `{ Authorization: 'Bearer ' + @auth.token }`.\r\n- `select`: dot‑path to pick a nested value from the JSON payload.\r\n- `sse-event`: for SSE, only handle a specific event type.\r\n\r\nChildren you can add inside a `jtx-src` (optional): `jtx-loading`, `jtx-error`, `jtx-empty`.\r\n\r\nProgrammatic refresh:\r\n- In JS: `JTX.refresh('orders')`\r\n- In expressions/handlers: `@orders.refresh()` or `refresh('orders')`\r\n\r\nSource status and error are readable in expressions:\r\n- `@orders.$status` is one of `idle | loading | ready | error`\r\n- `@orders.$error` contains last error, if any\r\n\r\nEvents you can listen to on the `<jtx-src>` element:\r\n- `init`: `{ name }` when registered.\r\n- `fetch`: `{ url, headers }` before an HTTP request.\r\n- `update`: `{ name, value }` after new data is set.\r\n- `error`: `{ name, type, status?, message, raw? }` on network/parse/connection errors.\r\n- `open`: `{ name, type: 'sse' | 'ws' }` when a stream opens.\r\n- `close`: `{ name, code?, reason? }` when a stream closes.\r\n- `message`: `{ name, type, data, lastEventId? }` for raw SSE/WS messages. For SSE events, JTX also dispatches a DOM event named after it's type on the `<jtx-src>` in addition to `message`.\r\n\r\n## Rendering Helpers (Attributes)\r\nUse these attributes anywhere in your HTML:\r\n\r\n- `jtx-if=\"expr\"`: add/remove the element based on truthiness.\r\n- `jtx-show=\"expr\"`: toggle `hidden` attribute.\r\n- `jtx-text=\"expr\"`: set `textContent` (falls back to original content if `null/undefined`).\r\n- `jtx-html=\"expr\"`: set `innerHTML` (you are responsible for sanitizing).\r\n- `jtx-attr-FOO=\"expr\"`: bind any attribute `FOO` (boolean true => present, false/null/undefined => removed).\r\n- `jtx-model=\"@state.key\"`: two‑way bind form inputs/selects/textarea to state (supports nested paths like `@state.user.name`).\r\n- `jtx-on=\"event: code; other: code\"`: run JS on events. Also supports timers: `every 5s: code`.\r\n\r\n## Lists and Templates — `<jtx-insert>`\r\nInsert text/HTML or render lists with a template.\r\n\r\nScalar insert:\r\n```html\r\nHello, <jtx-insert text=\"@user.name\">guest</jtx-insert>!\r\n```\r\n\r\nList insert:\r\n```html\r\n<jtx-insert for=\"item in @orders\" key=\"item.id\" strategy=\"replace\">\r\n  <jtx-template>\r\n    <div>\r\n      <span jtx-text=\"item.id\"></span>\r\n      <span jtx-text=\"item.title\"></span>\r\n    </div>\r\n  </jtx-template>\r\n</jtx-insert>\r\n```\r\n\r\nOptions:\r\n- `for` (required for lists): `item in <expr>` or `value,key in <expr>`.\r\n- `key`: stable key per item (recommended; required to accumulate with merge).\r\n- `strategy`:\r\n  - `replace` (default): remove all current items and insert the new ones from scratch.\r\n  - `append`: always add the received item(s) to the end.\r\n  - `prepend`: always add the received item(s) to the beginning.\r\n  - `append merge`: keyed upsert — update existing items by key; append new keys; respects `window` (trims from start).\r\n  - `prepend merge`: keyed upsert — update existing items by key; prepend new keys; respects `window` (trims from end).\r\n- `window`: required for merge strategies and optional for append/prepend — caps the number of rendered items.\r\n- Optional children: `jtx-loading`, `jtx-error`, `jtx-empty` (useful when nested under a `jtx-src`).\r\n\r\n## Initialization Hooks\r\n- Auto‑init on page load. To initialize a dynamically inserted subtree: `JTX.init(element)`.\r\n- Attributes inside `<jtx-template>` are compiled per item when the list renders.\r\n\r\n## Tips\r\n- Keep expressions simple and safe; they run in the browser.\r\n- Prefer `select` on `jtx-src` to avoid repeating deep paths in templates.\r\n- Unknown `@name` references warn in the console; check your `name` attributes.\r\n\r\n## Learn More\r\n- Detailed behavior, edge cases, and full semantics: see [SPEC.md](SPEC.md).\r\n\r\n## License\r\nMIT — see [LICENSE](LICENSE).\r\n","readmeFilename":"README.md","homepage":"https://github.com/angerenage/jtx#readme","repository":{"type":"git","url":"git+https://github.com/angerenage/jtx.git"},"bugs":{"url":"https://github.com/angerenage/jtx/issues"}}