{"_id":"@aeroapp/ae","_rev":"3-ee2d2b459bb7b67eb85e42ff457559b2","name":"@aeroapp/ae","dist-tags":{"latest":"0.6.0"},"versions":{"0.4.0":{"name":"@aeroapp/ae","version":"0.4.0","keywords":["reactivity","signals","dom","binder","frontend","lightweight","no-vdom","view-transitions"],"license":"MIT","_id":"@aeroapp/ae@0.4.0","maintainers":[{"name":"0xfbfe","email":"0xfbfe7617@gmail.com"}],"homepage":"https://appaero.github.io/ae/","bugs":{"url":"https://github.com/appaero/ae/issues"},"dist":{"shasum":"99548c6e55bd3c1408a3d87b601a8fed261d1aed","tarball":"https://registry.npmjs.org/@aeroapp/ae/-/ae-0.4.0.tgz","fileCount":9,"integrity":"sha512-oYuUQJbT2oCESYWAKZeVlgtwaFQiQxKfzXNONh3SLfUyUA3lMXavZVwIVRJTrGE6gKIeFhIEOONAKGPOpgjimQ==","signatures":[{"sig":"MEQCIDrVKw3w4jsmy4IaN5QSj769I9b3EZGlWm+WsOaV/lSkAiBfRx/Y+B2yJfB9++fJ+biTDqClCL7LUI2Q0SIcSp7Nuw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":106874},"main":"dist/ae.js","type":"module","types":"dist/ae.d.ts","unpkg":"dist/ae.min.js","exports":{".":{"types":"./dist/ae.d.ts","import":"./dist/ae.js","default":"./dist/ae.js"},"./min":"./dist/ae.min.js"},"gitHead":"a449c9242a375c7e909a049e596bd4b0a6a903b0","scripts":{"min":"bun build src/ae.ts --minify --outfile=dist/ae.min.js","test":"bun run build && bun test/smoke.mjs","build":"tsc","serve":"bun scripts/serve.ts","watch":"tsc -w","prepublishOnly":"bun run test && bun run min"},"_npmUser":{"name":"0xfbfe","email":"0xfbfe7617@gmail.com"},"jsdelivr":"dist/ae.min.js","repository":{"url":"git+https://github.com/appaero/ae.git","type":"git"},"_npmVersion":"11.6.2","description":"Tiny attribute-based behavior + reactivity library. HTML is the source of truth: one data-ae attribute, signals, keyed lists, two-way forms, View-Transition animation. No virtual DOM, no hydration, no build step required.","directories":{},"sideEffects":true,"_nodeVersion":"25.1.0","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^29.1.1","typescript":"^7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/ae_0.4.0_1784296415805_0.8611468511290672","host":"s3://npm-registry-packages-npm-production"}},"0.5.0":{"name":"@aeroapp/ae","version":"0.5.0","keywords":["reactivity","signals","dom","binder","frontend","lightweight","no-vdom","view-transitions"],"license":"MIT","_id":"@aeroapp/ae@0.5.0","maintainers":[{"name":"0xfbfe","email":"0xfbfe7617@gmail.com"}],"homepage":"https://nft.github.io/ae/","bugs":{"url":"https://github.com/nft/ae/issues"},"dist":{"shasum":"05dbeea5aed4b2548577edbbda9408dd4af00275","tarball":"https://registry.npmjs.org/@aeroapp/ae/-/ae-0.5.0.tgz","fileCount":9,"integrity":"sha512-v6jtrQLGMAI4h5wJleQJlNKNEU/mk5wmeb1mxEpF93jkeBSd7y7G2DyOH/SikAvgasWjC0wnoCowmSTtSQxVTQ==","signatures":[{"sig":"MEYCIQCNY7D0Nee3+baABd+TTTGEHd8iP/G3FALzVOMXph8JkAIhAPpeZs0LzM4GtH9vDlfjln6PDXBcJRx9WJ7kjaWf35CE","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aeroapp%2fae@0.5.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":107202},"main":"dist/ae.js","type":"module","types":"dist/ae.d.ts","unpkg":"dist/ae.min.js","exports":{".":{"types":"./dist/ae.d.ts","import":"./dist/ae.js","default":"./dist/ae.js"},"./min":"./dist/ae.min.js"},"gitHead":"4cad8f976ffd96d6eb9c44cfb778a9ddded902e7","scripts":{"min":"bun build src/ae.ts --minify --outfile=dist/ae.min.js","test":"bun run build && bun test/smoke.mjs","build":"tsc","serve":"bun scripts/serve.ts","watch":"tsc -w","prepublishOnly":"bun run test && bun run min"},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7cf50f13-2aed-4208-822b-05803c0a0ba2"}},"jsdelivr":"dist/ae.min.js","repository":{"url":"git+https://github.com/nft/ae.git","type":"git"},"_npmVersion":"12.0.1","description":"Tiny attribute-based behavior + reactivity library. HTML is the source of truth: one data-ae attribute, signals, keyed lists, two-way forms, View-Transition animation. No virtual DOM, no hydration, no build step required.","directories":{},"sideEffects":true,"_nodeVersion":"22.23.1","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jsdom":"^29.1.1","typescript":"^7.0.2"},"_npmOperationalInternal":{"tmp":"tmp/ae_0.5.0_1784458777342_0.7600137930637778","host":"s3://npm-registry-packages-npm-production"}},"0.6.0":{"name":"@aeroapp/ae","version":"0.6.0","description":"Tiny attribute-based behavior + reactivity library. HTML is the source of truth: one data-ae attribute, signals, keyed lists, two-way forms, View-Transition animation. No virtual DOM, no hydration, no build step required.","keywords":["reactivity","signals","dom","binder","frontend","lightweight","no-vdom","view-transitions"],"license":"MIT","repository":{"type":"git","url":"git+https://github.com/nft/ae.git"},"homepage":"https://nft.github.io/ae/","bugs":{"url":"https://github.com/nft/ae/issues"},"type":"module","main":"dist/ae.js","types":"dist/ae.d.ts","exports":{".":{"types":"./dist/ae.d.ts","import":"./dist/ae.js","default":"./dist/ae.js"},"./min":{"types":"./dist/ae.d.ts","import":"./dist/ae.min.js","default":"./dist/ae.min.js"}},"unpkg":"dist/ae.min.js","jsdelivr":"dist/ae.min.js","sideEffects":true,"publishConfig":{"access":"public"},"scripts":{"build":"tsc","watch":"tsc -w","test":"bun run build && bun test/smoke.mjs","test:browser":"playwright test","serve":"bun scripts/serve.ts","min":"bun build src/ae.ts --minify --outfile=dist/ae.min.js","site:css":"tailwindcss -c site/tailwind.config.js -i site/tailwind.in.css -o site/tailwind.css --minify","prepublishOnly":"bun run test && bun run min"},"devDependencies":{"@playwright/test":"^1.54.0","jsdom":"^29.1.1","tailwindcss":"^3.4.0","typescript":"^7.0.2"},"gitHead":"5cda0e112b5cc2273d5d616e7d798de7b271ab9e","_id":"@aeroapp/ae@0.6.0","_nodeVersion":"22.23.1","_npmVersion":"12.0.1","dist":{"integrity":"sha512-g5s60iuJR42N2XRTyEHLXXZ5N4hQ4oZoYlZlcuuKvlfqE535d+JMy5Ypd9tMVub0pyOXTZaHEFXNwYSbvn/+ig==","shasum":"53ee391254ffff031209bdc7ff7b1ac5dc001282","tarball":"https://registry.npmjs.org/@aeroapp/ae/-/ae-0.6.0.tgz","fileCount":25,"unpackedSize":144718,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@aeroapp%2fae@0.6.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCICDLGkVsChghVLIvaaHL9HqL7mVxqOB4tc1KsaUHsaOGAiAmhGDxdzoKc/EOICTSya9qRSaNDMoAPl/nXyfjoO6Iww=="}]},"_npmUser":{"name":"GitHub Actions","email":"npm-oidc-no-reply@github.com","trustedPublisher":{"id":"github","oidcConfigId":"oidc:7cf50f13-2aed-4208-822b-05803c0a0ba2"}},"directories":{},"maintainers":[{"name":"0xfbfe","email":"0xfbfe7617@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/ae_0.6.0_1784498804735_0.8424068686953663"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-17T13:53:35.666Z","modified":"2026-07-19T22:06:45.279Z","0.4.0":"2026-07-17T13:53:35.951Z","0.5.0":"2026-07-19T10:59:37.464Z","0.6.0":"2026-07-19T22:06:44.862Z"},"bugs":{"url":"https://github.com/nft/ae/issues"},"license":"MIT","homepage":"https://nft.github.io/ae/","keywords":["reactivity","signals","dom","binder","frontend","lightweight","no-vdom","view-transitions"],"repository":{"type":"git","url":"git+https://github.com/nft/ae.git"},"description":"Tiny attribute-based behavior + reactivity library. HTML is the source of truth: one data-ae attribute, signals, keyed lists, two-way forms, View-Transition animation. No virtual DOM, no hydration, no build step required.","maintainers":[{"name":"0xfbfe","email":"0xfbfe7617@gmail.com"}],"readme":"<p align=\"center\">\n  <img src=\"site/logo.svg\" alt=\"ae logo\" width=\"180\" />\n</p>\n\n# ae\n\n[![npm](https://img.shields.io/npm/v/%40aeroapp%2Fae?label=npm&color=b45309)](https://www.npmjs.com/package/@aeroapp/ae)\n[![CI](https://github.com/nft/ae/actions/workflows/ci.yml/badge.svg)](https://github.com/nft/ae/actions/workflows/ci.yml)\n[![license](https://img.shields.io/badge/license-MIT-stone)](LICENSE)\n\nTiny attribute-based behavior + reactivity library. **HTML is the source of\ntruth** — you write real markup, `ae` attaches behavior to it. No virtual DOM,\nno hydration, no template syntax, no build step required.\n\n**3.9 KB** min+gzip · zero dependencies · TypeScript · one `data-ae` attribute\n\n## Install\n\n```sh\nnpm install @aeroapp/ae\nyarn add @aeroapp/ae\npnpm add @aeroapp/ae\nbun add @aeroapp/ae\n```\n\nOr straight from a CDN, no tooling at all — esm.sh, unpkg, and jsDelivr all\nserve it the moment you need it:\n\n```html\n<script type=\"module\">\n  import { ae } from 'https://esm.sh/@aeroapp/ae';\n  // or: 'https://unpkg.com/@aeroapp/ae'                  (minified build)\n  // or: 'https://cdn.jsdelivr.net/npm/@aeroapp/ae/+esm'\n</script>\n```\n\nPin an exact version in production — `https://esm.sh/@aeroapp/ae@X.Y.Z` (see\nthe npm badge above for the current release).\n\n```html\n<button data-ae=\"save\">Save</button>\n<span data-ae=\"status\"></span>\n```\n\n```js\nimport { ae } from '@aeroapp/ae';\n\nconst count = ae.signal(0);\n\nae('status').render(el => el.textContent = `${count.value} items`);\n\nae('save')\n  .press(() => count.value++)\n  .hover(el => el.classList.add('hot'), el => el.classList.remove('hot'));\n```\n\nHandles are **live**: elements added to the DOM later — by you, by `.list()`,\nby anything — get bound automatically via one shared `MutationObserver`, and\ncleaned up completely when they leave. No manual unbinding, no leaks.\n\n## Feature tour\n\n**Signals** — `ae.signal(v)`, `ae.computed(fn)`, `ae.effect(fn)`. Writes are\nbatched per microtask; computeds are lazy and only notify when their value\nactually changes.\n\n**Rendering** — `.render(fn)` auto-tracks every signal read inside and re-runs\non change. Sugar helpers `.text()` / `.cls()` / `.attr()` / `.show()` accept a\nplain value (applied once), a signal, or a function (both reactive).\n\n**Events** — `.press(fn)` is semantic activation: click everywhere, plus\nnative-like Enter/Space only for elements the browser doesn't natively\nactivate (keyboard-accessible `div[tabindex]`, `[role=button]` for free, no\ndouble-fire on real buttons). Enter fires on keydown, Space on keyup —\nexactly like a native button — and keys inside nested form controls or\neditable text are never hijacked. `.hover(enter, leave)` and the `.on(type,\nfn, opts)` escape hatch round it out — all listeners per element, so\nnon-bubbling events just work.\n\n**Keyed lists** — `.list(items, render, key)` stamps a native `<template>`\nper item with keyed reconciliation: reorders move nodes without remounting,\nunchanged items don't re-render, removed items are disposed.\n\n```html\n<ul data-ae=\"todos\">\n  <template><li><b data-ae=\"title\"></b></li></template>\n</ul>\n```\n\n```js\nae('todos').list(todos, (li, todo, i) => {\n  ae.parts(li).title.textContent = `${i + 1}. ${todo.text}`;\n}, todo => todo.id);\n\nae('remove').press(btn => {                 // which item was clicked?\n  const todo = ae.itemOf(btn);              // ae knows — no key stamping\n  todos.value = todos.value.filter(t => t.id !== todo.id);\n});\n```\n\n**Two-way forms** — `.input(signal)` wires by field type: strings for\ntext/select, booleans for checkboxes, real numbers for number/range, a group\nvalue for radios, and `string[]` for `<select multiple>`. Writes are\nequality-guarded so echoes never move the caret.\n\n**Scoped roots** — `ae(name, root)` limits a handle to descendants of `root`:\nper-list behavior without global name collisions.\n\n**Shadow DOM** — `ae.observe(shadowRoot)` extends the same liveness into a\nshadow tree: existing marked content mounts immediately, host removal cleans\neverything up, and the returned disposer undoes it all.\n\n**Animation** — `ae.transition(fn)` runs your signal writes inside a browser\nView Transition: list enters, exits, and reorders animate in pure CSS, and\nelements with a `view-transition-name` morph — even across lists. Falls back\nto a plain call where unsupported.\n\nFull API and semantics: **[API.md](API.md)**. Compact API reference for AI\nagents: **[llms.txt](llms.txt)**. Live demos: `bun run serve` →\nhttp://localhost:4242.\n\nReal app: **[examples/kanban.html](examples/kanban.html)** — a kanban with\ndrag & drop, dynamic columns, inline editing, undo, filtering, and\nlocalStorage persistence in ~170 lines of JS. One-pager with live demos:\n**[site/index.html](site/index.html)** (deployed to GitHub Pages).\n\n## Performance\n\nKeyed-list stress numbers, measured **end-to-end** — signal write through\nreconciliation, mount pipeline, layout, and paint (headless Chrome, Apple\nM4 Max; median of 3 runs). Each row carries three live `data-ae` bindings,\ntwo of them event listeners.\n\n| operation | time |\n|---|---|\n| create 1,000 rows | 26 ms |\n| create 10,000 rows | 262 ms |\n| append 1,000 to 10,000 | 69 ms |\n| update every 10th of 11,000 | 117 ms |\n| swap 2 rows of 11,000 | 75 ms |\n| clear 11,000 rows | 58 ms |\n\nReproduce: `bun run serve` → `examples/bench.html` (add `?auto` for the\nfull suite).\n\n## Development\n\n```sh\nbun install\nbun run build          # tsc → dist/*.js + declarations (entry: dist/ae.js)\nbun run test           # jsdom smoke suite (build first)\nbun run test:browser   # Playwright: Chromium, Firefox, WebKit\nbun run serve          # demo at http://localhost:4242\nbun run min            # dist/ae.min.js\n```\n\n## Guarantees (the short version)\n\n- **Batching** — signal writes coalesce; each effect runs at most once per flush.\n- **Absolute disposal** — a disposed effect never runs again, even if already queued.\n- **Net-state lifecycle** — mount/cleanup reflect the *net* DOM change per task:\n  moves don't remount, `a→b→a` renames are no-ops.\n- **Fault isolation** — one throwing effect/binding/cleanup never takes down the rest.\n- **Runaway guard** — a self-triggering effect trips a circuit breaker instead of hanging the tab.\n\n## License\n\n[MIT](LICENSE)\n","readmeFilename":"README.md"}