0b61ff2bf4
* refactor(runtime)!: rename AnimationOptions to UseAnimationOptions
Align the useAnimation options type with VueUse's UseXOptions convention, matching its sibling composable options bags (UseInputOptions / UsePasteOptions / UseFocusOptions) and the already-correct UseAnimationReturn. Hard rename, no deprecated alias — done while the package is pre-1.0 (0.0.x), so no stability break.
Recorded under "Public composable naming follows Vue conventions" in .agents/docs/ink-divergences.md. Surfaced by the public-API audit.
BREAKING CHANGE: the exported type AnimationOptions is renamed to UseAnimationOptions; update `import { type AnimationOptions }` to `import { type UseAnimationOptions }`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(runtime)!: tighten public API to Ink + record aria decision & alignment principle
Public-API audit follow-ups. Where vue-tui had drifted from Ink with no real Vue reason, align to Ink; reduce speculative surface; and record decisions in .agents/docs/ink-divergences.md.
- renderToString: drop the public `isScreenReaderEnabled` option (Ink's public renderToString is layout-only). The SR-capable variant moves to `@vue-tui/runtime/internal` as `renderToStringWithScreenReader` for the accessibility test suite; SR output is unchanged.
- useTerminalSize -> useWindowSize: drop the invented name + alias, align to Ink's `useWindowSize`. The reactive ref return shape is unchanged (shallowRef divergence still applies).
- DevState/DevErrorInfo: move from the public barrel to `@vue-tui/runtime/internal` (internal HMR types, no public consumer; Ink exposes no HMR types).
- docs(divergences): add a standing "Why align to Ink — and when not to" principle (alignment is a means to reduce bugs, not an end; Vue idiom + reasonableness outrank parity); record the aria-props camelCase decision with its run-verified type-safety boundary; stamp the rawMode-default and measureElement-$el entries with their KEEP decisions.
BREAKING CHANGE: removed public exports `useTerminalSize`, `DevState`, `DevErrorInfo`, and `renderToString`'s `isScreenReaderEnabled` option. Use `useWindowSize`; import HMR types from `@vue-tui/runtime/internal`.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(runtime)!: move renderScreenReaderOutput to /internal-only
The screen-reader linearizer (ported from Ink's internal
`renderNodeToScreenReaderOutput`) was exported from the public barrel, but it
was never usefully public: its only parameter type `TuiNode` and the
node-construction primitives needed to build one are not public, so a public
consumer could not name or construct the argument. Ink keeps its counterpart
module-internal; we match that.
`renderScreenReaderOutput` + `ScreenReaderOptions` now live only in
`@vue-tui/runtime/internal` (already re-exported there). The live SR machinery
(render, the internal renderToStringWithScreenReader, the <Static> channel)
imports from the source module and is unaffected; public SR output is reached
via the mount `isScreenReaderEnabled` option.
public-api.test.ts: drop it from the public-members list; add a runtime guard
(absent from public, present on /internal) plus a compile-time @ts-expect-error
guard that the `ScreenReaderOptions` type cannot be re-added to the public
barrel.
Docs: new .agents/docs/accessibility-api.md (aria + SR design) and
api-contract.md (public surface = exports + their user-consumable types;
/internal is not the contract); resolve the open item and cross-link from
ink-divergences.md.
BREAKING CHANGE: renderScreenReaderOutput and ScreenReaderOptions are no longer
exported from @vue-tui/runtime; import from @vue-tui/runtime/internal if needed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* test(runtime-tests): snapshot the exact public value-export set
Upgrade public-api.test.ts from "documented members present + targeted
negatives" to an exhaustive snapshot of the exact runtime value-export surface
of `@vue-tui/runtime`: adding, removing, or renaming any value export now fails
the test, so every public-surface change must be a deliberate edit to the list.
Type-only exports are erased at runtime and cannot be enumerated, so the type
surface stays guarded individually (the `@ts-expect-error` ScreenReaderOptions
guard); api-contract.md is updated to state this boundary precisely.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
74 lines
3.2 KiB
TypeScript
74 lines
3.2 KiB
TypeScript
import { expect, test } from "vite-plus/test";
|
|
import * as api from "@vue-tui/runtime";
|
|
import * as internalApi from "@vue-tui/runtime/internal";
|
|
|
|
// The EXACT public runtime (value) export surface of `@vue-tui/runtime`. The test below snapshots
|
|
// it exhaustively: adding, removing, or renaming ANY value export fails — so every change to the
|
|
// public surface must be a deliberate edit here. Keep grouped + alphabetical-within-group for
|
|
// readable diffs. NOTE: type-only exports are erased at runtime and cannot be enumerated this way;
|
|
// they are guarded individually with `@ts-expect-error` (see the `ScreenReaderOptions` guard
|
|
// below). The type surface is therefore not exhaustively snapshotted.
|
|
const PUBLIC_VALUE_EXPORTS = [
|
|
// Entry point
|
|
"createApp",
|
|
// Components
|
|
"Box",
|
|
"Newline",
|
|
"Spacer",
|
|
"Static",
|
|
"Text",
|
|
"Transform",
|
|
// Composables
|
|
"useAnimation",
|
|
"useApp",
|
|
"useBoxMetrics",
|
|
"useCursor",
|
|
"useFocus",
|
|
"useFocusManager",
|
|
"useInput",
|
|
"useIsScreenReaderEnabled",
|
|
"usePaste",
|
|
"useStderr",
|
|
"useStdin",
|
|
"useStdout",
|
|
"useWindowSize",
|
|
"measureElement",
|
|
// Rendering
|
|
"renderToString",
|
|
// Kitty keyboard
|
|
"kittyFlags",
|
|
"kittyModifiers",
|
|
];
|
|
|
|
test("public API surface is exactly the documented value-export set", () => {
|
|
expect(Object.keys(api).sort()).toEqual([...PUBLIC_VALUE_EXPORTS].sort());
|
|
});
|
|
|
|
// Ink keeps its `measure-text` module internal and does not re-export it. vue-tui
|
|
// once exported `measureText`/`measureTextNatural` under the (incorrect) belief it
|
|
// "matched Ink's public API" — it does not. These stay internal; this guards the
|
|
// alignment against re-introduction. See .agents/docs/ink-divergences.md.
|
|
test("does not expose internal text-measurement helpers (Ink keeps them internal)", () => {
|
|
expect(api).not.toHaveProperty("measureText");
|
|
expect(api).not.toHaveProperty("measureTextNatural");
|
|
});
|
|
|
|
// `renderScreenReaderOutput` is the screen-reader linearizer — internal SR machinery,
|
|
// not a public API. Ink keeps its counterpart (`renderNodeToScreenReaderOutput`)
|
|
// module-internal and never re-exports it; we match that. It was never usefully
|
|
// callable from the public barrel anyway: its only parameter type (`TuiNode`) and the
|
|
// node-construction primitives needed to build one live only in
|
|
// `@vue-tui/runtime/internal`. It moves there. See .agents/docs/accessibility-api.md.
|
|
test("does not expose the screen-reader linearizer publicly (Ink keeps it internal)", () => {
|
|
expect(api).not.toHaveProperty("renderScreenReaderOutput");
|
|
expect(internalApi).toHaveProperty("renderScreenReaderOutput");
|
|
});
|
|
|
|
// Compile-time guard for the TYPE half of the contract (types are erased at runtime, so this
|
|
// can't be an `expect()`): `ScreenReaderOptions` is internal-only too. Importing it from the
|
|
// PUBLIC barrel must NOT type-check — if it is ever re-added there, this `@ts-expect-error` goes
|
|
// unused and `tsc --noEmit` fails. Same idiom as the prop-type fixtures in integration/pty/fixtures.
|
|
// It DOES type-check from `/internal`, which the runtime guard above already proves is the home.
|
|
// @ts-expect-error - ScreenReaderOptions is exported only from @vue-tui/runtime/internal
|
|
export type _ScreenReaderOptionsIsInternalOnly = import("@vue-tui/runtime").ScreenReaderOptions;
|