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>
FetchOptions['body'] listed `Record<string, unknown>`, which a named interface
is not assignable to (interfaces carry no implicit index signature), so every
caller passing a typed body had to cast it. Widen the object member to `object`:
named interfaces and arrays now assign directly, `any` is not introduced, and
bare primitives (number/boolean) are still rejected. Runtime is unchanged — the
serializer already narrows the body with its own casts.
Guard it with a type test (src/types.test-d.ts, run under vitest --typecheck):
a named interface must assign to the body type and flow through the method
shortcuts with no cast, while bare primitives stay rejected. Enable typecheck
for the package's vitest project so the assertions are enforced by tsc.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The SFC type resolver resolves `@robonen/*` package imports (e.g. PrimitiveProps,
used in `defineProps<X extends PrimitiveProps>()`) via the package `exports` →
`dist/*.d.ts`, independently of the Vite source-alias. On a fresh checkout (CI /
Vercel) those dist files don't exist yet, so the compiler throws 'Failed to
resolve extends base type'. `build`/`generate` now run `build:deps` first.
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.
Type guards take `unknown`; walkers/comparators (get/set/isEqual) narrow via
casts; generic defaults and constraints tightened. Truly-idiomatic any-function
constraints and load-bearing type-level any are kept with explanatory comments.
A 'tests' preset exempts *.test/*.spec/*.bench files from the type-boundary rules
(no-explicit-any, no-unused-vars, no-new-array, no-extraneous-class); base now
allows intentional console.warn/error (stray console.log still flagged).
Nuxt's dev vite-node IPC uses a unix socket under $TMPDIR. macOS's default /var/folders/… tmp dir pushes the path to ~110 chars, past the ~104-char sun_path limit, so every request 500s with 'connect EINVAL'. Point $TMPDIR at /tmp on darwin (guarded; other platforms untouched) before the builder generates the socket path.
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.
vitest browser mode writes failure-capture PNGs into .vitest-attachments/; keep them out of git (a tracked one was already being cleaned up in primitives).
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.)