상태: 1.0 semantic freeze 기준.
Selection은 DOM focus나 화면 highlight가 아니라 JSON document 위의 headless 주소 상태다. 앱은 이 상태를 사용해 keyboard focus, row focus, visual handles, text caret, review marker를 투영할 수 있지만, core selection 자체는 UI를 소유하지 않는다.
MUST, MUST NOT, SHOULD, SHOULD NOT, MAY는 규범 키워드다.
Selection snapshot은 JSON-serializable이어야 한다. Public selection API는 JSON Pointer를 주소로 사용해야 하며, DOM node, React ref, layout coordinate를 저장하면 안 된다.
SelectionMode는 reducer가 selection을 정규화하는 방식을 정한다.
| Mode | 의미 |
|---|---|
single |
마지막 target 하나만 유지한다 |
multiple |
여러 collapsed range 또는 range를 유지한다 |
extended |
multiple과 같은 다중 selection 표면을 제공하며 anchor/focus 확장 흐름에 쓴다 |
Mode는 UI keyboard policy가 아니다. shift, cmd, ctrl 같은 host gesture는
앱이나 adapter가 action으로 번역한다.
Selection point는 pointer 문자열 또는 point object다.
type SelectionPoint =
| Pointer
| {
path: Pointer;
offset?: number;
edge?: "before" | "after";
affinity?: "forward" | "backward";
};path는 JSON Pointer다. offset은 string이나 host-defined ordered scope에서
위치를 표현할 때 쓸 수 있다. edge와 affinity는 같은 pointer 안에서 caret
또는 boundary 방향을 복원하기 위한 hint다.
Selection range는 anchor와 focus를 가진다.
type SelectionRange = {
anchor: SelectionPoint;
focus: SelectionPoint;
};Collapsed selection은 anchor와 focus가 같은 pointer를 가리키는 range다. Range가 가리키는 pointer 목록은 document traversal과 값 종류에 따라 확장될 수 있다.
SelectionSnap은 selection의 stable serialized form이다.
type SelectionSnap = {
selectedPointers: Pointer[];
selectionRanges: SelectionRange[];
primaryIndex: number;
anchor: SelectionPoint | null;
focus: SelectionPoint | null;
context?: JSONValue;
};필드 의미는 다음과 같다.
| Field | 의미 |
|---|---|
selectedPointers |
bulk command, clipboard, query 결과 투영에 쓰는 ordered pointer set |
selectionRanges |
anchor/focus 보존이 필요한 range 목록 |
primaryIndex |
primary range index. empty selection은 -1 |
anchor |
primary range의 anchor. empty selection은 null |
focus |
primary range의 focus. empty selection은 null |
context |
앱이 복원하고 싶은 JSON-serializable selection context |
selectedPointers는 중복 없이 정규화되어야 한다. selectionRanges가 비어 있으면
selection은 empty이며 primaryIndex는 -1, anchor와 focus는 null이어야
한다.
Selection action은 snapshot을 새 snapshot으로 줄이는 pure 의미론을 가져야 한다.
| Action | 의미 |
|---|---|
collapse |
한 point로 collapsed selection을 만든다 |
setBaseAndExtent |
anchor와 focus로 range를 만든다 |
extend |
기존 anchor에서 새 focus로 확장한다 |
addRange |
range를 추가하고 primary로 만든다 |
removeRange |
range, point, index 중 하나에 맞는 range를 제거한다 |
toggleRange |
같은 range가 있으면 제거하고 없으면 추가한다 |
togglePointer |
pointer collapsed range를 toggle한다 |
selectRanges |
range 목록을 한 번에 설정한다 |
empty |
empty selection으로 만든다 |
setContext |
JSON context를 저장한다 |
clearContext |
context를 제거한다 |
single mode에서는 action 결과가 항상 마지막 range 하나로 정규화되어야 한다.
multiple과 extended mode에서는 중복 range를 제거하고 primary range를 유지해야
한다.
Document patch 이후 selection은 다음 순서로 결정된다.
- Mutation metadata가 explicit final selection인
selectionAfter를 제공하면 그 snapshot을 복원한다. - 제공하지 않으면 applied JSON Patch operation으로 기존 pointer를 track한다.
add,copy,move가 새 target을 만들면 auto target selection을 만들 수 있다.- 살아남은 pointer는 보존한다.
- 제거된 pointer는 recovery target이 있으면 재지정하고, 없으면 제거한다.
Structural command extension은 앱 의도를 가장 잘 아는 위치에 있으므로
selectionAfter를 제공하는 편이 좋다. Core auto tracking은 일반 patch에 대한
fallback이다.
Patch와 selectionAfter는 같은 history entry에 원자적으로 기록되어야 한다.
실패한 mutation은 selection을 바꾸면 안 된다.
Cursor와 scope API는 pointer traversal 위에서 동작한다.
| Code | 의미 |
|---|---|
invalid_pointer |
scope pointer 문법이 잘못됨 |
path_not_found |
scope 또는 point target이 없음 |
syntax_error |
traversal input 문법 오류 |
empty_scope |
scope 안에 움직일 point가 없음 |
cursor_boundary |
first/last 경계에서 더 이동할 수 없음 |
point_not_in_order |
anchor/focus point가 traversal order에 없음 |
empty_selection |
order 작업에 필요한 selection이 없음 |
Cursor 실패 result는 기존 selection snapshot을 함께 반환해야 한다. 실패한 cursor move가 selection을 바꾸면 안 되기 때문이다.
Text edit helper는 string 값 위의 headless selection replacement다.
텍스트 replacement는 한 range가 하나의 pointer 안에 있어야 한다. 여러 pointer를 가로지르는 rich text editing, mark formatting, inline decoration은 core selection의 책임이 아니다.
Text edit 실패 code는 다음을 포함할 수 있다.
| Code | 의미 |
|---|---|
missing_length |
point offset 계산에 필요한 string 길이가 없음 |
multi_pointer_range |
range가 여러 pointer를 가로지름 |
overlapping_ranges |
replacement range가 겹침 |
cursor_boundary |
collapsed deletion이 string 경계를 넘음 |
path_not_found |
target pointer가 없음 |
not_string |
target 값이 string이 아님 |
Selection contract는 다음을 제공하지 않는다.
- DOM focus ownership.
- row focus와 keyboard roving tabindex.
- 2D marquee, geometry, resize handles.
- rich text mark formatting.
- stable object id resolver.
- collaborative presence protocol.
이 기능들은 public selection snapshot과 pointer tracking 위에 adapter나 extension이 구현할 수 있다.
다음 변경은 1.0 이후 breaking change다.
SelectionSnap필드 제거 또는 의미 변경.- empty selection의
primaryIndex: -1규칙 변경. singlemode가 여러 range를 유지하도록 변경.- mutation failure가 selection을 변경하도록 변경.
- explicit
selectionAfter보다 auto tracking을 우선하도록 변경. - selection error code 제거, rename, 의미 변경.