# Migrating from older versions

<!--{ "pin": "bottom", "parent": "Appendices", "order": 60, "description": "Breaking changes in tosijs-ui releases and what to change when you upgrade past them, from the xinjs-ui rename to the current release." }-->

Notices for releases you may be upgrading *past*. If you are starting fresh, none of
this applies — go to the [Quick Start](/) instead.

Current releases are described in [CHANGELOG.md](https://github.com/tonioloewald/tosijs-ui/blob/main/CHANGELOG.md).

## tosijs `^1.10.9` — 1.16.21

tosijs-ui now needs **tosijs `^1.10.9`**; upgrade it alongside. `<tosi-table>` relies on that
release to keep a row in place when its detail opens or closes. On an older tosijs the row
jumps, with nothing in the console to say why. `dist/iife.js` already includes 1.10.9.

## `iconSvg()` throws for a name it cannot draw as one SVG — 1.16.19

A stack (`tosi$hat`), a composition rule (`unLock`, `spin90Loader`), a style suffix other
than rotation or flip (`check50o`), a redirect to a missing icon, or a redirect cycle used to
return `undefined`. Each now **throws**, naming the problem. A name nothing would draw still
returns `undefined`. Code that relied on `undefined` for those names should catch, or draw them
with `icons.<name>()` where there is a DOM.

## `tjs` examples compile with tjs-lang 0.14 — 1.16.17

Sites that load tjs-lang from the CDN (no copy of their own installed) now get
**0.14.0-rc.5**. It refuses some code 0.13 accepted, among others `||` in a type (a union is
`|`), `unsafe var` and `unsafe eval`; tjs-lang's
[changelog](https://github.com/tonioloewald/tjs-lang/blob/main/CHANGELOG.md) lists them. Fix
the example, or install `tjs-lang@0.13.13` in your project: the build ships the installed copy
with your pages and they prefer it to the CDN.

## `<tosi-md>` sanitizes by default — 1.16.0

A `<tosi-md>` with no `sanitize` attribute now strips executable content from the rendered
markdown, and **unwraps custom elements** (their content stays, the element goes). 1.15.3 logged a
console warning announcing this.

- **Markdown you control** (your own docs, posts you wrote) that embeds HTML such as a `<form>`,
  `<iframe>`, `<style>` or `<script>`: set `sanitize="off"` on that element to keep the old
  behaviour.
- **Markdown that embeds your own display components** (`<tosi-icon>`, a tag chip): keep
  sanitizing and allow them by name, `allowed-elements="tosi-icon tosi-tag"`.
- **Markdown from anyone else** (comments, issue bodies, API data): leave it sanitized. That is
  the point of the change: unsanitized, such text can run script in your page.

`tosi-md`, `tosi-example` and `tosi-doc-system` can't be allowed; they render raw HTML or run code.

## tosijs 1.10: components are typed from their attributes — 1.16.0

tosijs-ui now needs **tosijs `^1.10.3`**; upgrade it alongside. Nothing changes at runtime. What
changes is what TypeScript knows about a component instance:

```typescript
const rating = tosiRating()
rating.max        // number — was unknown to TypeScript on tosijs 1.9
rating.maxx       // now a type error (a typo)
rating.readonly = 'yes' // now a type error (wrong type)
```

So TypeScript code that read or wrote a property a component does not have, or with the wrong
type, stops compiling. That is the point: those were bugs the old typing hid. (Our own
migration found one: filter-builder read a `selectedIndex` that `<tosi-select>` never had, and
returned an empty string every time.)

**Your own components** built on tosijs `Component` get the same benefit by moving
`static initAttributes` into the class header, as tosijs's migration notes describe:

```typescript
// before
class MyWidget extends Component<MyParts> {
  static initAttributes = { size: 3, label: '' }
}
// after
class MyWidget extends withAttributes({ size: 3, label: '' })<MyParts> {}
```

Element-creator arguments are not typed by this: `tosiRating({ maxx: 1 })` still compiles.

## The doc-system cluster moved off the root barrel — 1.14.0

If you import `<tosi-code>`, the doc browser, `<tosi-doc-system>` or `<live-example>` from the
package root, change the import. Everything else is unaffected.

```typescript
// before
import { tosiCode, createDocBrowser } from 'tosijs-ui'

// after — the same things, by subpath
import { tosiCode } from 'tosijs-ui/code-editor'
import { createDocBrowser } from 'tosijs-ui/doc-browser'
```

**This one can fail at RUNTIME rather than at build time.** A bare `import 'tosijs-ui'` used to
register `<tosi-code>`, `<tosi-doc-system>` and `<live-example>` as a side effect; it no longer
does, so a page using those tags renders nothing and the console says only that an unknown
element was not upgraded. If a custom element stopped appearing after this upgrade, this is why.

Why: those four modules pull CodeMirror and tjs-lang, and because the package has no
`sideEffects` field (correctly — `elementCreator()` registers elements at import time, so a
blanket `sideEffects: false` would tree-shake a bare import down to zero registrations) a
bundler had to treat them as reachable from *any* import of the barrel. Measured on a real
15 MB app bundle: **1.35 MB / 8.9% saved**. The doc site and CDN `<script>` users are
unaffected — the IIFE imports all four explicitly.

## Validation is supplied, not imported — 1.11.0

If you use `<tosi-schema-form>`, `<tosi-crud>` or an editable `<tosi-table>` **from ESM**, add
one line. Nothing else changes, and nothing breaks silently — a form with no validator warns
in the console and reports `validationAvailable === false`.

```js:static
import { setSchemaValidator } from 'tosijs-ui'
import { validate, inferSchema, unenforcedKeywords } from 'tosijs-schema' // ^1.8.0

setSchemaValidator({ validate, inferSchema, unenforcedKeywords })
```

**Pass all three.** `unenforcedKeywords` is what lets a field ask the validator *"do you
actually check this keyword?"* — omit it and the form falls back to a list frozen at
tosijs-schema 1.7.0 and labels every `oneOf` and `exclusiveMinimum` field "not validated"
while it is being validated.

Nothing to do if you load the CDN `<script>` build or use `tosijs-ui/site` — both register it
themselves.

**Why it changed.** A bare `import('tosijs-schema')` in shipped code is either resolved by
your bundler — which fails the build for anyone who did not install it, including people using
only `<tosi-table>` — or left external, which cannot resolve in a browser and kills validation
for everyone. Both were measured; there is no third option. Asking for two functions instead
of a package also means anything can supply them: an Ajv wrapper, a house validator, a stub.

## `tjs-lang` peer moves to `^0.13.1` — 1.11.0

Only affects you if you have `tjs-lang` installed (it is an optional peer, for live examples
and `.tjs` sources). `^0.12.0` could not reach 0.13.x — caret pins the minor on `0.x` — so an
adopter on current tjs-lang hit a hard `ERESOLVE`.

**0.12.0 is deprecated on npm**, and the deprecation names this exact combination: *"tosijs-schema
>=1.5.0 breaks the battery atoms' output validation in these versions. Upgrade to 0.13.1."*
Since 1.11.0 also floors `tosijs-schema` at `^1.8.0`, staying on 0.12.0 is the pairing the
upstream author deprecated it over.

## Edit links are shorter and shorter-lived — 1.11.0

Only affects `tosijs-ui/site` users running the `tosijs-tunnel` bin. The token is now **7 Crockford
base32 characters** instead of 22, and `linkTtlMinutes` defaults to **5** rather than 15. A
link minted by an older dev server is not redeemable by a newer one; both live in memory, so
this only matters across a restart mid-session.

The token is case-insensitive and forgives the lookalikes — `I`/`L` read as `1`, `O` as `0`,
hyphens ignored — because it is meant to be read off one screen and typed on another.

**Changed again in 1.14.0:** the token is now eight letters with no digits. See
[the token is eight letters](/doc-site-system/#the-token-is-eight-letters-and-you-can-type-it).

## `Cannot find module` under Node — fixed in 1.9.1

If an import of `tosijs-ui` (any entry point) fails under **Node** with something like:

```text
Cannot find module '.../dist/doc-system/site/site-config'
imported from '.../dist/doc-system/site/index.js'
```

you are on **1.9.0 or earlier**. Upgrade to **1.9.1**; there is no workaround on the older
versions and no code change needed on yours.

Shipped `dist/` used extensionless relative imports (`from './site-config'`). Bun resolves
those; Node ESM does not — it requires the extension. So the package worked perfectly
under bun and failed on the very first import under Node, on every entry point, going back
well before 1.8.0.

**Not deprecated, deliberately.** The failure is loud and immediate — it stops your build
on the first import, so nobody is quietly running broken code. A deprecation warning would
only nag the bun users for whom every version worked. If you are pinned to an older line
and need this backported, open an issue; it is a mechanical change.

Worth knowing while you are here, because the error messages name symptoms rather than
causes:

| entry point | runtime it needs |
| --- | --- |
| `tosijs-ui/site` | **bun** — it shells out, builds and spawns. Under Node: `Cannot find package 'bun'` |
| `tosijs-ui`, `tosijs-ui/<component>` | a **browser** or a bundler targeting one. Under bare Node: `HTMLElement is not defined` |
| `tosijs-ui/icon-svg` | anything — deliberately DOM-free, which is why it exists |

Those three are unchanged in 1.9.1 and are not bugs; only the module *resolution* was.

## ⚠️ Breaking change in 1.7.0 — `<tosi-code>` (ACE → CodeMirror 6)

**1.7.0 is a breaking release shipping under a minor version, deliberately.** `<tosi-code>`
moved from ACE to CodeMirror 6. `value`, `mode`, the `change` event, `disabled`, and
`undo`/`redo` are unchanged; the ACE-era **`theme`** and **`options`** props are **removed**: setting
one warns once and does nothing. Dark mode is now automatic (`body.darkmode`) and styling comes from `--code-bg` /
`--text-color`. The `2.0` name is reserved for the tjs-native tosijs port, so this ships as
1.7.0 — **pin `tosijs-ui@1.6` to defer.** Full detail and rationale in
[CHANGELOG.md](https://github.com/tonioloewald/tosijs-ui/blob/main/CHANGELOG.md).

## Migrating to v1.3.0

v1.3.0 completes the rename from `xinjs-ui` to `tosijs-ui`. All custom element
tags now use the `tosi-` prefix and all exports use `Tosi*`/`tosi*` names.

### Breaking changes

- **Custom element tags** have changed from `<xin-*>` to `<tosi-*>`.
  For example: `<xin-select>` is now `<tosi-select>`, `<xin-icon>` is now
  `<tosi-icon>`, `<xin-example>` is now `<tosi-example>`, etc.
- **CSS selectors** targeting old tag names (e.g. `xin-select { ... }`) must
  be updated.
- **CSS custom properties** in component `styleSpec` objects retain `--xin-*`
  fallbacks for backward compatibility, but new code should use `--tosi-*`.

### Deprecated exports still work

The old `xin*` JavaScript exports (`xinSelect`, `xinTabs`, `xinTable`, etc.)
remain available and will continue to work. Most log a runtime deprecation
warning; a few are silent aliases marked with JSDoc `@deprecated`. They will
be removed in a future major version.

### Migration checklist

1. Search your HTML for `<xin-` and replace with `<tosi-`
2. Search your CSS for `xin-` selectors and update to `tosi-`
3. Search your JS/TS for `xinSelect`, `xinTabs`, etc. and switch to `tosiSelect`, `tosiTabs`, etc.
4. Search for `--xin-` CSS variable overrides and switch to `--tosi-`
