Changelog
1.1.10 — 2026-11-08
Section titled “1.1.10 — 2026-11-08”The JOPS website is live: jops.ui-db.com, with guides for every platform, concepts, the full API reference and examples. The library is identical to 1.1.9.
- The npm package’s homepage is now https://jops.ui-db.com, and the README links to it at the top.
- JOPS WordPress plugin: “Visit plugin site” opens the WordPress guide on the website, and the author link points to https://ui-db.com.
1.1.9 — 2026-11-07
Section titled “1.1.9 — 2026-11-07”Documentation only. The library is identical to 1.1.8.
Storeis described as an app-wide shared data store instead of a state container, since it stores data and has no reactivity: README heading “Store— Shared Data Store”, AI guide heading “Shared data and events:StoreandEventBus”, and theStoredescription in the type definitions.
1.1.8 — 2026-11-07
Section titled “1.1.8 — 2026-11-07”Fixes for npm install in projects created with npx jops-core init, more complete type definitions, and documentation corrections. The library only adds the Element export; its behaviour is unchanged.
npm installfailed where nobody can answer a question (CI, Docker) in web, Cordova and Capacitor projects created bynpx jops-core init: their"postinstall": "npx jops-core init"stopped at the template question and exited with an error. When input ends without an answer,initnow uses 5 (None), which only refreshes the library and adds what is missing. A piped answer (echo 2 | npx jops-core init) still works.initnow adds"postinstall": "jops-core update", which only copies the library. Existing projects keep their script; changing it tojops-core updateavoids the question.- Hello World template: the stylesheet was loaded twice (by
setStyle()and by a<link>in the layout); the layout’s<link>is removed.Media.jsis referenced with a root-based path like the other views.
Element(returned byget()andfind(id)) is exported, so it can be used in your own type annotations.Viewdeclares the optional lifecycle hooksonLayout(),onResume(),onPause()andonBackPressed(), so editors suggest and document them in subclasses.- Internal members (names starting with
_) are no longer part of the type definitions. hide(),show(),destroy()andinflate()describe their behaviour for layouts with several top-level elements.
- README:
setStyle()has no effect in any hosted mode (Next.js, WordPress,mount()), not only in Next.js; the default entry point whendata-appis missing (./src/App.js); the Electron exception to thefile://note; how the layout cache handles views loading the same file at the same moment; where to read route params; the missingimport { Router }in the Capacitor back-button example; the pin example uses the current version. - AI guide: written against 1.1.8; the same
setStyle()andpostinstallcorrections.
1.1.7 — 2026-11-07
Section titled “1.1.7 — 2026-11-07”Bug fix in addSubView(). Calls that worked before find the same container.
addSubView(containerId, view)now finds its container the same way asget(): in every top-level element of the view’s layout, in order, and the container may be a top-level element itself. Before, only the inside of the first top-level element was searched, so a container in a later top-level element (e.g.<h2>…</h2><table><tbody id="rows">) or a top-level container logged “no element #… in the view” and nothing was added.addSubView()with a container id that is not a valid CSS identifier (for example one starting with a digit) no longer throws aSyntaxError.
- README, AI guide and type definitions: the
addSubView()container lookup;insertSubView()inserts among the children of the first top-level element. TheaddSubView()parameter is namedcontainerIdin the type definitions, as in the README.
1.1.6 — 2026-11-07
Section titled “1.1.6 — 2026-11-07”Electron support in the CLI: a new Electron template, and init / update recognise Electron projects. The library is unchanged from 1.1.5.
npx jops-core inittemplate 4. Electron JOPS Desktop App: creates an Electron Forge project in the current folder (main process, preload bridge with two sample IPC calls, a JOPS SPA with a sidebar and<Router jops screens>, a Content-Security-Policy), vendors the library tosrc/lib/and runsnpm install. An existingpackage.jsonis merged (its entries are kept;jops-coregoes todevDependencies). “None” is now choice 5.initin an existing Electron project (Electron Forge’s default template, or any project withelectroninpackage.jsonthat loads a plain HTML page): vendors the library into the page’s folder (src/lib/), replaces Forge’s sample page (kept asindex.forge.html) or patches your own with the import map, the module script and a Content-Security-Policy, copies templates 1 and 2 next toindex.htmlwith page-relative paths, movesjops-coretodevDependenciesand adds ajops:updatescript. Forge’s vite and webpack templates are refused, since they bundle the page.--electronforces the project type.npx jops-core updaterefreshes the library in an Electron project;npx jops-core buildpoints tonpm run makethere.
- README: new section “Desktop Apps (Electron)”: the template, adding JOPS to an existing Electron project, paths under
file://(page-relative, no leading./or/), calling the main process through the preload bridge, events from the main process, the Content-Security-Policy, conventions. CLI and init menu updated. - AI guide: Electron section, and the path rule per setup gets an Electron line.
1.1.5 — 2026-11-03
Section titled “1.1.5 — 2026-11-03”Documentation only, no code changes.
- README and AI guide, Router screens mode: how to style screens and the Router container through the
.jops-screenand.jops-routerclasses (e.g. padding inside every screen), and which properties the Router sets inline and therefore take precedence over app CSS (position,inset,overflowandbackgroundon screens;positionandoverflowon the container). Use--jops-screen-bgfor the screen background.
1.1.4 — 2026-11-03
Section titled “1.1.4 — 2026-11-03”Maintenance release: fixes for Router transition glitches in app-like layouts, and documentation corrections. A Router without the new screens attribute behaves exactly as in 1.1.3.
Routerscreens mode, an opt-in fix for layouts where the Router fills part of a fixed app window (desktop, hybrid, a fixed toolbar). With<Router jops screens>, the Router renders into its own container (<div class="jops-router">, sized by the app’s CSS) instead of the tag’s parent element. Every route and stacked view is a full-size screen in it that scrolls on its own and has an opaque background (--jops-screen-bg, defaultCanvas). This fixes, for such layouts: views shrinking during theslideandfadetransitions, the previous view showing through the new one, the shared scroll position (Back now returns to where a list was scrolled), the transitions overwriting the parent element’s inline styles, and views with several top-level elements switching without animation. A new view covers the current one, which stays alive underneath.
- README and AI guide: new “Screens mode” section in the Router docs; removed the outdated rule that a route’s own layout (and the layout of a view added with
addSubView()) is not scanned for declared views, which no longer applies since 1.1.3.
1.1.3 — 2026-10-30
Section titled “1.1.3 — 2026-10-30”Bug fixes in rendering declared views (layouts with several top-level elements, top-level jops tags, views in Router routes, nested tags, views added with addSubView(), views removed while loading) and in the Router hiding routes. No API changes.
- Views declared in a layout with more than one top-level element are now rendered in every top-level element. Before, only the declared views (
<X jops …>tags) inside the first top-level element were rendered; tags in the second and later elements stayed in the page as unrendered elements. - A declared view (
<X jops …>) or<Router jops>that is itself a top-level element of a layout is now rendered, e.g. a layout that starts with<Header jops …></Header>followed by other elements. Before, it was rendered only when wrapped in another element. The view that owns the layout keeps the rendered elements as its own, soget(),find(),hide()/show()and removing the view also cover them. - Views declared in the layout of a
Routerroute are now rendered. Before, a route rendered only the plain HTML of its layout, and its<X jops …>tags (and those of the views inside it) stayed in the page as unrendered elements, with no error. - The
Routernow hides inactive routes and covered stacked views even when the app’s CSS sets theirdisplay(e.g..stats { display: grid }). It used only thehiddenattribute, which such CSS overrides, so the previous route stayed visible next to the new one. - A declared view nested inside another declared view’s tag (
<Outer jops><Inner jops></Inner></Outer>) is now created once and belongs to the outer view. Before, both the outer view and the view containing it could create it, depending on load timing, so it was rendered twice or owned by the wrong view. - A view added with
addSubView()orinsertSubView()now renders the views declared in its layout (<X jops …>tags), before itsonLayout(), as a declared view does. Before, only its plain HTML was shown and those tags stayed unrendered. - A view removed while its declared views are still loading now stops them: the ones that finish loading afterwards are destroyed instead of running
onLayout()/onResume()and staying attached to the removed view.
1.1.2 — 2026-10-28
Section titled “1.1.2 — 2026-10-28”WordPress integration: a JOPS SPA can now run inside a WordPress page, next to the theme and the page’s other content, through the new JOPS WordPress plugin. See the new README section “WordPress Integration”.
WordPress integration
Section titled “WordPress integration”- New JOPS WordPress plugin with the
[jops]shortcode:[jops app="/jops-spa/src/App.js" id="jops-spa-root"]embeds a JOPS app in a page, e.g. with Elementor’s Shortcode widget or the block editor’s Shortcode block. Attributes:app,id,class,lib. The plugin includes the jops-core library. One app per page; in the Elementor editor the widget shows a placeholder, and the app runs on the published page. - Install without npm:
jops-wordpress.zipis attached to every GitHub release (always the newest:https://github.com/uidb-dev/jops-core/releases/latest/download/jops-wordpress.zip); install it with wp-admin → Plugins → Add New Plugin → Upload Plugin. To update, upload the newer zip and choose “Replace current with uploaded”. npx jops-core init --wpinstalls the plugin with npm: intoplugins/jops/of awp-envproject (and adds it to.wp-env.json), otherwise into the plugins folder of the WordPress installation found in the current folder or above it (standard layout or Bedrock).--wp-root <path>points to WordPress instead of searching.npx jops-core updatealso refreshes an installed JOPS WordPress plugin and its library.
New API
Section titled “New API”View.removeSubViews(condition?): removes and destroys every subview, or only those matchingcondition(the others keep their order). Not available on aRouter(logs a warning).
- The
jops:readyevent now fires after jops-core has fully initialised, so callingmount()from the listener no longer fails (it threwCannot set properties of undefined (setting 'pushState')when the listener was registered before the library loaded).
1.1.1 — 2026-10-23
Section titled “1.1.1 — 2026-10-23”Documentation only; no library changes.
- README: hosted mode (
data-host,mount()/unmount()) moved out of the Next.js section into its own section, “Embedding JOPS in Other Pages (Hosted Mode)”, for plain HTML pages and other server frameworks. The example now loads the library from jsDelivr, and the section explains how paths resolve with the CDN (relative to the hosting page) and with a vendored library (root-absolute). Inside a Next.js page, always useJopsApp. - README:
data-root(render a standalone app into an element instead of<body>) is now documented in the CDN installation section.
1.1.0 — 2026-10-23
Section titled “1.1.0 — 2026-10-23”Next.js integration: a JOPS SPA can now run inside a page of a Next.js (App Router) app, next to React, with Next.js Route Handlers as its backend. See the new README section “Next.js Integration”. This release also adds new View and EventBus APIs and fixes found while building a full app on JOPS inside Next.js.
Next.js integration
Section titled “Next.js integration”- New
JopsAppReact component, imported fromjops-core/nextjs:<JopsApp app="/my-app/App.js" />loads the library once per page, adds the"jops-core"import map and mounts the app into its own<div>. Props:app,id,className,lib.reactandnextare optional peer dependencies; plain JOPS apps don’t need them. - Hosted mode: load jops-core with
data-hostand nothing starts automatically;window.JOPS.mount({ app, root })starts an app inside any element andwindow.JOPS.unmount()ends it.mountandunmountare also exported by the module. - Leaving the host page (a link or Back past the app’s first entry) ends the app completely: Router, views, container content,
Store,EventBusand JOPS’s history hooks are all removed. Coming back launches it again and restores the screen from the hash. Next.js links to the app’s own page are handled by the running app, and Next.js history state is kept in every entry JOPS writes. setStyle()has no effect inside Next.js: the host owns the CSS (Tailwind CSS in Next.js also scans the JOPS files inpublic/).npx jops-core inithas a new template, 3. Next.js JOPS Embedded SPA: a Next.js project with a React page, a page hosting a JOPS SPA (mock login and a quotes list) and a Route Handler backend. It is written into the current folder and merged into an existingpackage.json.npx jops-core updatedetects Next.js projects and copies the library topublic/lib/.- Standalone apps can render into an element instead of
<body>:data-root="<id>"on the jops-core script tag.
New APIs
Section titled “New APIs”onPause()lifecycle hook: called when another view comes to the front while this one stays alive (another route shown, a stacked view opened withnavigate(),replace()to another view). Pairs withonResume().- Tag props: attributes on a declared
jopstag reach the view as read-onlythis.props(camelCase names, string values), e.g.<Card jops src="/src/Card.js" title="Hi" item-id="7">→{ title: "Hi", itemId: "7" }. Views created in code can pass props as the second constructor argument:new View(layout, props). - Layouts may have several top-level elements.
get(id)searches all of them;this.domNodesholds them all (this.domNodestays the first). find(id)returns anElementfor every element with that id;find(predicate)is unchanged.EventBus.subscribe(owner, event, callback): the subscription is removed automatically when the owner (usually a view) is destroyed. Also new:EventBus.unsubscribeAll(owner)andEventBus.clear(). The globalsubscribe(event, callback)form is unchanged.Element.from(element, id).
Fixes and improvements
Section titled “Fixes and improvements”- The root view now gets the full lifecycle (
onLayout(),onResume(), event binding) andget()works on it; it used to get none, soonclickhandlers in its own layout failed. - Declared views keep their layout order, so the first route in
<Router>is reliably the default route (it used to depend on which view file loaded first). - Router routes are resumed only when shown: at startup only the selected route gets
onResume(), once (hidden routes got it too, and the selected one twice). - A view opened with
navigate()getsonResume()once (it was called twice). - An empty hash after startup (
href="#", Back to an entry without a hash) shows the default route instead of being ignored. Router.replace()keeps the existinghistory.state.loadLayout()loads once per view: overridingloadLayout()no longer fetches each layout twice, andnew View("/layout.html")+addSubView()now works (it threw aTypeError).setStyle()with inline CSS containing line breaks or quotes no longer throws aSyntaxError.Element.set(),attr()andvalue()never throw: a wrong id logs a warning with the id, and calls on a destroyed view (e.g. after an async request) do nothing.addSubView()/insertSubView()with a destroyed view, a missing container or a layout that failed to load log a warning and add nothing (they threw, or left the view half-added).View.destroy()removes the view’s ownedEventBussubscriptions; destroying the root view empties its container instead of removing it.
Behaviour changes to check
Section titled “Behaviour changes to check”npx jops-core init: “None” moved from choice 3 to choice 4. Scripts that pipe3intoinitnow get the Next.js template.find("some-id")with a string used to throw; it now returns an array ofElements.- New npm keywords:
nextjs,next-js,next.js,ssr.
1.0.15 — 2026-10-15
Section titled “1.0.15 — 2026-10-15”- CLI:
init,updateandbuildnow tell you when a newer jops-core is on npm, with the exact upgrade commands. If you runupdatebeforenpm i jops-core@latest, it explains that it copied the old version. The check takes at most 1.5 s, is silent when offline, and is skipped whenCIis set. Turn it off with--no-update-checkorJOPS_NO_UPDATE_CHECK=1. - CLI:
buildwarns whenlib/jops-core.min.jsdoesn’t match the installed package, i.e.npx jops-core updatewas forgotten after an upgrade.
1.0.14 — 2026-10-13
Section titled “1.0.14 — 2026-10-13”- Added npm keywords for hybrid mobile discoverability:
cordova,capacitor,ionic,mobile,android,ios,hybrid-app,hybrid-mobile,phonegap.
1.0.13 — 2026-10-13
Section titled “1.0.13 — 2026-10-13”Hybrid mobile support — JOPS apps now run in Apache Cordova and Capacitor (iOS + Android), tested with cordova-ios 8, cordova-android 15 and Capacitor 8. See the new README section “Hybrid Mobile Apps (Cordova, Ionic & Capacitor)”.
- Android back button: in Cordova and Capacitor (with
@capacitor/app), the hardware/gesture back button now navigates the Router (Router.back()) and closes the app on the first screen. Required on Android 16 (targetSdk 36), where back otherwise closes the app immediately. Activates only ondeviceready, so regular browsers are unaffected; opt out withdata-native-back="off"on the jops-core script tag. In Capacitor without@capacitor/app, a console warning explains what to install. npx jops-core initdetects Cordova (config.xml) and Capacitor (capacitor.config.*) projects — run it from the project root (or from insidewww//webDir) and it writes the app into the folder the shell serves. In hybrid projects it also:- adds
viewport-fit=covertoindex.html; - Cordova: allows the inline import map and
Threadworkers in the Content-Security-Policy ('unsafe-inline',blob:), addscordova.js, backs up Cordova’s sample page asindex.cordova.html, and sets the iOS custom scheme (app://localhost) inconfig.xml— existing values are never changed; - keeps
.vscode/andpackage.jsonscripts in the project root, skips thebuildscript, andnpx jops-core buildis not used there; --cordova,--capacitorand--weboverride the detection. Plain web projects get exactly the same output as before.
- adds
- Router: new
canGoBack()method. - Router fix:
onBackPressed()is no longer called on forward navigation (tapping anhref="#route"link fired it in every browser). It now runs only when the user actually navigates back. History entries carry a position (history.state.jopsIdx), so back and forward are told apart, including after a reload. - Router: tapping a flat-route link while
navigate()views are stacked now closes the stack (previously it played a back animation), and back skips the history entries of those closed views. - Hello World template: header and footer are padded with
env(safe-area-inset-*)for notches, the Dynamic Island and the home indicator (no change in regular browsers).
1.0.12 — 2026-10-10
Section titled “1.0.12 — 2026-10-10”- Router: deep links keep their query string on first load (
index.html#form?tab=2), sogetParams()returns the params immediately. - HTML file layouts:
loadLayout()and thelayout=attribute now accept.htmlfiles in addition to.jsmodules. The framework fetches and caches the file for the page lifetime — identical dedup behaviour to JS module layouts. - Path normalisation:
isCDNauto-detected at startup;normalizePath()ensures correct relative/absolute paths for CDN vs npm installs, applied at all dynamic import and fetch sites.
1.0.11 — 2026-10-09
Section titled “1.0.11 — 2026-10-09”- Router: all route subviews are now initialised as hidden, eliminating the brief flash of non-active views on first render.
- Router: initial navigation now honours a pre-existing URL hash — loading
index.html#mediaroutes directly to/mediainstead of always defaulting to the first route. - Path normalisation:
isCDNflag auto-detected at startup;normalizePath()ensures./-prefixed paths for CDN and/-prefixed paths for npm/lib installs, applied at all three dynamic import sites.
1.0.10 — 2026-10-07
Section titled “1.0.10 — 2026-10-07”- README: added “JOPS Demos” section with a link to the Hello World live demo.
1.0.9 — 2026-10-06
Section titled “1.0.9 — 2026-10-06”- New attribute syntax: use
jopsandjops-event-bindas plain boolean attributes instead oftype="jops"/type="jops-event-bind". Old syntax still works — fully backwards compatible.
1.0.8 — 2026-10-05
Section titled “1.0.8 — 2026-10-05”- README: moved “Updating the library” section to follow the npm installation section for better documentation flow.
1.0.7 — 2026-10-05
Section titled “1.0.7 — 2026-10-05”- Fixed
Thread.start(): class method shorthand (run() {}) was serialized into an invalid worker blob. Now correctly wrapped as a function expression.
1.0.6 — 2026-10-05
Section titled “1.0.6 — 2026-10-05”- Added
Threadclass: extend and overriderun(params)andonMessage(event)to run work on a Web Worker.start(params)spawns the worker;terminate()stops it. - Added
npx jops-core updatecommand: copies the latestlib/jops-core.min.jsfromnode_modulesinto the project’slib/folder without re-running full init. - README:
Threadclass reference,ThreadPoolfuture note, updating workflow docs.
1.0.5 — 2026-10-04
Section titled “1.0.5 — 2026-10-04”- Fixed CDN loading: bootstrap now uses
document.querySelector("script[data-app]")instead ofdocument.currentScript(which is alwaysnullin a module script). - Fixed CDN loading: all dynamic
import()calls for user-supplied paths now resolve againstdocument.baseURIvianew URL(path, document.baseURI).href, so layouts and view modules no longer 404 when the library is served from a different origin (e.g. jsDelivr). - README CDN snippet updated: added
type="module"to the script tag, changeddata-appto a relative path (./src/App.js), added HTTP server note.
1.0.4 — 2026-10-02
Section titled “1.0.4 — 2026-10-02”- README: added
npm i -D jops-corenote for CDN users to get editor autocomplete vialib/jops-core.d.ts.
1.0.3 — 2026-10-02
Section titled “1.0.3 — 2026-10-02”- Added TypeScript declarations (
lib/jops-core.d.ts) with JSDoc for all public exports:View,Router,Store,EventBus,layout,raw. Added"types"field topackage.json. - Updated CDN examples to jsDelivr (
@latest) in README and landing page. - MIT license.
1.0.2 — 2026-10-02
Section titled “1.0.2 — 2026-10-02”- Patch release.
1.0.1 — 2026-10-01
Section titled “1.0.1 — 2026-10-01”- Patch release.
1.0.0 — 2026-10-01
Section titled “1.0.0 — 2026-10-01”- Initial public release:
View,Router,Store,EventBus, CLI (npx jops-core init,npx jops-core build),emptyandhello-worldtemplates.