@operato/data-grist 8.2.23 → 8.2.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,26 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ### [8.2.25](https://github.com/hatiolab/operato/compare/v8.2.24...v8.2.25) (2026-09-23)
7
+
8
+
9
+ ### :bug: Bug Fix
10
+
11
+ * 그리드 마지막 라인 포커스 에러 수정, 편집시 폰트 크기 동일하게 ([f8c2b55](https://github.com/hatiolab/operato/commit/f8c2b553aa45f8b7085c6c1ce93b2c6af8e3cb48))
12
+
13
+
14
+
15
+ ### [8.2.24](https://github.com/hatiolab/operato/compare/v8.2.21...v8.2.24) (2026-04-14)
16
+
17
+
18
+ ### :bug: Bug Fix
19
+
20
+ * 그리드 복붙시 태그 제거 ([066f0d8](https://github.com/hatiolab/operato/commit/066f0d835f43f588f5bc3c677717c1cad1f8f832))
21
+ * 그리드 복붙시 태그 제거 ([a2c572c](https://github.com/hatiolab/operato/commit/a2c572c6f056744f1599bc61967364e273b77236))
22
+ * 그리드 셀 ime-buffer로 한글 입력시 composing 유지 ([690464f](https://github.com/hatiolab/operato/commit/690464f0ae8dddbf94612c573a6a6be8dc51fcea))
23
+
24
+
25
+
6
26
  ### [8.2.23](https://github.com/hatiolab/operato/compare/v8.2.22...v8.2.23) (2026-04-14)
7
27
 
8
28
 
@@ -53,7 +53,7 @@ export const dataGridBodyStyle = css `
53
53
  color: var(--grid-record-emphasized-color) !important;
54
54
  }
55
55
 
56
- ox-grid-field[editing] {
56
+ [editing] {
57
57
  background-color: var(--grid-record-editing-background-color);
58
58
  }
59
59
 
@@ -1 +1 @@
1
- {"version":3,"file":"data-grid-body-style.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-body-style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGnC,CAAA","sourcesContent":["import { css } from 'lit'\n\nexport const dataGridBodyStyle = css`\n :host {\n display: grid;\n grid-template-columns: var(--grid-template-columns);\n grid-auto-rows: var(--grid-record-height, min-content);\n\n overflow: auto;\n outline: none;\n color: var(--grid-record-color);\n position: relative;\n border-bottom: var(--grid-body-bottom-border);\n }\n\n ox-grid-field[odd] {\n background-color: var(--grid-record-odd-background-color);\n }\n\n ox-grid-field[disabled] {\n background-color: var(--grid-record-disabled-background-color, var(--grid-record-background-color));\n color: var(--grid-record-disabled-color, var(--grid-record-color));\n opacity: var(--grid-record-disabled-opacity, 1);\n }\n ox-grid-field[odd][disabled] {\n background-color: var(\n --grid-odd-record-disabled-background-color,\n var(--grid-record-disabled-background-color, var(--grid-record-odd-background-color))\n );\n color: var(--grid-odd-record-disabled-color, var(--grid-record-disabled-color, var(--grid-record-color)));\n opacity: var(--grid-odd-record-disabled-opacity, var(--grid-record-disabled-opacity, 1));\n }\n\n ox-grid-field[selected-row] {\n background-color: var(--grid-record-selected-background-color);\n color: var(--grid-record-selected-color);\n }\n\n ox-grid-field[focused-row] {\n box-shadow: var(--grid-record-focused-box-shadow);\n font-weight: bold;\n color: var(--grid-record-focused-color);\n background-image: var(--focused-background-image);\n background-blend-mode: darken;\n }\n\n ox-grid-field[focused] {\n border: var(--grid-record-focused-cell-border);\n }\n\n ox-grid-field[emphasized-row],\n ox-grid-field[emphasized-row][focused] {\n background-color: var(--grid-record-emphasized-background-color) !important;\n color: var(--grid-record-emphasized-color) !important;\n }\n\n ox-grid-field[editing] {\n background-color: var(--grid-record-editing-background-color);\n }\n\n @media print {\n :host {\n grid-template-columns: var(--grid-template-print-columns);\n }\n ox-grid-field[focused] {\n border: none;\n }\n\n ox-grid-field[selected-row] {\n background-color: transparent;\n }\n\n ox-grid-field[emphasized-row] {\n background-color: transparent;\n color: initial;\n }\n\n ox-grid-field[focused-row] {\n background-color: transparent;\n color: initial;\n }\n\n ox-grid-field[editing] {\n background-color: transparent;\n }\n }\n\n @media (prefers-color-scheme: dark) {\n ox-grid-field[focused-row] {\n background-blend-mode: lighten;\n }\n }\n\n @media (prefers-color-scheme: light) {\n ox-grid-field[focused-row] {\n background-blend-mode: darken;\n }\n }\n`\n"]}
1
+ {"version":3,"file":"data-grid-body-style.js","sourceRoot":"","sources":["../../../src/data-grid/data-grid-body-style.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAA;AAEzB,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGnC,CAAA","sourcesContent":["import { css } from 'lit'\n\nexport const dataGridBodyStyle = css`\n :host {\n display: grid;\n grid-template-columns: var(--grid-template-columns);\n grid-auto-rows: var(--grid-record-height, min-content);\n\n overflow: auto;\n outline: none;\n color: var(--grid-record-color);\n position: relative;\n border-bottom: var(--grid-body-bottom-border);\n }\n\n ox-grid-field[odd] {\n background-color: var(--grid-record-odd-background-color);\n }\n\n ox-grid-field[disabled] {\n background-color: var(--grid-record-disabled-background-color, var(--grid-record-background-color));\n color: var(--grid-record-disabled-color, var(--grid-record-color));\n opacity: var(--grid-record-disabled-opacity, 1);\n }\n ox-grid-field[odd][disabled] {\n background-color: var(\n --grid-odd-record-disabled-background-color,\n var(--grid-record-disabled-background-color, var(--grid-record-odd-background-color))\n );\n color: var(--grid-odd-record-disabled-color, var(--grid-record-disabled-color, var(--grid-record-color)));\n opacity: var(--grid-odd-record-disabled-opacity, var(--grid-record-disabled-opacity, 1));\n }\n\n ox-grid-field[selected-row] {\n background-color: var(--grid-record-selected-background-color);\n color: var(--grid-record-selected-color);\n }\n\n ox-grid-field[focused-row] {\n box-shadow: var(--grid-record-focused-box-shadow);\n font-weight: bold;\n color: var(--grid-record-focused-color);\n background-image: var(--focused-background-image);\n background-blend-mode: darken;\n }\n\n ox-grid-field[focused] {\n border: var(--grid-record-focused-cell-border);\n }\n\n ox-grid-field[emphasized-row],\n ox-grid-field[emphasized-row][focused] {\n background-color: var(--grid-record-emphasized-background-color) !important;\n color: var(--grid-record-emphasized-color) !important;\n }\n\n [editing] {\n background-color: var(--grid-record-editing-background-color);\n }\n\n @media print {\n :host {\n grid-template-columns: var(--grid-template-print-columns);\n }\n ox-grid-field[focused] {\n border: none;\n }\n\n ox-grid-field[selected-row] {\n background-color: transparent;\n }\n\n ox-grid-field[emphasized-row] {\n background-color: transparent;\n color: initial;\n }\n\n ox-grid-field[focused-row] {\n background-color: transparent;\n color: initial;\n }\n\n ox-grid-field[editing] {\n background-color: transparent;\n }\n }\n\n @media (prefers-color-scheme: dark) {\n ox-grid-field[focused-row] {\n background-blend-mode: lighten;\n }\n }\n\n @media (prefers-color-scheme: light) {\n ox-grid-field[focused-row] {\n background-blend-mode: darken;\n }\n }\n`\n"]}
@@ -32,10 +32,6 @@ export declare class DataGridBody extends LitElement {
32
32
  private _recordViewRow?;
33
33
  private _draggable?;
34
34
  private _gridElement?;
35
- private _imeBuffer?;
36
- _imeComposing: boolean;
37
- _imeEditing: boolean;
38
- _lastPointerTouch: boolean;
39
35
  resetEdit(): void;
40
36
  handleOnScroll(e: WheelEvent): void;
41
37
  render(): import("lit-html").TemplateResult<1>;
@@ -52,20 +48,9 @@ export declare class DataGridBody extends LitElement {
52
48
  row: number;
53
49
  record: GristRecord;
54
50
  }): void;
55
- getSelectedBlockValues(): {
56
- html: string;
57
- text: string;
58
- } | undefined;
51
+ getSelectedBlockValues(): Array<Array<any>> | any | undefined;
59
52
  copy(): Promise<void>;
60
53
  paste(): Promise<void>;
61
54
  setSelectBlock(start?: DataGridField, end?: DataGridField): void;
62
55
  buildAccumulatorRecord(): GristRecord;
63
- /** IME buffer를 포커스된 셀 위에 위치시킨다 */
64
- private _positionIMEBuffer;
65
- /** IME buffer 값을 field-change 이벤트로 커밋한다 */
66
- _commitIMEBuffer(row: number, column: number): void;
67
- /** IME buffer 취소 (값 버리기) */
68
- _discardIMEBuffer(): void;
69
- /** IME buffer 초기화 */
70
- private _resetIMEBuffer;
71
56
  }
@@ -55,9 +55,6 @@ let DataGridBody = class DataGridBody extends LitElement {
55
55
  this.from = -1;
56
56
  this.to = -1;
57
57
  this.fixedLefts = [];
58
- this._imeComposing = false;
59
- this._imeEditing = false;
60
- this._lastPointerTouch = false;
61
58
  // 검색시 스크롤 맨 위로
62
59
  this._onFetchParamsChange = () => {
63
60
  this.scrollTop = 0;
@@ -159,7 +156,6 @@ let DataGridBody = class DataGridBody extends LitElement {
159
156
  `
160
157
  : nothing}
161
158
  ${start && end && start !== end ? html ` <div select-block></div> ` : html ``}
162
- <input id="ime-buffer" type="text" />
163
159
  <slot></slot>
164
160
  `;
165
161
  }
@@ -168,43 +164,12 @@ let DataGridBody = class DataGridBody extends LitElement {
168
164
  // this.addEventListener('scroll', this.handleOnScroll.bind(this))
169
165
  /* focus() 를 받을 수 있도록 함. */
170
166
  this.setAttribute('tabindex', '-1');
171
- /* 한글 IME composition을 위한 숨겨진 input 버퍼 설정 */
172
- const imeBuffer = this.renderRoot.querySelector('#ime-buffer');
173
- this._imeBuffer = imeBuffer;
174
- imeBuffer.addEventListener('compositionstart', () => {
175
- this._imeComposing = true;
176
- this._imeEditing = true;
177
- imeBuffer.classList.add('active');
178
- this._positionIMEBuffer();
179
- });
180
- imeBuffer.addEventListener('compositionend', () => {
181
- this._imeComposing = false;
182
- });
183
- imeBuffer.addEventListener('input', () => {
184
- if (!this._imeComposing && !this._imeEditing && imeBuffer.value) {
185
- /* 영어/숫자: 실제 값이 입력된 경우에만 활성화 */
186
- this._imeEditing = true;
187
- imeBuffer.classList.add('active');
188
- this._positionIMEBuffer();
189
- }
190
- });
191
167
  /*
192
168
  * focusout 으로 property를 변경시키는 경우, focusout에 의해 update가 발생하는 경우에는,
193
169
  * 그리드 내부의 컴포넌트가 갱신되는 현상을 초래하게 된다.
194
170
  * 따라서, focusout 핸들러에서 update를 유발하는 코드는 강력하게 금지시킨다.
195
171
  */
196
172
  this.addEventListener('focusout', e => {
197
- var _a;
198
- /* IME buffer로 포커스가 이동하는 경우 keydown listener 유지 */
199
- const related = e.relatedTarget;
200
- if (related && ((_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.contains(related))) {
201
- return;
202
- }
203
- /* 그리드 외부로 포커스 이동 시 IME buffer 커밋 */
204
- if (this._imeEditing) {
205
- const { row = 0, column = 0 } = this.focused || {};
206
- this._commitIMEBuffer(row, column);
207
- }
208
173
  if (this._focusedListener) {
209
174
  this.removeEventListener('keydown', this._focusedListener);
210
175
  delete this._focusedListener;
@@ -238,26 +203,12 @@ let DataGridBody = class DataGridBody extends LitElement {
238
203
  }
239
204
  }));
240
205
  });
241
- this.renderRoot.addEventListener('pointerdown', (e) => {
242
- const pe = e;
243
- const isTouch = pe.pointerType === 'touch';
244
- /* 터치 이벤트 여부 기록 — 태블릿에서 input focus로 가상 키보드가 뜨는 것을 방지 */
245
- this._lastPointerTouch = isTouch;
246
- /* 클릭 시 IME buffer가 활성 상태면 먼저 커밋 */
247
- if (this._imeEditing) {
248
- const { row = 0, column = 0 } = this.focused || {};
249
- this._commitIMEBuffer(row, column);
250
- }
206
+ this.renderRoot.addEventListener('mousedown', (event) => {
207
+ const e = event;
251
208
  this.setSelectBlock();
252
- if (isTouch) {
253
- /* 터치: click 이벤트에서 처리 (스크롤 시에는 click이 발생하지 않음) */
209
+ if (e.buttons !== 1) {
254
210
  return;
255
211
  }
256
- if ('buttons' in e && pe.buttons !== 1) {
257
- return;
258
- }
259
- e.preventDefault();
260
- e.stopPropagation();
261
212
  this._draggable = true;
262
213
  var target = e.target.closest('ox-grid-field');
263
214
  var { rowIndex, columnIndex } = target || {};
@@ -273,13 +224,11 @@ let DataGridBody = class DataGridBody extends LitElement {
273
224
  this.startEditTarget(rowIndex, columnIndex);
274
225
  }
275
226
  });
276
- this.renderRoot.addEventListener('pointermove', (event) => {
227
+ this.renderRoot.addEventListener('mousemove', (event) => {
277
228
  const e = event;
278
- if (('buttons' in e && e.buttons !== 1) || !this._draggable) {
229
+ if (e.buttons !== 1 || !this._draggable) {
279
230
  return;
280
231
  }
281
- e.preventDefault();
282
- e.stopPropagation();
283
232
  const field = e.target;
284
233
  if (!this._selectBlock) {
285
234
  this.setSelectBlock(this.focusedField || field, this.focusedField || field);
@@ -291,11 +240,7 @@ let DataGridBody = class DataGridBody extends LitElement {
291
240
  this.setSelectBlock(start, end);
292
241
  }
293
242
  });
294
- this.renderRoot.addEventListener('pointerup', (event) => {
295
- if (event.pointerType !== 'touch') {
296
- event.preventDefault();
297
- event.stopPropagation();
298
- }
243
+ this.renderRoot.addEventListener('mouseup', (event) => {
299
244
  this._draggable = false;
300
245
  });
301
246
  this.renderRoot.addEventListener('click', dataGridBodyClickHandler.bind(this));
@@ -335,11 +280,14 @@ let DataGridBody = class DataGridBody extends LitElement {
335
280
  return this.renderRoot.children.item(rowIndex * (columns + 1) /* 1 means last dummy column */ + ((columnIndex + columns) % columns));
336
281
  }
337
282
  startEditTarget(row, column, valueWith = null) {
338
- var { editable } = this.columns.filter(column => !column.hidden)[column].record;
283
+ /* columnIndex 는 보이는 컬럼 기준이므로 editable 판단도 같은 배열로 한다.
284
+ (기존 this.columns[column + 1] 은 원본 배열 오프셋이 어긋나 있었고,
285
+ 함수형 editable 이 마지막 컬럼이면 undefined 참조로 편집이 아예 안 열렸다) */
286
+ const visibleColumn = this.columns.filter(column => !column.hidden)[column];
287
+ var { editable } = visibleColumn.record;
339
288
  if (typeof editable === 'function') {
340
289
  const curRow = this.data.records[row] || {};
341
- const curCol = this.columns[column + 1];
342
- editable = editable.call(this, curRow[curCol.name], curCol, curRow, row, this);
290
+ editable = editable.call(this, curRow[visibleColumn.name], visibleColumn, curRow, row, this);
343
291
  }
344
292
  if (!editable) {
345
293
  return;
@@ -347,8 +295,6 @@ let DataGridBody = class DataGridBody extends LitElement {
347
295
  if (this.editTarget && this.editTarget.row == row && this.editTarget.column == column) {
348
296
  return;
349
297
  }
350
- /* 에디터 편집 전환 시 IME buffer 정리 */
351
- this._resetIMEBuffer();
352
298
  this.editTarget = {
353
299
  row,
354
300
  column,
@@ -384,11 +330,6 @@ let DataGridBody = class DataGridBody extends LitElement {
384
330
  if (left !== undefined) {
385
331
  this.scrollLeft = left;
386
332
  }
387
- /* IME buffer 위치 업데이트 */
388
- this._positionIMEBuffer();
389
- if (!this.editTarget && this._imeBuffer && !this._lastPointerTouch) {
390
- this._imeBuffer.focus();
391
- }
392
333
  }
393
334
  // 페이징 바뀌면 스크롤 맨 위로
394
335
  if (changes.has('data')) {
@@ -404,18 +345,7 @@ let DataGridBody = class DataGridBody extends LitElement {
404
345
  }
405
346
  }
406
347
  focus() {
407
- if (this.editTarget) {
408
- /* 에디터 편집 모드에서는 에디터가 자체적으로 포커스를 관리하므로 간섭하지 않는다 */
409
- return;
410
- }
411
- if (this._imeBuffer && !this._lastPointerTouch) {
412
- /* 비편집 모드에서는 IME buffer로 포커스 리다이렉트 (터치 시에는 가상 키보드 방지를 위해 제외) */
413
- this._positionIMEBuffer();
414
- this._imeBuffer.focus();
415
- }
416
- else {
417
- super.focus();
418
- }
348
+ super.focus();
419
349
  if (this.focused === ZERO_FOCUS) {
420
350
  let { records } = this.data;
421
351
  let row = records.findIndex(record => record['__selected__']);
@@ -438,7 +368,6 @@ let DataGridBody = class DataGridBody extends LitElement {
438
368
  delete this._recordViewRow;
439
369
  });
440
370
  }
441
- /* 선택된 셀 블록의 값을 HTML(table)과 plain text(TSV) 두 가지 포맷으로 반환 */
442
371
  getSelectedBlockValues() {
443
372
  var { start, end } = this._selectBlock || {};
444
373
  if (!(start && end)) {
@@ -452,81 +381,34 @@ let DataGridBody = class DataGridBody extends LitElement {
452
381
  const endColumnIndex = start.columnIndex < end.columnIndex ? end.columnIndex : start.columnIndex;
453
382
  const columnArray = new Array(endColumnIndex - startColumnIndex + 1).fill(startColumnIndex);
454
383
  const columns = this.columns.filter(column => !column.hidden);
455
- /*
456
- * 클립보드에 두 가지 포맷(text/html, text/plain)을 동시에 저장한다.
457
- * 붙여넣기하는 앱이 자신이 지원하는 포맷을 골라 읽는다.
458
- * 생성되는 HTML:
459
- * <td type=object data-value="{&quot;id&quot;:...}">탈수 절임배추</td>
460
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
461
- * 그리드만 읽는 숨겨진 JSON Excel/메모장이 보는 텍스트
462
- */
463
- const rows = new Array(endRowIndex - startRowIndex + 1).fill(startRowIndex).map((start, index) => {
464
- const rowIndex = start + index;
465
- const record = this.data.records[rowIndex];
466
- const cells = columnArray.map((start, index) => {
467
- var _a, _b;
468
- const columnIndex = start + index;
469
- const column = columns[columnIndex];
470
- const value = record === null || record === void 0 ? void 0 : record[column.name];
471
- const type = typeof value;
472
- /* htmlText: object는 JSON 문자열로 보존 → data-value 속성에 저장되어 그리드 붙여넣기 시 복원됨 */
473
- const htmlText = value === undefined || value === null ? '' : type == 'object' ? JSON.stringify(value) : value;
474
- /* plainText: ① null/undefined → renderer ② object → name → renderer ③ 기타 → 값 그대로 */
475
- let plainText = '';
476
- if (value === undefined || value === null) {
477
- /* 값이 없지만 renderer가 record의 다른 경로로 텍스트를 표시할 수 있음 */
478
- if ((_a = column.record) === null || _a === void 0 ? void 0 : _a.renderer) {
479
- try {
480
- const r = column.record.renderer(value, column, record, rowIndex, null);
481
- if (typeof r === 'string')
482
- plainText = r;
483
- }
484
- catch (e) { }
485
- }
486
- }
487
- else if (type == 'object') {
488
- /* object: name 필드 우선, 없으면 renderer */
489
- plainText = (value === null || value === void 0 ? void 0 : value.name) || '';
490
- if (!plainText && ((_b = column.record) === null || _b === void 0 ? void 0 : _b.renderer)) {
491
- try {
492
- const r = column.record.renderer(value, column, record, rowIndex, null);
493
- if (typeof r === 'string')
494
- plainText = r;
495
- }
496
- catch (e) { }
497
- }
498
- }
499
- else {
500
- plainText = value;
501
- }
502
- return { type, htmlText, plainText };
503
- });
504
- return cells;
505
- });
506
- const html = '<table>' +
507
- rows
508
- .map(cells => '<tr>' +
509
- cells
510
- .map(c => c.type == 'object' && c.htmlText
511
- ? `<td type=${c.type} data-value="${String(c.htmlText).replace(/"/g, '&quot;')}">${c.plainText}</td>`
512
- : `<td type=${c.type}>${c.htmlText}</td>`)
513
- .join('') +
514
- '</tr>')
384
+ return ('<table>' +
385
+ new Array(endRowIndex - startRowIndex + 1)
386
+ .fill(startRowIndex)
387
+ .map((start, index) => {
388
+ const rowIndex = start + index;
389
+ const record = this.data.records[rowIndex];
390
+ const tds = columnArray
391
+ .map((start, index) => {
392
+ const columnIndex = start + index;
393
+ const column = columns[columnIndex];
394
+ const value = record === null || record === void 0 ? void 0 : record[column.name];
395
+ const type = typeof value;
396
+ const text = value === undefined || value === null ? '' : type == 'object' ? JSON.stringify(value) : value;
397
+ return `<td type=${type}>${text}</td>`;
398
+ })
399
+ .join('');
400
+ return `<tr>${tds}</tr>`;
401
+ })
515
402
  .join('') +
516
- '</table>';
517
- /* 태그 없는 TSV 포맷 (object는 name만) */
518
- const text = rows.map(cells => cells.map(c => String(c.plainText)).join('\t')).join('\n');
519
- return { html, text };
403
+ '</table>');
520
404
  }
521
405
  }
522
406
  async copy() {
523
407
  const copied = this.getSelectedBlockValues();
524
- if (!copied)
525
- return;
526
408
  await navigator.clipboard.write([
527
409
  new ClipboardItem({
528
- 'text/html': new Blob([copied.html], { type: 'text/html' }),
529
- 'text/plain': new Blob([copied.text], { type: 'text/plain' })
410
+ 'text/html': new Blob([copied], { type: 'text/html' }),
411
+ 'text/plain': new Blob([copied], { type: 'text/plain' })
530
412
  })
531
413
  ]);
532
414
  const selectBlock = this.selectBlock || this.focusedField;
@@ -603,8 +485,8 @@ let DataGridBody = class DataGridBody extends LitElement {
603
485
  const cells = record.querySelectorAll('td');
604
486
  cells.forEach((item, columnIndex) => {
605
487
  const targetColumn = columns[column + columnIndex];
606
- /* data-value 속성이 있으면 우선 사용 (그리드에서 복사한 object 데이터 복원용) */
607
- let value = (item.dataset.value || item.textContent);
488
+ let value = item.textContent;
489
+ // let value = item.textContent?.trim() as any
608
490
  let type = targetColumn.type || item.getAttribute('type') || 'string';
609
491
  type = type.includes('object') ? 'object' : type; // 오브젝트 타입 예외처리
610
492
  let { editable } = targetColumn.record;
@@ -672,48 +554,31 @@ let DataGridBody = class DataGridBody extends LitElement {
672
554
  });
673
555
  return;
674
556
  }
675
- else if (type === 'text/plain') {
676
- /* TSV 포맷 파싱: 줄바꿈으로 행 분리, 탭으로 열 분리 (엑셀 등 외부 소스 붙여넣기 지원) */
677
- const tsvRows = content.split('\n');
678
- tsvRows.forEach((line, rowOffset) => {
679
- const targetRowIndex = row + rowOffset;
680
- var targetRecord = records[targetRowIndex] || { __dirty__: '+' };
681
- if (targetRowIndex >= records.length) {
682
- records.push(targetRecord);
683
- }
684
- const tsvCells = line.split('\t');
685
- tsvCells.forEach((cellValue, colOffset) => {
686
- const targetColumn = columns[column + colOffset];
687
- if (!targetColumn || targetColumn.gutterName)
688
- return;
689
- let { editable } = targetColumn.record;
690
- if (typeof editable === 'function') {
691
- editable = editable.call(this, cellValue, targetColumn, targetRecord, targetRowIndex, this);
692
- }
693
- if (editable) {
694
- this.dispatchEvent(new CustomEvent('field-change', {
695
- bubbles: true,
696
- composed: true,
697
- detail: {
698
- before: targetRecord[targetColumn.name],
699
- after: cellValue || undefined,
700
- column: targetColumn,
701
- record: targetRecord,
702
- row: targetRowIndex
703
- }
704
- }));
557
+ else if (!selection && type === 'text/plain') {
558
+ const targetRecord = records[row] || { __dirty__: '+' };
559
+ const targetColumn = columns[column];
560
+ let { editable } = targetColumn.record;
561
+ if (typeof editable === 'function') {
562
+ editable = editable.call(this, content, targetColumn, targetRecord, row, this);
563
+ }
564
+ if (targetColumn && !targetColumn.gutterName && editable) {
565
+ this.dispatchEvent(new CustomEvent('field-change', {
566
+ bubbles: true,
567
+ composed: true,
568
+ detail: {
569
+ before: targetRecord[targetColumn.name],
570
+ after: content,
571
+ column: targetColumn,
572
+ record: targetRecord,
573
+ row: row
705
574
  }
706
- });
707
- });
575
+ }));
576
+ }
708
577
  }
709
578
  }
710
579
  catch (e) {
711
580
  console.log('e : ', e);
712
581
  }
713
- finally {
714
- /* paste 완료 후 포커스를 그리드로 복원 */
715
- this.focus();
716
- }
717
582
  }
718
583
  setSelectBlock(start, end) {
719
584
  var _a;
@@ -752,84 +617,12 @@ let DataGridBody = class DataGridBody extends LitElement {
752
617
  return record;
753
618
  }, {});
754
619
  }
755
- /** IME buffer를 포커스된 셀 위에 위치시킨다 */
756
- _positionIMEBuffer() {
757
- var _a;
758
- const focusedEl = (_a = this.renderRoot) === null || _a === void 0 ? void 0 : _a.querySelector('[focused]');
759
- if (focusedEl && this._imeBuffer) {
760
- this._imeBuffer.style.left = focusedEl.offsetLeft + 'px';
761
- this._imeBuffer.style.top = focusedEl.offsetTop + 'px';
762
- this._imeBuffer.style.width = focusedEl.offsetWidth + 'px';
763
- this._imeBuffer.style.height = focusedEl.offsetHeight + 'px';
764
- }
765
- }
766
- /** IME buffer 값을 field-change 이벤트로 커밋한다 */
767
- _commitIMEBuffer(row, column) {
768
- var _a;
769
- const text = (_a = this._imeBuffer) === null || _a === void 0 ? void 0 : _a.value;
770
- this._resetIMEBuffer();
771
- if (!text)
772
- return;
773
- const columns = this.columns.filter(c => !c.hidden);
774
- const col = columns[column];
775
- if (!col || col.gutterName)
776
- return;
777
- const record = this.data.records[row] || { __dirty__: '+' };
778
- let { editable } = col.record;
779
- if (typeof editable === 'function') {
780
- editable = editable.call(this, record[col.name], col, record, row, this);
781
- }
782
- if (!editable)
783
- return;
784
- /* 타입에 따른 값 변환 */
785
- let value = text;
786
- switch (col.type) {
787
- case 'number':
788
- case 'float':
789
- case 'integer':
790
- case 'progress':
791
- value = parseToNumberOrNull(text);
792
- if (value === null)
793
- return;
794
- break;
795
- case 'boolean':
796
- case 'checkbox':
797
- return; /* boolean은 키보드 텍스트 입력으로 편집 불가 */
798
- }
799
- this.dispatchEvent(new CustomEvent('field-change', {
800
- bubbles: true,
801
- composed: true,
802
- detail: {
803
- before: record[col.name],
804
- after: value,
805
- column: col,
806
- record,
807
- row
808
- }
809
- }));
810
- }
811
- /** IME buffer 취소 (값 버리기) */
812
- _discardIMEBuffer() {
813
- this._resetIMEBuffer();
814
- }
815
- /** IME buffer 초기화 */
816
- _resetIMEBuffer() {
817
- if (this._imeBuffer) {
818
- this._imeBuffer.value = '';
819
- this._imeBuffer.classList.remove('active');
820
- }
821
- this._imeEditing = false;
822
- this._imeComposing = false;
823
- }
824
620
  };
825
621
  DataGridBody.styles = [
826
622
  dataGridBodyStyle,
827
623
  css `
828
624
  :host {
829
625
  font-variation-settings: 'FILL' 1;
830
-
831
- overscroll-behavior: none;
832
- user-select: none;
833
626
  }
834
627
 
835
628
  [select-block] {
@@ -841,7 +634,6 @@ DataGridBody.styles = [
841
634
  border: var(--grid-record-focused-cell-border);
842
635
  background-image: var(--focused-background-image);
843
636
  pointer-events: none;
844
-
845
637
  z-index: 5;
846
638
  }
847
639
 
@@ -874,38 +666,6 @@ DataGridBody.styles = [
874
666
  box-shadow: none !important;
875
667
  }
876
668
  }
877
-
878
- @media (pointer: coarse) {
879
- /* 터치 디바이스에서는 길게 눌러 텍스트 선택 허용 */
880
- :host {
881
- user-select: auto;
882
- }
883
- }
884
-
885
- /* 한글 IME composition을 위한 숨겨진 input 버퍼 — 기존 에디터 셀 스타일과 일치 */
886
- #ime-buffer {
887
- position: absolute;
888
- opacity: 0;
889
- z-index: 10;
890
- background-color: var(--grid-record-editing-background-color, var(--grid-record-background-color, #fff));
891
- color: var(--md-sys-color-on-background, inherit);
892
- font: inherit;
893
- font-size: var(--grid-record-wide-fontsize);
894
- border: 1px solid transparent;
895
- border-width: 1px 0;
896
- border-top: var(--grid-record-editing-border, none);
897
- border-bottom: var(--grid-record-editing-border, none);
898
- padding: var(--grid-record-padding);
899
- box-sizing: border-box;
900
- outline: none;
901
- overflow: hidden;
902
- pointer-events: none;
903
- }
904
-
905
- #ime-buffer.active {
906
- opacity: 1;
907
- pointer-events: auto;
908
- }
909
669
  `
910
670
  ];
911
671
  __decorate([