Skip to content

Selection Method Reference

유용태 edited this page Jun 18, 2026 · 1 revision

Selection Method Reference

SelectionState는 DOM focus가 아니라 JSON document 위의 headless address state다. Selection은 pointer, range, caret, context를 저장하고, document patch 이후에도 가능한 한 같은 논리적 대상을 따라가도록 설계되어 있다.

Selection은 createJSONDocument(..., { selection: true }) 또는 selection: SelectionOptions로 켠 경우 doc.selection에서 접근한다.

기본 모델

type SelectionMode = "single" | "multiple" | "extended";
type SelectionEdge = "before" | "after";
type SelectionAffinity = "forward" | "backward";
type SelectionType = "None" | "Caret" | "Range";
type SelectionSource = Pointer | ReadonlyArray<Pointer>;

Selection point는 pointer 문자열이거나 offset/edge/affinity를 가진 object다.

interface SelectionPointObject {
  path: Pointer;
  offset?: number;
  edge?: SelectionEdge;
  affinity?: SelectionAffinity;
}

type SelectionPoint = Pointer | SelectionPointObject;

interface SelectionRange {
  anchor: SelectionPoint;
  focus: SelectionPoint;
}

type SelectionRangeInput = SelectionPoint | SelectionRange;

문자열 pointer는 해당 node 전체 또는 node boundary를 뜻하는 고수준 point로 쓴다. 문자열 내부 caret이나 부분 text range가 필요하면 object point의 offset을 쓴다.

읽기 전용 속성

readonly selectedPointers: ReadonlyArray<Pointer>;
readonly selectionRanges: ReadonlyArray<SelectionRange>;
readonly primaryIndex: number;
readonly anchor: SelectionPoint | null;
readonly focus: SelectionPoint | null;
readonly context?: SelectionContext | undefined;

readonly rangeCount: number;
readonly selectedCount: number;
readonly hasSelection: boolean;
readonly isCollapsed: boolean;
readonly type: SelectionType;
readonly primaryRange: SelectionRange | null;
readonly anchorPointer: Pointer | null;
readonly focusPointer: Pointer | null;
readonly selectedSource: SelectionSource | null;
readonly primaryPointer: Pointer | null;
readonly caret: SelectionPoint | null;
readonly caretPointer: Pointer | null;

selectedPointers

현재 선택된 pointer 목록이다. copy, cut, delete, move의 source로 그대로 넘길 수 있다.

selectedSource

선택이 없으면 null, pointer 하나면 Pointer, 여러 개면 ReadonlyArray<Pointer>다.

const source = doc.selection?.selectedSource;
if (source) doc.copy(source);

primaryPointer

현재 selection의 primary range에서 대표 pointer를 반환한다. duplicate()처럼 하나의 source가 필요한 command가 기본값으로 사용한다.

caret / caretPointer

Selection이 collapsed 상태일 때 현재 caret point와 pointer를 반환한다. Text editor adapter에서 주로 쓴다.

Selection 변경 method

collapse(point)

collapse(point: SelectionPoint): void;

Selection을 하나의 collapsed caret으로 만든다.

doc.selection?.collapse({ path: "/title", offset: 3 });

setBaseAndExtent(anchor, focus)

setBaseAndExtent(anchor: SelectionPoint, focus: SelectionPoint): void;

Anchor와 focus를 직접 지정해 range를 만든다. DOM Selection의 base/extent 모델과 비슷하지만, 대상은 DOM node가 아니라 JSON Pointer다.

extend(point)

extend(point: SelectionPoint): void;

현재 anchor를 유지하고 focus를 새 point로 이동한다. Shift+Arrow, drag selection, range extension에 적합하다.

addRange(pointOrRange)

addRange(pointOrRange: SelectionPoint | SelectionRange): void;

기존 selection에 range를 추가한다. mode: "single"에서는 최종 selection이 하나로 정규화될 수 있다.

removeRange(pointOrRangeOrIndex)

removeRange(pointOrRangeOrIndex: SelectionPoint | SelectionRange | number): void;

Range 또는 index를 기준으로 selection에서 제거한다.

toggleRange(pointOrRange)

toggleRange(pointOrRange: SelectionPoint | SelectionRange): void;

같은 range가 있으면 제거하고, 없으면 추가한다.

togglePointer(pointer)

togglePointer(pointer: Pointer): void;

Pointer 단위 selection을 toggle한다. List item, table row, 블록 selection UI에서 자주 쓴다.

selectRanges(ranges, anchor?, focus?, primaryIndex?)

selectRanges(
  ranges: ReadonlyArray<SelectionRangeInput>,
  anchor?: SelectionPoint | null,
  focus?: SelectionPoint | null,
  primaryIndex?: number,
): void;

Selection 전체를 명시적으로 교체한다.

외부 selection snapshot, search result, review comment anchor를 selection으로 복원할 때 적합하다.

empty()

empty(): void;

Selection을 비운다.

Cursor method

Cursor method는 document state를 순회 가능한 point 목록으로 보고 이동한다.

type SelectionCursorDirection = "first" | "previous" | "next" | "last";

interface SelectionCursorOptions {
  points?: ReadonlyArray<SelectionPoint>;
  query?: string;
  scope?: Pointer;
  includeScope?: boolean;
  wrap?: boolean;
}

points를 직접 주면 그 순서를 사용한다. query를 주면 JSONPath 검색 결과를 cursor scope로 쓴다. scope는 탐색 범위를 제한한다.

moveCursor(direction, options?)

moveCursor(
  direction: SelectionCursorDirection,
  options?: SelectionCursorOptions,
): SelectionCursorResult;

Cursor를 이동하고 selection을 collapsed 상태로 바꾼다.

doc.selection?.moveCursor("next", { scope: "/items" });

extendCursor(direction, options?)

extendCursor(
  direction: SelectionCursorDirection,
  options?: SelectionCursorOptions,
): SelectionCursorResult;

Cursor target까지 selection range를 확장한다.

resolveCursor(direction, options?)

resolveCursor(
  direction: SelectionCursorDirection,
  options?: SelectionCursorOptions,
): SelectionCursorResult;

Selection을 바꾸지 않고 이동할 target만 계산한다.

주요 실패:

  • invalid_pointer
  • path_not_found
  • syntax_error
  • empty_scope
  • cursor_boundary

Ordering, scope, span

orderPrimaryRange(options?)

orderPrimaryRange(options?: SelectionOrderOptions): SelectionRangeOrderResult;

Primary range의 anchor/focus를 document traversal order 기준으로 정렬한다.

orderRanges(options?)

orderRanges(options?: SelectionOrderOptions): SelectionRangesOrderResult;

모든 range를 document traversal order 기준으로 정렬한다.

중첩 range, 역방향 range, multi-range selection을 처리하기 전에 호출한다.

spansForPointer(pointer, options?)

spansForPointer(
  pointer: Pointer,
  options?: SelectionSpanOptions,
): SelectionPointerSpansResult;

특정 pointer 안에서 selection이 차지하는 span을 계산한다.

interface SelectionSpanOptions extends SelectionOrderOptions {
  length?: number;
  getLength?: (pointer: Pointer, value: unknown) => number | null | undefined;
}

Text input adapter는 startOffset, endOffset, collapsed, full을 보고 실제 문자열 편집 범위를 만든다.

selectScope(options?)

selectScope(options?: SelectionScopeOptions): SelectionScopeResult;

Scope 안의 선택 가능한 point들을 찾아 selection으로 만든다.

doc.selection?.selectScope({ scope: "/items", query: "$[*]" });

resolveScope(options?)

resolveScope(options?: SelectionScopeOptions): SelectionScopeTarget;

Selection을 바꾸지 않고 scope target만 계산한다.

Text editing method

Text editing method는 selection을 patch로 낮춘다. 직접 state를 바꾸지 않고, patch 또는 edit 계획을 반환한다.

textEdits(replacement, options?)

textEdits(
  replacement: string,
  options?: SelectionTextEditOptions,
): SelectionTextEditsResult;

Selection을 문자열 replacement edit 목록으로 변환한다. 실제 document 변경은 호출자가 별도로 수행한다.

textPatch(replacement, options?)

textPatch(
  replacement: string,
  options?: SelectionTextEditOptions,
): ReplaceSelectionTextResult;

Selection을 JSON Patch와 다음 selection snapshot으로 변환한다.

const plan = doc.selection?.textPatch("hello");
if (plan?.ok) {
  doc.commit(plan.patch, { selection: plan.selection });
}

deleteText(options?)

deleteText(options?: SelectionTextDeleteOptions): DeleteSelectionTextResult;

Selection range를 삭제하거나 collapsed caret 기준으로 앞/뒤 문자를 삭제하는 patch를 만든다.

doc.selection?.deleteText({ direction: "backward", count: 1 });

Text edit 주요 실패:

  • missing_length
  • multi_pointer_range
  • overlapping_ranges
  • cursor_boundary
  • path_not_found
  • not_string
  • point_not_in_order

Context, snapshot, lifecycle

setContext(context) / clearContext()

setContext(context: SelectionContext): void;
clearContext(): void;

Selection에 제품별 context를 붙이거나 제거한다.

isSelected(pointer)

isSelected(pointer: Pointer): boolean;

Pointer가 현재 selection에 포함되는지 확인한다.

snapshot() / toJSON()

snapshot(): SelectionSnap;
toJSON(): SelectionSnap;

현재 selection을 serializable snapshot으로 반환한다. History metadata, persistence, test assertion에 사용한다.

restore(snapshot)

restore(snapshot: SelectionSnap): void;

Snapshot으로 selection을 복원한다.

subscribe(listener)

subscribe(listener: (
  snapshot: SelectionSnap,
  previous: SelectionSnap,
) => void): () => void;

Selection 변경을 구독한다. 반환값은 unsubscribe 함수다.

const unsubscribe = doc.selection?.subscribe((next, prev) => {
  console.log(prev, next);
});

unsubscribe?.();

Patch 이후 selection

Document 변경이 성공하면 selection은 applied patch를 기준으로 자동 조정된다.

예를 들어 /items/0 앞에 새 item이 삽입되면 기존 /items/0 selection은 /items/1처럼 이동할 수 있다. 삭제된 target은 selection에서 제거될 수 있다.

이 동작 때문에 selection은 DOM focus보다 document state에 가까운 모델이다.

Clone this wiki locally