Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
133 commits
Select commit Hold shift + click to select a range
48789eb
Add the v2 component review as the decision record
titouanmathis Aug 26, 2026
2f3c95f
Switch the workspace to js-toolkit v4
titouanmathis Aug 26, 2026
8d5412f
Port the component families onto js-toolkit v4
titouanmathis Aug 26, 2026
1d2958a
Move the ported specs into the tests package
titouanmathis Aug 26, 2026
336d54a
Port the Slider family onto js-toolkit v4
titouanmathis Aug 26, 2026
b5a1e50
Migrate the Disclosure family onto js-toolkit v4
titouanmathis Aug 26, 2026
f75793e
Migrate ScrollReveal onto js-toolkit v4
titouanmathis Aug 26, 2026
690e685
Move the workspace to js-toolkit 4.0.0-alpha.1
titouanmathis Aug 27, 2026
441ccf3
Import the real SmoothToRecord type in Cursor
titouanmathis Aug 27, 2026
7860391
Run the test suite in a real browser
titouanmathis Aug 27, 2026
d7dff96
Namespace the Disclosure events and restore the default exports
titouanmathis Aug 27, 2026
02e6436
Port LargeText onto js-toolkit v4
titouanmathis Aug 27, 2026
118192c
Remove the internal helpers from the public export surface
titouanmathis Aug 27, 2026
54979e2
Follow the v2 component port in the Reference
titouanmathis Aug 27, 2026
32f655d
Port the Reference stories onto js-toolkit v4
titouanmathis Aug 27, 2026
c4961d5
Describe the js-toolkit v4 runtime in the guide and the Reference
titouanmathis Aug 27, 2026
9962d2f
Correct the v3 code samples the twoslash blocks never checked
titouanmathis Aug 27, 2026
9fee34e
Port ui-motion onto js-toolkit v4
titouanmathis Aug 28, 2026
d82486a
Port ui-mapbox onto js-toolkit v4
titouanmathis Aug 28, 2026
5727055
Remove the decorators from the ui components
titouanmathis Aug 28, 2026
437fded
Drop the SWC decorator transform from the test setup
titouanmathis Aug 28, 2026
c8e430f
Correct the registration guidance in the guide
titouanmathis Aug 28, 2026
0141ee9
Bundle ui-mapbox and ui-motion in the playground again
titouanmathis Aug 28, 2026
abcfbb3
Follow the mapbox and motion ports in the documentation
titouanmathis Aug 28, 2026
d2819ef
Wait for the children before reading them in the ported components
titouanmathis Aug 28, 2026
cbedffe
Stop warning about a map that has simply not mounted yet
titouanmathis Aug 28, 2026
7aae478
Port the mapbox and motion specs onto js-toolkit v4
titouanmathis Aug 28, 2026
bd06b0e
Merge branch 'feat/v2-port-mapbox-motion' into feat/v2-component-port
titouanmathis Aug 28, 2026
5817b7c
Update the playground defaults to js-toolkit v4
titouanmathis Aug 28, 2026
cabaea3
Move the playground to 0.4.0
titouanmathis Aug 28, 2026
1919363
Rewrite the v1 → v2 migration guide
titouanmathis Aug 31, 2026
2ccc86c
Correct the registration guidance in the Reference
titouanmathis Aug 31, 2026
d5d7170
Follow the migrated component sources in the Reference
titouanmathis Aug 31, 2026
41587f7
Follow the mapbox and motion sources in the Reference
titouanmathis Aug 31, 2026
becd9d0
Document that Dialog no longer exposes waitUntil
titouanmathis Aug 31, 2026
4c74078
Restore Dialog's waitUntil extension point on emitExtendable()
titouanmathis Aug 31, 2026
5dec493
Wire MotionView back onto the events it claims to listen for
titouanmathis Aug 31, 2026
13f9fe7
Document the restored waitUntil extension point
titouanmathis Aug 31, 2026
e649e78
Restore withIndex as the mixin Indexable is built from
titouanmathis Sep 1, 2026
d29a5c6
Cover the withIndex mixin form with specs
titouanmathis Sep 1, 2026
dc74220
Follow the restored withIndex in the documentation
titouanmathis Sep 1, 2026
dbf714d
Record the withIndex resolution in the v2 review
titouanmathis Sep 1, 2026
c5e7cde
Reduce the v1 to v2 migration guide to facts and steps
titouanmathis Sep 1, 2026
b06f531
Rewrite Tabs onto js-toolkit v4 and the WAI-ARIA tabs pattern
titouanmathis Sep 1, 2026
4c9ed58
Cover the rewritten Tabs with specs
titouanmathis Sep 1, 2026
6672ae6
Follow the Tabs rewrite in the Reference
titouanmathis Sep 1, 2026
e5355dd
Record the Tabs rewrite in the migration guide and the v2 review
titouanmathis Sep 1, 2026
fb79e4a
Merge branch 'feat/v2-rewrite-tabs' into feat/v2-component-port
titouanmathis Sep 1, 2026
5333064
Redefine the Slider rewrite as a transport consolidation
titouanmathis Sep 1, 2026
7edbbdd
Fix Fetch dropping repeated form fields and leaking src into history
titouanmathis Sep 1, 2026
5d6dee6
Implement the accessibility contract on the Carousel family
titouanmathis Sep 1, 2026
7bf292f
Cover the Carousel accessibility contract with specs
titouanmathis Sep 1, 2026
67ad592
Document the Carousel accessibility contract
titouanmathis Sep 1, 2026
7f64b3c
Merge branch 'feat/v2-carousel-a11y' into feat/v2-component-port
titouanmathis Sep 1, 2026
83db960
Drop the playground patch that 0.4.0 made obsolete
titouanmathis Sep 1, 2026
cd8b8b9
Clamp a flicked carousel drag to one snap and restore snapping
titouanmathis Sep 1, 2026
859f29b
Add CarouselPlay, the carousel rotation control
titouanmathis Sep 1, 2026
f9e4b24
Document the drag settle and the CarouselPlay control
titouanmathis Sep 1, 2026
e88d70d
Get CI past install and green
titouanmathis Sep 1, 2026
a6f0780
Merge pull request #643 from studiometa/fix/fetch-multi-value-and-his…
titouanmathis Sep 1, 2026
4f2e0bd
Add 1.11.0 changelog entry
titouanmathis Sep 1, 2026
f6147c5
Prepare 1.11.0
titouanmathis Sep 1, 2026
e7025f5
Merge pull request #645 from studiometa/chore/prepare-1.11.0
titouanmathis Sep 1, 2026
3f85478
Widen the Track throttle window so a slow runner cannot cross it
titouanmathis Sep 1, 2026
2b8c699
Merge branch 'feat/v2-carousel-drag-autoplay' into feat/v2-component-…
titouanmathis Sep 1, 2026
99792e5
Register CarouselPlay as a Carousel child
titouanmathis Sep 1, 2026
f9f7ae4
Fix Fetch keeping src in history on a click or a submit
titouanmathis Sep 1, 2026
0c6baeb
Merge pull request #646 from studiometa/fix/fetch-history-declarative
titouanmathis Sep 1, 2026
06e3525
Add 1.11.1 changelog entry
titouanmathis Sep 1, 2026
d1be85b
Prepare 1.11.1
titouanmathis Sep 1, 2026
5720cd2
Merge pull request #647 from studiometa/chore/prepare-1.11.1
titouanmathis Sep 1, 2026
8e056a7
Bring the migration guide up to the current round
titouanmathis Sep 1, 2026
60bc443
Make the last two CI-only failures speed-independent
titouanmathis Sep 1, 2026
76b7f83
Remove the Slider family from the ui package
titouanmathis Sep 1, 2026
7d69503
Remove the Slider specs and drop its names from the export snapshots
titouanmathis Sep 1, 2026
1fc3985
Remove the Slider reference docs and repoint what named it
titouanmathis Sep 1, 2026
4dd343c
Attach the progress recorder before the countdown arms
titouanmathis Sep 1, 2026
d799b0d
Write the Slider to Carousel migration path
titouanmathis Sep 1, 2026
7ab1e45
Record the Slider drop in the component inventory
titouanmathis Sep 1, 2026
0a013fb
Publish the carousel scroll progress on its context
titouanmathis Sep 1, 2026
8a5ec6c
Add the four Carousel controls
titouanmathis Sep 1, 2026
8e13400
Export the four Carousel controls from the package and the reference
titouanmathis Sep 1, 2026
d121641
Cover the four Carousel controls with specs
titouanmathis Sep 1, 2026
47f7301
Document the four Carousel controls
titouanmathis Sep 1, 2026
d1ebaca
Merge branch 'feat/v2-carousel-controls' into feat/v2-component-port
titouanmathis Sep 1, 2026
850a026
Merge branch 'feat/v2-remove-slider' into feat/v2-component-port
titouanmathis Sep 1, 2026
166e1ed
docs: record round 8 and fix the CarouselPlay registration claim
titouanmathis Sep 1, 2026
1dee2cb
fix(carousel): hold the index through a programmatic scroll
titouanmathis Sep 2, 2026
71e852b
feat(carousel): read the scroll alignment from the slide's CSS, keep …
titouanmathis Sep 2, 2026
89442f9
feat(carousel): let the track's scroll-snap-type decide whether a dro…
titouanmathis Sep 2, 2026
f32774a
docs(carousel): add alignment and free-scroll examples
titouanmathis Sep 2, 2026
0e8c6d5
fix(carousel): carry the pointer's velocity into the drag settle
titouanmathis Sep 2, 2026
3d89de3
refactor(ui): one marker for a picker, one source for the lint list
titouanmathis Sep 2, 2026
e6125c3
fix(docs): make js twoslash blocks actually type-check
titouanmathis Sep 2, 2026
ce7c302
fix(lint): quote the prettier glob so it checks every doc
titouanmathis Sep 2, 2026
243f8a3
style(docs): format the 10 markdown files the glob had never reached
titouanmathis Sep 2, 2026
a9a2a8e
chore(ui): drop the unused alien-signals dependency
titouanmathis Sep 2, 2026
419e568
docs(api): replace dropped Accordion in PHP examples with Disclosure
titouanmathis Sep 2, 2026
0f17cef
perf(ui): import js-toolkit symbols from their subpaths
titouanmathis Sep 2, 2026
41680f2
fix(docs): point the v1 reference redirects at their v2 destinations
titouanmathis Sep 2, 2026
57d25d9
chore(ui): drop the three remaining unused runtime dependencies
titouanmathis Sep 2, 2026
d3b6cd0
Merge remote-tracking branch 'origin/fix/v2-twoslash-typecheck' into …
titouanmathis Sep 2, 2026
d3ce704
Merge remote-tracking branch 'origin/fix/v2-prettier-glob' into feat/…
titouanmathis Sep 2, 2026
8a54507
Merge remote-tracking branch 'origin/chore/v2-twig-extension' into fe…
titouanmathis Sep 2, 2026
1835aad
Merge remote-tracking branch 'origin/chore/v2-drop-alien-signals' int…
titouanmathis Sep 2, 2026
c5a37c6
Merge remote-tracking branch 'origin/perf/v2-subpath-imports' into fe…
titouanmathis Sep 2, 2026
1acb59d
chore: finish the v2 sweep the PHP-side audit left behind
titouanmathis Sep 2, 2026
829b0e4
Merge remote-tracking branch 'origin/chore/v2-twig-extension' into fe…
titouanmathis Sep 2, 2026
c7fd36a
fix(docs): redirect the renamed and dropped items on the current pref…
titouanmathis Sep 2, 2026
c30e3d3
fix(api): remove the dead /source endpoint and its path traversal
titouanmathis Sep 2, 2026
e00eb38
Merge remote-tracking branch 'origin/fix/api-source-path-traversal' i…
titouanmathis Sep 2, 2026
1f103c0
chore: drop the stale dependency references the v2 removal left behind
titouanmathis Sep 2, 2026
300df9a
Merge remote-tracking branch 'origin/chore/v2-stale-peer-lists' into …
titouanmathis Sep 2, 2026
982b3e1
feat(ui)!: redesign Cursor around published CSS hooks
titouanmathis Sep 2, 2026
4f9d7a3
Merge remote-tracking branch 'origin/feat/v2-cursor-redesign' into fe…
titouanmathis Sep 2, 2026
fcb834c
feat(ui): merge LargeText and CircularMarquee into one generic Marquee
titouanmathis Sep 2, 2026
febaebc
Merge remote-tracking branch 'origin/feat/v2-marquee' into feat/v2-co…
titouanmathis Sep 2, 2026
73a032b
docs: correct the round 9 and 10 test counts for the merged tree
titouanmathis Sep 2, 2026
0abc61b
docs(ui-motion,ui-mapbox): describe the code instead of the port
titouanmathis Sep 3, 2026
fbddf06
docs(ui-motion,ui-mapbox): point the injectors at the real setup API
titouanmathis Sep 3, 2026
bee2d36
Merge remote-tracking branch 'origin/chore/v2-comments-packages' into…
titouanmathis Sep 3, 2026
8551a83
docs(tests): describe what the specs assert, not what changed
titouanmathis Sep 3, 2026
013d35c
Merge remote-tracking branch 'origin/chore/v2-comments-tests' into fe…
titouanmathis Sep 3, 2026
5d6c331
test: drop the version comparison from three test names
titouanmathis Sep 3, 2026
94900eb
docs(tests): drop comparisons that name no version
titouanmathis Sep 3, 2026
c00e35c
Merge remote-tracking branch 'origin/chore/v2-comments-tests' into fe…
titouanmathis Sep 3, 2026
63098cf
docs(ui): describe the code as it is, not as a port
titouanmathis Sep 3, 2026
c57d573
Merge remote-tracking branch 'origin/chore/v2-comments-ui' into feat/…
titouanmathis Sep 3, 2026
c536334
fix(fetch): keep repeated GET form fields and keep `src` out of history
titouanmathis Sep 3, 2026
dbd5b6c
Merge remote-tracking branch 'origin/chore/v2-merge-main' into feat/v…
titouanmathis Sep 3, 2026
341371d
docs(changelog): add the 2.0.0-alpha.0 section
titouanmathis Sep 3, 2026
18ab0ad
Merge remote-tracking branch 'origin/chore/v2-changelog' into feat/v2…
titouanmathis Sep 3, 2026
2d5253b
chore: prepare 2.0.0-alpha.0
titouanmathis Sep 3, 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
  •  
  •  
  •  
96 changes: 92 additions & 4 deletions .ddev/nginx/prod-10-reference-redirects.conf
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,98 @@ location = /components.md {
return 301 /reference/$is_args$args;
}

# Normalize the historical AnchorScrollto directory casing while preserving
# nested API/example paths and query strings.
location ~* ^/components/AnchorScrollto(.*)$ {
return 301 /reference/items/AnchorScrollTo$1$is_args$args;
# v2 renamed three items. The rule below would send these to their old names,
# which no longer exist, so a v1 link would 301 into a 404. Case-insensitive on
# the first, which also normalizes the historical `AnchorScrollto` casing.
location ~* ^/components/AnchorScrollTo(.*)$ {
return 301 /reference/items/ScrollTo$1$is_args$args;
}

location ~ ^/components/LazyInclude(.*)$ {
return 301 /reference/items/Defer$1$is_args$args;
}

location ~ ^/components/PrefetchWhenOver(.*)$ {
return 301 /reference/items/Prefetch$1$is_args$args;
}

# v2 merged the two marquees into one `Marquee`. Both v1 names keep their
# sub-path, because the successor has the same `js-api`, `twig-api` and
# `examples` pages the two of them had between them.
location ~ ^/components/(LargeText|CircularMarquee)(.*)$ {
return 301 /reference/items/Marquee$2$is_args$args;
}

# v2 dropped six families. Their pages are gone, so each goes to the component
# that supersedes it rather than to a 404 — the successor page is where a
# reader following a v1 link needs to end up. Nested paths are dropped: the
# successor has its own anatomy and examples, and a v1 sub-path has no
# counterpart under a different component.
location ~ ^/components/Accordion {
return 301 /reference/items/Disclosure/$is_args$args;
}

location ~ ^/components/Frame {
return 301 /reference/items/Fetch/$is_args$args;
}

location ~ ^/components/(Modal|Panel) {
return 301 /reference/items/Dialog/$is_args$args;
}

location ~ ^/components/ScrollAnimation {
return 301 /reference/items/Motion/$is_args$args;
}

location ~ ^/components/Slider {
return 301 /reference/items/Carousel/$is_args$args;
}

# The same renames and drops, on the current prefix.
#
# `/components/` is the pre-1.0 prefix, but v1.10's own reference already lived
# at `/reference/items/`, so every link published from the 1.10 site to an item
# v2 renamed or dropped 404s without these. Each pattern is anchored to the end
# of the item name, so a longer v2 name starting with the same letters is never
# caught by one of them.
location ~* ^/reference/items/AnchorScrollTo(/.*)?$ {
return 301 /reference/items/ScrollTo$1$is_args$args;
}

location ~ ^/reference/items/LazyInclude(/.*)?$ {
return 301 /reference/items/Defer$1$is_args$args;
}

location ~ ^/reference/items/PrefetchWhenOver(/.*)?$ {
return 301 /reference/items/Prefetch$1$is_args$args;
}

location ~ ^/reference/items/(LargeText|CircularMarquee)(/.*)?$ {
return 301 /reference/items/Marquee$2$is_args$args;
}

location ~ ^/reference/items/(Accordion|AccordionItem)(/.*)?$ {
return 301 /reference/items/Disclosure/$is_args$args;
}

location ~ ^/reference/items/Frame[A-Za-z]*(/.*)?$ {
return 301 /reference/items/Fetch/$is_args$args;
}

location ~ ^/reference/items/(Modal|ModalWithTransition|Panel)(/.*)?$ {
return 301 /reference/items/Dialog/$is_args$args;
}

location ~ ^/reference/items/(animationScrollWithEase|ScrollAnimation[A-Za-z]*|withScrollAnimationDebug)(/.*)?$ {
return 301 /reference/items/Motion/$is_args$args;
}

location ~ ^/reference/items/Slider[A-Za-z]*(/.*)?$ {
return 301 /reference/items/Carousel/$is_args$args;
}

location ~ ^/reference/items/withDeprecation(/.*)?$ {
return 301 /reference/$is_args$args;
}

# Preserve all former item, example and API paths below /components/.
Expand Down
4 changes: 2 additions & 2 deletions .ddev/nginx/prod-api.conf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Route the Symfony API app (symlinked at <docroot>/api -> packages/api/public)
# through its front controller so `/api/` and sub-routes such as /api/mcp and
# /api/source resolve, matching production. The existing `location ~ \.php$` block
# through its front controller so `/api/` and sub-routes such as /api/mcp
# resolve, matching production. The existing `location ~ \.php$` block
# handles the FastCGI pass; REQUEST_URI is preserved across the internal redirect, so
# Symfony derives the correct base path (/api) and path info.
#
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ jobs:
restore-keys: ${{ runner.os }}-node-
- name: Install modules
run: npm install --no-audit --no-fund
# The component specs run in a real Chromium through Vitest browser mode,
# so the runner needs the browser binary. No `--with-deps`: that installs
# system packages through apt and is Ubuntu-only.
- name: Install Playwright Chromium
run: npx playwright install chromium
- name: Run tests
run: npm run test -- -- --coverage.enabled
- name: Upload coverage to Codecov
Expand Down
65 changes: 64 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,76 @@ All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
## [v2.0.0-alpha.0](https://github.com/studiometa/ui/compare/1.11.1..2.0.0-alpha.0) (2026-09-03)

This is the first release of the v2 line. It moves every package onto [`@studiometa/js-toolkit` v4](https://js-toolkit-v4.studiometa.dev/), removes six component families that a newer component already covers, renames three components, merges `LargeText` and `CircularMarquee` into `Marquee`, rewrites `Tabs` on the WAI-ARIA Tabs pattern, redesigns `Cursor` around published CSS hooks, completes the `Carousel` family and gives it an accessibility contract, and changes the shape of every event payload. There is no compatibility layer.

Read [the v1 → v2 migration guide](https://ui.studiometa.dev/migration-guides/1.0-2.0/) before upgrading: it lists every replacement, every renamed ref, option and event, and the markup and CSS each one needs.

This is an alpha. The API may still change before `2.0.0`, and the packages install from the `next` dist-tag — `npm install @studiometa/ui@next`.

### Removed

- **@studiometa/ui:** remove `Accordion` and `AccordionItem` — use `DisclosureGroup` and `Disclosure`. `autoclose` was off by default and its replacement `multiple` is on by default, so the two are inverted rather than renamed ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `Frame` family (`Frame`, `FrameAnchor`, `FrameForm`, `FrameLoader`, `FrameTarget`, `FrameTriggerLoader`) and `AbstractFrameTrigger` — use `Fetch`, declared on the anchor or the form itself; `FrameTarget` becomes a plain `id` and the `frame-*` events become the `fetch-*` set ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove `Modal`, `ModalWithTransition` and `Panel` — use `Dialog`, whose root element must be a native `<dialog>` ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `ScrollAnimation` family, the `animationScrollWithEase` helper and the `withScrollAnimationDebug` decorator — use the `Motion` and `MotionScrollTimeline` components from `@studiometa/ui-motion` ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `Slider` family (`Slider`, `SliderBtn`, `SliderCount`, `SliderDots`, `SliderDrag`, `SliderItem`, `SliderProgress`) and `AbstractSliderChild` — use the `Carousel` family. `Carousel` moves the slides with native scrolling and `scroll-snap` instead of a transform, so the overflow moves from the root to the track and every v1 stylesheet has to follow ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `ImageGrid`, `Reinsurance`, `StyledModal` and `StyledPanel` Twig templates — copy the template into your project if you still need it ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `withDeprecation` decorator ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `Tabs` `styles` option and the `Transition` `group` option — style `[aria-selected="true"]` or nest a `Transition`, and give one component a list target to replace a group ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `@studiometa/ui/scheduler` subpath — `viewTransition` is exported by `@studiometa/js-toolkit` now — and the `@studiometa/ui/types` subpath, which went with the `Frame` family. Every dropped or renamed component takes its own subpath with it ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove the `CarouselStore`, `SliderStore`, `IndexableInstructions`, `TransitionConstructor`, `FetchConstructor`, `FetchShopifyPartialConstructor` and `FetchShopifySectionConstructor` types, along with the props types of the components that declare none; `Disclosure` and `DisclosureGroup` lose their props type parameter ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui-motion, @studiometa/ui:** remove `MotionView`'s `toggle` event and `withTransition`'s `transition-toggle` event — listen for the enter and leave events instead ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** remove every runtime dependency. `alien-signals`, `compute-scroll-into-view`, `deepmerge` and `morphdom` are all unreferenced since the port, so the package declares its runtime needs entirely through its `@studiometa/js-toolkit` peer ([#642](https://github.com/studiometa/ui/pull/642))

### Changed

- **@studiometa/ui, @studiometa/ui-mapbox, @studiometa/ui-motion:** require `@studiometa/js-toolkit` `^4.0.0-alpha.1` as a peer dependency. v4 is a major of its own — `createApp()` is removed, `$parent` and `$children` are removed, `destroyed()` becomes `unmounted()`, `$options` is read-only, every option is responsive, a boolean option reads presence and a handler payload is one object. See [the js-toolkit v3 → v4 migration guide](https://js-toolkit-v4.studiometa.dev/guide/migration/v3-to-v4.html) ([#642](https://github.com/studiometa/ui/pull/642))
- **Events:** `event.detail` is the payload object, or `null` when there is none, where v1 passed an array of the positional arguments. Every `event.detail[0]` becomes a named read, in `@studiometa/ui` and in `@studiometa/ui-mapbox` alike; `Fetch` and `Draggable` were `[{ … }]` and are `{ … }` ([#642](https://github.com/studiometa/ui/pull/642))
- **Disclosure, DisclosureGroup, Tabs:** namespace the shared event names, since `$emit()` bubbles in v4 and a listener on a group heard its children under the old names — `open`/`close`/`after-open`/`after-close` become `disclosure-*`, the group's `open`/`close`/`change` become `disclosure-group-*`, and `enable`/`disable` become `tabs-enable`/`tabs-disable` ([#642](https://github.com/studiometa/ui/pull/642))
- **Defer:** rename `LazyInclude` to `Defer`, with its `content`, `error` and `always` events renamed to `defer-content`, `defer-error` and `defer-always` ([#642](https://github.com/studiometa/ui/pull/642))
- **ScrollTo:** rename `AnchorScrollTo` to `ScrollTo`; `AnchorNavLink` extends it and follows the rename with no change of its own ([#642](https://github.com/studiometa/ui/pull/642))
- **PrefetchOnInteraction:** rename `PrefetchWhenOver` to `PrefetchOnInteraction`, which prefetches on the first of `pointerenter`, `pointerdown` or `focusin` instead of the `mouseenter` that never fired for touch or keyboard ([#642](https://github.com/studiometa/ui/pull/642))
- **Marquee:** merge `LargeText` and `CircularMarquee` into a single `Marquee` component that publishes `--marquee-progress`, `--marquee-offset` and `--marquee-velocity` and lets the stylesheet decide whether the travel is a translation, a rotation or a skew, instead of writing one hardcoded transform. `speed`, `sensitivity` and `damping` replace the old option set in units that say what they mean, the idle travel stops under `prefers-reduced-motion: reduce`, and `CircularMarquee.twig` survives as a Twig-only helper at `@ui/Marquee/CircularMarquee.twig` ([#642](https://github.com/studiometa/ui/pull/642))
- **Cursor:** redesign around published CSS hooks. The eight visual options become `states` and `damping`, and the component publishes `--cursor-x`, `--cursor-y`, `data-cursor-state` and `data-cursor-down` on its own element so a stylesheet draws the cursor. The position is written into `translate` rather than `transform`, so an author `scale` composes instead of multiplying the position ([#642](https://github.com/studiometa/ui/pull/642))
- **Tabs:** rewrite on the [WAI-ARIA Tabs pattern](https://www.w3.org/WAI/ARIA/apg/patterns/tabs/) — a new required `list` ref carries `role="tablist"` and the name, panels hide with the `hidden` property instead of `aria-hidden`, `enableItem()` and `disableItem()` become `goTo()`, `goNext()` and `goPrev()`, the open tab is the `btn` carrying `aria-selected="true"`, and arrow, <kbd>Home</kbd> and <kbd>End</kbd> keys drive a roving `tabindex`. `Tabs.twig` follows, with new `label` and `list_attr` parameters ([#642](https://github.com/studiometa/ui/pull/642))
- **Carousel:** ship an accessibility contract — an `aria-label` or `aria-labelledby` on the root and a name on every `CarouselBtn` are required and diagnosed, `role="group"` is written on the root and on every slide, a slide that does not intersect the track is `inert`, the current picker carries `aria-current="true"` instead of `disabled`, and a `slide-label` option names each slide ([#642](https://github.com/studiometa/ui/pull/642))
- **Carousel:** read the scroll alignment from each slide's own `scroll-snap-align` rather than hardcoding `center`, so `goTo()` lands exactly where a native snap would. `Slider`'s `mode` option becomes that CSS declaration: `left` is `scroll-snap-align: start`, `center` is `center` and `right` is `end` ([#642](https://github.com/studiometa/ui/pull/642))
- **CarouselDrag:** let the track's own `scroll-snap-type` decide whether a drop snaps — on `none` the drag coasts to the projected position and stops between slides, which is what `fitBounds: false` did ([#642](https://github.com/studiometa/ui/pull/642))
- **CarouselDrag:** carry the pointer's velocity into the drag settle. The track now leaves the pointer at the speed the hand had and decays at the drag service's own rate, instead of `behavior: 'smooth'` easing in from a standstill. The projection comes from the service too, so the same flick throws the same distance on every device ([#642](https://github.com/studiometa/ui/pull/642))
- **Disclosure:** stop writing the open state back to the DOM — a stylesheet selecting `[data-option-open]` after the first render must select `[aria-expanded="true"]` instead ([#642](https://github.com/studiometa/ui/pull/642))
- **Dialog:** look up a duck-typed `waitUntil()` extension by the event's own name (`open()`, `close()`) instead of v1's `enter()`/`leave()` pair, built on js-toolkit v4's `emitExtendable()`. Thenables are unaffected ([#642](https://github.com/studiometa/ui/pull/642))
- **Indexable:** read `reverse` and `boundary` from `this.isReverse` and `this.boundary` — `$options` is read-only in v4, so `this.$options.reverse = true` no longer works ([#642](https://github.com/studiometa/ui/pull/642))

### Added

- **Carousel:** add the `CarouselDots`, `CarouselThumbnails`, `CarouselCount`, `CarouselProgress` and `CarouselPlay` controls, each on its own element and each optional. `Carousel` declares its whole family, so `registerComponent(Carousel)` is enough to register every child ([#642](https://github.com/studiometa/ui/pull/642))
- **Carousel:** publish a `progress` event and a `--carousel-progress` custom property that follow the scroll offset continuously, plus `--carousel-item-active` on each slide in place of an `.is-active` class ([#642](https://github.com/studiometa/ui/pull/642))
- **@studiometa/ui:** add the `/AbstractFigure`, `/AbstractFigureDynamic`, `/AbstractTrack`, `/ActionEvent`, `/TrackEvent` and `/DataRegistry` subpaths ([#642](https://github.com/studiometa/ui/pull/642))

## [v1.11.1](https://github.com/studiometa/ui/compare/1.11.0..1.11.1) (2026-09-01)

This patch extends the `historyUrl` separation introduced in `1.11.0` to the declarative link and form handlers, which still bypassed it.

### Fixed

- **Fetch:** apply the `historyUrl` separation to a link click and a form submit, not only to a bare `fetch()` call — the declarative handlers passed the resolved URL on, which read as a caller naming a destination and kept a `src` in the address bar ([#646](https://github.com/studiometa/ui/pull/646))

## [v1.11.0](https://github.com/studiometa/ui/compare/1.10.0..1.11.0) (2026-09-01)

This release is led by `@studiometa/ui-motion`, a new package for declarative animation with [Motion](https://motion.dev), and by the `dom-update` protocol event — a shared announcement that lets a component substitute how an imminent DOM change is applied, which `DataBind`, `Dialog` and `Fetch` all now speak.

### Added

- **@studiometa/ui-motion:** add a new `@studiometa/ui-motion` package with the `Motion`, `MotionScrollTimeline`, `MotionSequence` and `MotionView` components to animate elements declaratively with [Motion](https://motion.dev) ([#628](https://github.com/studiometa/ui/pull/628), [#629](https://github.com/studiometa/ui/pull/629), [#630](https://github.com/studiometa/ui/pull/630), [#633](https://github.com/studiometa/ui/pull/633), [#636](https://github.com/studiometa/ui/pull/636), [#637](https://github.com/studiometa/ui/pull/637), [#638](https://github.com/studiometa/ui/pull/638), [#640](https://github.com/studiometa/ui/pull/640), [#641](https://github.com/studiometa/ui/pull/641))
- **DataBind:** add the `data-bind:if` virtual binding to render `<template>` content conditionally, announcing each change with the bubbling `dom-update` protocol event ([#626](https://github.com/studiometa/ui/pull/626), [#634](https://github.com/studiometa/ui/pull/634))

### Fixed

- **Fetch:** send every value of a repeated GET form field instead of the last one, so a checkbox group or a `<select multiple>` no longer reaches the server with one of its values ([#643](https://github.com/studiometa/ui/pull/643))
- **Fetch:** push the element's own destination in history rather than the fetched URL, so a `src` pointing at a lighter endpoint no longer leaks into the address bar — see the new `historyUrl` getter ([#643](https://github.com/studiometa/ui/pull/643))

### Changed

- **Dialog:** make the `open` and `close` events bubble and extendable with `event.detail.waitUntil()`, which also accepts a transitioner ([#627](https://github.com/studiometa/ui/pull/627), [#635](https://github.com/studiometa/ui/pull/635))
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ Import the components from the package as needed:

```js
import { registerComponents } from '@studiometa/js-toolkit';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue: README still registers removed components

The example imports Frame and ScrollAnimation, but this change removes both exported families. Following the documented setup therefore produces unresolved imports; replace them with components that remain in the v2 surface.

Confidence: high.


Reviewed by @weareikko/code-review v0.9.5 for commit f32774a.

import { Action, Dialog, Frame, ScrollAnimation, ScrollReveal, Slider } from '@studiometa/ui';
import { Action, Carousel, Dialog, Fetch, ScrollReveal } from '@studiometa/ui';

registerComponents(Action, Dialog, Frame, ScrollAnimation, ScrollReveal, Slider);
registerComponents(Action, Carousel, Dialog, Fetch, ScrollReveal);
```

Heads up to [ui.studiometa.dev](https://ui.studiometa.dev) for more informations.
Expand Down
Loading
Loading