@operato/data-grist 10.29.6 → 10.29.8
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 +18 -0
- package/dist/src/data-grid/data-grid-body-style.js +2 -10
- package/dist/src/data-grid/data-grid-body-style.js.map +1 -1
- package/dist/src/data-grid/data-grid-body.d.ts +1 -0
- package/dist/src/data-grid/data-grid-body.js +35 -12
- package/dist/src/data-grid/data-grid-body.js.map +1 -1
- package/dist/src/data-grid/data-grid-header.js +5 -10
- package/dist/src/data-grid/data-grid-header.js.map +1 -1
- package/dist/src/data-grid/data-grid.d.ts +2 -1
- package/dist/src/data-grid/data-grid.js +74 -21
- package/dist/src/data-grid/data-grid.js.map +1 -1
- package/dist/test/accessible-name.test.js +6 -4
- package/dist/test/accessible-name.test.js.map +1 -1
- package/dist/test/field-contains-content.test.js +8 -5
- package/dist/test/field-contains-content.test.js.map +1 -1
- package/dist/test/first-click-stays.test.d.ts +1 -0
- package/dist/test/first-click-stays.test.js +77 -0
- package/dist/test/first-click-stays.test.js.map +1 -0
- package/dist/test/grid-single-scroller.test.d.ts +1 -0
- package/dist/test/grid-single-scroller.test.js +107 -0
- package/dist/test/grid-single-scroller.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/test/accessible-name.test.ts +6 -4
- package/test/field-contains-content.test.ts +10 -5
- package/test/first-click-stays.test.ts +101 -0
- package/test/grid-single-scroller.test.ts +150 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,24 @@
|
|
|
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
|
+
### [10.29.8](https://github.com/hatiolab/operato/compare/v10.29.7...v10.29.8) (2026-10-05)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :bug: Bug Fix
|
|
10
|
+
|
|
11
|
+
* **data-grist:** keep the grid still on the first cell click ([97348f1](https://github.com/hatiolab/operato/commit/97348f1f424dc66d4137201748071d6439fcb5f5))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### [10.29.7](https://github.com/hatiolab/operato/compare/v10.29.6...v10.29.7) (2026-10-05)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
### :bug: Bug Fix
|
|
19
|
+
|
|
20
|
+
* **data-grist:** scroll grid header and body in one scroller ([b004080](https://github.com/hatiolab/operato/commit/b0040800ce32634bcb2f3ecf0ebbac174199570f))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
6
24
|
### [10.29.6](https://github.com/hatiolab/operato/compare/v10.29.5...v10.29.6) (2026-10-04)
|
|
7
25
|
|
|
8
26
|
|
|
@@ -5,18 +5,10 @@ export const dataGridBodyStyle = css `
|
|
|
5
5
|
grid-template-columns: var(--grid-template-columns);
|
|
6
6
|
grid-auto-rows: var(--grid-record-height, min-content);
|
|
7
7
|
|
|
8
|
-
overflow: auto;
|
|
9
8
|
/*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* 머리는 overflow: hidden 이라 스크롤바에 자리를 내주지 않고, 몸은 긴 목록에서 스크롤바 폭만큼
|
|
13
|
-
* 좁아진다. 그래서 갈 수 있는 거리가 몸이 그만큼 더 길었고, 오른쪽 끝에서 몸만 더 갔다.
|
|
14
|
-
* 확인해 보니 정확히 --scrollbar-width 만큼(5px)이었다.
|
|
15
|
-
*
|
|
16
|
-
* 자리를 늘 비워 두면 목록 길이와 무관하게 두 폭이 같다. 목록이 길어질 때 열이 움찔하는 것도
|
|
17
|
-
* 함께 없어진다 — 스크롤바가 생기는 순간 폭이 바뀌지 않는다.
|
|
9
|
+
* 몸은 스크롤하지 않는다 — 머리와 함께 data-grid 의 div[grid] 안에서 움직인다(data-grid.ts 주석).
|
|
10
|
+
* 몸이 스크롤러였을 때는 머리를 이벤트로 따라오게 해야 했고, 그것이 이격과 흔들림을 만들었다.
|
|
18
11
|
*/
|
|
19
|
-
scrollbar-gutter: stable;
|
|
20
12
|
outline: none;
|
|
21
13
|
color: var(--grid-record-color);
|
|
22
14
|
position: relative;
|
|
@@ -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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8InC,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 /*\n * 몸은 스크롤하지 않는다 — 머리와 함께 data-grid 의 div[grid] 안에서 움직인다(data-grid.ts 주석).\n * 몸이 스크롤러였을 때는 머리를 이벤트로 따라오게 해야 했고, 그것이 이격과 흔들림을 만들었다.\n */\n outline: none;\n color: var(--grid-record-color);\n position: relative;\n border-bottom: var(--grid-body-bottom-border);\n }\n\n /*\n * Row wrapper — generates no box.\n *\n * It exists only to carry role=row, so it must stay out of layout. With display: contents the\n * element produces no box and its children remain items of the outer grid — column widths, fixed\n * columns and the grid-column placement of group headers are untouched.\n */\n div[grid-row] {\n display: contents;\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 /*\n * 마우스가 지나는 줄.\n *\n * 고른 줄보다 **훨씬 옅다.** 지나는 것은 사실이 아니고 눈이 어디 있는지 알려 주는 것뿐이라, 고른\n * 줄과 같은 무게로 그리면 무엇이 골라졌는지 헷갈린다. 그래서 고른 줄 규칙 뒤에 둔다 — 둘이 겹칠\n * 때는 고른 쪽이 이겨야 하므로 색을 옅게 두고 순서로 다투지 않는다.\n *\n * 값은 표가 정한다. 고치는 표에서는 비운다(data-grid.ts) — 거기서는 점선 셀 테두리가 이미 자리를\n * 말하고, 둘이 함께 있으면 시끄럽다.\n */\n @media (hover: hover) {\n ox-grid-field[hovered-row]:not([selected-row]) {\n background-color: var(--grid-record-hover-background-color, transparent);\n }\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 /*\n * 초점 셀 표식 — border 가 아니라 outline 으로 그린다.\n *\n * border 로 그리면 두 가지가 깨진다.\n * · 네 면 테두리가 셀 크기를 바꿔 줄이 어긋난다\n * · 아래 면이 **줄을 나누는 선 자리**를 차지해, 그 셀만 줄 선이 사라진다\n *\n * outline 은 자리를 차지하지 않는다. outline-offset: -1px 로 안쪽에 그려 옆 셀과 겹치지 않게 한다.\n * 표식을 감추고 싶은 화면은 토큰을 none 으로 두면 되고, 그래도 줄 선은 남는다.\n */\n ox-grid-field[focused] {\n outline: var(--grid-record-focused-cell-border);\n outline-offset: -1px;\n }\n\n ox-grid-field[emphasized-row],\n ox-grid-field[emphasized-row][focused] {\n background-color: var(--grid-record-emphasized-background-color);\n color: var(--grid-record-emphasized-color);\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 outline: none;\n }\n\n ox-grid-field[selected-row] {\n background-color: transparent;\n }\n\n /* 종이에는 마우스가 없다. */\n ox-grid-field[hovered-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"]}
|
|
@@ -48,6 +48,7 @@ export declare class DataGridBody extends LitElement {
|
|
|
48
48
|
handleOnScroll(e: WheelEvent): void;
|
|
49
49
|
render(): import("lit-html").TemplateResult<1>;
|
|
50
50
|
firstUpdated(): void;
|
|
51
|
+
get scroller(): HTMLElement;
|
|
51
52
|
connectedCallback(): void;
|
|
52
53
|
disconnectedCallback(): void;
|
|
53
54
|
_onFetchParamsChange: EventListener;
|
|
@@ -23,10 +23,15 @@ const THRESHOLD = 300;
|
|
|
23
23
|
const DATA_PADDING = 3;
|
|
24
24
|
const ROW_HEIGHT = 40;
|
|
25
25
|
const GAP_SIZE = 1;
|
|
26
|
-
|
|
26
|
+
/*
|
|
27
|
+
* parent 는 스크롤러다. stickyTop 은 그 위쪽에 붙어 칸을 가리는 머리의 높이다 — 머리 밑으로 들어간
|
|
28
|
+
* 칸은 화면 안에 있어도 보이지 않으므로 그만큼 내려서 판단한다.
|
|
29
|
+
*/
|
|
30
|
+
function calcScrollPos(parent, child, stickyTop = 0) {
|
|
27
31
|
/* getBoundingClientRect는 safari에서 스크롤 상태에서 다른 브라우저와는 다른 값을 리턴함 - 사파리는 약간 이상 작동함. */
|
|
28
32
|
var { top: ct, left: cl, right: cr, bottom: cb } = child.getBoundingClientRect();
|
|
29
33
|
var { top: pt, left: pl, right: pr, bottom: pb } = parent.getBoundingClientRect();
|
|
34
|
+
pt += stickyTop;
|
|
30
35
|
var { scrollLeft, scrollTop } = parent;
|
|
31
36
|
var scrollbarWidth = parent.clientWidth - parent.offsetWidth;
|
|
32
37
|
var scrollbarHeight = parent.clientHeight - parent.offsetHeight;
|
|
@@ -104,7 +109,7 @@ let DataGridBody = class DataGridBody extends LitElement {
|
|
|
104
109
|
this._lastPointerTouch = false;
|
|
105
110
|
// 검색시 스크롤 맨 위로
|
|
106
111
|
this._onFetchParamsChange = () => {
|
|
107
|
-
this.scrollTop = 0;
|
|
112
|
+
this.scroller.scrollTop = 0;
|
|
108
113
|
};
|
|
109
114
|
this._hoveredRow = -1;
|
|
110
115
|
}
|
|
@@ -444,9 +449,13 @@ let DataGridBody = class DataGridBody extends LitElement {
|
|
|
444
449
|
`url("data:image/svg+xml,${encodedSvg}")`);
|
|
445
450
|
});
|
|
446
451
|
this.addEventListener('show-record-view', (e) => this.popupRecordView(e.detail));
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
452
|
+
}
|
|
453
|
+
/*
|
|
454
|
+
* 몸을 옮기는 스크롤러. 표 안에서는 머리와 몸을 함께 담은 div[grid] 이고(data-grid.ts), 몸만 홀로
|
|
455
|
+
* 세웠을 때는 몸 자신이다.
|
|
456
|
+
*/
|
|
457
|
+
get scroller() {
|
|
458
|
+
return this.closest('div[grid]') || this;
|
|
450
459
|
}
|
|
451
460
|
connectedCallback() {
|
|
452
461
|
var _a;
|
|
@@ -559,7 +568,9 @@ let DataGridBody = class DataGridBody extends LitElement {
|
|
|
559
568
|
if (!element) {
|
|
560
569
|
return;
|
|
561
570
|
}
|
|
562
|
-
|
|
571
|
+
const scroller = this.scroller;
|
|
572
|
+
const header = scroller === this ? null : scroller.querySelector('ox-grid-header');
|
|
573
|
+
let { top, left } = calcScrollPos(scroller, element, (header === null || header === void 0 ? void 0 : header.offsetHeight) || 0);
|
|
563
574
|
// TODO this.scroll()을 사용하면, 효과가 좋으나 left 계산에 문제가 있는 것 같음.
|
|
564
575
|
// this.scroll({
|
|
565
576
|
// top,
|
|
@@ -567,15 +578,15 @@ let DataGridBody = class DataGridBody extends LitElement {
|
|
|
567
578
|
// behavior: 'smooth'
|
|
568
579
|
// })
|
|
569
580
|
if (top !== undefined) {
|
|
570
|
-
|
|
581
|
+
scroller.scrollTop = top;
|
|
571
582
|
}
|
|
572
583
|
if (left !== undefined) {
|
|
573
|
-
|
|
584
|
+
scroller.scrollLeft = left;
|
|
574
585
|
}
|
|
575
586
|
/* IME buffer 위치 업데이트 */
|
|
576
587
|
this._positionIMEBuffer();
|
|
577
588
|
if (!this.editTarget && this._imeBuffer && !this._lastPointerTouch && this._hasEditableColumn) {
|
|
578
|
-
this._imeBuffer.focus();
|
|
589
|
+
this._imeBuffer.focus({ preventScroll: true });
|
|
579
590
|
}
|
|
580
591
|
}
|
|
581
592
|
// 페이징 바뀌면 스크롤 맨 위로
|
|
@@ -584,13 +595,25 @@ let DataGridBody = class DataGridBody extends LitElement {
|
|
|
584
595
|
const prevPage = prevData && prevData.page;
|
|
585
596
|
const currPage = this.data.page;
|
|
586
597
|
if (prevPage !== undefined && prevPage !== currPage) {
|
|
587
|
-
this.scrollTop = 0;
|
|
598
|
+
this.scroller.scrollTop = 0;
|
|
588
599
|
}
|
|
589
600
|
}
|
|
590
601
|
if (this._recordView) {
|
|
591
602
|
this._recordView.record = this.data.records[this._recordViewRow];
|
|
592
603
|
}
|
|
593
604
|
}
|
|
605
|
+
/*
|
|
606
|
+
* ── 초점을 줄 때 **브라우저가 스크롤하지 않게 한다** (2026-10-05) ──────────────
|
|
607
|
+
*
|
|
608
|
+
* 초점 칸을 화면 안으로 들이는 일은 이 표가 직접 한다(updated 의 calcScrollPos). 그런데 초점을 받는
|
|
609
|
+
* 입력 버퍼는 그 전에 불린다 — 칸을 누르면 표가 새 초점을 정하고 곧바로 focus() 를 부르는데, 몸은
|
|
610
|
+
* 아직 새 초점으로 다시 그려지기 전이다. 버퍼는 이전 초점 칸 자리에, 처음이면 놓인 적 없는 기본
|
|
611
|
+
* 자리(왼쪽 위)에 있다. 브라우저는 그 버퍼를 보이게 하려고 표를 스크롤한다.
|
|
612
|
+
*
|
|
613
|
+
* [확인함] 1000px 오른쪽으로 민 표에서 처음 칸을 누르면 0 으로 갔다가, 다시 그려진 뒤 581 로 왔다.
|
|
614
|
+
* 가운데에서 누른 칸이 오른쪽 끝으로 밀려났다. 두 번째부터는 버퍼가 직전 칸 근처에 있어
|
|
615
|
+
* 안 보였다 — 「처음에만 그런다」(사용자, 2026-10-05).
|
|
616
|
+
*/
|
|
594
617
|
focus() {
|
|
595
618
|
if (this.editTarget) {
|
|
596
619
|
/* 에디터 편집 모드에서는 에디터가 자체적으로 포커스를 관리하므로 간섭하지 않는다 */
|
|
@@ -599,10 +622,10 @@ let DataGridBody = class DataGridBody extends LitElement {
|
|
|
599
622
|
if (this._imeBuffer && !this._lastPointerTouch && this._hasEditableColumn) {
|
|
600
623
|
/* 비편집 모드에서는 IME buffer로 포커스 리다이렉트 (터치 시/읽기 전용 그리드에서는 제외) */
|
|
601
624
|
this._positionIMEBuffer();
|
|
602
|
-
this._imeBuffer.focus();
|
|
625
|
+
this._imeBuffer.focus({ preventScroll: true });
|
|
603
626
|
}
|
|
604
627
|
else {
|
|
605
|
-
super.focus();
|
|
628
|
+
super.focus({ preventScroll: true });
|
|
606
629
|
}
|
|
607
630
|
if (this.focused === ZERO_FOCUS) {
|
|
608
631
|
let { records } = this.data;
|