@operato/data-grist 10.7.0 → 10.8.1
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 +26 -0
- package/dist/src/data-grid/data-grid-body.js +18 -0
- package/dist/src/data-grid/data-grid-body.js.map +1 -1
- package/dist/src/data-grid/data-grid-footer.js +5 -1
- package/dist/src/data-grid/data-grid-footer.js.map +1 -1
- package/dist/src/data-grid/data-grid.js +18 -3
- package/dist/src/data-grid/data-grid.js.map +1 -1
- package/dist/src/data-grist.d.ts +19 -1
- package/dist/src/data-grist.js +60 -8
- package/dist/src/data-grist.js.map +1 -1
- package/dist/src/filters/filters-form.js +10 -1
- package/dist/src/filters/filters-form.js.map +1 -1
- package/dist/test/fixed-column-opaque.test.d.ts +1 -0
- package/dist/test/fixed-column-opaque.test.js +134 -0
- package/dist/test/fixed-column-opaque.test.js.map +1 -0
- package/dist/test/row-hover-visible.test.d.ts +1 -0
- package/dist/test/row-hover-visible.test.js +127 -0
- package/dist/test/row-hover-visible.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/test/fixed-column-opaque.test.ts +183 -0
- package/test/row-hover-visible.test.ts +164 -0
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing';
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
import '../src/data-grid/data-grid-body.js';
|
|
4
|
+
import { ZERO_CONFIG, ZERO_DATA } from '../src/configure/zero-config.js';
|
|
5
|
+
/**
|
|
6
|
+
* 고정 열의 바탕.
|
|
7
|
+
*
|
|
8
|
+
* ## 왜 시험이 필요한가
|
|
9
|
+
*
|
|
10
|
+
* 고정 칸은 `position: sticky` 로 스크롤되는 열 **위에** 떠 있다. 그래서 이 칸의 바탕이 투명해지면
|
|
11
|
+
* 아래로 지나가는 열이 그대로 비쳐, 한 줄에 글자 두 벌이 겹쳐 보인다
|
|
12
|
+
* (`P-CAM-I-0001` 위에 `CAM-INSP-01` 이 찍혔다).
|
|
13
|
+
*
|
|
14
|
+
* 바탕이 지워지는 것은 색을 잘못 고른 것이 아니라 **줄 상태 색을 `transparent` 로 둔 것**이었다.
|
|
15
|
+
* 그 값은 「칠하지 않는다」가 아니라 「칸의 바탕을 지운다」다. 지워진 자리에는 표 뒤에 있는 것이
|
|
16
|
+
* 비치고, 그것은 표가 정한 색이 아니다.
|
|
17
|
+
*
|
|
18
|
+
* ## 두 가지를 함께 잰다
|
|
19
|
+
*
|
|
20
|
+
* ```
|
|
21
|
+
* 불투명한가 투명해지면 스크롤되는 열이 비친다
|
|
22
|
+
* 같은 색인가 고정 열만 다르면 줄 하나가 두 색으로 갈린다
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* 둘을 따로 두면 **한쪽만 지키는 고침이 통과한다.** 실제로 그랬다 — 뒤에 불투명한 층을 깔아 첫째를
|
|
26
|
+
* 지켰는데, 그 층이 상태 색을 덮어 둘째가 깨졌다(음수 z-index 자식은 자기 요소의 배경 **위에**
|
|
27
|
+
* 그려진다).
|
|
28
|
+
*/
|
|
29
|
+
/** 상태마다 실제로 쓰는 색. 표(data-grist.ts)가 채우는 자리를 같이 채운다. */
|
|
30
|
+
const 색들 = `
|
|
31
|
+
--grid-record-background-color: #ffffff;
|
|
32
|
+
--grid-record-odd-background-color: #f4f5f7;
|
|
33
|
+
--grid-record-selected-background-color: #dbe7f3;
|
|
34
|
+
--grid-record-emphasized-background-color: #fdf3d7;
|
|
35
|
+
--grid-record-editing-background-color: #eef6ff;
|
|
36
|
+
--grid-record-disabled-background-color: #f0f1f3;
|
|
37
|
+
`;
|
|
38
|
+
async function 표를세운다(hover = 'rgb(247, 248, 250)') {
|
|
39
|
+
const el = (await fixture(html `
|
|
40
|
+
<ox-grid-body style="${색들} --grid-record-hover-background-color: ${hover};"></ox-grid-body>
|
|
41
|
+
`));
|
|
42
|
+
/*
|
|
43
|
+
* 칸은 column.record.renderer 로 내용을 그린다. 그것이 없으면 칸마다 예외가 나고, 예외가 나는
|
|
44
|
+
* 칸의 색을 재면 무엇을 잰 것인지 알 수 없다.
|
|
45
|
+
*/
|
|
46
|
+
const 열 = (name, width) => ({
|
|
47
|
+
name,
|
|
48
|
+
type: 'string',
|
|
49
|
+
width,
|
|
50
|
+
record: { renderer: (value) => html `<span>${value !== null && value !== void 0 ? value : ''}</span>`, align: 'left' }
|
|
51
|
+
});
|
|
52
|
+
el.config = { ...ZERO_CONFIG, columns: [] };
|
|
53
|
+
el.columns = [열('name', 120), 열('description', 200), 열('tail', 200)];
|
|
54
|
+
el.data = { ...ZERO_DATA, records: [{ name: 'P-CAM-I-0001' }, { name: 'P-CAM-P-0001' }] };
|
|
55
|
+
/* 첫 열만 고정한다 — 왼쪽 오프셋이 있는 열이 곧 고정 열이다. */
|
|
56
|
+
el.fixedLefts = [0];
|
|
57
|
+
el.from = 0;
|
|
58
|
+
el.to = 2;
|
|
59
|
+
await el.updateComplete;
|
|
60
|
+
return el;
|
|
61
|
+
}
|
|
62
|
+
const 칸들 = (el) => Array.from(el.renderRoot.querySelectorAll('ox-grid-field'));
|
|
63
|
+
const 고정 = (el) => 칸들(el).filter(c => c.hasAttribute('fixed'));
|
|
64
|
+
const 스크롤 = (el) => 칸들(el).filter(c => !c.hasAttribute('fixed'));
|
|
65
|
+
/**
|
|
66
|
+
* **칸에 칠해진 색.**
|
|
67
|
+
*
|
|
68
|
+
* `background-color` 하나만 본다 — 요소의 배경은 그것이 맨 아래이고, 그 위에 무엇을 깔면
|
|
69
|
+
* (`::before` · inset 그림자) 상태 색을 **덮는다.** 그래서 그 둘을 합쳐 재면 「덮여서 안 보이는
|
|
70
|
+
* 색」을 「칠해진 색」으로 읽는다. 한 번 그렇게 재고 고쳤다고 말했다.
|
|
71
|
+
*/
|
|
72
|
+
const 칠해진색 = (cell) => getComputedStyle(cell).backgroundColor;
|
|
73
|
+
const 알파 = (color) => {
|
|
74
|
+
const parts = (color.match(/[\d.]+/g) || []).map(Number);
|
|
75
|
+
return parts.length > 3 ? parts[3] : 1;
|
|
76
|
+
};
|
|
77
|
+
const 상태들 = ['hovered-row', 'selected-row', 'emphasized-row', 'editing', 'disabled'];
|
|
78
|
+
describe('고정 열의 바탕', () => {
|
|
79
|
+
describe('어떤 줄 상태에서도 불투명하다', () => {
|
|
80
|
+
it('아무 상태도 아닌 줄', async () => {
|
|
81
|
+
const el = await 표를세운다();
|
|
82
|
+
expect(고정(el).length, '고정 열이 안 그려지면 이 시험이 아무것도 재지 않는다').to.be.greaterThan(0);
|
|
83
|
+
expect(알파(칠해진색(고정(el)[0]))).to.equal(1);
|
|
84
|
+
});
|
|
85
|
+
상태들.forEach(상태 => {
|
|
86
|
+
it(`${상태} 인 줄`, async () => {
|
|
87
|
+
const el = await 표를세운다();
|
|
88
|
+
칸들(el).forEach(cell => cell.setAttribute(상태, ''));
|
|
89
|
+
await el.updateComplete;
|
|
90
|
+
expect(알파(칠해진색(고정(el)[0])), '이 상태가 바탕을 지우면 스크롤되는 열이 고정 열 아래에서 비쳐 보인다').to.equal(1);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
it('홀수 줄', async () => {
|
|
94
|
+
const el = await 표를세운다();
|
|
95
|
+
칸들(el).forEach(cell => cell.setAttribute('odd', ''));
|
|
96
|
+
await el.updateComplete;
|
|
97
|
+
expect(알파(칠해진색(고정(el)[0]))).to.equal(1);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
describe('줄 하나는 한 색이다', () => {
|
|
101
|
+
상태들.forEach(상태 => {
|
|
102
|
+
it(`${상태} — 고정 열과 스크롤되는 열이 같은 색`, async () => {
|
|
103
|
+
const el = await 표를세운다();
|
|
104
|
+
칸들(el).forEach(cell => cell.setAttribute(상태, ''));
|
|
105
|
+
await el.updateComplete;
|
|
106
|
+
expect(칠해진색(고정(el)[0]), '고정 열만 다르면 줄 하나가 두 색으로 갈린다').to.equal(칠해진색(스크롤(el)[0]));
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
it('마우스가 지나는 줄은 표가 정한 색이다', async () => {
|
|
110
|
+
const el = await 표를세운다('rgb(247, 248, 250)');
|
|
111
|
+
칸들(el).forEach(cell => cell.setAttribute('hovered-row', ''));
|
|
112
|
+
await el.updateComplete;
|
|
113
|
+
expect(칠해진색(고정(el)[0])).to.equal('rgb(247, 248, 250)');
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
['::before', '::after'].forEach(층 => {
|
|
117
|
+
it(`고정 칸을 ${층} 로 덮지 않는다`, async () => {
|
|
118
|
+
const el = await 표를세운다();
|
|
119
|
+
칸들(el).forEach(cell => cell.setAttribute('hovered-row', ''));
|
|
120
|
+
await el.updateComplete;
|
|
121
|
+
const cs = getComputedStyle(고정(el)[0], 층);
|
|
122
|
+
expect(알파(cs.backgroundColor), '이 층이 줄 상태의 색을 덮는다').to.equal(0);
|
|
123
|
+
expect(cs.backgroundImage, '이 층이 줄 상태의 색을 덮는다').to.equal('none');
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
/** 고침이 아니라 **왜 그 방식이 안 되는지**를 못박는다. 고치는 표가 이렇게 두고 있었다. */
|
|
127
|
+
it('색을 비우면 칸의 바탕이 지워진다 — 그래서 비우지 않는다', async () => {
|
|
128
|
+
const el = await 표를세운다('transparent');
|
|
129
|
+
칸들(el).forEach(cell => cell.setAttribute('hovered-row', ''));
|
|
130
|
+
await el.updateComplete;
|
|
131
|
+
expect(칠해진색(스크롤(el)[0]), 'transparent 는 「칠하지 않는다」가 아니라 「지운다」다 — 표 뒤가 무엇이든 그것이 줄 색이 된다').to.equal('rgba(0, 0, 0, 0)');
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
//# sourceMappingURL=fixed-column-opaque.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fixed-column-opaque.test.js","sourceRoot":"","sources":["../../test/fixed-column-opaque.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport '../src/data-grid/data-grid-body.js'\nimport { ZERO_CONFIG, ZERO_DATA } from '../src/configure/zero-config.js'\n\n/**\n * 고정 열의 바탕.\n *\n * ## 왜 시험이 필요한가\n *\n * 고정 칸은 `position: sticky` 로 스크롤되는 열 **위에** 떠 있다. 그래서 이 칸의 바탕이 투명해지면\n * 아래로 지나가는 열이 그대로 비쳐, 한 줄에 글자 두 벌이 겹쳐 보인다\n * (`P-CAM-I-0001` 위에 `CAM-INSP-01` 이 찍혔다).\n *\n * 바탕이 지워지는 것은 색을 잘못 고른 것이 아니라 **줄 상태 색을 `transparent` 로 둔 것**이었다.\n * 그 값은 「칠하지 않는다」가 아니라 「칸의 바탕을 지운다」다. 지워진 자리에는 표 뒤에 있는 것이\n * 비치고, 그것은 표가 정한 색이 아니다.\n *\n * ## 두 가지를 함께 잰다\n *\n * ```\n * 불투명한가 투명해지면 스크롤되는 열이 비친다\n * 같은 색인가 고정 열만 다르면 줄 하나가 두 색으로 갈린다\n * ```\n *\n * 둘을 따로 두면 **한쪽만 지키는 고침이 통과한다.** 실제로 그랬다 — 뒤에 불투명한 층을 깔아 첫째를\n * 지켰는데, 그 층이 상태 색을 덮어 둘째가 깨졌다(음수 z-index 자식은 자기 요소의 배경 **위에**\n * 그려진다).\n */\n\n/** 상태마다 실제로 쓰는 색. 표(data-grist.ts)가 채우는 자리를 같이 채운다. */\nconst 색들 = `\n --grid-record-background-color: #ffffff;\n --grid-record-odd-background-color: #f4f5f7;\n --grid-record-selected-background-color: #dbe7f3;\n --grid-record-emphasized-background-color: #fdf3d7;\n --grid-record-editing-background-color: #eef6ff;\n --grid-record-disabled-background-color: #f0f1f3;\n`\n\nasync function 표를세운다(hover = 'rgb(247, 248, 250)') {\n const el = (await fixture(html`\n <ox-grid-body style=\"${색들} --grid-record-hover-background-color: ${hover};\"></ox-grid-body>\n `)) as any\n\n /*\n * 칸은 column.record.renderer 로 내용을 그린다. 그것이 없으면 칸마다 예외가 나고, 예외가 나는\n * 칸의 색을 재면 무엇을 잰 것인지 알 수 없다.\n */\n const 열 = (name: string, width: number) => ({\n name,\n type: 'string',\n width,\n record: { renderer: (value: unknown) => html`<span>${value ?? ''}</span>`, align: 'left' }\n })\n\n el.config = { ...ZERO_CONFIG, columns: [] }\n el.columns = [열('name', 120), 열('description', 200), 열('tail', 200)]\n el.data = { ...ZERO_DATA, records: [{ name: 'P-CAM-I-0001' }, { name: 'P-CAM-P-0001' }] }\n /* 첫 열만 고정한다 — 왼쪽 오프셋이 있는 열이 곧 고정 열이다. */\n el.fixedLefts = [0]\n el.from = 0\n el.to = 2\n\n await el.updateComplete\n\n return el\n}\n\nconst 칸들 = (el: any): HTMLElement[] => Array.from(el.renderRoot.querySelectorAll('ox-grid-field'))\nconst 고정 = (el: any) => 칸들(el).filter(c => c.hasAttribute('fixed'))\nconst 스크롤 = (el: any) => 칸들(el).filter(c => !c.hasAttribute('fixed'))\n\n/**\n * **칸에 칠해진 색.**\n *\n * `background-color` 하나만 본다 — 요소의 배경은 그것이 맨 아래이고, 그 위에 무엇을 깔면\n * (`::before` · inset 그림자) 상태 색을 **덮는다.** 그래서 그 둘을 합쳐 재면 「덮여서 안 보이는\n * 색」을 「칠해진 색」으로 읽는다. 한 번 그렇게 재고 고쳤다고 말했다.\n */\nconst 칠해진색 = (cell: Element) => getComputedStyle(cell).backgroundColor\nconst 알파 = (color: string) => {\n const parts = (color.match(/[\\d.]+/g) || []).map(Number)\n return parts.length > 3 ? parts[3] : 1\n}\n\nconst 상태들 = ['hovered-row', 'selected-row', 'emphasized-row', 'editing', 'disabled']\n\ndescribe('고정 열의 바탕', () => {\n describe('어떤 줄 상태에서도 불투명하다', () => {\n it('아무 상태도 아닌 줄', async () => {\n const el = await 표를세운다()\n\n expect(고정(el).length, '고정 열이 안 그려지면 이 시험이 아무것도 재지 않는다').to.be.greaterThan(0)\n expect(알파(칠해진색(고정(el)[0]))).to.equal(1)\n })\n\n 상태들.forEach(상태 => {\n it(`${상태} 인 줄`, async () => {\n const el = await 표를세운다()\n\n 칸들(el).forEach(cell => cell.setAttribute(상태, ''))\n await el.updateComplete\n\n expect(\n 알파(칠해진색(고정(el)[0])),\n '이 상태가 바탕을 지우면 스크롤되는 열이 고정 열 아래에서 비쳐 보인다'\n ).to.equal(1)\n })\n })\n\n it('홀수 줄', async () => {\n const el = await 표를세운다()\n\n 칸들(el).forEach(cell => cell.setAttribute('odd', ''))\n await el.updateComplete\n\n expect(알파(칠해진색(고정(el)[0]))).to.equal(1)\n })\n })\n\n describe('줄 하나는 한 색이다', () => {\n 상태들.forEach(상태 => {\n it(`${상태} — 고정 열과 스크롤되는 열이 같은 색`, async () => {\n const el = await 표를세운다()\n\n 칸들(el).forEach(cell => cell.setAttribute(상태, ''))\n await el.updateComplete\n\n expect(칠해진색(고정(el)[0]), '고정 열만 다르면 줄 하나가 두 색으로 갈린다').to.equal(\n 칠해진색(스크롤(el)[0])\n )\n })\n })\n\n it('마우스가 지나는 줄은 표가 정한 색이다', async () => {\n const el = await 표를세운다('rgb(247, 248, 250)')\n\n 칸들(el).forEach(cell => cell.setAttribute('hovered-row', ''))\n await el.updateComplete\n\n expect(칠해진색(고정(el)[0])).to.equal('rgb(247, 248, 250)')\n })\n })\n\n /**\n * **칸 위에 덮는 층을 두지 않는다.**\n *\n * 위의 시험들은 `background-color` 를 읽으므로 이것을 못 잡는다 — 그 위에 층을 깔아도 속성은\n * 그대로다. 실제로 그렇게 한 번 놓쳤다: `[fixed]::before` 로 불투명한 바탕을 깔고 「같은\n * 색이다」라고 쟀는데, 화면에서는 그 층이 상태 색을 덮어 고정 열에서만 띠가 사라졌다.\n *\n * 음수 z-index 자식은 자기 요소의 배경 **위에** 그려진다. 요소의 배경보다 아래에 층을 깔\n * 방법은 없다. 그러니 규칙은 하나다 — **덮지 않는다.**\n */\n ;['::before', '::after'].forEach(층 => {\n it(`고정 칸을 ${층} 로 덮지 않는다`, async () => {\n const el = await 표를세운다()\n\n 칸들(el).forEach(cell => cell.setAttribute('hovered-row', ''))\n await el.updateComplete\n\n const cs = getComputedStyle(고정(el)[0], 층)\n\n expect(알파(cs.backgroundColor), '이 층이 줄 상태의 색을 덮는다').to.equal(0)\n expect(cs.backgroundImage, '이 층이 줄 상태의 색을 덮는다').to.equal('none')\n })\n })\n\n /** 고침이 아니라 **왜 그 방식이 안 되는지**를 못박는다. 고치는 표가 이렇게 두고 있었다. */\n it('색을 비우면 칸의 바탕이 지워진다 — 그래서 비우지 않는다', async () => {\n const el = await 표를세운다('transparent')\n\n 칸들(el).forEach(cell => cell.setAttribute('hovered-row', ''))\n await el.updateComplete\n\n expect(\n 칠해진색(스크롤(el)[0]),\n 'transparent 는 「칠하지 않는다」가 아니라 「지운다」다 — 표 뒤가 무엇이든 그것이 줄 색이 된다'\n ).to.equal('rgba(0, 0, 0, 0)')\n })\n})\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { expect, fixture } from '@open-wc/testing';
|
|
2
|
+
import { html } from 'lit';
|
|
3
|
+
import { DataGrist } from '../src/data-grist.js';
|
|
4
|
+
import { DataGrid } from '../src/data-grid/data-grid.js';
|
|
5
|
+
/**
|
|
6
|
+
* 마우스가 지나는 줄이 **보이는가.**
|
|
7
|
+
*
|
|
8
|
+
* ## 왜 이 시험이 따로 있나
|
|
9
|
+
*
|
|
10
|
+
* `fixed-column-opaque.test.ts` 는 색이 **같은지**를 잰다. 그것만으로는 「띠가 보인다」를 못 지킨다 —
|
|
11
|
+
* 줄과 띠가 나란히 안 보여도 그 시험은 전부 초록이다. 실제로 그랬다.
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* [재봤음] 2026-09-04 · operato-plant 인원 화면(어두운 모드)
|
|
15
|
+
* 줄 rgb(30 34 40) · 띠 rgb(26 30 35) → 대비 1.048 보이지 않는다
|
|
16
|
+
* 그때 고정 열 시험 열여섯 건은 전부 초록이었다
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* 원인은 색이 아니라 **어디서 색을 가져오나**였다. 면 사다리에서 한 단 옮겨 오면, 그 사다리의
|
|
20
|
+
* 밝기 순서가 앱마다 맞아야 한다. operato-plant 의 어두운 팔레트는 그 순서가 밝은 모드와 같아서
|
|
21
|
+
* 띠가 줄보다 어두워지는 쪽으로 4단 움직였을 뿐이다.
|
|
22
|
+
*
|
|
23
|
+
* 그래서 지금은 **줄 자신의 색에서 만든다.** 이 시험은 그 규칙이 두 테마에서 다 서는지를 잰다.
|
|
24
|
+
*/
|
|
25
|
+
/** 스타일 뭉치에서 그 토큰의 선언값을 꺼낸다 — 시험이 값을 베끼지 않게. */
|
|
26
|
+
function 선언값(styles, token) {
|
|
27
|
+
const cssText = (Array.isArray(styles) ? styles : [styles])
|
|
28
|
+
.map(style => { var _a; return String((_a = style === null || style === void 0 ? void 0 : style.cssText) !== null && _a !== void 0 ? _a : style); })
|
|
29
|
+
.join('\n');
|
|
30
|
+
/* 여러 줄에 걸친 color-mix(...) 도 담기게 다음 세미콜론까지 가져온다. */
|
|
31
|
+
const found = cssText.match(new RegExp(`${token}\\s*:\\s*([^;]+);`));
|
|
32
|
+
return found === null || found === void 0 ? void 0 : found[1].replace(/\s+/g, ' ').trim();
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* 색 문자열을 0~255 세 값으로 만든다 — **캔버스에 칠해서 읽는다.**
|
|
36
|
+
*
|
|
37
|
+
* 문자열을 직접 파싱하면 안 된다. `color-mix` 는 계산되면 `color(srgb 0.954 0.957 0.958)` 로
|
|
38
|
+
* 나오고, 그 숫자를 0~255 로 읽으면 거의 검정이 된다. 실제로 그렇게 한 번 재서 이 시험이
|
|
39
|
+
* 「대비 20.9」라는 헛것을 냈다. 캔버스는 어떤 표기든 브라우저가 칠한 픽셀로 돌려준다.
|
|
40
|
+
*/
|
|
41
|
+
const 칠 = document.createElement('canvas').getContext('2d', { willReadFrequently: true });
|
|
42
|
+
function 픽셀(color) {
|
|
43
|
+
칠.clearRect(0, 0, 1, 1);
|
|
44
|
+
칠.fillStyle = '#000';
|
|
45
|
+
칠.fillStyle = color;
|
|
46
|
+
칠.fillRect(0, 0, 1, 1);
|
|
47
|
+
const [r, g, b] = 칠.getImageData(0, 0, 1, 1).data;
|
|
48
|
+
return [r, g, b];
|
|
49
|
+
}
|
|
50
|
+
const lum = (color) => {
|
|
51
|
+
const [r, g, b] = 픽셀(color);
|
|
52
|
+
const f = (v) => {
|
|
53
|
+
const x = v / 255;
|
|
54
|
+
return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
|
|
55
|
+
};
|
|
56
|
+
return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b);
|
|
57
|
+
};
|
|
58
|
+
const 대비 = (a, b) => {
|
|
59
|
+
const [x, y] = [lum(a), lum(b)].sort((p, q) => q - p);
|
|
60
|
+
return (x + 0.05) / (y + 0.05);
|
|
61
|
+
};
|
|
62
|
+
/** 그 팔레트에서 선언값이 실제로 무슨 색이 되는지 — 브라우저에게 계산시킨다. */
|
|
63
|
+
async function 칠해보다(값, 팔레트) {
|
|
64
|
+
const probe = (await fixture(html `
|
|
65
|
+
<div
|
|
66
|
+
style="${팔레트.사다리} --grid-record-background-color:${팔레트.줄}; --grid-record-color:${팔레트.잉크}; background-color:${값};"
|
|
67
|
+
></div>
|
|
68
|
+
`));
|
|
69
|
+
return getComputedStyle(probe).backgroundColor;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* operato-plant 의 두 팔레트에서 실제로 쓰는 값이다.
|
|
73
|
+
*
|
|
74
|
+
* 면 사다리도 함께 준다 — 선언이 사다리에서 색을 가져오는 방식으로 되돌아가도 **그 앱에서 실제로
|
|
75
|
+
* 나오는 색**으로 재기 위해서다. 주지 않으면 리터럴 폴백으로 떨어져 두 테마가 같은 색이 되고,
|
|
76
|
+
* 어두운 모드에서 띠가 사라지던 그 일을 이 시험이 못 잡는다.
|
|
77
|
+
*/
|
|
78
|
+
const 팔레트들 = {
|
|
79
|
+
밝은: {
|
|
80
|
+
줄: 'rgb(255, 255, 255)',
|
|
81
|
+
잉크: 'rgb(23, 36, 44)',
|
|
82
|
+
사다리: '--md-sys-color-surface-container-lowest: rgb(255,255,255); --md-sys-color-surface-container-low: rgb(247,248,250);'
|
|
83
|
+
},
|
|
84
|
+
어두운: {
|
|
85
|
+
줄: 'rgb(30, 34, 40)',
|
|
86
|
+
잉크: 'rgb(228, 232, 236)',
|
|
87
|
+
사다리: '--md-sys-color-surface-container-lowest: rgb(30,34,40); --md-sys-color-surface-container-low: rgb(26,30,35);'
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* 얼마나 벌어져야 보이나.
|
|
92
|
+
*
|
|
93
|
+
* 지나는 줄 표시는 **훨씬 옅어야 한다** — 고른 줄과 같은 무게로 그리면 무엇이 골라졌는지 흐려진다.
|
|
94
|
+
* 그래서 큰 값을 요구하지 않는다. 다만 1.05 는 눈에 안 들어온다(위 [재봤음]). 눈으로 확인한 값이
|
|
95
|
+
* 1.11 · 1.14 이므로 그 아래에 문턱을 둔다.
|
|
96
|
+
*/
|
|
97
|
+
const 최소분리 = 1.08;
|
|
98
|
+
describe('마우스가 지나는 줄이 보인다', () => {
|
|
99
|
+
const 값 = 선언값(DataGrist.styles, '--grid-record-hover-background-color');
|
|
100
|
+
it('그 토큰이 선언되어 있다 — 이름이 바뀌면 아래 시험들이 헛돈다', () => {
|
|
101
|
+
expect(값, '--grid-record-hover-background-color 를 못 찾았다').to.be.a('string');
|
|
102
|
+
});
|
|
103
|
+
Object.entries(팔레트들).forEach(([이름, 팔레트]) => {
|
|
104
|
+
it(`${이름} 팔레트에서 줄과 띠가 갈린다`, async () => {
|
|
105
|
+
const 띠 = await 칠해보다(값, 팔레트);
|
|
106
|
+
const 벌어짐 = 대비(띠, 팔레트.줄);
|
|
107
|
+
expect(벌어짐, `줄 ${팔레트.줄} · 띠 ${픽셀(띠).join(' ')} → 대비 ${벌어짐.toFixed(3)}. 이만큼이면 마우스가 어느 줄에 있는지 안 보인다`).to.be.greaterThan(최소분리);
|
|
108
|
+
});
|
|
109
|
+
it(`${이름} 팔레트에서 띠가 줄을 덮지 않는다 — 옅어야 한다`, async () => {
|
|
110
|
+
const 띠 = await 칠해보다(값, 팔레트);
|
|
111
|
+
expect(대비(띠, 팔레트.줄), '고른 줄과 같은 무게가 되면 무엇이 골라졌는지 흐려진다').to.be.lessThan(1.6);
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
[
|
|
115
|
+
['DataGrist', DataGrist.styles],
|
|
116
|
+
['DataGrid', DataGrid.styles]
|
|
117
|
+
].forEach(([이름, styles]) => {
|
|
118
|
+
it(`${이름} 이 줄 상태의 색을 비우지 않는다`, () => {
|
|
119
|
+
const cssText = styles
|
|
120
|
+
.map(style => { var _a; return String((_a = style === null || style === void 0 ? void 0 : style.cssText) !== null && _a !== void 0 ? _a : style); })
|
|
121
|
+
.join('\n');
|
|
122
|
+
const 비운것 = cssText.match(/--grid-record-[a-z-]*background-color\s*:\s*transparent/g);
|
|
123
|
+
expect(비운것, `${비운것 === null || 비운것 === void 0 ? void 0 : 비운것.join(' · ')} — 비우는 대신 그 줄의 색을 주어야 한다`).to.be.null;
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
//# sourceMappingURL=row-hover-visible.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"row-hover-visible.test.js","sourceRoot":"","sources":["../../test/row-hover-visible.test.ts"],"names":[],"mappings":"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","sourcesContent":["import { expect, fixture } from '@open-wc/testing'\nimport { html } from 'lit'\n\nimport { DataGrist } from '../src/data-grist.js'\nimport { DataGrid } from '../src/data-grid/data-grid.js'\n\n/**\n * 마우스가 지나는 줄이 **보이는가.**\n *\n * ## 왜 이 시험이 따로 있나\n *\n * `fixed-column-opaque.test.ts` 는 색이 **같은지**를 잰다. 그것만으로는 「띠가 보인다」를 못 지킨다 —\n * 줄과 띠가 나란히 안 보여도 그 시험은 전부 초록이다. 실제로 그랬다.\n *\n * ```\n * [재봤음] 2026-09-04 · operato-plant 인원 화면(어두운 모드)\n * 줄 rgb(30 34 40) · 띠 rgb(26 30 35) → 대비 1.048 보이지 않는다\n * 그때 고정 열 시험 열여섯 건은 전부 초록이었다\n * ```\n *\n * 원인은 색이 아니라 **어디서 색을 가져오나**였다. 면 사다리에서 한 단 옮겨 오면, 그 사다리의\n * 밝기 순서가 앱마다 맞아야 한다. operato-plant 의 어두운 팔레트는 그 순서가 밝은 모드와 같아서\n * 띠가 줄보다 어두워지는 쪽으로 4단 움직였을 뿐이다.\n *\n * 그래서 지금은 **줄 자신의 색에서 만든다.** 이 시험은 그 규칙이 두 테마에서 다 서는지를 잰다.\n */\n\n/** 스타일 뭉치에서 그 토큰의 선언값을 꺼낸다 — 시험이 값을 베끼지 않게. */\nfunction 선언값(styles: unknown, token: string) {\n const cssText = (Array.isArray(styles) ? styles : [styles])\n .map(style => String((style as { cssText?: string })?.cssText ?? style))\n .join('\\n')\n\n /* 여러 줄에 걸친 color-mix(...) 도 담기게 다음 세미콜론까지 가져온다. */\n const found = cssText.match(new RegExp(`${token}\\\\s*:\\\\s*([^;]+);`))\n\n return found?.[1].replace(/\\s+/g, ' ').trim()\n}\n\n/**\n * 색 문자열을 0~255 세 값으로 만든다 — **캔버스에 칠해서 읽는다.**\n *\n * 문자열을 직접 파싱하면 안 된다. `color-mix` 는 계산되면 `color(srgb 0.954 0.957 0.958)` 로\n * 나오고, 그 숫자를 0~255 로 읽으면 거의 검정이 된다. 실제로 그렇게 한 번 재서 이 시험이\n * 「대비 20.9」라는 헛것을 냈다. 캔버스는 어떤 표기든 브라우저가 칠한 픽셀로 돌려준다.\n */\nconst 칠 = document.createElement('canvas').getContext('2d', { willReadFrequently: true })!\n\nfunction 픽셀(color: string) {\n 칠.clearRect(0, 0, 1, 1)\n 칠.fillStyle = '#000'\n 칠.fillStyle = color\n 칠.fillRect(0, 0, 1, 1)\n\n const [r, g, b] = 칠.getImageData(0, 0, 1, 1).data\n\n return [r, g, b]\n}\n\nconst lum = (color: string) => {\n const [r, g, b] = 픽셀(color)\n const f = (v: number) => {\n const x = v / 255\n return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4)\n }\n\n return 0.2126 * f(r) + 0.7152 * f(g) + 0.0722 * f(b)\n}\n\nconst 대비 = (a: string, b: string) => {\n const [x, y] = [lum(a), lum(b)].sort((p, q) => q - p)\n return (x + 0.05) / (y + 0.05)\n}\n\n/** 그 팔레트에서 선언값이 실제로 무슨 색이 되는지 — 브라우저에게 계산시킨다. */\nasync function 칠해보다(값: string, 팔레트: { 줄: string; 잉크: string; 사다리: string }) {\n const probe = (await fixture(html`\n <div\n style=\"${팔레트.사다리} --grid-record-background-color:${팔레트.줄}; --grid-record-color:${팔레트.잉크}; background-color:${값};\"\n ></div>\n `)) as HTMLElement\n\n return getComputedStyle(probe).backgroundColor\n}\n\n/**\n * operato-plant 의 두 팔레트에서 실제로 쓰는 값이다.\n *\n * 면 사다리도 함께 준다 — 선언이 사다리에서 색을 가져오는 방식으로 되돌아가도 **그 앱에서 실제로\n * 나오는 색**으로 재기 위해서다. 주지 않으면 리터럴 폴백으로 떨어져 두 테마가 같은 색이 되고,\n * 어두운 모드에서 띠가 사라지던 그 일을 이 시험이 못 잡는다.\n */\nconst 팔레트들 = {\n 밝은: {\n 줄: 'rgb(255, 255, 255)',\n 잉크: 'rgb(23, 36, 44)',\n 사다리: '--md-sys-color-surface-container-lowest: rgb(255,255,255); --md-sys-color-surface-container-low: rgb(247,248,250);'\n },\n 어두운: {\n 줄: 'rgb(30, 34, 40)',\n 잉크: 'rgb(228, 232, 236)',\n 사다리: '--md-sys-color-surface-container-lowest: rgb(30,34,40); --md-sys-color-surface-container-low: rgb(26,30,35);'\n }\n}\n\n/**\n * 얼마나 벌어져야 보이나.\n *\n * 지나는 줄 표시는 **훨씬 옅어야 한다** — 고른 줄과 같은 무게로 그리면 무엇이 골라졌는지 흐려진다.\n * 그래서 큰 값을 요구하지 않는다. 다만 1.05 는 눈에 안 들어온다(위 [재봤음]). 눈으로 확인한 값이\n * 1.11 · 1.14 이므로 그 아래에 문턱을 둔다.\n */\nconst 최소분리 = 1.08\n\ndescribe('마우스가 지나는 줄이 보인다', () => {\n const 값 = 선언값(DataGrist.styles, '--grid-record-hover-background-color')\n\n it('그 토큰이 선언되어 있다 — 이름이 바뀌면 아래 시험들이 헛돈다', () => {\n expect(값, '--grid-record-hover-background-color 를 못 찾았다').to.be.a('string')\n })\n\n Object.entries(팔레트들).forEach(([이름, 팔레트]) => {\n it(`${이름} 팔레트에서 줄과 띠가 갈린다`, async () => {\n const 띠 = await 칠해보다(값!, 팔레트)\n const 벌어짐 = 대비(띠, 팔레트.줄)\n\n expect(\n 벌어짐,\n `줄 ${팔레트.줄} · 띠 ${픽셀(띠).join(' ')} → 대비 ${벌어짐.toFixed(3)}. 이만큼이면 마우스가 어느 줄에 있는지 안 보인다`\n ).to.be.greaterThan(최소분리)\n })\n\n it(`${이름} 팔레트에서 띠가 줄을 덮지 않는다 — 옅어야 한다`, async () => {\n const 띠 = await 칠해보다(값!, 팔레트)\n\n expect(대비(띠, 팔레트.줄), '고른 줄과 같은 무게가 되면 무엇이 골라졌는지 흐려진다').to.be.lessThan(1.6)\n })\n })\n\n /**\n * **줄 상태의 색을 `transparent` 로 두지 않는다.**\n *\n * 그 값은 「칠하지 않는다」가 아니라 「칸의 바탕을 지운다」다. 지워진 자리에는 표 뒤에 있는 것이\n * 비치고, 그것은 표가 정한 색이 아니다 — 어두운 페이지에 표를 놓으면 지나는 줄이 검게 된다.\n * 그리고 고정 열은 불투명해야 하므로 구멍이 안 뚫려, 줄 하나가 두 색으로 갈린다.\n *\n * 실제로 고치는 표가 그렇게 두고 있었다. 앞의 시험들은 **자기가 세운 표에 자기가 값을 넣으므로**\n * 이것을 못 잡는다 — 그 줄이 되돌아와도 초록이다. 그래서 선언 자체를 본다.\n */\n ;[\n ['DataGrist', DataGrist.styles],\n ['DataGrid', DataGrid.styles]\n ].forEach(([이름, styles]) => {\n it(`${이름} 이 줄 상태의 색을 비우지 않는다`, () => {\n const cssText = (styles as unknown[])\n .map(style => String((style as { cssText?: string })?.cssText ?? style))\n .join('\\n')\n\n const 비운것 = cssText.match(/--grid-record-[a-z-]*background-color\\s*:\\s*transparent/g)\n\n expect(비운것, `${비운것?.join(' · ')} — 비우는 대신 그 줄의 색을 주어야 한다`).to.be.null\n })\n })\n})\n"]}
|