All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
refresh re-runs the element's live reactive functions instead of re-patching config properties: static values are not re-applied, and detail must name a bound path ("style" for a reactive style map, "style.color" for a function inside a static one).mounted no longer sorts new nodes by document position, and the children diff skips serializing nodes when one side is empty.npm run build checks dist/ against browserslist in a postbuild step, replacing npm run check.neux global (const { signal } = neux) use the global context, as neux.effect() does, instead of a separate window context that left their signals and effects disconnected.untrack()), so list.push() or state.count++ inside it no longer loops; a write to the same key from elsewhere still re-runs it.untrack() or a setter tracks its own reads and owns its writes, from its getter and setter alike, without changing the enclosing effect's tracking.children list replaces its children before their bindings re-run against stale state.refresh event no longer revives it.length readers; assigning a smaller length re-runs readers of dropped indices, keys, and in.state.selected === state.items[0]); an assigned proxy is stored as its plain object.state.list.constructor === Array); a plain object with its own constructor key is reactive.DocumentFragment in children or render() contributes its child nodes, which now mount, release their bindings on removal, and are diffed individually.children list holding an existing Node and an equal new sibling no longer drops one of them.children re-render whose new child binding throws releases the nodes it already built.removed cascades through elements Neux did not build (such as a supplied wrapper), so Neux elements inside release their bindings and re-mount on re-insertion.value that started undefined) instead of keeping the last value.style key removes the empty style attribute.style key for a custom property with uppercase letters (--myColor) is applied.use string with surrounding whitespace ("span ") is trimmed instead of rendering a div.i18n() resolves a language to the closest locale: an exact key (case- and separator-insensitive, ru_RU ≡ ru-RU) or the longest key the language starts with at a subtag boundary (de_DE → de, but not run-BI → ru). Odd tags such as ru_RU.UTF-8 and an unparseable language or fallback no longer throw.i18n() formatting keeps a script subtag (sr-Latn, zh-Hant).i18n() reports a missing key once per locale (the matched one, or the requested language when none matches); a null placeholder value is left as is; null data (t(5, null, "de")) no longer throws.README.md, SKILL.md, AGENTS.md, and TypeDoc corrected to match behavior, with fixed examples. New notes: Object.defineProperty() on a signal does not re-run effects; elements inserted with DOM APIs into a mounted parent never get mounted/removed; the children diff ignores Shadow DOM content; use markup with no element renders an empty div; dataset keys must be camelCase.npm run format (Prettier) and npm run check (verifies dist/ against the browserslist targets via es-check).NodeConfigList and ClassName types; children and render() accept nested arrays, and className entries may be numbers, booleans, null, or undefined. classList is typed as an alias of className.README.md warns that children that look identical share the existing element, including its event handlers, and shows how to tell them apart.mounted fires top-down on the initial mount and on re-mounts, matching removed.NodeConfig includes number and boolean. null, undefined, and booleans are skipped in children and className; strings and numbers (including 0) are used as is.render() returns null for a config it cannot render (boolean, null, undefined, a class instance, Date, function, or symbol) instead of an empty div. Null-prototype objects render like plain objects.ReactiveProperty<T> accepts functions returning Promise<T>. A binding that resolves to null or undefined restores the property's original value.list.splice() re-runs a children function once.children re-run matches reordered items by markup lookup, so the work grows linearly with the list size. Equal nodes whose attributes were set in a different order are rebuilt.updated no longer fires when className or children re-run to the same result; its details are the applied class names and the child nodes in the DOM.i18n() keys are reported through reportError (or console.error) instead of being swallowed or left unhandled. i18n() reports each missing key once per language and returns the key.Proxy objects and record each effect subscription once per run..d.ts.map files.require export condition: the package is ESM-only. require("neux") works on Node 22.12+; the UMD build stays for browsers.Node passed as a child is never released when an equal existing child is kept.mounted/removed exactly once per insertion.refresh with a nested path or a key of a reactive attributes, style, or dataset function works, no longer overwrites config functions, and ignores properties the config does not bind and removed elements.attributes, style, and dataset maps remove dropped keys and clear only what they applied. Clearing a camelCase style key reports undefined in updated.use markup keeps elements such as <tr>, <td>, and <option> and tolerates leading whitespace; #id and .class selectors apply to custom elements.className entries with spaces no longer throw, and a numeric 0 is applied as a class. Children of an SVG foreignObject are HTML elements.Object.keys(), in, for...in); a computed getter that returns a function is evaluated on every read; writing NaN over NaN or deleting a missing key does not re-run effects; a throwing getter or setter no longer leaves the context stuck; an effect created inside another no longer stops its tracking; empty subscriber sets are released.effect() whose first run throws is disposed before the error propagates.signal(), effect(), untrack(), and render() work through a module namespace (import * as neux, UMD global) using the global context.i18n() falls back from a regional language to its base (ru-RU → ru), also for fallback; ignores inherited keys such as toString; treats a key naming a nested group as missing; leaves unknown %{key} placeholders as is; and no longer throws where navigator is undefined.node16/nodenext get types, and test coverage instruments src/**/*.ts.README.md, SKILL.md, TypeDoc) corrected and extended: className replaces existing classes, style keys are camelCase, updated semantics, detached render(), nested function properties, i18n() formatting, the children diff ignoring element properties, and the signal limits (only plain objects and arrays are reactive, length truncation, frozen data).Node type for this inside render event handlers and reactive properties.render function to return a typed value.Node[] instead of DocumentFragment.Proxy objects from signals.mounted events on nested render children.mounted events firing on unrelated target children.render() now skips falsy entries in children arrays.typedoc-plugin-markdown.neux.dev.@skillit/typedoc with per-module entry points.npm run docs).AGENTS.md with project conventions and development guidelines for AI agents.use config option in render() for specifying an alternate element source (config, HTML markup, or existing Element).untrack() function for non-reactive reads.typecheck script for standalone type checking.effect() function is now debounced and simplifies subscription management.get) instead of callback functions.render() signature has been simplified to accept a single config object; the HyperScript-style multi-argument syntax is removed.classList option has been renamed to className for consistency with the DOM API; classList still works as a backwards-compatible alias.l10n() function has been renamed to i18n().tests/ to co-located src/**/*.test.ts files, run via tsx.dist/ instead of a separate types/ directory.MutationObserver.render() API.$ property prefix; use plain property names instead.mount() function; render() now accepts an optional second argument (target element, DocumentFragment, or CSS selector) and mounts automatically.changed lifecycle event; attribute changes from external sources are no longer observed.$$on(), $$once(), $$off(), and $$emit() helpers on signal proxies.tag property in element config; use tagName or use instead.ref callback in element config; use the mounted event handler instead.(obj, prop) arguments; use this and getter syntax instead.context.js, emitter.js, and utils.js; functionality was inlined.types/*.d.ts declaration files.