Consuming the package under `verbatimModuleSyntax` + `strictTemplates` surfaced
four defects that forced workarounds downstream.
- Drop the deprecated `SelectValue` string alias. It collided with the
`SelectValue` component exported from the same barrel, so the component
resolved to the type meaning and could not be imported (TS1484).
- Narrow the select's model to `SelectModelValue<T, Multiple>` and make
`TabsRoot` generic over its value, so a plain `v-model` on a `Ref<string>`
type-checks. Both roots declare the value prop and emit explicitly instead of
via `defineModel`, which would widen the payload with `| undefined` even
though neither control ever clears its value.
- Stop declaring `defineModel` keys in `defineEmits` as well. The duplicate
erased the payload type from the generated declarations, shipping
`(...args: unknown[]) => any` for eleven components' model events.
- Let every part accept global DOM attributes (`id`, `role`, `aria-*`,
`data-*`, ...) through `PrimitiveAttributes`. The heritage clause is marked
`@vue-ignore`, so they stay out of the runtime props and keep falling through
via `$attrs` exactly as before.
- Give `SelectContent` and `SelectViewport` a single styleable root: the
content forwards `$attrs` onto the panel, and the viewport's scrollbar CSS
moves to a reference-counted `<head>` style tag. A forwarded `class` was
previously dropped, leaving the panel unstyled.
The tsconfig vue preset gains `htmlAttributes: ["aria-*", "data-*"]` so
hyphenated data attributes are not camelized before they reach those types.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Genuinely type composable any usages (useStepper/useStorage/useForm/
createEventHook/useSorted/etc.) as proper generics/unknown; keep idiomatic
any-function and overload-impl signatures with comments; skipped test -> .todo.
Reworks the editor playground into a tabbed showcase:
- Rich text & blocks: drag-to-reorder handles, bubble/slash menus, and a live output panel (block/word counts, selection readout, document JSON).
- Multiplayer: two CRDT replicas synced over an in-memory channel with remote cursors, an in-sync indicator, and a Connected/Offline toggle that demonstrates divergence → convergence.
Also removes the focus outline on the contenteditable (outline: none on the editable surface).
A live @robonen/editor instance (default registry) as a doc section at /editor/playground: a reactive formatting toolbar, the bubble/slash menus, and a sample document exercising every block and mark — styled with the docs design tokens and wrapped in <ClientOnly> for SSR. Links it from the editor intro.
Setting a custom property to 'initial' (a CSS-wide keyword) computes to the guaranteed-invalid value, so getComputedStyle returns '' — correct per spec and now implemented by jsdom 29 (the deps bump from jsdom 28). Use a normal token ('start') so the read returns the value.
selectionchange is dispatched on a macrotask, so awaiting nextTick (microtasks) didn't wait for the editor to sync the native selection into the model — the assertion saw the initial selection. Poll with vi.waitFor instead. (Surfaced now that per-package CI runs editor's browser tests, which the root vitest projects list omitted.)
An intro.vue landing for all 12 packages, plus a multi-section crdt guide (Concepts, Primitives, Replication & Sync, and an interactive convergence Playground).