feat(marko): add Marko v6 adapter#2023
Conversation
…p syncs in onUpdate + playwright trace
🦋 Changeset detectedLatest commit: 1555b04 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@clauderic can you pls help with this? |
Bullet list inside <ParamField> had zero-indent items and no separating blank line, causing MDX parser to misattribute the closing tag to the list scope. Standardize on 2-space indent with surrounding blank lines.
OptimisticSortingPlugin.ts imports 'move' from @dnd-kit/helpers but the package was missing from dom's dependencies and tsup external list. Pre-existing upstream issue exposed by clean install.
StyleInjector.ts in @dnd-kit/dom references process.env.NODE_ENV without @types/node available; tsup DTS build fails on a fresh checkout. Add at workspace root since @types/node is conventionally a monorepo-wide shared type.
Both packages previously relied on bun hoisting deps from sibling workspace packages. Lockfile regeneration after upstream merge changed the hoist targets, breaking npx and Node resolution respectively. Declaring deps where they're used makes the contract correct and immune to future hoist changes.
apps/docs/src/components/CodeBlock.tsx and SandpackCodeEditor.tsx import shiki/*, @shikijs/transformers, @codemirror/*, @lezer/highlight, and remark-gfm — none of which were in package.json. Worked locally via hoisting; broke on fresh install.
|
@clauderic can you pls help with this? |
clauderic
left a comment
There was a problem hiding this comment.
Summary
Adds @dnd-kit/marko, a new Marko v6 framework adapter for @dnd-kit/dom, alongside React/Vue/Svelte/Solid. End-user API mirrors the other adapters (<drag-drop-provider> + consumer tags). Includes SSR unit tests, Playwright e2e tests, Storybook stories, and 6 new docs pages. The PR also bundles several pre-existing upstream build fixes and a lockfile format change.
This is a large PR (~8.7k additions). Whether to take on another framework adapter is a strategic decision for @clauderic — I'm leaving that to the maintainer and flagging the concrete things that need attention regardless of that call.
Feedback
Blocking issues
.changeset/yellow-mice-warn.md— bump type ismajor. The project is pre-1.0 and onlypatch/minorare allowed per the changeset rules. For a brand-new package that ships alongside the existing fixed-versioning set this should beminor. The.changeset/config.jsonchange adds@dnd-kit/markoto thefixedarray, so it will release in lockstep with the rest of the adapters at the next coordinated bump — amajorhere would force a major-version bump on every package in the fixed group.
Suggestions
- PR size & scope — at 8.7k additions across 70+ files this is well past the threshold where splitting helps. The PR notes already cleanly separate the contents into three groups. Consider splitting into:
- The pre-existing upstream build fixes — these stand on their own and would be uncontroversial:
config/typescript/vanilla.json(ES2015 → ES2017)packages/dom/tsconfig.json(skipLibCheck: true) andpackages/dom/package.json+tsup.config.ts(declare@dnd-kit/helpers)- root
package.json(@types/node) apps/docs/package.json(shiki, codemirror, lezer deps)apps/stories-shared/package.json(@playwright/test)
- The
bun.lockb→bun.lockformat change — this is a one-line repo-wide decision (whether to track text or binary lockfiles) and should be deliberate, not a side effect. - The Marko adapter itself + docs + stories.
Each piece becomes much easier to review and revert independently.
- The pre-existing upstream build fixes — these stand on their own and would be uncontroversial:
- PR base/head — the head branch is
defunkt-dev:main, which works but means the contributor's fork'smainis now tied to this PR. A feature branch likefeat/marko-adapteris friendlier for follow-ups and for the contributor's own fork hygiene. packages/marko/src/runtime/renderer.ts:1— the double-queueMicrotaskrationale and its tie toactions.tsawait points is well-explained in the JSDoc. Worth keeping that comment as-is; it'll be the first thing anyone debugs.- Upstream issues flagged but not fixed — the PR notes call out
packages/react(missing@dnd-kit/collisionin deps/tsup external) andpackages/vue(TS2742). Worth filing as separate issues so they aren't lost; I can do that if it's helpful. - Marko-specific limitations are honestly documented (nested providers, overlay children). Good. The maintainer should weigh whether the v6-no-scoped-context constraint on overlay children is acceptable given the existing API contract on other adapters.
Changeset
- Status: present.
- Bump type: incorrect —
majornot allowed pre-1.0. Should beminor. (See blocking issues.) - Package name: correct (
@dnd-kit/marko).
Overall
A lot of careful work went into this — the deep-equality prop syncing, the <let-global> context bridge, the per-property Preact signal effect bridge, and the SSR + Playwright test coverage all reflect real attention to how the adapter has to interoperate with the existing core. The honest enumeration of upstream issues (fixed and unfixed) is appreciated. The main asks here are mechanical (changeset bump type + splitting); the bigger question of whether to take on Marko is for @clauderic. Thanks for the thoroughness!
[claude-review]
|
Thank you for looking into this. im working on this & will update this soon. |
Summary
Adds
@dnd-kit/marko, a MarkoJS v6 adapter for@dnd-kit/domas the sixth major framework adapter alongside React, Vue, Svelte, Solid, and vanilla.End-user API mirrors the other adapters: a root
<drag-drop-provider>delivers aDragDropManagerto descendant consumers via implicit context, and consumer tags (<create-draggable>,<create-droppable>,<create-sortable>,<drag-overlay>) register entities without explicit prop threading.Context delivery
Marko v6 has no public context API today. After discussion with the Marko core team, this adapter uses the officially-recommended
<let-global>pattern — reactive
$globalbacked by a per-key subscriptionMap. An internal<let-global>tag lives inpackages/marko/tags/let-global/. The provider writes the manager to$global.__dndKit_managerduring the render phase (via<const>IIFE, before children render), so consumers see it immediately at mount without timing workarounds.This replaces our earlier translator-based prototype, which depended on unstable compiler internals the Marko team explicitly ruled out exposing to third parties. The
<let-global>approach uses only public, documented APIs.Reactivity bridge
dnd-kituses@preact/signals-corefor entity state (isDragging,isDropTarget, etc.). Marko's reactivity is a separate compile-time graph over<let>variables.<create-deep-signal>bridges the two with per-property Preacteffect()subscriptions lazily created on first Proxy access; when a Preact signal fires, adirtycounter increments, which Marko sees and re-renders from.Deep-equality prop syncing
Matches the pattern applied to the React adapter in #2021. Consumer tags (
create-sortable,create-draggable,create-droppable) now deep-comparesensors,modifiers,plugins,accept, andtransitionbefore reassigning them to the entity on re-render. Without this, inline literals likeplugins={[MyPlugin]}create a new array reference every render, triggering redundant Preact reactive cascades and causing timing bugs in the Feedback plugin during drag.Lockfile format
bun.lockb(binary) →bun.lock(text). Side effect of regenerating thelockfile under bun 1.3+, which defaults to text format. If the maintainer
prefers staying on binary, happy to revert; this PR just reflects what
bun installproduced after the merge conflict resolution.Changes outside
packages/marko/Genuine additions for the Marko adapter
.changeset/config.json: add@dnd-kit/markoto thefixedarray so theMarko adapter versions in lockstep with the other adapters.
apps/docs/*: Marko navigation anchor, "Getting Started" card, logo asset,6 new MDX pages (quickstart + 5 tag pages), and a Storybook config entry
(port 6011).
README.md: Marko added to the Getting Started and Packages tables.apps/docs/docs/marko/components/drag-overlay.mdx: corrected ParamFieldbullet-list indentation (MDX parser rejected the original).
Pre-existing upstream build issues patched
These all worked on the maintainer's machine via bun hoisting or stale turbo
cache, but fail on a clean checkout. Each is a one-line fix in package
metadata; nothing source-level was changed.
config/typescript/vanilla.json:ES2015→ES2017.packages/geometry/src/types/axis.tsusesObject.values.packages/dom/tsconfig.json:skipLibCheck: true.packages/dom/package.json+tsup.config.ts: declare@dnd-kit/helpersas dependency and tsup external.
OptimisticSortingPlugin.tsimportsmovefrom it; was relying on workspace hoisting.package.json: add@types/nodedevDep soStyleInjector.tsprocess.env.NODE_ENVreference type-checks in the dom DTS build.apps/stories-marko/package.json: declarehttp-serverexplicitly(Playwright
webServerinvokesnpx http-server).apps/stories-shared/package.json: declare@playwright/testexplicitly(
tests/fixtures.tsimports it).apps/docs/package.json: declareshiki,@shikijs/transformers,@codemirror/{view,state,commands,lang-javascript,language},@lezer/highlight, andremark-gfmas devDeps. All are imported byupstream's
src/components/CodeBlock.tsxandSandpackCodeEditor.tsx.Pre-existing upstream build issues not fixed (out of scope)
Worth flagging so the maintainer is aware:
packages/react:useDroppable.tsimports@dnd-kit/collisionbut it'snot in deps or tsup external. Same class of bug as the dom/helpers fix.
packages/vue: TS d.ts portability error inDragDropProvider.ts(
TS2742— type leaks throughabstract/node_modules/@dnd-kit/geometry).Testing
packages/marko/tests/ssr.test.ts— cover compilation to HTML mode and rendering of sortable, draggable, droppable, and overlay fixtures. Verify thatDragDropManageris never constructed during SSR and that consumer tags render with default state.apps/stories-marko/tests/— use the shared suite fromapps/stories-shared/tests/. Cover vertical sortable (basic + drag handle + keyboard + cancel), draggable (pointer + keyboard + handle + state classes), and droppable (single + multiple zones + pointer + keyboard cancel).apps/stories-marko/stories/— 6 story groups covering the same scenarios, parallel in structure to the Svelte and Solid adapters. All verified manually in Storybook.All 20 tests pass.
bun run buildand the existing adapter test suites (React, Svelte, Vue, Solid) continue to pass — nothing shared was altered behaviorally.Documentation
Six new MDX pages under
apps/docs/docs/marko/:quickstart.mdxcomponents/drag-drop-provider.mdxcomponents/drag-overlay.mdxtags/create-draggable.mdxtags/create-droppable.mdxtags/create-sortable.mdxMarko uses
<Story>embeds (Storybook iframe on port 6011) like the other adapters. CodeSandbox embeds are omitted because Sandpack does not support Marko. So, static fenced code blocks are used instead.The
packages/marko/README.mdalso documents the full public API with examples.Known limitations (documented)
<drag-drop-provider>— two providers of the same type will conflict on the shared$globalkey. For single-manager pages (the common case, including TanStack Table row reordering) this is a non-issue. A stack-based fix is planned for v2 after Marko v6 ships its native context API.<drag-overlay>children — do not render<create-draggable>,<create-droppable>, or<create-sortable>inside the overlay. React/Svelte/Vue solve this with scoped context to prevent duplicate ID conflicts; Marko v6 has no scoped-context primitive yet. Documented in the overlay page.Related
Changeset
@dnd-kit/marko→major