# Seventh UI VanillaJS

`@seventh-ui/vanillajs` is the framework-agnostic runtime layer for Seventh UI components.

It complements `@seventh-ui/css`: the CSS package owns visual styling, tokens, component classes, icons, and assets. This package owns behavior that CSS cannot provide, such as initialization, state synchronization, events, keyboard interaction, focus management, and cleanup.

## Install

```sh
npm config set "@seventh-ui:registry" https://npm.seventh.com.br/
npm install @seventh-ui/css @seventh-ui/vanillajs
```

## Package Boundary

- Keep visual implementation in `@seventh-ui/css`.
- Consume the public runtime contract from `@seventh-ui/css/contracts/runtime-integration.json`.
- Preserve `.sui-*` classes from the CSS package.
- Use `data-sui-*` attributes only as runtime hooks.
- Prefer native HTML and ARIA before custom state.
- Do not require React, Vue, Angular, Quasar, jQuery, or Bootstrap.

The CSS package owns CSS artifacts, `.sui-*` classes, icons, illustrations, tokens, and manifests. This package owns runtime behavior: initialization, lifecycle cleanup, `sui:*` events, keyboard/focus behavior, ARIA state, data-table modeling, and synchronization of documented shared state such as `hidden`, native state, `aria-*`, and `data-sui-state`.

Compatibility with `@seventh-ui/css` is declared in `package.json` through the peer dependency range and `seventhUI.cssContract.version`.

## Initial API

```js
import { emit, init, initComponent, on } from "@seventh-ui/vanillajs";

const app = init(document);

const dialog = initComponent(document.querySelector("[data-sui-dialog]"), (element) => {
  const off = on(element, "click", () => {
    emit(element, "dialog:open");
  });

  return () => off();
});

dialog.destroy();
app.destroy();
```

## Browser Bundle

The build emits an ESM distribution entry and a browser global bundle:

```html
<script src="./dist/seventh-ui.js"></script>
<script>
  const app = SeventhUI.init(document);
  app.destroy();
</script>
```

For legacy applications that cannot import ESM, load the CSS package first and then the browser bundle from `dist/seventh-ui.js`. The bundle exposes `window.SeventhUI` and should be loaded once per page. See `docs/legacy-installation.html` for installation order, safety rules, and browser compatibility.

## Local Docs

Run the playground through a local web server:

```sh
npm run docs
```

The server prints the localhost URL for the docs home and component playgrounds.

## Runtime Events

Runtime events use the `sui:` prefix:

```js
emit(element, "dialog:open", { source: "trigger" });
```

This dispatches:

```txt
sui:dialog:open
```

Use cancellable events for before-action flows:

```js
const allowed = emit(element, "dialog:before-close", {}, { cancelable: true });
```

## Accessibility Utilities

The core exports shared helpers for component controllers:

- `getFocusableElements`, `focusFirst`, and `focusLast` for enabled visible focus targets.
- `createFocusTrap` for overlay focus containment and restoration.
- `createRovingTabindex` for Tabs, Menu, and similar composite widgets.
- `setAriaExpanded`, `setAriaSelected`, `setAriaHidden`, `setHidden`, and `setDataState` for DOM state synchronization.

## Component Runtime Matrix

Native/static components remain CSS-first: Button, Input, Checkbox, Radio, Switch, Divider, Tag, Breadcrumb, layout primitives, icons, and illustrations.

Required runtime components are implemented in backlog order: Dialog, Tabs, Menu, Tooltip, Toast, Navigation drawer/mobile behavior, and Data Table.

Optional enhancements are progressive and run only when documented hooks are present: Segmented Button, Notification dismissal, Slider helpers, Stepper helpers, and People Picker/Multi Select helpers.

## Dialog Runtime

Dialog initializes automatically through `init(root)`:

```html
<button data-sui-trigger="dialog" data-sui-target="account-dialog">
  Open
</button>

<section id="account-dialog" class="sui-dialog" data-sui-dialog>
  <button data-sui-dialog-close>Close</button>
</section>
```

The runtime synchronizes `hidden`, `aria-hidden`, `aria-modal`, trigger `aria-expanded`, and `data-sui-state`. It emits cancellable `sui:dialog:before-open` and `sui:dialog:before-close` events, followed by `sui:dialog:open` and `sui:dialog:close`.

## Tabs Runtime

Tabs initialize automatically through `init(root)`:

```html
<section class="sui-tabs" data-sui-tabs>
  <div class="sui-tabs__list" role="tablist">
    <button class="sui-tabs__tab" data-sui-tab data-sui-target="panel-a">
      Overview
    </button>
  </div>
  <div class="sui-tabs__panel" id="panel-a" data-sui-tab-panel>
    Panel content
  </div>
</section>
```

The runtime synchronizes `aria-selected`, roving `tabindex`, panel `hidden` state, `aria-hidden`, and `data-sui-state`. It emits cancellable `sui:tabs:before-change` and `sui:tabs:change` events.

## Menu Runtime

Menu initializes automatically through `init(root)`:

```html
<section data-sui-menu>
  <button data-sui-trigger="menu" data-sui-target="actions-menu">
    Actions
  </button>
  <div class="sui-menu" id="actions-menu" data-sui-menu-content hidden>
    <button class="sui-menu__item" data-sui-menu-item data-sui-value="rename">
      Rename
    </button>
  </div>
</section>
```

The runtime synchronizes trigger `aria-expanded`, `aria-controls`, content `hidden`, `aria-hidden`, roving item `tabindex`, and `data-sui-state`. It emits cancellable `sui:menu:before-open` and `sui:menu:before-close` events, plus `sui:menu:open`, `sui:menu:close`, and `sui:menu:select`.

## Tooltip Runtime

Tooltip initializes automatically through `init(root)`:

```html
<button data-sui-tooltip data-sui-target="save-tooltip">
  Save changes
</button>

<div class="sui-tooltip" id="save-tooltip" data-sui-tooltip-content hidden>
  Saves run after validation.
</div>
```

The runtime synchronizes content `hidden`, `aria-hidden`, trigger `aria-describedby`, and `data-sui-state`. It supports `data-sui-target`, existing `aria-describedby`, generated relationships when safe, hover/focus delays, Escape dismissal, reduced-motion timing, and cancellable `sui:tooltip:before-show` / `sui:tooltip:before-hide` events.

## Toast Runtime

Toast initializes automatically through `init(root)`:

```html
<div class="sui-toast-region" data-sui-toast-region>
  <article class="sui-toast" data-sui-toast data-sui-duration="5000">
    <div class="sui-toast__content">
      <h3 class="sui-toast__title">Profile saved</h3>
      <button class="sui-toast__close" data-sui-toast-dismiss>
        Close
      </button>
    </div>
  </article>
</div>
```

The runtime configures polite live regions by default, supports assertive regions when explicitly requested, synchronizes `hidden`, `aria-hidden`, and `data-sui-state`, wires dismiss controls, emits `sui:toast:show`, cancellable `sui:toast:before-dismiss`, and `sui:toast:dismiss`, and clears auto-dismiss timers on cleanup.

## Navigation Runtime

Navigation initializes automatically through `init(root)`:

```html
<section data-sui-navigation>
  <button data-sui-trigger="navigation" data-sui-target="mobile-nav">
    Open navigation
  </button>

  <nav class="sui-navigation" id="mobile-nav" data-sui-navigation-drawer hidden>
    <button data-sui-navigation-disclosure data-sui-target="nav-group">
      Cameras
    </button>
    <div id="nav-group" hidden>
      <a href="/live">Live view</a>
    </div>
  </nav>
</section>
```

The runtime synchronizes drawer `hidden`, `aria-hidden`, trigger `aria-expanded`, `aria-controls`, and `data-sui-state`. It emits cancellable `sui:navigation:before-open` and `sui:navigation:before-close` events, followed by `sui:navigation:open` and `sui:navigation:close`, closes on Escape/outside pointer, restores focus to the trigger, and keeps static desktop links unchanged when no runtime hooks are present.

## Data Table Runtime

Data Table uses `@tanstack/table-core` as a headless engine and renders Seventh UI CSS classes:

```html
<section id="cameras-table" data-sui-data-table></section>
<script>
  SeventhUI.createDataTableController(document.querySelector("#cameras-table"), {
    columns: [
      { id: "name", accessorKey: "name", header: "Camera" },
      { id: "status", accessorKey: "status", header: "Status" }
    ],
    data: [
      { id: "cam-1", name: "Entrance", status: "Online" }
    ],
    enableRowSelection: true,
    getRowId: (row) => row.id,
    pageSize: 10
  });
</script>
```

The runtime owns sorting, filtering/search, pagination, row selection, row expansion, cancellable `sui:data-table:*` events, ARIA/native state synchronization, and cleanup. The CSS package remains responsible only for Data Table styling.

## Current Status

Foundation, runtime core, accessibility utilities, Dialog, Tabs, Menu, Tooltip, Toast, Navigation, Data Table, browser bundle, local docs, and behavior tests are implemented through the current primary runtime backlog.
