Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
324d0e8
A1: Require React 19
n4ff4h Nov 1, 2026
d05c72d
A2: Release every package at one version
n4ff4h Nov 1, 2026
85509ba
A3: Load the Thaana fonts without the optional font pack
n4ff4h Nov 1, 2026
c4de3d5
A4: Make react-hook-form and TanStack Query peers
n4ff4h Nov 1, 2026
f78af77
A5: Remove the unused base-ui Combobox primitive
n4ff4h Nov 1, 2026
ca42386
A6: Drop optional peers nothing imports
n4ff4h Nov 1, 2026
7b30030
B1: Stop the calendar's month arrows flipping twice in RTL
n4ff4h Nov 1, 2026
c105788
B2: Keep touch targets when a Button sets its own slot
n4ff4h Nov 1, 2026
c0b9a84
B3: Translate three hard-coded English strings
n4ff4h Nov 1, 2026
bf91ce2
B4: Give the toast close button a usable size, and test toasts
n4ff4h Nov 1, 2026
e7503ac
B5: Use the editor's thaana prop on the image alt text field
n4ff4h Nov 1, 2026
f96bcc7
B6: Use placeholders instead of gluing translated labels together
n4ff4h Nov 1, 2026
b03561d
B7: Stop the vertical carousel arrows mirroring in RTL
n4ff4h Nov 1, 2026
46ec8a5
B8: Give the kanban count screen reader text instead of an aria-label…
n4ff4h Nov 1, 2026
1a13337
B9: Don't read the clock or Math.random during the first render
n4ff4h Nov 1, 2026
f9ebac5
B10: Guard useLayoutEffect for server rendering
n4ff4h Nov 1, 2026
8302a59
B11: Use tokens for overlays and the app shell
n4ff4h Nov 1, 2026
178e966
B12: Type SegmentedControl's name prop
n4ff4h Nov 1, 2026
18ad3c8
B13: Take logical sides on Tip, PopoverPanel and ActionMenu
n4ff4h Nov 1, 2026
0213d57
C1: Share one useControllableState
n4ff4h Nov 1, 2026
a2d7f1e
C2: Use onValueChange for every callback that reports a value
n4ff4h Nov 1, 2026
2d504ab
C3: Use one severity scale, tone
n4ff4h Nov 1, 2026
d3399b3
C4: Use one size scale
n4ff4h Nov 1, 2026
56ae1f7
C5: Accept rest props, ref and classNames consistently
n4ff4h Nov 1, 2026
ebb8254
C6: Share one copy of each duplicated helper
n4ff4h Nov 1, 2026
4d2b26b
C7: Give every controlled prop an uncontrolled partner
n4ff4h Nov 1, 2026
b76ac6f
C8: Use label and minChars everywhere
n4ff4h Nov 1, 2026
9d44964
C9: Remove unused locale keys and announce filter and selection changes
n4ff4h Nov 1, 2026
361bddb
C10: Split the auth forms into one file per form
n4ff4h Nov 1, 2026
166879a
D1: Run a Chromium E2E smoke on pull requests
n4ff4h Nov 1, 2026
0368548
D2: Run the Figma plugin tests in CI
n4ff4h Nov 1, 2026
148a695
D3: Cover src/ui in the coverage run
n4ff4h Nov 1, 2026
9647285
D4: Stop the canvas and focus noise in unit tests
n4ff4h Nov 1, 2026
3b5afba
D5: Add keyboard tests for DateCalendar and tests for IconText
n4ff4h Nov 1, 2026
cc03f37
D6: Give lint suppressions a reason and extend the physical-utility rule
n4ff4h Nov 1, 2026
0f54e89
E1: Complete the installation page and give each entry one install list
n4ff4h Nov 1, 2026
754c7fe
E2: Fill the Props table gaps
n4ff4h Nov 1, 2026
5abe307
E3: Correct stale text across the docs
n4ff4h Nov 1, 2026
2f63f59
E4: Say what thin Accessibility sections render for assistive tech
n4ff4h Nov 1, 2026
5f2a4f1
Record the pinned pnpm in the lockfile
n4ff4h Nov 1, 2026
f3f853c
Update dependencies with known vulnerabilities
n4ff4h Nov 1, 2026
ac8de2f
Merge the CI lockfile and security updates into Part A
n4ff4h Nov 1, 2026
9c3a3ff
Merge the CI lockfile and security updates
n4ff4h Nov 1, 2026
ab0c1e6
Merge the CI lockfile and security updates
n4ff4h Nov 1, 2026
aba5b60
Merge the CI lockfile and security updates
n4ff4h Nov 1, 2026
561e134
Merge the CI lockfile and security updates
n4ff4h Nov 1, 2026
6c798f8
B5: Close the image dialog at the end of the thaana test
n4ff4h Nov 1, 2026
ff8af40
Merge the Part B test fix
n4ff4h Nov 1, 2026
983bfc4
Merge the Part B test fix
n4ff4h Nov 1, 2026
ccf655c
Merge the Part B test fix
n4ff4h Nov 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
5 changes: 5 additions & 0 deletions .changeset/class-names-and-rest-props.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

More components accept rest props and `ref` on their root and a `classNames` slot map, and `BackToTop`, `ConditionalLink` and `LinkButton` gain `asChild`.
2 changes: 1 addition & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"fixed": [["@javaabu/onu", "@javaabu/onu-mcp"]],
"linked": [],
"access": "public",
"baseBranch": "main",
Expand Down
5 changes: 5 additions & 0 deletions .changeset/docs-pass.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

Docs: an installation page with requirements and per-entry peer dependencies, complete Props tables, and corrected stale text.
5 changes: 5 additions & 0 deletions .changeset/drop-unused-peers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

Removed four optional peers nothing imports: `@tiptap/extension-link`, `@tiptap/extension-drag-handle-react`, `@tiptap/extension-code-block-lowlight` and `lowlight`.
5 changes: 5 additions & 0 deletions .changeset/editor-dialog-thaana.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

The editors' image alt text field now follows the editor's `thaana` prop.
5 changes: 5 additions & 0 deletions .changeset/hard-coded-english.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

`DialogFooter`'s close button, the `useConfirm` `window.confirm` fallback and a `ValidationError` without a message no longer show hard-coded English.
5 changes: 5 additions & 0 deletions .changeset/labels-with-placeholders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

The move, switch account and inline edit labels are now whole translated sentences with a placeholder, instead of two strings joined together.
5 changes: 5 additions & 0 deletions .changeset/locale-cleanup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

Remove unused locale keys, give Dhivehi separate words for clear and delete, and announce applied filters and cleared selections to screen readers.
5 changes: 5 additions & 0 deletions .changeset/logical-sides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

`Tip`, `PopoverPanel` and `ActionMenu` take `side="top" | "bottom" | "start" | "end"`; `left` and `right` are gone.
5 changes: 5 additions & 0 deletions .changeset/navigation-menu-rtl-motion.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

`NavigationMenu` content slides in from the logical side, so its motion follows the reading direction in RTL.
5 changes: 5 additions & 0 deletions .changeset/on-value-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

Every component that reports a value now uses `onValueChange(value)`; `onChange` only ever means the native event. `FileInput` loses `onChange(files)` (use `onValueChange(entries)`), and `onReject` always takes an array.
5 changes: 5 additions & 0 deletions .changeset/overlay-token.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

New `--onu-overlay` token for the dim behind dialogs, sheets and drawers (`bg-overlay`). The app shell classes use the shell token utilities instead of hex fallbacks.
5 changes: 5 additions & 0 deletions .changeset/peer-form-and-query.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

`react-hook-form` and `@tanstack/react-query` are now peer dependencies. `getOnuQueryClient` is gone: the fallback client belongs to each `OnuProvider`, and `invalidateApiOptions` takes the client first.
5 changes: 5 additions & 0 deletions .changeset/primitive-a11y-fixes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

Fix axe violations in three primitives: `Calendar` week numbers, the `role="list"` on `ItemGroup`, and `CommandSeparator` inside its listbox.
5 changes: 5 additions & 0 deletions .changeset/prop-names.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

The accessible name of a root region is `label` everywhere (`CommandPalette` and `OverlayMenu` `title`, `TopNav` `navLabel`, `Tabs` `listLabel`), and the minimum query length is `minChars` everywhere (`CommandPalette` `minQueryLength`, `PlaceSearchBox` `minLength`).
5 changes: 5 additions & 0 deletions .changeset/react-19-only.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

Onu now requires React 19; React 18 is no longer in the peer range.
5 changes: 5 additions & 0 deletions .changeset/remove-base-ui-combobox.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

Removed the unused `Combobox` primitive from `@javaabu/onu/primitives`, and with it the `@base-ui/react` dependency.
5 changes: 5 additions & 0 deletions .changeset/segmented-control-name.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

`SegmentedControl`'s `name` prop is now part of its type.
5 changes: 5 additions & 0 deletions .changeset/shared-helpers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

Shared helpers move to `src/lib` and `src/hooks` with one behaviour each: `toArray` and the `initials` media export are gone, `normalizeUrl` returns `string | null`, the editor's `Callout` node is now `CalloutNode`, `CommandPalette` debounces by 300 ms, and the auth forms use `PasswordInput`.
5 changes: 5 additions & 0 deletions .changeset/size-scale.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

`Tag`, `SkeletonText`, `Modal` and `UserAvatar` rename size `md` to `default`. `NumberInput` is now `h-8` like every other field, and `TextInput` gains the same `size` prop.
5 changes: 5 additions & 0 deletions .changeset/stable-first-render.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

`Countdown`, `RelativeDate`, `Timeline`, `PublishBox` and `SidebarMenuSkeleton` render the same markup on the server and the client's first render. `SidebarMenuSkeleton` takes an `index` to vary its width.
5 changes: 5 additions & 0 deletions .changeset/stable-labels.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

The vertical `Carousel` arrows point the right way in RTL, and `KanbanBoard`'s column count is real screen reader text instead of an `aria-label` on a `span`.
5 changes: 5 additions & 0 deletions .changeset/thaana-fonts-always.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

Faruma and MV Faseyha now load from `tailwind.css` and `styles.css`, so Thaana text works without the optional font pack.
5 changes: 5 additions & 0 deletions .changeset/toast-close-size.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": patch
---

The toast close button is now 24 px, and 44 px on touch screens.
5 changes: 5 additions & 0 deletions .changeset/tone-scale.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

One severity scale, `tone`: `neutral`, `info`, `success`, `warning`, `danger`. `Callout`, `AnnouncementBar` and `NotificationCenter` items rename `variant` to `tone`, `destructive` and `error` become `danger`, and `default` becomes `neutral` (also on `IconText`). `AnnouncementBar` gains `success` and `danger`. `Button` keeps `variant="destructive"`.
5 changes: 5 additions & 0 deletions .changeset/uncontrolled-partners.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@javaabu/onu": minor
---

`LanguageSwitcher` and `RepeatingGroup` gain `defaultValue`, `Callout`, `FilterPanel` and `Lightbox` gain `defaultOpen`, and `Lightbox` `open` and `onOpenChange` become optional with `index` controlled only when it is passed.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ jobs:
fail_ci_if_error: false
- name: MCP server tests
run: pnpm --filter @javaabu/onu-mcp test
- name: Figma plugin tests
run: pnpm figma:test
- name: Build packages
run: pnpm build
- name: Size budgets
Expand Down
40 changes: 40 additions & 0 deletions .github/workflows/e2e-smoke.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: E2E smoke

# The quick E2E tier: on a pull request that touches the library, the web app or the E2E
# tests, run the accessibility scans and the Thaana keyboard check in Chromium. No visual
# diff and no baseline download: the full five-browser and visual run stays in e2e.yml.
on:
pull_request:
paths:
- "packages/onu/**"
- "web/**"
- "e2e/**"

concurrency:
group: e2e-smoke-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
smoke:
name: Playwright smoke (chromium)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm exec playwright install --with-deps chromium
- run: pnpm build:web
- run: pnpm e2e:chromium e2e/a11y.spec.ts e2e/thaana.spec.ts
- uses: actions/upload-artifact@v4
if: failure()
with:
name: playwright-report-smoke
path: playwright-report
retention-days: 7
1 change: 1 addition & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ jobs:
exit 1
fi
done
node scripts/sync-plugin-version.mjs --check
- name: Check the npm token
run: |
if [ -z "$NPM_TOKEN" ]; then
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pnpm e2e:chromium # Playwright (a11y with axe, visual)

## Rules

- A component is done only with: light/dark, LTR/RTL, `dv` strings, `thaana` on free-text fields, tokens-only colours, `className`/`classNames`/`asChild`, axe-clean, unit tests, a demo, a docs page and a changeset (`.changeset/*.md`).
- A component is done only with: light/dark, LTR/RTL, `dv` strings, `thaana` on free-text fields, tokens-only colours, `className`/`classNames`, `asChild` where the component renders one element an app may need to replace (links, buttons, triggers), axe-clean, unit tests, a demo, a docs page and a changeset (`.changeset/*.md`).
- Logical Tailwind utilities only (`ms-`, `pe-`, `start-`, `text-start`); ESLint rejects `left`/`right` ones. Theme tokens only, never raw colours.
- Icons through `<Icon name="…">` with semantic names; never render Lucide components or import `src/icons/lucide-map` in a component.
- No hard-coded English: strings live in `src/locales/{en,dv}/<namespace>.ts`, and a module registers the English namespaces it uses with `registerEnglish(...)`.
Expand Down
14 changes: 10 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Maps in the web app use Google Maps when `VITE_GOOGLE_MAPS_API_KEY` (and optiona

## Definition of done

A component is done only when it meets REQUIREMENTS §21: light/dark, LTR/RTL, `dv` locale, `thaana` prop for free text, tokens-only colours, responsive and touch-friendly, `className`/`classNames`/`asChild` overrides, WCAG 2.2 AA with axe tests, unit tests, a showcase demo in `web/src/showcase`, a docs page in `docs/`, and a changeset.
A component is done only when it meets REQUIREMENTS §21: light/dark, LTR/RTL, `dv` locale, `thaana` prop for free text, tokens-only colours, responsive and touch-friendly, `className`/`classNames` overrides, `asChild` where the component renders one element an app may need to replace (links, buttons, triggers), WCAG 2.2 AA with axe tests, unit tests, a showcase demo in `web/src/showcase`, a docs page in `docs/`, and a changeset.

## Where things go

Expand All @@ -33,6 +33,7 @@ A component is done only when it meets REQUIREMENTS §21: light/dark, LTR/RTL, `
## Rules of thumb

- Use logical Tailwind utilities (`ms-`, `pe-`, `start-`, `text-start`, …). ESLint rejects physical `left`/`right` ones.
- Report a value with `onValueChange(value)`; `onChange` is only for the native event.
- Use theme tokens (`bg-primary`, `text-muted-foreground`), never raw colours.
- Use `<Icon name="…">` (from `src/icons/icon`) with semantic names, so `OnuProvider icons` overrides apply. Never render a Lucide component directly. When a component always shows the same glyph (a spinner, a close button, a chevron), also pass that Lucide icon as `fallback`, e.g. `<Icon name="loading" fallback={Loader2Icon} />`: overrides still win, and the component keeps its glyph outside `OnuProvider`.
- Never import `src/icons/lucide-map` in a component. `OnuProvider` loads the default set on demand, so neither a single component nor the provider ships ~250 icons. ESLint and `src/icons/icon-imports.test.ts` enforce this, and `pnpm --filter @javaabu/onu size` checks the bundle budgets.
Expand All @@ -52,7 +53,12 @@ The files in `packages/onu/src/ui` started as shadcn/ui's components (Radix base

## Checks

E2E (Playwright: accessibility in five browsers, and Chromium screenshots) is slow, so CI runs it only when the last commit pushed to `main` starts with `e2e` (for example `e2e: new date picker`), or when you run the **E2E** workflow by hand from the Actions tab. Run it locally with `pnpm e2e:chromium`.
E2E (Playwright) runs in two tiers:

- **Smoke, on pull requests.** The **E2E smoke** workflow runs `e2e/a11y.spec.ts` and `e2e/thaana.spec.ts` in Chromium, with no screenshots, when a pull request touches `packages/onu/**`, `web/**` or `e2e/**`.
- **Full, on demand.** The **E2E** workflow (accessibility in five browsers, and Chromium screenshots) is slow, so CI runs it only when the last commit pushed to `main` starts with `e2e` (for example `e2e: new date picker`), or when you run it by hand from the Actions tab.

Run either locally with `pnpm e2e:chromium`, adding the two spec files for the smoke tier.

The Chromium job compares a desktop screenshot of every component demo, in light LTR and dark RTL, with baselines stored as the `visual-baselines` Actions artifact (not in git). After an intended visual change, or when you add a component, run **E2E** by hand with **Update the visual baselines** ticked. Look at the screenshots in that run's `visual-baselines` artifact before relying on them. Baselines are kept for 90 days (about 90 MB). If none are stored (the first run, or 90 days after the last update), the run takes new ones instead of comparing.

Expand Down Expand Up @@ -85,10 +91,10 @@ Every change that affects a published package adds a changeset (`pnpm changeset`

To release:

1. On `dev`, run `pnpm changeset version`. It bumps every package with pending changesets, writes their `CHANGELOG.md` and deletes the changesets. All packages share one version, so check that `packages/onu` and `packages/onu-mcp` match.
1. On `dev`, run `pnpm changeset version && node scripts/sync-plugin-version.mjs`. `@javaabu/onu` and `@javaabu/onu-mcp` are a fixed group in `.changeset/config.json`, so they always move to the same version; the script copies that version into `plugins/onu/.claude-plugin/plugin.json`, which changesets can't see. `changeset version` also writes their `CHANGELOG.md` and deletes the changesets.
2. Commit (`Release v0.1.0`) and merge `dev` into `main`. Wait for CI to pass on `main`.
3. Tag that commit on `main` and push the tag: `git tag v0.1.0 && git push origin v0.1.0`.

The **Release** workflow runs only for `v*` tags. It checks that the tagged commit is on `main` and that every package's version matches the tag, then builds and publishes to npm (versions already on npm are skipped). Tags with a pre-release suffix (`v1.0.0-beta.1`) publish under the `next` dist-tag.
The **Release** workflow runs only for `v*` tags. It checks that the tagged commit is on `main` and that every package's version and the plugin's match the tag, then builds and publishes to npm (versions already on npm are skipped). Tags with a pre-release suffix (`v1.0.0-beta.1`) publish under the `next` dist-tag.

Publishing needs an `NPM_TOKEN` repository secret: an npm granular access token with read and write access to the `@javaabu` scope and "bypass 2FA" allowed, from an account that can publish to `@javaabu`. Write tokens expire after about 90 days. Provenance is signed only once the repository is public. After the first release, you can switch to npm trusted publishing (each package's settings on npmjs.com, pointing at `release.yml`) and remove the token.
Loading
Loading