Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 3 additions & 19 deletions packages/document-api/scripts/check-contract-parity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,10 @@ import { OPERATION_REFERENCE_DOC_PATH_MAP } from '../src/contract/reference-doc-
import { buildDispatchTable } from '../src/invoke/invoke.js';

/**
* Meta-methods and helper methods on DocumentApi that are not contract
* operations:
*
* - `ranges.scrollIntoView` is a browser-only UI side-effect (scrolls
* the viewport via the presentation editor). It has no headless
* implementation, so it is intentionally excluded from the RPC
* dispatch surface and the CLI command catalog. Direct calls through
* `editor.doc.ranges.scrollIntoView()` are still supported.
* - `selection.onChange` is a subscription primitive (push-based, no
* request/response shape) rather than a request-response operation,
* so it is not represented in `OPERATION_DEFINITIONS` / schemas /
* dispatch. Direct calls through `editor.doc.selection.onChange()`
* are still supported.
* Meta-methods on DocumentApi that are not contract operations: the
* dispatcher itself plus the documented reference aliases.
*/
const META_MEMBER_PATHS = [
'invoke',
'ranges.scrollIntoView',
'selection.onChange',
...REFERENCE_OPERATION_ALIASES.map((alias) => alias.memberPath),
];
const META_MEMBER_PATHS = ['invoke', ...REFERENCE_OPERATION_ALIASES.map((alias) => alias.memberPath)];

function collectFunctionMemberPaths(value: unknown, prefix = ''): string[] {
if (!value || typeof value !== 'object') return [];
Expand Down
12 changes: 0 additions & 12 deletions packages/document-api/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2173,18 +2173,6 @@ describe('createDocumentApi', () => {
expect(e.code).toBe('SELECTION_ADAPTER_UNAVAILABLE');
}
});

it('throws SELECTION_ADAPTER_UNAVAILABLE when selection.onChange is called without a selection adapter', () => {
const api = makeApiWithoutSelection();
try {
api.selection.onChange(() => {});
expect.fail('expected SELECTION_ADAPTER_UNAVAILABLE to be thrown');
} catch (err: unknown) {
const e = err as { name: string; code: string };
expect(e.name).toBe('DocumentApiValidationError');
expect(e.code).toBe('SELECTION_ADAPTER_UNAVAILABLE');
}
});
});

describe('comments.patch target validation', () => {
Expand Down
50 changes: 4 additions & 46 deletions packages/document-api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,9 @@ export type {
RangeResolverAdapter,
ScrollIntoViewInput,
ScrollIntoViewOutput,
RangeScrollAdapter,
} from './ranges/index.js';
export { executeResolveRange, executeScrollIntoView } from './ranges/index.js';
export type {
SelectionApi,
SelectionAdapter,
SelectionCurrentInput,
SelectionInfo,
SelectionChangeListener,
} from './selection/selection.js';
export { executeResolveRange } from './ranges/index.js';
export type { SelectionApi, SelectionAdapter, SelectionCurrentInput, SelectionInfo } from './selection/selection.js';
export { executeSelectionCurrent } from './selection/selection.js';
export type { HeaderFootersAdapter, HeaderFootersApi } from './header-footers/header-footers.js';
export * from './header-footers/header-footers.types.js';
Expand Down Expand Up @@ -136,22 +129,9 @@ import {
import type { InsertInput } from './insert/insert.js';
import { executeDelete } from './delete/delete.js';
import { executeResolveRange } from './ranges/resolve.js';
import { executeScrollIntoView } from './ranges/scroll-into-view.js';
import type {
RangeResolverAdapter,
ResolveRangeInput,
ResolveRangeOutput,
ScrollIntoViewInput,
ScrollIntoViewOutput,
} from './ranges/ranges.types.js';
import type { RangeResolverAdapter, ResolveRangeInput, ResolveRangeOutput } from './ranges/ranges.types.js';
import { executeSelectionCurrent } from './selection/selection.js';
import type {
SelectionApi,
SelectionAdapter,
SelectionCurrentInput,
SelectionInfo,
SelectionChangeListener,
} from './selection/selection.js';
import type { SelectionApi, SelectionAdapter, SelectionCurrentInput, SelectionInfo } from './selection/selection.js';
import { executeInsert } from './insert/insert.js';
import type { ListsAdapter, ListsApi } from './lists/lists.js';
import type {
Expand Down Expand Up @@ -1507,19 +1487,10 @@ export interface MutationsApi {

export interface RangesApi {
resolve(input: ResolveRangeInput): ResolveRangeOutput;
/**
* Scroll the editor viewport so the target range is visible. Handles
* paginated, virtualized layouts by mounting the target page on demand.
* Async — resolves once the scroll settles (or the page-mount timeout
* expires). Target accepts `TextAddress`, `TextTarget`, or `EntityAddress`
* (comment / tracked change by id).
*/
scrollIntoView(input: ScrollIntoViewInput): Promise<ScrollIntoViewOutput>;
}

export interface RangesAdapter {
resolve(input: ResolveRangeInput): ResolveRangeOutput;
scrollIntoView(input: ScrollIntoViewInput): Promise<ScrollIntoViewOutput>;
}

export interface QueryAdapter {
Expand Down Expand Up @@ -3183,9 +3154,6 @@ export function createDocumentApi(adapters: DocumentApiAdapters): DocumentApi {
resolve(input: ResolveRangeInput): ResolveRangeOutput {
return executeResolveRange(adapters.ranges, input);
},
scrollIntoView(input: ScrollIntoViewInput): Promise<ScrollIntoViewOutput> {
return executeScrollIntoView(adapters.ranges, input);
},
},
selection: {
current(input?: SelectionCurrentInput): SelectionInfo {
Expand All @@ -3198,16 +3166,6 @@ export function createDocumentApi(adapters: DocumentApiAdapters): DocumentApi {
}
return executeSelectionCurrent(adapter, input);
},
onChange(listener: SelectionChangeListener): () => void {
const adapter = adapters.selection;
if (!adapter) {
throw new DocumentApiValidationError(
'SELECTION_ADAPTER_UNAVAILABLE',
'No selection adapter was registered. Pass `selection` in DocumentApiAdapters to call selection.onChange().',
);
}
return adapter.onChange(listener);
},
},
mutations: {
preview(input: MutationsPreviewInput): MutationsPreviewOutput {
Expand Down
2 changes: 0 additions & 2 deletions packages/document-api/src/ranges/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,5 @@ export type {
RangeResolverAdapter,
ScrollIntoViewInput,
ScrollIntoViewOutput,
RangeScrollAdapter,
} from './ranges.types.js';
export { executeResolveRange } from './resolve.js';
export { executeScrollIntoView } from './scroll-into-view.js';
23 changes: 8 additions & 15 deletions packages/document-api/src/ranges/ranges.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,13 +122,14 @@ export interface RangeResolverAdapter {
}

// ---------------------------------------------------------------------------
// scrollIntoView
// scrollIntoView — input/output value types
// ---------------------------------------------------------------------------

/**
* Input for `ranges.scrollIntoView` — scrolls the editor viewport so the
* given text target is visible. Handles paginated, virtualized layouts by
* mounting the target page if it isn't yet in the DOM.
* Input for `ui.viewport.scrollIntoView` — scrolls the editor
* viewport so the given target is visible. Handles paginated,
* virtualized layouts by mounting the target page if it isn't yet in
* the DOM.
*/
export interface ScrollIntoViewInput {
/**
Expand All @@ -146,18 +147,10 @@ export interface ScrollIntoViewInput {
}

/**
* Result of `ranges.scrollIntoView`.
* `success: false` when the target couldn't be resolved or a page failed to
* mount within the navigation timeout.
* Result of `ui.viewport.scrollIntoView`. `success: false` when the
* target couldn't be resolved or a page failed to mount within the
* navigation timeout.
*/
export interface ScrollIntoViewOutput {
success: boolean;
}

/**
* Adapter method for `ranges.scrollIntoView`. Async because virtualized
* pages may need to mount before the scroll completes.
*/
export interface RangeScrollAdapter {
scrollIntoView(input: ScrollIntoViewInput): Promise<ScrollIntoViewOutput>;
}
175 changes: 0 additions & 175 deletions packages/document-api/src/ranges/scroll-into-view.test.ts

This file was deleted.

Loading
Loading