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
7 changes: 7 additions & 0 deletions codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,10 @@ coverage:
default:
target: 90%
threshold: 0%

# Type-only declaration files (`.d.ts`) carry no runnable code — they
# describe shapes consumed at compile time. Coverage tools count any
# changed line as "0% covered" because there's nothing to instrument.
# Excluding them keeps the patch coverage signal honest.
ignore:
- '**/*.d.ts'
35 changes: 20 additions & 15 deletions packages/super-editor/src/ui/create-super-doc-ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -843,16 +843,13 @@ export function createSuperDocUI(options: SuperDocUIOptions): SuperDocUI {
return receipt;
},
async scrollTo(commentId) {
// Preserve `address.story` for non-body comments so navigation
// resolves to the right header / footer / note rather than
// defaulting to body.
const story = lookupItemStory(commentId);
const target =
story != null
? { kind: 'entity' as const, entityType: 'comment' as const, entityId: commentId, story }
: { kind: 'entity' as const, entityType: 'comment' as const, entityId: commentId };
// `CommentAddress` is body-scoped in the contract — it has no
// `story` field today. Story-aware comment navigation lands as
// a separate doc-API extension; until then, just route the id
// and let `presentation.navigateTo` resolve through the comment
// entity store.
return runScrollIntoView({
target,
target: { kind: 'entity', entityType: 'comment', entityId: commentId },
block: 'center',
behavior: 'smooth',
});
Expand Down Expand Up @@ -990,14 +987,22 @@ export function createSuperDocUI(options: SuperDocUIOptions): SuperDocUI {
},
async scrollTo(id) {
const kind = entityKindForId(id);
const entityType = kind === 'change' ? 'trackedChange' : 'comment';
activeReviewId = id;
scheduleNotify();
const story = lookupItemStory(id);
const target =
story != null
? { kind: 'entity' as const, entityType, entityId: id, story }
: { kind: 'entity' as const, entityType, entityId: id };
// `EntityAddress` is a discriminated union: `CommentAddress`
// doesn't carry a `story` field, only `TrackedChangeAddress`
// does. Branch on `kind` so the constructed target matches the
// right union member exactly.
let target: import('@superdoc/document-api').EntityAddress;
if (kind === 'change') {
const story = lookupItemStory(id) as import('@superdoc/document-api').TrackedChangeAddress['story'];
target =
story != null
? { kind: 'entity', entityType: 'trackedChange', entityId: id, story }
: { kind: 'entity', entityType: 'trackedChange', entityId: id };
} else {
target = { kind: 'entity', entityType: 'comment', entityId: id };
}
return runScrollIntoView({
target,
block: 'center',
Expand Down
2 changes: 2 additions & 0 deletions packages/super-editor/src/ui/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ export interface SuperDocEditorLike {
empty: boolean;
text?: string;
target?: unknown;
/** Active mark names at the caret / across the selection. */
activeMarks?: string[];
/** Present after SD-2792; absent on older builds — controller falls back to []. */
activeCommentIds?: string[];
activeChangeIds?: string[];
Expand Down
83 changes: 83 additions & 0 deletions tests/consumer-typecheck/src/customer-scenario.ts
Original file line number Diff line number Diff line change
Expand Up @@ -834,6 +834,88 @@ function testVueComponents() {
const slashMenu = SlashMenu;
}

// ============================================
// SECTION 18: superdoc/ui sub-entry — `createSuperDocUI({ superdoc })`
// ============================================

/**
* Type-level smoke test for the published `superdoc/ui` sub-entry.
*
* Mirrors the `superdoc/headless-toolbar` shim pattern: this module
* is a thin re-export of the browser-only UI controller from
* `@superdoc/super-editor`. Without a consumer-perspective import,
* the published sub-entry would only be type-checked from inside the
* monorepo and a broken re-export could ship undetected.
*/
import {
createSuperDocUI,
shallowEqual,
type CommentsHandle,
type CommentsSlice,
type EqualityFn,
type ReviewHandle,
type ReviewItem,
type ReviewSlice,
type SelectionSlice,
type SelectorFn,
type Subscribable,
type SuperDocEditorLike,
type SuperDocLike,
type SuperDocUI,
type SuperDocUIOptions,
type SuperDocUIState,
type ViewportGetRectInput,
type ViewportHandle,
type ViewportRect,
type ViewportRectResult,
} from 'superdoc/ui';

function testSuperDocUISubEntry() {
// Runtime exports compile and have callable shapes.
const factory: (options: SuperDocUIOptions) => SuperDocUI = createSuperDocUI;
const eq: EqualityFn<unknown> = shallowEqual;
void factory;
void eq;

// Public handle / slice types resolve through the sub-entry.
type AssertHandles = {
toolbar: SuperDocUI['toolbar'];
commands: SuperDocUI['commands'];
comments: CommentsHandle;
review: ReviewHandle;
viewport: ViewportHandle;
state: SuperDocUIState;
};
type AssertSlices = {
selection: SelectionSlice;
comments: CommentsSlice;
review: ReviewSlice;
reviewItem: ReviewItem;
};
type AssertViewportShapes = {
input: ViewportGetRectInput;
rect: ViewportRect;
result: ViewportRectResult;
};
type AssertSubstrate = {
selector: SelectorFn<SuperDocUIState, SelectionSlice>;
sub: Subscribable<SelectionSlice>;
};
type AssertHostShapes = {
superdoc: SuperDocLike;
editor: SuperDocEditorLike;
};

// `void` the type aliases so the file stays a smoke test, not a
// sample. Touching each at value level via `null as never` keeps
// the typechecker honest without runtime work.
void (null as never as AssertHandles);
void (null as never as AssertSlices);
void (null as never as AssertViewportShapes);
void (null as never as AssertSubstrate);
void (null as never as AssertHostShapes);
}

export {
testTypeShapes,
testEditorOptions,
Expand All @@ -860,4 +942,5 @@ export {
testAdditionalFunctions,
testAdditionalClasses,
testVueComponents,
testSuperDocUISubEntry,
};
Loading