feat: Marko v6 integration (@formkit/auto-animate/marko)#239
Open
defunkt-dev wants to merge 5 commits into
Open
feat: Marko v6 integration (@formkit/auto-animate/marko)#239defunkt-dev wants to merge 5 commits into
defunkt-dev wants to merge 5 commits into
Conversation
|
@defunkt-dev is attempting to deploy a commit to the Formkit Team on Vercel. A member of the Team first needs to authorize it. |
Author
|
@justin-schroeder can you pls help us with this when you get a moment? Thanks in advance. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds an official Marko v6 integration, exposed as a
./markopackage export alongside the existing Vue, React, Solid, Preact, and Angular adapters. The integration is a single<auto-animate>custom tag that wraps the framework‑agnosticautoAnimate(el, options)core. This PR also includes a docs‑site framework tab and a Playwright e2e suite covering both client‑side rendering and SSR + resume.With options and a reactive on/off switch:
Motivation
Marko ships no built‑in animation system, so AutoAnimate fills a real gap for the common list/layout case (enter, leave, reorder of a container's children). Marko v6's reactivity is Svelte‑aligned, and the core controller is already shaped to satisfy a Svelte action, so it maps cleanly onto Marko's
<lifecycle>tag with no new abstractions.API
A single tag with three attributes — no body, no return value, no wrapper element:
parent: () => HTMLElement— the element whose direct children animate. The user owns the element and passes its native tag‑variable ref (e.g.<ul/listRef>→parent=listRef), mirroring the FormKit drag‑and‑drop integration and the ref pattern used by the React/Vue adapters.options?: Partial<AutoAnimateOptions> | AutoAnimationPlugin— read once at mount (the core has nosetOptions); to change options, remount the tag.enabled?: boolean— reactive; toggling it callsenable()/disable()on the controller without re‑initializing.What's included
src/marko/auto-animate.marko(the entire integration;Inputtyped inline).marko.json({"exports": "./tags"}), a"./marko"entry inpackage.jsonexports, amarkokeyword, and amarkoBuild()step inbuild/bundle.tsthat copies the source tag todist/tags/(the manifest is copied verbatim alongside README/LICENSE).IconMarkobrand mark.tests/marko/) and SSR + resume (tests/marko-ssr/).Design notes (for reviewers)
<lifecycle>wrapper.onMountcallsautoAnimate(parent(), options)once and stores the controller on the lifecyclethis;onUpdateflipsenable()/disable()behind a guard;onDestroycallscontroller.destroy(). Teardown is also wired to the scope'sAbortSignal, so an enclosing<if>going false or a<for>item being removed cleans up the observers.this, not in a<let>. It's created client‑only inonMount, so it never reaches the serializer.optionsare static at mount by design (matches the core and the other adapters)..marko, and Marko tags are compiled by the consumer's@marko/vite. The build therefore copies the.markosource intodist; tag discovery is handled by the committed rootmarko.jsonexportsfield. The tag's relative../indeximport is left extensionless and resolves todist/index.mjsfor consumers.client importfor the core. Keeps the DOM‑only core out of the server bundle.<lifecycle>emits no HTML and never runs on the server; on resume the tag reads its parent as a real DOM node via the ref (not a value produced by another effect), so there's no resume‑ordering dependency. Plainoptionsobjects survive serialization; plugin‑function options are a client‑only path (documented).<for>lists must key by identity so nodes move (FLIP) rather than being recreated —by="id"for objects,by=(n => String(n))for primitives.Testing
The adapter's repo uses Playwright (no vitest), and animations are timing/visual‑sensitive, so coverage is e2e. Two self‑contained harnesses are added so they don't touch the Vue docs build.
CSR (
tests/marko/) — a four‑sectionApp.markodriven by Playwright. Covers: add / remove / reorder with FLIP, node‑identity survival across reorder (keyed<for>), the reactiveenabledtoggle (no re‑init), the all‑removedtextContent=""fast path plus re‑add, rapid overlapping mutations, primitive‑keyed lists, conditional/co‑located parent mount‑unmount, reactive‑unmount teardown via an enclosing<if>, andprefers-reduced-motion.SSR + resume (
tests/marko-ssr/) — a small render+resume server. Asserts the list is server‑rendered, the page resumes, server‑rendered children do not animate on load, a post‑resume mutation does animate, a plainoptionsobject survives resume, and characterizes an inline‑pluginoptionsroute.How to run (from the repo root):
Note:
@marko/viteis pinned to the5.4.xline because it runs on the repo's existing Vite 7 (its major version tracks Vite compatibility, not the Marko version, and it still compiles Marko 6 tags). The shipped adapter has no build‑time Marko dependency — these are devDependencies for the test harness only.Docs notes
Consistent with the existing site, the live
<ActualMarkoApp>demo is a Vue stand‑in built on the Vue adapter — exactly likeActualReactApp.vueand the other framework demos. The.markoexample files are imported as raw text (?raw) and shown as code only, so nothing Marko enters the docs' vite‑ssg build. The framework‑specific content is the code samples; the running previews share the same core.Out of scope (possible follow‑ups)
optionsunder SSR (would require the consumer to apply the core directly in their ownclient‑imported<lifecycle>).Checklist
.markotag and exposed via./markomarko.json,package.jsonexport + keyword,bundle.tscopy step.markosources type‑check clean (@marko/type-check)