# 범위, 선택 영역 및 셀

- Human documentation: [https://docs.univer.ai/ko-KR/guides/sheets/features/core/range-selection](https://docs.univer.ai/ko-KR/guides/sheets/features/core/range-selection)

- Agent Markdown: [https://docs.univer.ai/ko-KR/guides/sheets/features/core/range-selection.md](https://docs.univer.ai/ko-KR/guides/sheets/features/core/range-selection.md)

- Requested language: `ko-KR`

- Content language: `ko-KR`

- Documentation version: `1.0.4`

- Source: [sheets/features/core/range-selection.ko-KR.mdx](https://github.com/dream-num/documentation/blob/dev/content/guides/sheets/features/core/range-selection.ko-KR.mdx)

---

아래에서 작업에 맞는 섹션으로 이동하세요. 기본 작업, 고급 예제, 설정과 문제 해결은 이 페이지에 모아 두고 전체 API 정의는 Reference에서 관리합니다.

* [범위](#range)
* [선택 영역](#selection)
* [고급 범위 작업](#range-operations)
* [워크시트 경계에서 키보드 이동](#keyboard-navigation)
* [셀 이벤트와 편집](#events)
* [셀 편집 문제 해결](#troubleshooting)

## 범위

범위는 워크시트의 직사각형 영역을 의미하며 시작 행 번호, 시작 열 번호, 높이와 너비 또는 끝 행 번호와 끝 열 번호로 결정됩니다.

값 설정 및 가져오기, 스타일 설정 및 가져오기 등 스프레드시트의 대부분 작업은 Range API를 통해 수행할 수 있습니다.

범위 관련 Facade API의 전체 정의는 [FRange FacadeAPI](https://docs.univer.ai/ko-KR/reference/facade/range.md)를 참고하세요.

### 범위 만들기

범위를 가져오려면 시작 행 번호, 시작 열 번호, 높이와 너비를 알아야 합니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Create a range of A1 cell:
const fRange = fWorksheet.getRange(0, 0)
console.log(fRange, fRange.getA1Notation())

// Creates a range of A1:B2:
const fRange2 = fWorksheet.getRange(0, 0, 2, 2)
console.log(fRange2, fRange2.getA1Notation())
```

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Get the A1:B2 range on named Sheet1
const fRange1 = fWorksheet.getRange('Sheet1!A1:B2')
console.log(fRange1, fRange1.getA1Notation())

// Get a single cell A1
const fRange2 = fWorksheet.getRange('A1')
console.log(fRange2, fRange2.getA1Notation())

// Get the A1:B2 range
const fRange3 = fWorksheet.getRange('A1:B2')
console.log(fRange3, fRange3.getA1Notation())

// Get the range of column A
const fRange4 = fWorksheet.getRange('A:A')
console.log(fRange4, fRange4.getA1Notation())

// Get the range of row 1
const fRange5 = fWorksheet.getRange('1:1')
console.log(fRange5, fRange5.getA1Notation())
```

### 범위 데이터 가져오기

범위에서 첫 번째 셀의 값을 가져옵니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) throw new Error('No active workbook')
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')

console.log(fRange.getValue()) // The value of the top-left cell in the range
console.log(fRange.getRawValue()) // The raw value of the top-left cell in the range
console.log(fRange.getDisplayValue()) // The displayed value of the top-left cell in the range
console.log(fRange.getCellData()) // The cell data of the top-left cell in the range
const value = fRange.getValue(true)
console.log(value)
if (value !== null && typeof value === 'object') {
  console.log(value.toPlainText())
}
```

`getValue(true)`는 서식 있는 텍스트 객체를 유지합니다. 빈 셀은 `null` / `undefined`을, 일반 셀은 문자열, 숫자 또는 불리언을 반환합니다. `toPlainText()`는 서식 있는 텍스트 객체에만 호출하세요.

범위에 있는 모든 셀의 값을 가져옵니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) throw new Error('No active workbook')
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')

console.log(fRange.getValues()) // The values of all cells in the range
console.log(fRange.getRawValues()) // The raw values of all cells in the range
console.log(fRange.getDisplayValues()) // The displayed values of all cells in the range
console.log(fRange.getCellDataGrid()) // The cell data of all cells in the range
console.log(fRange.getValues(true))
```

범위에 있는 모든 수식을 가져옵니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')

console.log(fRange.getFormula()) // The formula of the top-left cell in the range
console.log(fRange.getFormulas()) // The formulas of all cells in the range
```

### 범위 값 설정하기

#### 단일 값 설정하기

값 또는 셀 객체를 전달하면 범위의 모든 셀을 덮어씁니다. 값이 `=`로 시작하면 수식으로 해석됩니다.

예를 들어 A1:B2의 값을 `Hello, Univer`로 설정하려면 다음과 같이 합니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
fRange.setValue('Hello, Univer')
```

입력 셀과 분리된 C1에 `=A1+B1` 수식을 설정합니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
if (!fWorkbook) throw new Error('No active workbook')
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('C1')
fRange.setValue('=A1+B1')
```

A1:B2의 값을 셀 객체로 설정합니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
fRange.setValue({
  v: 'Hello, Univer',
  custom: {
    key: 'value',
  },
})
```

범위의 왼쪽 위 셀 값만 설정하려면 [`FRange.setValueForCell`](https://docs.univer.ai/ko-KR/reference/facade/range.md#setvalueforcell) 메서드를 사용할 수 있습니다.

```typescript
fRange.setValueForCell('Hello, Univer')
```

#### 배열로 여러 값 설정하기

배열의 행 수와 열 수는 범위의 행 수와 열 수와 일치해야 합니다.

셀 값 또는 셀 객체를 전달할 수 있습니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
fRange.setValues([
  ['A1', 'B1'],
  ['A2', 'B2'],
])

fRange.setValues([
  [{ v: 'A1' }, { v: 'B1' }],
  [{ v: 'A2' }, { v: 'B2' }],
])
```

#### 객체로 여러 값 설정하기

객체를 전달할 경우 첫 번째 인덱스는 행 번호를, 두 번째 인덱스는 열 번호를 나타내며 객체의 행 수와 열 수가 범위와 일치할 필요는 없습니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
fRange.setValues({
  0: {
    0: 'A1',
    1: 'B1',
  },
  1: {
    0: 'A2',
    1: 'B2',
  },
})
```

### 범위 데이터 지우기

* [`FRange.clear`](https://docs.univer.ai/ko-KR/reference/facade/range.md#clear) 메서드는 범위의 콘텐츠와 서식 정보를 지울 수 있습니다.
* [`FRange.clearContent`](https://docs.univer.ai/ko-KR/reference/facade/range.md#clearcontent) 메서드는 범위의 콘텐츠 정보를 지울 수 있습니다.
* [`FRange.clearFormat`](https://docs.univer.ai/ko-KR/reference/facade/range.md#clearformat) 메서드는 범위의 서식 정보를 지울 수 있습니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorkSheet = fWorkbook.getActiveSheet()
const fRange = fWorkSheet.getRange('A1:D10')

// Clears content and formatting information of the range.
fRange.clear()
```

### 범위 스타일 가져오기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
console.log(fRange.getCellStyleData()) // The style data of the top-left cell in the range
console.log(fRange.getCellStyle()) // The style of the top-left cell in the range
console.log(fRange.getCellStyles()) // The styles of all cells in the range
```

### 범위 스타일 설정하기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
fRange
  .setValues([
    [1, 2],
    [3, 4],
  ])
  .setFontWeight('bold')
  .setFontLine('underline')
  .setFontFamily('Arial')
  .setFontSize(24)
  .setFontColor('red')
```

### 범위 스타일 지우기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
fRange.setFontWeight(null).setFontLine(null).setFontFamily(null).setFontSize(null).setFontColor(null)
```

## 선택 영역

Univer Sheets는 다중 선택을 지원합니다. 따라서 선택 영역은 범위의 배열이며 Range API를 통해 선택 영역 데이터를 조작할 수 있습니다.

현재 선택 영역을 가져오거나 설정하고 선택 영역의 변경을 감지하는 API도 제공합니다.

선택 영역 관련 Facade API의 전체 정의는 [FSelection FacadeAPI](https://docs.univer.ai/ko-KR/reference/facade/selection.md)를 참고하세요.

### 활성 선택 영역 가져오기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Activate the new selection of A1:B2
const fRange = fWorksheet.getRange('A1:B2')
fRange.activate()

// Get the current active selection
const fSelection = fWorksheet.getSelection()
console.log(fSelection)
const activeRange = fSelection.getActiveRange()
console.log(activeRange.getA1Notation()) // A1:B2
```

### 선택 영역 설정하기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Set the selection to A1:B2 by FRange
const fRange = fWorksheet.getRange('A1:B2')
fRange.activate()

// Set the selection to C1:D2 by FWorksheet
fWorksheet.setActiveSelection(fWorksheet.getRange('C1:D2'))
```

### 현재 셀 가져오기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Activate the new selection of A10:B11
const fRange = fWorksheet.getRange('A10:B11')
fRange.activate()

// Get the current active cell
let fSelection = fWorksheet.getSelection()
const { actualRow, actualColumn } = fSelection.getCurrentCell()
console.log(fWorksheet.getRange(actualRow, actualColumn).getA1Notation()) // A10

// Update the new active cell to B11
fSelection = fSelection.updatePrimaryCell(fWorksheet.getRange('B11'))
const { actualRow: newRow, actualColumn: newColumn } = fSelection.getCurrentCell()
console.log(fWorksheet.getRange(newRow, newColumn).getA1Notation()) // B11
```

### 선택 영역 비활성화/활성화/숨기기/표시하기

비활성화하면 선택 영역이 입력에 반응하지 않습니다. `transparentSelection`은 선택 영역을 보이지 않게 하지만 `disableSelection`과 달리 선택 기능은 계속 작동하며 화면에만 표시되지 않습니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()

// Disable selection
fWorkbook.disableSelection()

// Enable selection
fWorkbook.enableSelection()

// Hide selection
fWorkbook.transparentSelection()

// Show selection
fWorkbook.showSelection()
```

### 선택 영역 변경 감지하기

```typescript
univerAPI.addEvent(univerAPI.Event.SelectionChanged, (params) => {
  const { worksheet, workbook, selections } = params
  console.log(params)
})
```

## 셀

셀 데이터는 워크시트에 2차원 Map으로 저장되며 첫 번째 인덱스와 두 번째 인덱스는 각각 행 번호와 열 번호를 나타냅니다.

다음은 일반적인 셀 객체입니다.

```typescript
const data = {
  v: 'Hello, Univer',
  s: 'styleId',
  t: CellValueType.STRING,
}
```

각 필드에 관한 자세한 설명은 [셀 데이터 구성](https://docs.univer.ai/ko-KR/guides/sheets/model/cell-data.md)을 참고하세요.

### 알아두면 좋은 내용

1. 셀 작업은 높이와 너비가 각각 1인 범위에 대한 작업으로 볼 수 있습니다. 범위 작업은 [범위](https://docs.univer.ai/ko-KR/guides/sheets/features/core/range-selection.md#range)를 참고하세요.
2. Univer API 플러그인은 확장된 셀 속성도 `Workbook`의 `resources` 속성에 저장합니다. 자세한 내용은 [플러그인 사용자 지정 모델](/blog/custom-model)을 참고하세요.

## 고급 범위 작업

### 셀 삽입하기

[`FRange.insertCells`](https://docs.univer.ai/ko-KR/reference/facade/range.md#insertcells) 메서드는 이 범위에 빈 셀을 삽입합니다. 지정한 차원을 따라 시트의 기존 데이터가 삽입된 범위의 반대쪽으로 이동합니다.

```typescript
// Assume the active sheet empty sheet.
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const values = [
  [1, 2, 3, 4],
  [2, 3, 4, 5],
  [3, 4, 5, 6],
  [4, 5, 6, 7],
  [5, 6, 7, 8],
]

// Set the range A1:D5 with some values, the range A1:D5 will be:
// 1 | 2 | 3 | 4
// 2 | 3 | 4 | 5
// 3 | 4 | 5 | 6
// 4 | 5 | 6 | 7
// 5 | 6 | 7 | 8
const fRange = fWorksheet.getRange('A1:D5')
fRange.setValues(values)
console.log(fWorksheet.getRange('A1:D5').getValues()) // [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]

// Insert the empty cells into the range A1:B2 along the columns dimension, the range A1:D5 will be:
//   |   | 1 | 2
//   |   | 2 | 3
// 3 | 4 | 5 | 6
// 4 | 5 | 6 | 7
// 5 | 6 | 7 | 8
const fRange2 = fWorksheet.getRange('A1:B2')
fRange2.insertCells(univerAPI.Enum.Dimension.COLUMNS)
console.log(fWorksheet.getRange('A1:D5').getValues()) // [[null, null, 1, 2], [null, null, 2, 3], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]

// Set the range A1:D5 values again, the range A1:D5 will be:
// 1 | 2 | 3 | 4
// 2 | 3 | 4 | 5
// 3 | 4 | 5 | 6
// 4 | 5 | 6 | 7
// 5 | 6 | 7 | 8
fRange.setValues(values)

// Insert the empty cells into the range A1:B2 along the rows dimension, the range A1:D5 will be:
//   |   | 3 | 4
//   |   | 4 | 5
// 1 | 2 | 5 | 6
// 2 | 3 | 6 | 7
// 3 | 4 | 7 | 8
const fRange3 = fWorksheet.getRange('A1:B2')
fRange3.insertCells(univerAPI.Enum.Dimension.ROWS)
console.log(fWorksheet.getRange('A1:D5').getValues()) // [[null, null, 3, 4], [null, null, 4, 5], [1, 2, 5, 6], [2, 3, 6, 7], [3, 4, 7, 8]]
```

### 셀 삭제하기

[`FRange.deleteCells`](https://docs.univer.ai/ko-KR/reference/facade/range.md#deletecells) 메서드는 이 범위의 셀을 삭제합니다. 지정한 차원을 따라 시트의 기존 데이터가 삭제된 범위 쪽으로 이동합니다.

```typescript
// Assume the active sheet empty sheet.
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const values = [
  [1, 2, 3, 4],
  [2, 3, 4, 5],
  [3, 4, 5, 6],
  [4, 5, 6, 7],
  [5, 6, 7, 8],
]

// Set the range A1:D5 with some values, the range A1:D5 will be:
// 1 | 2 | 3 | 4
// 2 | 3 | 4 | 5
// 3 | 4 | 5 | 6
// 4 | 5 | 6 | 7
// 5 | 6 | 7 | 8
const fRange = fWorksheet.getRange('A1:D5')
fRange.setValues(values)
console.log(fWorksheet.getRange('A1:D5').getValues()) // [[1, 2, 3, 4], [2, 3, 4, 5], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]

// Delete the range A1:B2 along the columns dimension, the range A1:D5 will be:
// 3 | 4 |   |
// 4 | 5 |   |
// 3 | 4 | 5 | 6
// 4 | 5 | 6 | 7
// 5 | 6 | 7 | 8
const fRange2 = fWorksheet.getRange('A1:B2')
fRange2.deleteCells(univerAPI.Enum.Dimension.COLUMNS)
console.log(fWorksheet.getRange('A1:D5').getValues()) // [[3, 4, null, null], [4, 5, null, null], [3, 4, 5, 6], [4, 5, 6, 7], [5, 6, 7, 8]]

// Set the range A1:D5 values again, the range A1:D5 will be:
// 1 | 2 | 3 | 4
// 2 | 3 | 4 | 5
// 3 | 4 | 5 | 6
// 4 | 5 | 6 | 7
// 5 | 6 | 7 | 8
fRange.setValues(values)

// Delete the range A1:B2 along the rows dimension, the range A1:D5 will be:
// 3 | 4 | 3 | 4
// 4 | 5 | 4 | 5
// 5 | 6 | 5 | 6
//   |   | 6 | 7
//   |   | 7 | 8
const fRange3 = fWorksheet.getRange('A1:B2')
fRange3.deleteCells(univerAPI.Enum.Dimension.ROWS)
console.log(fWorksheet.getRange('A1:D5').getValues()) // [[3, 4, 3, 4], [4, 5, 4, 5], [5, 6, 5, 6], [null, null, 6, 7], [null, null, 7, 8]]
```

### 셀 병합하기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Merge B1:B2
const fRange = fWorksheet.getRange('B1:B2')
fRange.merge()
console.log(fRange.isMerged()) // true

// A1:B2 is merged
const fRange2 = fWorksheet.getRange('A1:B2')
console.log(fRange2.isMerged()) // false
console.log(fRange2.isPartOfMerge()) // true

// Break apart the merged range
fRange2.breakApart()

// merge horizontally: fRange2.mergeAcross();
// merge vertically: fRange2.mergeVertically();
// Get all merged ranges in the worksheet: fWorksheet.getMergedRanges();
```

### 범위 강조 표시하기

[`FRange.highlight`](https://docs.univer.ai/ko-KR/reference/facade/range.md#highlight) 메서드는 지정한 스타일과 기본 셀로 범위를 강조 표시합니다.

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// Highlight the range C3:E5 with default style
const fRange = fWorksheet.getRange('C3:E5')
fRange.highlight()

// Highlight the range C7:E9 with custom style and primary cell D8
const fRange2 = fWorksheet.getRange('C7:E9')
const primaryCell = fWorksheet.getRange('D8').getRange()
const disposable = fRange2.highlight(
  {
    stroke: 'red',
    fill: 'yellow',
  },
  {
    ...primaryCell,
    actualRow: primaryCell.startRow,
    actualColumn: primaryCell.startColumn,
  },
)

// Remove the range C7:E9 highlight after 5 seconds
setTimeout(() => {
  disposable.dispose()
}, 5000)
```

### 텍스트를 열로 분할하기

[`FRange.splitTextToColumns`](https://docs.univer.ai/ko-KR/reference/facade/range.md#splittexttocolumns) 메서드는 지정한 구분 기호에 따라 범위의 텍스트를 여러 열로 분할합니다.

기본 구분 기호 예시:

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// A1:A3 has following values:
//  A      |
//  1,2,3  |
//  4,,5,6 |
const fRange = fWorksheet.getRange('A1:A3')
fRange.setValues([['A'], ['1,2,3'], ['4,,5,6']])

// After calling splitTextToColumns(true), the range will be:
//  A |   |
//  1 | 2 | 3
//  4 | 5 | 6
fRange.splitTextToColumns(true)

// After calling splitTextToColumns(false), the range will be:
//  A |   |   |
//  1 | 2 | 3 |
//  4 |   | 5 | 6
fRange.splitTextToColumns(false)
```

지정 구분 기호 예시:

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// A1:A3 has following values:
//     A   |
//  1;;2;3 |
//  1;,2;3 |
const fRange = fWorksheet.getRange('A1:A3')
fRange.setValues([['A'], ['1;;2;3'], ['1;,2;3']])

// After calling splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Semicolon|univerAPI.Enum.SplitDelimiterType.Comma), the range will be:
//  A |   |   |
//  1 |   | 2 | 3
//  1 |   | 2 | 3
fRange.splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Semicolon | univerAPI.Enum.SplitDelimiterType.Comma)

// After calling splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Semicolon|univerAPI.Enum.SplitDelimiterType.Comma), the range will be:
//  A |   |
//  1 | 2 | 3
//  1 | 2 | 3
fRange.splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Semicolon | univerAPI.Enum.SplitDelimiterType.Comma)
```

사용자 지정 구분 기호 예시:

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()

// A1:A3 has following values:
//     A   |
//  1#2#3  |
//  4##5#6 |
const fRange = fWorksheet.getRange('A1:A3')
fRange.setValues([['A'], ['1#2#3'], ['4##5#6']])

// After calling splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Custom, '#'), the range will be:
//  A |   |   |
//  1 | 2 | 3 |
//  4 |   | 5 | 6
fRange.splitTextToColumns(false, univerAPI.Enum.SplitDelimiterType.Custom, '#')

// After calling splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Custom, '#'), the range will be:
//  A |   |
//  1 | 2 | 3
//  4 | 5 | 6
fRange.splitTextToColumns(true, univerAPI.Enum.SplitDelimiterType.Custom, '#')
```

### 범위 좌표 가져오기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
console.log(fRange.getCellRect()) // width、heigh、left、right、top、bottom、x、y
```

### 범위의 병합 정보와 좌표를 함께 가져오기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
const fWorksheet = fWorkbook.getActiveSheet()
const fRange = fWorksheet.getRange('A1:B2')
console.log(fRange.getCell())
```

## 워크시트 경계에서 키보드 이동

`allowArrowKeyWrapOnSheetBoundary`는 방향키가 시트 경계에 도달했을 때 다른 행이나 열로 이어서 이동할지 제어합니다. 기본값은 `true`이며, `false`이면 경계에서 멈춥니다. 선택 범위 안에서 Enter/Tab으로 순환하는 동작에는 영향을 주지 않습니다. 프리셋에서는 `sheets` 아래에, 플러그인에서는 `UniverSheetsUIPlugin`에 직접 전달합니다.

#### 플러그인 모드

```typescript
univer.registerPlugin(UniverSheetsUIPlugin, {
  allowArrowKeyWrapOnSheetBoundary: false,
})
```

#### 프리셋 모드

```typescript
createUniver({
  presets: [
    UniverSheetsCorePreset({
      sheets: {
        allowArrowKeyWrapOnSheetBoundary: false,
      },
    }),
  ],
})
```

## 셀 이벤트와 편집

포인터, 렌더링, 편집, 클립보드 작업별 예제입니다. 전체 이벤트와 매개변수 타입은 [이벤트 Reference](https://docs.univer.ai/ko-KR/reference/facade/events.md#univerjssheets-ui)를 참고하세요. 플러그인 모드에서는 구독 전에 `@univerjs/sheets-ui/facade`를 가져오세요. Sheets Core 프리셋에는 포함되어 있습니다. 컴포넌트나 페이지가 제거되면 구독을 해제하세요.

### 사용 예시

모든 이벤트는 `addEvent` 메서드로 수신할 수 있습니다. 기본 형식은 다음과 같습니다.

```typescript
import '@univerjs/sheets-ui/facade'

const subscription = univerAPI.addEvent(univerAPI.Event.CellClicked, ({ row, column }) => {
  console.log(row, column)
})

// Call subscription.dispose() when the owning component or page is removed.
```

### Cell PointerMove 이벤트

`CellPointerMove` 이벤트는 마우스가 셀 위에서 움직일 때 발생하며 현재 마우스 포인터 아래에 있는 셀의 정보를 제공합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.CellPointerMove, (params) => {
  // Get event parameters
  const { worksheet, workbook, row, column } = params
  console.log('Current cell position:', worksheet.getRange(row, column).getA1Notation())
})
```

### Cell PointerDown 이벤트

`CellPointerDown` 이벤트는 셀에서 마우스 버튼을 누를 때 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.CellPointerDown, (params) => {
  const { worksheet, workbook, row, column } = params
  console.log('Mouse down cell:', worksheet.getRange(row, column).getA1Notation())
})
```

### Cell PointerUp 이벤트

`CellPointerUp` 이벤트는 셀에서 마우스 버튼을 놓을 때 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.CellPointerUp, (params) => {
  const { worksheet, workbook, row, column } = params
  console.log('Mouse up cell:', worksheet.getRange(row, column).getA1Notation())
})
```

### Cell Hover 이벤트

`CellHover` 이벤트는 마우스가 셀 위에 머물 때 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.CellHover, (params) => {
  const { worksheet, workbook, row, column } = params
  console.log('Hovered cell:', worksheet.getRange(row, column).getA1Notation())
})
```

### Cell DragOver 이벤트

`DragOver` 이벤트는 셀 위로 요소를 드래그할 때 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.DragOver, (params) => {
  const { worksheet, workbook, row, column } = params
  console.log('Drag over cell:', worksheet.getRange(row, column).getA1Notation())
})
```

### Cell Drop 이벤트

`Drop` 이벤트는 셀에 요소를 놓을 때 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.Drop, (params) => {
  const { worksheet, workbook, row, column } = params
  console.log('Drop target cell:', worksheet.getRange(row, column).getA1Notation())
})
```

### 셀 클릭 이벤트

`CellClicked` 이벤트는 셀을 클릭할 때 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.CellClicked, (params) => {
  const { worksheet, workbook, row, column } = params
  console.log('Clicked cell:', worksheet.getRange(row, column).getA1Notation())
})
```

### 셀 렌더링 이벤트

`registerCellCustomRender`는 셀의 사용자 지정 렌더러를 등록합니다.

예시 1: 고정 위치 렌더링 - 행을 추가해도 렌더링 위치가 바뀌지 않습니다.

```typescript
// Fixed position rendering
univerAPI.registerCellCustomRender([
  {
    drawWith: (ctx, info, skeleton, spreadsheets) => {
      const { row, col } = info
      // Render a checkmark at position (1,1)
      if (row === 1 && col === 1) {
        const { primaryWithCoord } = info
        const { startX, startY } = primaryWithCoord
        ctx.fillText('✅', startX, startY + 10)
      }
    },
  },
])

// Refresh canvas to apply rendering
univerAPI.getActiveWorkbook().getActiveSheet().refreshCanvas()
```

예시 2: 마커 기반 렌더링 - 행이나 열이 변경되면 렌더링 위치도 바뀝니다.

```typescript
// Set marker
univerAPI
  .getActiveWorkbook()
  .getActiveSheet()
  .getRange('B2')
  .setValue({ custom: { key: 'needCheck' } })

// Render based on marker
univerAPI.registerCellCustomRender([
  {
    drawWith: (ctx, info, skeleton, spreadsheets) => {
      const { row, col, data } = info
      // Render checkmark at marked position
      if (data?.custom?.key === 'needCheck') {
        const { primaryWithCoord } = info
        const { startX, startY } = primaryWithCoord
        ctx.fillText('✅', startX, startY + 10)
      }
    },
  },
])

// Refresh canvas to apply rendering
univerAPI.getActiveWorkbook().getActiveSheet().refreshCanvas()
```

### 셀 편집 이벤트

#### 편집 시작하기

```typescript
const fWorkbook = univerAPI.getActiveWorkbook()
fWorkbook.startEditing()
```

#### 편집 끝내기

```typescript
// Pass true to commit changes, false to cancel editing
// This is an async function, requires await
const fWorkbook = univerAPI.getActiveWorkbook()
await fWorkbook.endEditingAsync(true)
```

#### 편집 시작 이벤트

`BeforeSheetEditStart` 이벤트는 셀 편집이 시작되기 전에 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.BeforeSheetEditStart, (params) => {
  const { worksheet, workbook, row, column, eventType, keycode } = params
  console.log('Before cell edit:', params)

  // If you want to prevent entering the editing state
  params.cancel = true
})
```

`SheetEditStarted` 이벤트는 셀 편집이 시작될 때 발생합니다.

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.SheetEditStarted, (params) => {
  const { worksheet, workbook, row, column, eventType, keycode } = params
  console.log(params)
})

// Remove the event listener, use `disposable.dispose()`
```

#### 편집 종료 이벤트

`BeforeSheetEditEnd` 이벤트는 셀 편집이 끝나기 전에 발생합니다.

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.BeforeSheetEditEnd, (params) => {
  const { worksheet, workbook, row, column, value, eventType, keycode, isConfirm } = params
  console.log(params)

  // Cancel the cell edit end operation
  params.cancel = true
})

// Remove the event listener, use `disposable.dispose()`
```

`SheetEditEnded` 이벤트는 셀 편집이 끝난 후 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.SheetEditEnded, (params) => {
  const { worksheet, workbook, row, column, eventType, keycode, isConfirm } = params
  console.log('After cell edit:', params)
})
```

### 클립보드 이벤트

#### BeforeClipboardChange

`BeforeClipboardChange` 이벤트는 클립보드 콘텐츠가 변경되기 전에 발생합니다. 이 이벤트를 사용하면 변경 전에 클립보드 콘텐츠를 감지하거나 수정할 수 있습니다.

```typescript
univerAPI.addEvent(univerAPI.Event.BeforeClipboardChange, (params) => {
  const { text, html } = params
  console.log('Clipboard content:', text, html)
  // If you want to cancel the clipboard change
  // params.cancel = true;
})
```

#### BeforeClipboardPaste

`BeforeClipboardPaste` 이벤트는 콘텐츠를 붙여넣기 전에 발생합니다. 이 이벤트를 사용하면 붙여넣기 전에 콘텐츠를 감지하거나 수정할 수 있습니다.

```typescript
univerAPI.addEvent(univerAPI.Event.BeforeClipboardPaste, (params) => {
  const { text, html } = params
  console.log('Content to paste:', text, html)
  // If you want to cancel the paste operation
  // params.cancel = true;
})
```

#### ClipboardChanged

`ClipboardChanged` 이벤트는 클립보드 콘텐츠가 변경된 후 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.ClipboardChanged, (params) => {
  const { text, html } = params
  console.log('New clipboard content:', text, html)
})
```

#### ClipboardPasted

`ClipboardPasted` 이벤트는 콘텐츠를 붙여넣은 후 발생합니다.

```typescript
univerAPI.addEvent(univerAPI.Event.ClipboardPasted, (params) => {
  const { text, html } = params
  console.log('Pasted content:', text, html)
})
```

## 셀 편집 문제 해결

### 셀 편집기의 데이터를 실시간으로 가져오려면 어떻게 해야 하나요?

`SheetEditChanging`을 구독하면 셀 편집 중 현재 리치 텍스트 값을 읽을 수 있습니다. 이 값은 아직 편집기에 있으며 편집이 끝나면 워크시트에 반영됩니다.

```typescript
import '@univerjs/sheets-ui/facade'

const subscription = univerAPI.addEvent(univerAPI.Event.SheetEditChanging, ({ value }) => {
  console.log(value.toPlainText())
})

// Call subscription.dispose() when the owning component or page is removed.
```

### 셀 편집기에 포커스가 있는 상태에서 외부 버튼을 클릭해 이벤트를 발생시키면 스냅샷에 포커스된 셀의 데이터가 포함되지 않습니다.

셀 편집기가 포커스를 잃을 때, 즉 편집이 끝날 때 셀 데이터가 스냅샷에 동기화됩니다. 따라서 스냅샷 데이터를 가져오기 전에 셀이 포커스를 잃었는지 확인하세요. 다음과 같이 편집을 직접 끝낼 수 있습니다.

```typescript
import '@univerjs/sheets-ui/facade'

async function saveWorkbook() {
  const fWorkbook = univerAPI.getActiveWorkbook()
  if (!fWorkbook) return

  await fWorkbook.endEditingAsync(true)
  const snapshot = fWorkbook.save()
  console.log(snapshot)
}

$btn.addEventListener('click', () => {
  saveWorkbook().catch(console.error)
})
```

참고: [https://github.com/dream-num/univer/issues/1314](https://github.com/dream-num/univer/issues/1314)

### Facade API로 Workbook을 만들면 일부 API가 생성 직후에 작동하지 않을 수 있습니다. 일부 API는 인터페이스가 완전히 렌더링되어야 올바르게 작동하기 때문입니다. 관련 작업은 수명 주기의 `Rendered` 또는 `Steady` 단계에서 수행하는 것이 좋습니다.

많은 API는 인터페이스가 완전히 렌더링되어야 올바르게 작동합니다. Workbook을 만든 직후 관련 API를 호출하면 인터페이스가 아직 완전히 렌더링되지 않아 작동하지 않을 수 있습니다. 관련 작업은 수명 주기의 `Rendered` 또는 `Steady` 단계에서 수행하는 것이 좋습니다.

```typescript
const disposable = univerAPI.addEvent(univerAPI.Event.LifeCycleChanged, ({ stage }) => {
  if (stage === univerAPI.Enum.LifecycleStages.Steady) {
    // code...
  }
})

// To remove the event listener, you can call `disposable.dispose()`
```

참고: [수명 주기](https://docs.univer.ai/ko-KR/guides/sheets/getting-started/lifecycle.md)
