Skip to content

기본 편집 Profile의 전체 선택·확정·Undo 연결을 구현한다 #727

Closed

Description

@developer-1px

Goal Anchor

  • Outcome: 기본 편집 Profile에서 전체 선택을 반복해도 유지하고, 명시적 draft의 확정이 거절되면 수정 후 재시도할 수 있으며, Undo 입력이 기존 정본 해석과 편집 전후 선택 복원으로 연결되게 한다.
  • Done: 아래 네 구현을 기존 owner의 공개 API·reference·site Usage·source 등록에 연결하고, 기존 호출 호환성과 성공·거절·반복·빈 대상의 동작을 테스트한다. 앞서 확인한 Rich Text의 선택 → 교체 → Undo → Redo 사례를 영구 회귀 테스트에 넣고 실제 변경된 입력 경로를 검증한다. 학습 댓글과 구현 PR로 제공한다.
  • Don't: Core six-member 계약·Stable profile·package 배치를 변경하지 않는다. 새 editor·command bus·profile registry를 만들지 않는다. 기존 토글 입력과 void rename callback의 의미를 몰래 바꾸지 않는다. 비동기 확정, 새로운 IME·native Cut·여러 view History 정책이나 모든 Hands의 완성·독립 상호운용 인증으로 범위를 넓히지 않는다.

승인 근거와 설계 의존

사용자는 #725 / #726에서 정리한 기본 동작 12개 계약표와 최소 변경안을 전달받은 뒤 “진행해”라고 요청했다. 직전 전달의 네 범위는 전체 선택의 반복 입력 정책, 구조 editor의 한 번에 전체 선택하기, 확정 거절 시 draft를 유지하는 경로, 공통 Undo 입력 해석이다.

설계 정본은 #726의 97405f78에 있는 standards/editing-grammar.md의 “기본 동작별 계약”과 “하이라키 검토와 최소 코드 변경안”이다. #725는 설계 작업의 기록을 유지하고 이 이슈가 runtime 구현을 소유한다. 설계 문서 PR의 머지는 이번 요청의 전제가 아니다.

구체적인 구현 계약

  1. 반복 전체 선택 — Affordance
    • selectAllAffordance(stroke, state, { repeat: "preserve" }) 경로는 전체 선택 상태에서 다시 입력해도 select-all을 유지한다.
    • 옵션 생략과 명시적 토글은 기존 allSelected에 따른 select-all / clear 동작을 보존한다.
    • 기본 동작을 보여 주는 Usage는 preserve 경로를 소비한다. Host에서 입력 해석이나 토글 판정을 재구현하지 않는다.
  2. 구조 editor의 전체 선택 — Editing의 기존 domain owner
    • Document·Order·Tree·Sheet의 기존 Intent에 전체 선택 작업을 추가하고 기존 Selection family를 사용한다.
    • Document·Order는 해당 문서의 순서, Tree는 visible topology, Sheet는 선언된 행·열 topology를 전체 집합으로 삼는다.
    • 0·1·여러 대상에서 한 작업으로 최종 선택을 발행하며 첫·끝 선택을 연속 dispatch하는 중간 상태를 노출하지 않는다. 같은 집합의 반복 선택은 내용과 문서 Undo/Redo 기록을 보존한다.
    • 기존 point 선택 호출·Copy/Cut/Paste 대상과 Object의 기존 한 번에 ID 집합 선택하기는 유지한다.
  3. 거절 후 draft 유지 — Affordance rename session
    • 기존 onCommit: (...) => void와 새 동기 tryCommit: (...) => boolean 중 하나를 받는 경로를 제공한다. 둘을 함께 허용하지 않는다.
    • tryCommit이 false이면 draft와 편집 맥락을 유지하고 onFinish를 호출하지 않는다. 수정 후 성공하면 한 번 확정·종료·복귀한다. 취소는 확정 없이 종료한다.
    • 편집 검증과 문서 변경은 domain이 소유하고 Affordance는 성공 여부만 받는다. 기존 commits.push(...) 형태의 callback 호환성도 유지한다.
    • Order Usage는 정본 session과 item.rename 결과를 연결한다. Host에 별도 draft 복구 구현을 추가하지 않는다.
  4. 공통 Undo 해석과 복원 증거 — Web·Rich Text Web·기존 테스트 owner
    • Rich Text Web의 공통 Undo/Redo 키 해석은 createWebKeyboardAdapter를 소비한다. Text 삭제·IME·root 소유권은 기존 Rich Text Web에 둔다.
    • 기존 Rich Text 입력의 추가 modifier 수용 범위도 명시적으로 보존해 공통 resolver 연결이 기존 입력 의미를 바꾸지 않게 한다.
    • Alpha의 ph를 X로 교체하는 정방향·역방향 선택에서 Undo/Redo가 내용·선택·기록을 복원하고, Undo 후 선택 이동이 Redo를 지우지 않는 영구 회귀 증거를 남긴다. 직접 호출·기본 metaKey·ctrlKey 해석과 실제 binding의 관찰 범위를 구별한다.

검증과 전달

  • 관련 owner의 동작·타입 호환성 테스트, typecheck·build, 문서 및 source/Usage 등록 검사.
  • 실제 변경되는 선택·rename·Undo 입력 경로의 browser 검증. 사용자 Chrome의 기존 연결을 우선 사용한다.
  • API reference와 Usage는 기존 owner 경로에서 갱신한다. 구현 중 관찰한 근거와 판단은 이슈 댓글에 남긴다.
  • 현재 사용자의 원래 checkout은 dirty이므로 보존한다. 소유한 별도 checkout의 최신 origin/main에서 구현 브랜치를 만든다.
  • 구현 PR은 이 이슈만 닫으며, 머지는 별도 승인 전까지 수행하지 않는다.

Activity

  1. self-assigned this
    on Sep 8, 2026
  2. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    구현 작업 계획

    이슈 본문의 Goal Anchor와 네 구현 계약을 기준으로 진행한다. 새 동작은 기존 owner의 추가 API로 제공하며, Core·Stable profile·기존 callback과 입력 호환성을 유지한다.

    공개 API와 회귀 증거
    ├─ Affordance: repeat 정책·tryCommit 경로
    ├─ Editing: Document·Order·Tree·Sheet 전체 선택
    ├─ Rich Text Web: 공통 Undo resolver와 기존 modifier 정책
    └─ Rich Text: 범위 교체·Undo·Redo 영구 증거
         |
         v
    기존 Usage·reference·source 등록
         |
         v
    타입·동작·browser·문서 검증 → 구현 PR
    

    설계에서 이미 확인한 12개 공개 API 사례와 두 정책 공백을 회귀 근거로 사용한다. 이번에는 해당 owner의 테스트에 남겨 재실행할 수 있게 한다. Preview와 browser 경로는 repository의 실행 계약을 먼저 확인하고 사용자 Chrome 연결을 우선한다.

    #725 / #726은 문서 설계 작업으로 유지한다. 구현은 별도 브랜치에서 진행하고 하나의 PR로 #727을 닫는다. 진행 중 다른 목표에 해당하는 발견은 현재 변경에 포함하지 않는다.

  3. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    구현에서 확인한 경계: 전체 선택의 의미와 입력 정책

    selection.select-all과 Mod+A는 서로 다른 계약이다. 전자는 대상 전체를 고르는 의미이고, 후자는 그 의미를 호출하는 입력이다. 따라서 기존 토글 사용자를 깨뜨리지 않고도 새 기본 Usage를 제공할 수 있다.

    Mod+A
    └─ Affordance: repeat 정책
       ├─ preserve → select-all (반복해도 유지)
       └─ toggle   → allSelected이면 clear (기존 호출 호환)
           |
           v
    Domain Intent: selection.select-all
    ├─ Document → 첫 블록 offset 0 ... 마지막 블록 text 끝
    ├─ Order    → 문서의 전체 항목 순서
    ├─ Tree     → 주어진 visibleIds
    └─ Sheet    → 주어진 행 × 열, 생략하면 문서의 축
           |
           v
    기존 Range Selection family: replace-range / clear
    └─ 기존 EditingSession: 선택 한 번 발행, 문서 History 보존
    

    여기서 “전체”는 모든 editor에 동일한 데이터 구조를 강제하지 않는다. 예를 들어 접힌 Tree의 숨겨진 자식은 전체 선택의 visibleIds에 없지만, 기존 Copy/Cut은 선택한 부모의 후손을 포함한다. 이번 변경은 이 두 범위를 혼동하지 않는다. Sheet도 지정한 축의 순서와 부분 집합을 사용하며, 기존 primary rectangle Copy/Cut 정책을 보존한다.

    반복 입력은 선택의 의미와 문서 내용을 유지한다. 기존 Session 계약에 따라 선택 revision은 한 번 발행한다. “의미가 멱등적이다”와 “구독 알림이 0번이다”는 같은 요구가 아니다. 테스트는 중간 첫·끝 선택이 노출되지 않고 최종 선택만 한 번 발행되는지 확인한다.

    확정 실패는 편집 종료가 아니다

    기존 onCommit(...): void는 완료를 알리는 callback이다. 여기에 실패 의미를 몰래 추가하면 array.push(...)처럼 값을 반환하는 기존 callback의 해석이 달라질 수 있다. 그래서 tryCommit(...): boolean을 별도 선택지로 제공한다.

    • domain 검증이 거절하면 문서·선택·History는 그대로이고, session은 draft를 유지한다.
    • 수정 후 성공하면 draft를 비우고 onFinish를 한 번 호출한다.
    • Escape는 commit 없이 종료한다.
    • 두 callback을 동시에 지정하거나 비동기 tryCommit을 전달하는 호출은 타입 검사에서 거절한다.

    Order editor와 실제 JSONDocument validator를 연결한 회귀 사례도 넣었다. 빈 label 거절 → draft 유지 → Beta로 재시도 → Undo가 Alpha와 이전 선택 복원의 순서다. 빈 label 금지는 이 테스트의 검증 정책이며, Order 전체에 새 제약을 추가한 것은 아니다.

    현재 확인한 증거

    • 관련 6개 package의 63개 테스트 파일, 583개 테스트 통과.
    • 변경한 4개 owner의 테스트 타입 검사와 전체 library build 통과.
    • 문서 검사·생성 API reference 검사, Site 타입·정본 module guard 통과.
    • Rich Text domain의 정·역방향 교체/Undo/Redo와 Web binding의 meta/control 입력을 각 owner에 영구 테스트로 보관했다.
    • Site 전체 단위 테스트와 실제 browser 입력 검증을 진행 중이다. Source 등록으로 늘어난 목록은 해당 기대값을 갱신했다.

    읽어 볼 코드: packages/json-document-editing/tests/conformance/select-all.test.ts, packages/json-document-affordance/tests/conformance/editing-grammar.test.ts, packages/json-document-rich-text/tests/conformance/editing-grammar.test.ts, packages/json-document-rich-text-web/tests/history-keyboard.test.ts.

    이번 변경은 Profile registry나 Stable 선언을 추가하지 않는다. 기본 편집 관습을 선택할 수 있는 기존 owner의 계약과 그 증거를 보강한다.

  4. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    구현 PR과 검증 결과

    PR: #728 (59c6eb89). 구현 계약과 회귀 증거는 9d3a9354, Usage·Source·browser 연결은 59c6eb89에 나눴다. #727만 닫는 runtime PR이며 설계 PR #726은 별도로 유지한다.

    완료한 계약:

    • Document·Order·Tree·Sheet가 전체 범위를 한 번에 선택한다. 빈 대상·한 대상·여러 대상, 필터/순서 topology, 반복 발행과 History 보존을 검사했다.
    • 기본 Demo의 Mod+A는 반복해도 유지한다. 기존 Affordance 옵션 생략은 토글이며, 내부 text field의 native 전체 선택도 보존한다.
    • Order Usage가 rename 결과를 tryCommit으로 전달한다. domain 거절 후 draft 유지와 재시도는 실제 Order/JSONDocument 연결 테스트로, 성공·취소·복귀는 browser로 검증했다.
    • Rich Text가 정본 Web Undo resolver를 사용한다. 역방향 범위와 Undo 뒤 선택 이동까지 내용·선택·Redo 복원을 검사했다.
    • API reference, owning README, Usage의 실제 public API import, canonical Source 탭이 연결되었다. Source 탭에서 해당 domain의 selection.select-all과 Affordance의 preserve를 읽는 browser 사례도 포함했다.

    검증 기록:

    검사 결과
    전체 library build / 변경 owner 4개의 테스트 타입 검사 통과
    관련 6개 package 63개 파일, 583개 테스트 통과
    Site 타입·정본 모듈 guard 통과
    Site 단위 테스트 25개 파일, 138개 통과
    Chrome browser 60개 통과
    Firefox·WebKit Rich Text browser 41개 통과, 기존 Chromium 전용 IME 2개 skip
    workspace:check, standard:check 통과; Core conformance 347개 통과, 기존 선택적 사례 4개 skip
    문서·생성 reference·Pages build/HTTP 통과

    Source 목록을 확장하면서 기존 목록 기대값 4개를 갱신했다. Browser와 Site 단위 테스트를 동시에 실행한 한 차례에는 기존 문서 navigation 테스트가 5초 timeout에 걸렸고, 단위 테스트 병렬도를 2로 두고 전체를 재실행해 통과했다. timeout 설정이나 해당 테스트의 기대 동작은 변경하지 않았다.

    사용자 기존 Chrome 프로필의 실제 Order 화면에서도 전체 선택 반복 → 이름 확정·포커스 복귀 → Undo → 전체 선택 → Redo를 확인했다. 이 확인은 기존 Chrome의 DOM 제어를 사용했고, 별도 Playwright suite는 테스트 전용 browser에서 실제 키 입력을 실행했다. 로그인 상태는 변경하지 않았다.

    원격 PR 본문·변경 파일 32개·HEAD·closing issue를 읽어 구현과 대조했다. 현재 GitHub CI의 Package·Site·External kit 검증이 실행 중이다. 로컬에서 미완료된 구현 항목은 없으며, 머지는 이번 실행 범위에 포함하지 않는다.

  5. developer-1px commented on Sep 8, 2026

    @developer-1px
    OwnerAuthor

    CI 완료 — PR 검토 대기

    #728의 59c6eb89에서 Plan·Package·Site·External kit가 모두 통과했다.

    CI 실행 결과

    원격 PR head와 로컬 HEAD가 일치하고, 작업 checkout은 clean이다. 로컬 Usage 검증도 같은 HEAD에서 확인했다. 이슈의 구현·문서·회귀·browser 검증 항목을 완료했으며 PR은 열린 상태로 유지한다. 머지 이후 이슈가 닫히도록 Closes #727을 연결했다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions