@operato/data-grist 10.10.3 → 10.10.5
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 +19 -0
- package/dist/src/data-card/data-card.js +33 -8
- package/dist/src/data-card/data-card.js.map +1 -1
- package/dist/src/data-card/record-card.js +20 -46
- package/dist/src/data-card/record-card.js.map +1 -1
- package/dist/src/data-grist.d.ts +0 -3
- package/dist/src/data-grist.js +82 -57
- package/dist/src/data-grist.js.map +1 -1
- package/dist/src/data-list/data-list.js +21 -8
- package/dist/src/data-list/data-list.js.map +1 -1
- package/dist/src/types.d.ts +9 -6
- package/dist/src/types.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +5 -5
- package/yarn-error.log +16971 -0
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -866
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov-report/webpack/bootstrap.html +0 -118
- package/coverage/lcov-report/webpack/index.html +0 -116
- package/coverage/lcov-report/webpack/runtime/define property getters.html +0 -118
- package/coverage/lcov-report/webpack/runtime/global.html +0 -118
- package/coverage/lcov-report/webpack/runtime/hasOwnProperty shorthand.html +0 -118
- package/coverage/lcov-report/webpack/runtime/index.html +0 -161
- package/coverage/lcov-report/webpack/runtime/make namespace object.html +0 -118
- package/coverage/lcov.info +0 -53451
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,25 @@
|
|
|
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.10.5](https://github.com/hatiolab/operato/compare/v10.10.4...v10.10.5) (2026-09-10)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### :bug: Bug Fix
|
|
10
|
+
|
|
11
|
+
* 그리드 홀수 색상 정의, 팝업 X버튼 색상 정의 ([71b8d27](https://github.com/hatiolab/operato/commit/71b8d27a4f1f97cd5bf942ee0275d7409393d8a1))
|
|
12
|
+
* **data-grist:** card and list fill their wrapper, so an empty list can speak ([6b07c8f](https://github.com/hatiolab/operato/commit/6b07c8fd483ff0094bb11869ff103f440c5d790b))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### [10.10.4](https://github.com/hatiolab/operato/compare/v10.10.3...v10.10.4) (2026-09-10)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
### :bug: Bug Fix
|
|
20
|
+
|
|
21
|
+
* **data-grist:** stop reserving a band the list cannot use, and fix the scroll-to-top button ([9beae1d](https://github.com/hatiolab/operato/commit/9beae1db4fa17ff7d6a2b015b534c44b2a6735ad))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
6
25
|
### [10.10.3](https://github.com/hatiolab/operato/compare/v10.10.2...v10.10.3) (2026-09-09)
|
|
7
26
|
|
|
8
27
|
|
|
@@ -107,16 +107,41 @@ DataCard.styles = [
|
|
|
107
107
|
background-color: var(--grid-record-selected-background-color);
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
/*
|
|
111
|
+
── 맨 위로 가는 단추 ──────────────────────────────────────────────────
|
|
112
|
+
자리를 먹지 않는다(absolute). 기준 상자는 ox-grist 의 host 인데(그쪽이 position: relative),
|
|
113
|
+
그래서 **목록과 함께 스크롤되지 않고** 상자에 붙어 있다.
|
|
114
|
+
|
|
115
|
+
고친 것 둘.
|
|
116
|
+
|
|
117
|
+
1. 위가 아니라 **아래**다. 오른쪽 위는 머리말·검색·필터가 있는 자리여서 단추가 그것들과
|
|
118
|
+
겹쳤다. 맨 위로 보내는 단추는 사람이 아래에 있을 때만 나오므로 손이 있는 쪽에 둔다.
|
|
119
|
+
2. rgba(255,255,255,0.7) 이 박혀 있었다 — 어두운 테마에서 흰 알약이 떠 있고, 아이콘은
|
|
120
|
+
--icon-size-large 라 알약보다 커 보였다. 테마 토큰으로 그리고 크기를 정한다.
|
|
121
|
+
*/
|
|
110
122
|
#upward {
|
|
111
|
-
--md-icon-size:
|
|
123
|
+
--md-icon-size: 20px;
|
|
112
124
|
position: absolute;
|
|
113
|
-
|
|
114
|
-
right: var(--data-card-fab-position-horizontal);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
125
|
+
bottom: var(--data-card-fab-position-vertical, var(--spacing-large));
|
|
126
|
+
right: var(--data-card-fab-position-horizontal, var(--spacing-large));
|
|
127
|
+
display: grid;
|
|
128
|
+
place-items: center;
|
|
129
|
+
width: 36px;
|
|
130
|
+
height: 36px;
|
|
131
|
+
box-sizing: border-box;
|
|
132
|
+
color: var(--data-card-fab-color, var(--md-sys-color-on-surface-variant));
|
|
133
|
+
background-color: var(--data-card-fab-background-color, var(--md-sys-color-surface-container-high));
|
|
134
|
+
/* 떠 있는 단추의 모서리는 알약이다 — 담는 면(6px)이 아니라 그 자신의 격을 따른다 */
|
|
135
|
+
border-radius: var(--md-sys-shape-corner-full, 50%);
|
|
136
|
+
border: 1px solid var(--md-sys-color-outline-variant);
|
|
137
|
+
box-shadow: var(--data-card-fab-shadow, 0 1px 3px rgba(0, 0, 0, 0.18));
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
z-index: 9;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
#upward:hover {
|
|
143
|
+
color: var(--md-sys-color-on-secondary-container);
|
|
144
|
+
background-color: var(--md-sys-color-secondary-container);
|
|
120
145
|
}
|
|
121
146
|
|
|
122
147
|
slot {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-card.js","sourceRoot":"","sources":["../../../src/data-card/data-card.ts"],"names":[],"mappings":";AACA,OAAO,4BAA4B,CAAA;AACnC,OAAO,kBAAkB,CAAA;AACzB,OAAO,kBAAkB,CAAA;AAEzB,OAAO,EAAkB,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,CAAA;AACxD,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAA;AAElE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AAIjD,IAAM,QAAQ,GAAd,MAAM,QAAS,SAAQ,eAAe;IAAtC;;
|
|
1
|
+
{"version":3,"file":"data-card.js","sourceRoot":"","sources":["../../../src/data-card/data-card.ts"],"names":[],"mappings":"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","sourcesContent":["import i18next from 'i18next'\nimport '@material/web/icon/icon.js'\nimport '../empty-note.js'\nimport './record-card.js'\n\nimport { PropertyValues, css, html, nothing } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { DataManipulator } from '../data-manipulator.js'\nimport { GristRecord } from '../types.js'\n\n@customElement('ox-card')\nexport class DataCard extends DataManipulator {\n static styles = [\n css`\n :host {\n overflow-y: auto;\n padding: var(--spacing-medium);\n\n display: grid;\n /*\n 카드 한 장의 최소 폭. 화면마다 실리는 것이 다르므로 값을 밖에서 정할 수 있어야 한다 —\n 그림이 주인공인 목록(자산 카탈로그)은 좁게 여러 장을, 글이 많은 목록은 넓게 몇 장을 놓는다.\n 기본값은 지금까지의 값 그대로다.\n */\n grid-template-columns: repeat(auto-fill, minmax(var(--data-card-min-width, 300px), 1fr));\n grid-template-rows: min-content;\n grid-gap: var(--spacing-large);\n }\n\n [selected-row] {\n background-color: var(--grid-record-selected-background-color);\n }\n\n /*\n ── 맨 위로 가는 단추 ──────────────────────────────────────────────────\n 자리를 먹지 않는다(absolute). 기준 상자는 ox-grist 의 host 인데(그쪽이 position: relative),\n 그래서 **목록과 함께 스크롤되지 않고** 상자에 붙어 있다.\n\n 고친 것 둘.\n\n 1. 위가 아니라 **아래**다. 오른쪽 위는 머리말·검색·필터가 있는 자리여서 단추가 그것들과\n 겹쳤다. 맨 위로 보내는 단추는 사람이 아래에 있을 때만 나오므로 손이 있는 쪽에 둔다.\n 2. rgba(255,255,255,0.7) 이 박혀 있었다 — 어두운 테마에서 흰 알약이 떠 있고, 아이콘은\n --icon-size-large 라 알약보다 커 보였다. 테마 토큰으로 그리고 크기를 정한다.\n */\n #upward {\n --md-icon-size: 20px;\n position: absolute;\n bottom: var(--data-card-fab-position-vertical, var(--spacing-large));\n right: var(--data-card-fab-position-horizontal, var(--spacing-large));\n display: grid;\n place-items: center;\n width: 36px;\n height: 36px;\n box-sizing: border-box;\n color: var(--data-card-fab-color, var(--md-sys-color-on-surface-variant));\n background-color: var(--data-card-fab-background-color, var(--md-sys-color-surface-container-high));\n /* 떠 있는 단추의 모서리는 알약이다 — 담는 면(6px)이 아니라 그 자신의 격을 따른다 */\n border-radius: var(--md-sys-shape-corner-full, 50%);\n border: 1px solid var(--md-sys-color-outline-variant);\n box-shadow: var(--data-card-fab-shadow, 0 1px 3px rgba(0, 0, 0, 0.18));\n cursor: pointer;\n z-index: 9;\n }\n\n #upward:hover {\n color: var(--md-sys-color-on-secondary-container);\n background-color: var(--md-sys-color-secondary-container);\n }\n\n slot {\n width: 100%;\n }\n\n ox-empty-note {\n display: block;\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n }\n\n [card][emphasized-row],\n [card][emphasized-row][focused] {\n background-color: var(--grid-record-emphasized-background-color);\n color: var(--grid-record-emphasized-color);\n }\n\n @media screen and (max-width: 460px) {\n #setting {\n grid-template-columns: 1fr;\n grid-template-rows: 1fr 1fr;\n }\n }\n `\n ]\n\n @property({ type: Boolean }) empty?: boolean\n\n /** 비었을 때 무슨 말을 하나 — 판단은 data-grist 가 하고 여기서는 그리기만 한다. */\n @property({ type: Object }) emptyNote?: { icon?: string; title: string; description?: string }\n\n @state() private _records: GristRecord[] = []\n @state() private isTop: boolean = false\n\n private _total: number = 0\n private _limit: number = 20\n private _page: number = 1\n\n firstUpdated(changes: PropertyValues<this>) {\n this.isTop = true\n\n /* infinite scrolling */\n this.addEventListener('scroll', e => {\n const totalScrollHeight = this.scrollHeight\n const screenHeight = this.offsetHeight\n const currentScrollTop = this.scrollTop\n\n if (totalScrollHeight <= screenHeight + currentScrollTop + 1) {\n /* 마지막 페이지까지 계속 페이지를 증가시킨다. */\n var lastPage = Math.ceil(this._total / this._limit)\n\n if (this._page < lastPage) {\n this.dispatchEvent(new CustomEvent('attach-page', { bubbles: true, composed: true }))\n }\n }\n\n this.isTop = this.scrollTop == 0\n })\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('config')) {\n this._records = []\n this._page = 1\n }\n\n if (changes.has('data')) {\n this._records = this.data.records\n this._total = this.data.total || 0\n this._limit = this.data.limit || 20\n this._page = this.data.page || 0\n }\n }\n\n render() {\n var { classifier } = this.config.rows\n var records = this._records || []\n\n if (this.config && this.config.rows.appendable) {\n records = [...records, { __dirty__: '+' }]\n }\n\n return html`\n ${records.map((record, rowIndex) => {\n var { emphasized } = classifier.call(null, record, rowIndex) || {}\n\n return html`\n <ox-record-card\n .config=${this.config}\n .data=${this.data}\n .record=${record}\n .rowIndex=${rowIndex}\n .emphasized=${emphasized}\n ?selected-row=${record['__selected__']}\n ?dirty=${record['__dirty__']}\n card\n ></ox-record-card>\n `\n })}\n ${this.empty\n ? html`<ox-empty-note\n icon=${this.emptyNote?.icon ?? nothing}\n title=${this.emptyNote?.title ?? ''}\n description=${this.emptyNote?.description ?? nothing}\n ></ox-empty-note>`\n : html``}\n ${this.isTop\n ? html``\n : html` <md-icon id=\"upward\" @click=${(e: Event) => this.gotoTop(e)}>arrow_upward</md-icon> `}\n `\n }\n\n gotoTop(e: Event) {\n this.scrollTop = 0\n\n e.stopPropagation()\n }\n\n get pullToRefreshTarget() {\n return this\n }\n}\n"]}
|
|
@@ -59,13 +59,9 @@ let RecordCard = class RecordCard extends LitElement {
|
|
|
59
59
|
this.addEventListener('show-record-view', () => this.popupRecordView());
|
|
60
60
|
}
|
|
61
61
|
updated(changes) {
|
|
62
|
-
var _a, _b;
|
|
63
62
|
if (changes.has('record') && this._recordView) {
|
|
64
63
|
this._recordView.record = this.record;
|
|
65
64
|
}
|
|
66
|
-
if (changes.has('config')) {
|
|
67
|
-
this.toggleAttribute('gutters-hover', ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.list) === null || _b === void 0 ? void 0 : _b.gutters) == 'hover');
|
|
68
|
-
}
|
|
69
65
|
const emphasized = this.emphasized;
|
|
70
66
|
if (!!emphasized) {
|
|
71
67
|
this.setAttribute('emphasized-row', '');
|
|
@@ -80,6 +76,7 @@ let RecordCard = class RecordCard extends LitElement {
|
|
|
80
76
|
}
|
|
81
77
|
}
|
|
82
78
|
render() {
|
|
79
|
+
var _a;
|
|
83
80
|
const record = this.record;
|
|
84
81
|
const rowIndex = this.rowIndex;
|
|
85
82
|
const { columns, list } = this.config;
|
|
@@ -95,9 +92,15 @@ let RecordCard = class RecordCard extends LitElement {
|
|
|
95
92
|
* 제목은 잘렸다. 없는 것의 자리를 비워 두는 것이다.
|
|
96
93
|
*/
|
|
97
94
|
const thumbnailValue = thumbnailColumn ? record === null || record === void 0 ? void 0 : record[thumbnailColumn.name] : undefined;
|
|
98
|
-
const hasThumbnail =
|
|
99
|
-
|
|
100
|
-
|
|
95
|
+
const hasThumbnail =
|
|
96
|
+
/*
|
|
97
|
+
* 자기가 그리겠다고 한 renderer 에게는 값이 비어도 자리를 준다. 그림이 없다는 말도, 그림
|
|
98
|
+
* 위에 얹는 것들(상태 표시 · 단추)도 renderer 안에 있고, 그 사정을 아는 것은 renderer 뿐이다.
|
|
99
|
+
*/
|
|
100
|
+
((_a = thumbnailColumn === null || thumbnailColumn === void 0 ? void 0 : thumbnailColumn.record) === null || _a === void 0 ? void 0 : _a.renderEmpty) ||
|
|
101
|
+
(Array.isArray(thumbnailValue)
|
|
102
|
+
? thumbnailValue.length > 0
|
|
103
|
+
: thumbnailValue !== null && thumbnailValue !== undefined && thumbnailValue !== '');
|
|
101
104
|
const gutters = (columns || []).filter(column => column.type == 'gutter' && column.forList);
|
|
102
105
|
if (this.hasAttribute('dirty')) {
|
|
103
106
|
var dirtyIcon;
|
|
@@ -200,7 +203,11 @@ RecordCard.styles = [
|
|
|
200
203
|
border-radius: var(--data-card-record-card-border-radius, var(--md-sys-shape-corner-medium));
|
|
201
204
|
border: var(--data-card-record-card-border);
|
|
202
205
|
height: min-content;
|
|
203
|
-
|
|
206
|
+
/*
|
|
207
|
+
그림이 카드 끝까지 닿아야 하는 목록은 이 여백을 0 으로 두고 그림 칸의 radius 로 위쪽
|
|
208
|
+
모서리를 맞춘다. 글이 실리는 카드는 지금까지의 값 그대로다.
|
|
209
|
+
*/
|
|
210
|
+
padding: var(--data-card-record-card-padding, var(--spacing-small) var(--spacing-none));
|
|
204
211
|
}
|
|
205
212
|
|
|
206
213
|
:host(:hover) {
|
|
@@ -305,8 +312,9 @@ RecordCard.styles = [
|
|
|
305
312
|
글자 크기에 따라 줄이 붙어 버리고 제목 묶음(brief)과도 구분되지 않았다. 세로로 세우고
|
|
306
313
|
간격을 준다 — 카드에서 「무엇인가」와 「어떤가」는 다른 묶음이다.
|
|
307
314
|
|
|
308
|
-
|
|
309
|
-
아무것도 없는 카드가
|
|
315
|
+
제목과는 옅은 선으로 가른다 — 카드에서 「무엇인가」와 「어떤가」는 다른 묶음이다. 값이
|
|
316
|
+
**전부** 빌 수 있는 목록이라면 선 아래에 아무것도 없는 카드가 생기므로, 그런 화면은
|
|
317
|
+
--data-card-detail-border-top: none 으로 끈다.
|
|
310
318
|
|
|
311
319
|
「이름 : 값」이 아니라 짧은 표식 몇 개(상태 · 점수)를 다는 목록에서는 세로로 세우는 것이
|
|
312
320
|
자리만 먹는다. 그때는 화면이 한 줄로 뉘일 수 있다(--data-card-detail-direction: row).
|
|
@@ -318,6 +326,8 @@ RecordCard.styles = [
|
|
|
318
326
|
align-items: baseline;
|
|
319
327
|
gap: var(--spacing-tiny) var(--spacing-medium);
|
|
320
328
|
margin-top: var(--spacing-small);
|
|
329
|
+
padding-top: var(--spacing-small);
|
|
330
|
+
border-top: var(--data-card-detail-border-top, 1px solid var(--md-sys-color-outline-variant));
|
|
321
331
|
overflow: hidden;
|
|
322
332
|
}
|
|
323
333
|
|
|
@@ -330,42 +340,6 @@ RecordCard.styles = [
|
|
|
330
340
|
align-items: stretch;
|
|
331
341
|
}
|
|
332
342
|
|
|
333
|
-
/*
|
|
334
|
-
── 손이 갈 때만 나오는 단추 ────────────────────────────────────────
|
|
335
|
-
단추가 그 카드의 주된 할 일인 목록(결재함의 「상세정보」)에서는 늘 보여야 한다. 반대로
|
|
336
|
-
고르는 것이 주된 일인 목록(자산 카탈로그)에서 삭제 단추가 카드마다 떠 있으면, 사람이
|
|
337
|
-
고르려고 보는 자리에 되돌릴 수 없는 조작이 먼저 눈에 든다.
|
|
338
|
-
|
|
339
|
-
어느 쪽인지는 화면이 정한다(list.gutters: 'hover'). 눌리지 않게 함께 막아야 한다 —
|
|
340
|
-
보이지 않는 단추가 눌리는 것이 더 나쁘다.
|
|
341
|
-
*/
|
|
342
|
-
/*
|
|
343
|
-
감춘 단추는 **자리도 차지하지 않는다.** opacity 만 0 으로 두면 카드마다 빈 줄이 남아,
|
|
344
|
-
늘 보이는 것보다 되레 카드가 길어진다. 그림 위 오른쪽 끝으로 띄운다 — 손이 갈 때만
|
|
345
|
-
나오는 단추가 있을 자리다. 그림이 어두울 수 있으니 옅은 바탕을 깐다.
|
|
346
|
-
*/
|
|
347
|
-
:host([gutters-hover]) [gutters] {
|
|
348
|
-
position: absolute;
|
|
349
|
-
top: var(--spacing-small);
|
|
350
|
-
right: var(--spacing-small);
|
|
351
|
-
margin: var(--spacing-none);
|
|
352
|
-
padding: 1px;
|
|
353
|
-
border-radius: var(--md-sys-shape-corner-small);
|
|
354
|
-
background-color: var(
|
|
355
|
-
--data-card-gutters-floating-background,
|
|
356
|
-
color-mix(in srgb, var(--md-sys-color-surface, #fff) 78%, transparent)
|
|
357
|
-
);
|
|
358
|
-
opacity: 0;
|
|
359
|
-
pointer-events: none;
|
|
360
|
-
transition: opacity 0.12s ease-out;
|
|
361
|
-
}
|
|
362
|
-
|
|
363
|
-
:host([gutters-hover]:hover) [gutters],
|
|
364
|
-
:host([gutters-hover]:focus-within) [gutters] {
|
|
365
|
-
opacity: 1;
|
|
366
|
-
pointer-events: auto;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
343
|
ox-card-field {
|
|
370
344
|
font: var(--data-card-item-etc-font);
|
|
371
345
|
color: var(--data-card-item-etc-color, var(--md-sys-color-on-surface));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"record-card.js","sourceRoot":"","sources":["../../../src/data-card/record-card.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '../record-view/record-view.js'\nimport './data-card-field.js'\nimport './data-card-gutter.js'\nimport './data-card-gutter-menu.js'\n\nimport { LitElement, PropertyValues, css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { GristConfig, GristData, GristRecord } from '../types.js'\nimport { ZERO_CONFIG, ZERO_DATA, ZERO_RECORD } from '../configure/zero-config.js'\nimport { RecordViewHandler } from '../record-view/record-view-handler.js'\nimport { recordCardClickHandler } from './event-handlers/record-card-click-handler.js'\nimport { recordCardDblClickHandler } from './event-handlers/record-card-dblclick-handler.js'\n\n// TODO 로케일 설정에 따라서 포맷이 바뀌도록 해야한다.\nconst OPTIONS: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n hour12: false\n // timeZone: 'America/Los_Angeles'\n}\n\nfunction getSafeFormatter(locale: string, options: Intl.DateTimeFormatOptions) {\n try {\n const safeLocale = locale || 'en-US'\n return new Intl.DateTimeFormat(safeLocale, options)\n } catch (e) {\n return new Intl.DateTimeFormat('en-US', options)\n }\n}\n\nconst formatter = getSafeFormatter(navigator.language, OPTIONS)\n\n@customElement('ox-record-card')\nexport class RecordCard extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n position: relative;\n background-color: var(--data-card-record-card-background-color);\n /* Theme 정의가 누락된 application 에서도 합리적 radius 보장. */\n border-radius: var(--data-card-record-card-border-radius, var(--md-sys-shape-corner-medium));\n border: var(--data-card-record-card-border);\n height: min-content;\n padding: var(--spacing-small) var(--spacing-none);\n }\n\n :host(:hover) {\n background-color: var(--md-sys-color-surface);\n border: var(--data-card-record-card-border-hover);\n box-shadow: var(--data-card-record-card-boxshadow-hover);\n }\n\n :host([dirty])::before {\n content: '';\n position: absolute;\n left: var(--spacing-none);\n top: var(--spacing-none);\n\n width: var(--spacing-none);\n height: var(--spacing-none);\n border-top: var(--grid-record-dirty-border-top);\n border-right: var(--grid-record-dirty-border-left);\n }\n\n :host[emphasized-row] {\n background-color: var(--grid-record-emphasized-background-color);\n color: var(--grid-record-emphasized-color);\n }\n\n [dirty] {\n position: absolute;\n margin: var(--spacing-none);\n height: 20px;\n\n font: var(--grid-record-dirty-icon-font);\n text-indent: 1px;\n left: var(--spacing-none);\n top: var(--spacing-none);\n color: var(--grid-record-dirty-color, var(--md-sys-color-error));\n }\n\n [thumbnail] {\n /*\n 높이 대신 **비율**로 잡을 수 있다.\n\n 그림이 자산인 목록에서는 카드 폭이 달라져도 그림 칸의 비율이 같아야 나란히 읽힌다. 높이만\n 있으면 좁은 카드에서는 납작하고 넓은 카드에서는 홀쭉해진다. 둘 다 안 주면 지금까지처럼\n 내용 높이를 따른다.\n */\n height: var(--data-card-thumbnail-height, auto);\n aspect-ratio: var(--data-card-thumbnail-aspect, auto);\n /*\n 그림 안쪽 여백과 바탕도 밖에서 정한다.\n\n 목록마다 그림이 하는 일이 다르다. 사람 얼굴(직원 목록)은 여백이 있어야 카드 안에 놓인\n 것처럼 보이고, 자산 카탈로그의 그림은 **그림이 주인공**이라 여백이 그림을 작게 만든다.\n 바탕도 마찬가지다 — 배경이 없는 그림(투명 png · 3D 미리보기)은 놓일 면이 있어야 한다.\n */\n padding: var(--data-card-thumbnail-padding, var(--spacing-large));\n background-color: var(--data-card-thumbnail-background, transparent);\n box-sizing: border-box;\n /* 동심 안쪽 radius — Material 3 shape token (외곽 = corner-medium, 안쪽 =\n * corner-small). board-ui 카드와 동일 톤. */\n border-radius: var(--data-card-thumbnail-radius, var(--md-sys-shape-corner-small));\n overflow: hidden;\n }\n\n /*\n 그림이 없는 것도 **자리는 지킨다.**\n\n 전에는 값이 없으면 썸네일 요소를 아예 그리지 않았다. 그러면 한 목록 안에서 카드 높이가\n 들쭉날쭉해져 눈이 줄을 못 잡고, 「아직 그림이 없다」는 사실을 말할 자리도 사라진다.\n 빈 자리는 조용한 바탕으로 두고, 무엇이라고 부를지는 쓰는 쪽이 정한다.\n */\n [thumbnail][empty] {\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--data-card-thumbnail-empty-background, var(--md-sys-color-surface-container));\n color: var(--data-card-thumbnail-empty-color, var(--md-sys-color-outline));\n font: var(--data-card-item-etc-font);\n }\n\n [thumbnail][empty] md-icon {\n --md-icon-size: 28px;\n }\n\n [content] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-tiny);\n margin: var(--data-card-item-margin);\n }\n\n [brief] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-tiny);\n overflow: hidden;\n }\n\n /*\n 곁들이는 칸들 — 이 자리에 규칙이 아예 없었다.\n\n details 는 「이름 : 값」이 여러 줄 서는 자리인데 그 줄들을 세우는 규칙이 없어서, 카드가\n 글자 크기에 따라 줄이 붙어 버리고 제목 묶음(brief)과도 구분되지 않았다. 세로로 세우고\n 간격을 준다 — 카드에서 「무엇인가」와 「어떤가」는 다른 묶음이다.\n\n 선으로 가르지는 않는다. 값이 없는 줄이 섞이는 목록(있을 때만 말하는 칸)에서는 선 아래에\n 아무것도 없는 카드가 생긴다.\n\n 「이름 : 값」이 아니라 짧은 표식 몇 개(상태 · 점수)를 다는 목록에서는 세로로 세우는 것이\n 자리만 먹는다. 그때는 화면이 한 줄로 뉘일 수 있다(--data-card-detail-direction: row).\n */\n [detail] {\n display: flex;\n flex-direction: var(--data-card-detail-direction, column);\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--spacing-tiny) var(--spacing-medium);\n margin-top: var(--spacing-small);\n overflow: hidden;\n }\n\n [gutters] {\n display: flex;\n flex-direction: row;\n gap: var(--spacing-small);\n margin: var(--spacing-small) var(--spacing-medium);\n justify-content: end;\n align-items: stretch;\n }\n\n /*\n ── 손이 갈 때만 나오는 단추 ────────────────────────────────────────\n 단추가 그 카드의 주된 할 일인 목록(결재함의 「상세정보」)에서는 늘 보여야 한다. 반대로\n 고르는 것이 주된 일인 목록(자산 카탈로그)에서 삭제 단추가 카드마다 떠 있으면, 사람이\n 고르려고 보는 자리에 되돌릴 수 없는 조작이 먼저 눈에 든다.\n\n 어느 쪽인지는 화면이 정한다(list.gutters: 'hover'). 눌리지 않게 함께 막아야 한다 —\n 보이지 않는 단추가 눌리는 것이 더 나쁘다.\n */\n /*\n 감춘 단추는 **자리도 차지하지 않는다.** opacity 만 0 으로 두면 카드마다 빈 줄이 남아,\n 늘 보이는 것보다 되레 카드가 길어진다. 그림 위 오른쪽 끝으로 띄운다 — 손이 갈 때만\n 나오는 단추가 있을 자리다. 그림이 어두울 수 있으니 옅은 바탕을 깐다.\n */\n :host([gutters-hover]) [gutters] {\n position: absolute;\n top: var(--spacing-small);\n right: var(--spacing-small);\n margin: var(--spacing-none);\n padding: 1px;\n border-radius: var(--md-sys-shape-corner-small);\n background-color: var(\n --data-card-gutters-floating-background,\n color-mix(in srgb, var(--md-sys-color-surface, #fff) 78%, transparent)\n );\n opacity: 0;\n pointer-events: none;\n transition: opacity 0.12s ease-out;\n }\n\n :host([gutters-hover]:hover) [gutters],\n :host([gutters-hover]:focus-within) [gutters] {\n opacity: 1;\n pointer-events: auto;\n }\n\n ox-card-field {\n font: var(--data-card-item-etc-font);\n color: var(--data-card-item-etc-color, var(--md-sys-color-on-surface));\n }\n\n ox-card-field[name] {\n font: var(--data-card-item-name-font);\n color: var(--data-card-item-name-color, var(--md-sys-color-secondary));\n }\n\n ox-card-field[desc] {\n font: var(--data-card-item-disc-font);\n color: var(--data-card-item-disc-color, var(--md-sys-color-tertiary));\n }\n `\n ]\n\n @property({ type: Object }) config: GristConfig = ZERO_CONFIG\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: Object }) record: GristRecord = ZERO_RECORD\n @property({ type: Number }) rowIndex: number = -1\n /*\n * row-selector를 사용자가 변경할 때, record-card의 update를 유도하기 위해 selected-row attribute를 property에 추가함.\n * (이를 해주지 않으면, 리스트 refresh 경우에 selected-row checkbox가 클리어되지 않는 현상이 발생함.)\n */\n @property({ type: Boolean, attribute: 'selected-row' }) selectedRow: boolean = false\n @property({ attribute: false }) emphasized: any = false\n\n private _recordView: any\n private clickHandler = recordCardClickHandler.bind(this) as EventListener\n private dblclickHandler = recordCardDblClickHandler.bind(this) as EventListener\n\n firstUpdated() {\n /*\n long-press\n TODO. performance를 확인한 후에 활성화하자.\n */\n // longpressable(this.renderRoot.querySelector('[content]'))\n // this.renderRoot.addEventListener('long-press', recordPartialLongPressHandler.bind(this))\n this.renderRoot.addEventListener('click', this.clickHandler)\n this.renderRoot.addEventListener('dblclick', this.dblclickHandler)\n\n this.addEventListener('show-record-view', () => this.popupRecordView())\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('record') && this._recordView) {\n this._recordView.record = this.record\n }\n\n if (changes.has('config')) {\n this.toggleAttribute('gutters-hover', this.config?.list?.gutters == 'hover')\n }\n\n const emphasized = this.emphasized\n\n if (!!emphasized) {\n this.setAttribute('emphasized-row', '')\n\n if (Symbol.iterator in Object(emphasized)) {\n const [backgroundColor, foregroundColor] = emphasized as string[]\n backgroundColor && this.style.setProperty('--grid-record-emphasized-background-color', backgroundColor)\n foregroundColor && this.style.setProperty('--grid-record-emphasized-color', foregroundColor)\n }\n } else {\n this.removeAttribute('emphasized-row')\n }\n }\n\n render() {\n const record = this.record\n const rowIndex = this.rowIndex\n const { columns, list } = this.config\n const { thumbnail, fields, details, emptyThumbnail } = list || {}\n\n const briefFields = fields.map(field => columns.find(column => column.name == field)).filter(column => column) || []\n const detailFields =\n details.map(field => columns.find(column => column.name == field)).filter(column => column) || []\n\n const thumbnailColumn = thumbnail ? columns.find(column => column.name == thumbnail) : undefined\n /*\n * 값이 없으면 썸네일 자리를 만들지 않는다.\n *\n * 전에는 설정에 썸네일 컬럼 이름이 있으면 **레코드에 값이 있는지 보지 않고** 그렸다. 그래서 이미지를\n * 갖지 않는 목록(결재함 · 업무함)에서 카드마다 깨진 이미지 표시가 세로의 절반을 차지하고, 정작\n * 제목은 잘렸다. 없는 것의 자리를 비워 두는 것이다.\n */\n const thumbnailValue = thumbnailColumn ? record?.[thumbnailColumn.name] : undefined\n const hasThumbnail = Array.isArray(thumbnailValue)\n ? thumbnailValue.length > 0\n : thumbnailValue !== null && thumbnailValue !== undefined && thumbnailValue !== ''\n\n const gutters = (columns || []).filter(column => column.type == 'gutter' && column.forList)\n\n if (this.hasAttribute('dirty')) {\n var dirtyIcon\n\n switch (this.record['__dirty__']) {\n case 'M':\n dirtyIcon = 'done'\n break\n case '+':\n dirtyIcon = 'add'\n break\n case '-':\n dirtyIcon = 'remove'\n break\n }\n }\n\n return html`\n ${dirtyIcon ? html` <md-icon dirty>${dirtyIcon}</md-icon> ` : html``}\n ${thumbnailColumn\n ? hasThumbnail\n ? html` <ox-card-field\n thumbnail\n .rowIndex=${rowIndex}\n .column=${thumbnailColumn}\n .record=${record}\n .value=${record[thumbnailColumn?.name || '']}\n ></ox-card-field>`\n : html`<div thumbnail empty>\n ${emptyThumbnail?.icon ? html`<md-icon>${emptyThumbnail.icon}</md-icon>` : ''}\n ${emptyThumbnail?.label || ''}\n </div>`\n : html``}\n\n <div content>\n <div brief>\n ${briefFields.map(\n (column, idx) => html`\n <ox-card-field\n .rowIndex=${rowIndex}\n .column=${column}\n .record=${record}\n .value=${record[column?.name || '']}\n ?name=${idx == 0}\n ?desc=${idx == 1}\n ></ox-card-field>\n `\n )}\n </div>\n ${detailFields.length > 0\n ? html`\n <div detail>\n ${detailFields.map(\n (column, idx) => html`\n <ox-card-field\n .rowIndex=${rowIndex}\n .column=${column}\n .record=${record}\n .value=${record[column?.name || '']}\n ></ox-card-field>\n `\n )}\n </div>\n `\n : html``}\n </div>\n\n <div gutters>\n ${gutters.map(gutter => {\n return html`\n <ox-card-gutter\n .rowIndex=${rowIndex}\n .column=${gutter}\n .record=${record}\n .value=${record[gutter.name]}\n ></ox-card-gutter>\n `\n })}\n </div>\n `\n }\n\n popupRecordView() {\n var titleField = this.config.list.fields[0] || 'name'\n var title = this.record[titleField]\n\n /* field가 오브젝트형인 경우에는 렌더러를 타이틀로 사용한다. */\n if (typeof title == 'object') {\n var column = this.config.columns.find(column => column.name == titleField)\n title = column?.record.renderer(title, column, this.record, this.rowIndex, this /* cautious */)\n }\n\n this._recordView = RecordViewHandler(\n this.config.columns,\n this.record,\n this.rowIndex,\n this,\n {\n title\n },\n () => {\n delete this._recordView\n }\n )\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"record-card.js","sourceRoot":"","sources":["../../../src/data-card/record-card.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport '../record-view/record-view.js'\nimport './data-card-field.js'\nimport './data-card-gutter.js'\nimport './data-card-gutter-menu.js'\n\nimport { LitElement, PropertyValues, css, html } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\nimport { GristConfig, GristData, GristRecord } from '../types.js'\nimport { ZERO_CONFIG, ZERO_DATA, ZERO_RECORD } from '../configure/zero-config.js'\nimport { RecordViewHandler } from '../record-view/record-view-handler.js'\nimport { recordCardClickHandler } from './event-handlers/record-card-click-handler.js'\nimport { recordCardDblClickHandler } from './event-handlers/record-card-dblclick-handler.js'\n\n// TODO 로케일 설정에 따라서 포맷이 바뀌도록 해야한다.\nconst OPTIONS: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: 'numeric',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n hour12: false\n // timeZone: 'America/Los_Angeles'\n}\n\nfunction getSafeFormatter(locale: string, options: Intl.DateTimeFormatOptions) {\n try {\n const safeLocale = locale || 'en-US'\n return new Intl.DateTimeFormat(safeLocale, options)\n } catch (e) {\n return new Intl.DateTimeFormat('en-US', options)\n }\n}\n\nconst formatter = getSafeFormatter(navigator.language, OPTIONS)\n\n@customElement('ox-record-card')\nexport class RecordCard extends LitElement {\n static styles = [\n css`\n :host {\n display: flex;\n flex-direction: column;\n align-items: stretch;\n position: relative;\n background-color: var(--data-card-record-card-background-color);\n /* Theme 정의가 누락된 application 에서도 합리적 radius 보장. */\n border-radius: var(--data-card-record-card-border-radius, var(--md-sys-shape-corner-medium));\n border: var(--data-card-record-card-border);\n height: min-content;\n /*\n 그림이 카드 끝까지 닿아야 하는 목록은 이 여백을 0 으로 두고 그림 칸의 radius 로 위쪽\n 모서리를 맞춘다. 글이 실리는 카드는 지금까지의 값 그대로다.\n */\n padding: var(--data-card-record-card-padding, var(--spacing-small) var(--spacing-none));\n }\n\n :host(:hover) {\n background-color: var(--md-sys-color-surface);\n border: var(--data-card-record-card-border-hover);\n box-shadow: var(--data-card-record-card-boxshadow-hover);\n }\n\n :host([dirty])::before {\n content: '';\n position: absolute;\n left: var(--spacing-none);\n top: var(--spacing-none);\n\n width: var(--spacing-none);\n height: var(--spacing-none);\n border-top: var(--grid-record-dirty-border-top);\n border-right: var(--grid-record-dirty-border-left);\n }\n\n :host[emphasized-row] {\n background-color: var(--grid-record-emphasized-background-color);\n color: var(--grid-record-emphasized-color);\n }\n\n [dirty] {\n position: absolute;\n margin: var(--spacing-none);\n height: 20px;\n\n font: var(--grid-record-dirty-icon-font);\n text-indent: 1px;\n left: var(--spacing-none);\n top: var(--spacing-none);\n color: var(--grid-record-dirty-color, var(--md-sys-color-error));\n }\n\n [thumbnail] {\n /*\n 높이 대신 **비율**로 잡을 수 있다.\n\n 그림이 자산인 목록에서는 카드 폭이 달라져도 그림 칸의 비율이 같아야 나란히 읽힌다. 높이만\n 있으면 좁은 카드에서는 납작하고 넓은 카드에서는 홀쭉해진다. 둘 다 안 주면 지금까지처럼\n 내용 높이를 따른다.\n */\n height: var(--data-card-thumbnail-height, auto);\n aspect-ratio: var(--data-card-thumbnail-aspect, auto);\n /*\n 그림 안쪽 여백과 바탕도 밖에서 정한다.\n\n 목록마다 그림이 하는 일이 다르다. 사람 얼굴(직원 목록)은 여백이 있어야 카드 안에 놓인\n 것처럼 보이고, 자산 카탈로그의 그림은 **그림이 주인공**이라 여백이 그림을 작게 만든다.\n 바탕도 마찬가지다 — 배경이 없는 그림(투명 png · 3D 미리보기)은 놓일 면이 있어야 한다.\n */\n padding: var(--data-card-thumbnail-padding, var(--spacing-large));\n background-color: var(--data-card-thumbnail-background, transparent);\n box-sizing: border-box;\n /* 동심 안쪽 radius — Material 3 shape token (외곽 = corner-medium, 안쪽 =\n * corner-small). board-ui 카드와 동일 톤. */\n border-radius: var(--data-card-thumbnail-radius, var(--md-sys-shape-corner-small));\n overflow: hidden;\n }\n\n /*\n 그림이 없는 것도 **자리는 지킨다.**\n\n 전에는 값이 없으면 썸네일 요소를 아예 그리지 않았다. 그러면 한 목록 안에서 카드 높이가\n 들쭉날쭉해져 눈이 줄을 못 잡고, 「아직 그림이 없다」는 사실을 말할 자리도 사라진다.\n 빈 자리는 조용한 바탕으로 두고, 무엇이라고 부를지는 쓰는 쪽이 정한다.\n */\n [thumbnail][empty] {\n display: flex;\n align-items: center;\n justify-content: center;\n background-color: var(--data-card-thumbnail-empty-background, var(--md-sys-color-surface-container));\n color: var(--data-card-thumbnail-empty-color, var(--md-sys-color-outline));\n font: var(--data-card-item-etc-font);\n }\n\n [thumbnail][empty] md-icon {\n --md-icon-size: 28px;\n }\n\n [content] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-tiny);\n margin: var(--data-card-item-margin);\n }\n\n [brief] {\n display: flex;\n flex-direction: column;\n gap: var(--spacing-tiny);\n overflow: hidden;\n }\n\n /*\n 곁들이는 칸들 — 이 자리에 규칙이 아예 없었다.\n\n details 는 「이름 : 값」이 여러 줄 서는 자리인데 그 줄들을 세우는 규칙이 없어서, 카드가\n 글자 크기에 따라 줄이 붙어 버리고 제목 묶음(brief)과도 구분되지 않았다. 세로로 세우고\n 간격을 준다 — 카드에서 「무엇인가」와 「어떤가」는 다른 묶음이다.\n\n 제목과는 옅은 선으로 가른다 — 카드에서 「무엇인가」와 「어떤가」는 다른 묶음이다. 값이\n **전부** 빌 수 있는 목록이라면 선 아래에 아무것도 없는 카드가 생기므로, 그런 화면은\n --data-card-detail-border-top: none 으로 끈다.\n\n 「이름 : 값」이 아니라 짧은 표식 몇 개(상태 · 점수)를 다는 목록에서는 세로로 세우는 것이\n 자리만 먹는다. 그때는 화면이 한 줄로 뉘일 수 있다(--data-card-detail-direction: row).\n */\n [detail] {\n display: flex;\n flex-direction: var(--data-card-detail-direction, column);\n flex-wrap: wrap;\n align-items: baseline;\n gap: var(--spacing-tiny) var(--spacing-medium);\n margin-top: var(--spacing-small);\n padding-top: var(--spacing-small);\n border-top: var(--data-card-detail-border-top, 1px solid var(--md-sys-color-outline-variant));\n overflow: hidden;\n }\n\n [gutters] {\n display: flex;\n flex-direction: row;\n gap: var(--spacing-small);\n margin: var(--spacing-small) var(--spacing-medium);\n justify-content: end;\n align-items: stretch;\n }\n\n ox-card-field {\n font: var(--data-card-item-etc-font);\n color: var(--data-card-item-etc-color, var(--md-sys-color-on-surface));\n }\n\n ox-card-field[name] {\n font: var(--data-card-item-name-font);\n color: var(--data-card-item-name-color, var(--md-sys-color-secondary));\n }\n\n ox-card-field[desc] {\n font: var(--data-card-item-disc-font);\n color: var(--data-card-item-disc-color, var(--md-sys-color-tertiary));\n }\n `\n ]\n\n @property({ type: Object }) config: GristConfig = ZERO_CONFIG\n @property({ type: Object }) data: GristData = ZERO_DATA\n @property({ type: Object }) record: GristRecord = ZERO_RECORD\n @property({ type: Number }) rowIndex: number = -1\n /*\n * row-selector를 사용자가 변경할 때, record-card의 update를 유도하기 위해 selected-row attribute를 property에 추가함.\n * (이를 해주지 않으면, 리스트 refresh 경우에 selected-row checkbox가 클리어되지 않는 현상이 발생함.)\n */\n @property({ type: Boolean, attribute: 'selected-row' }) selectedRow: boolean = false\n @property({ attribute: false }) emphasized: any = false\n\n private _recordView: any\n private clickHandler = recordCardClickHandler.bind(this) as EventListener\n private dblclickHandler = recordCardDblClickHandler.bind(this) as EventListener\n\n firstUpdated() {\n /*\n long-press\n TODO. performance를 확인한 후에 활성화하자.\n */\n // longpressable(this.renderRoot.querySelector('[content]'))\n // this.renderRoot.addEventListener('long-press', recordPartialLongPressHandler.bind(this))\n this.renderRoot.addEventListener('click', this.clickHandler)\n this.renderRoot.addEventListener('dblclick', this.dblclickHandler)\n\n this.addEventListener('show-record-view', () => this.popupRecordView())\n }\n\n updated(changes: PropertyValues<this>) {\n if (changes.has('record') && this._recordView) {\n this._recordView.record = this.record\n }\n\n const emphasized = this.emphasized\n\n if (!!emphasized) {\n this.setAttribute('emphasized-row', '')\n\n if (Symbol.iterator in Object(emphasized)) {\n const [backgroundColor, foregroundColor] = emphasized as string[]\n backgroundColor && this.style.setProperty('--grid-record-emphasized-background-color', backgroundColor)\n foregroundColor && this.style.setProperty('--grid-record-emphasized-color', foregroundColor)\n }\n } else {\n this.removeAttribute('emphasized-row')\n }\n }\n\n render() {\n const record = this.record\n const rowIndex = this.rowIndex\n const { columns, list } = this.config\n const { thumbnail, fields, details, emptyThumbnail } = list || {}\n\n const briefFields = fields.map(field => columns.find(column => column.name == field)).filter(column => column) || []\n const detailFields =\n details.map(field => columns.find(column => column.name == field)).filter(column => column) || []\n\n const thumbnailColumn = thumbnail ? columns.find(column => column.name == thumbnail) : undefined\n /*\n * 값이 없으면 썸네일 자리를 만들지 않는다.\n *\n * 전에는 설정에 썸네일 컬럼 이름이 있으면 **레코드에 값이 있는지 보지 않고** 그렸다. 그래서 이미지를\n * 갖지 않는 목록(결재함 · 업무함)에서 카드마다 깨진 이미지 표시가 세로의 절반을 차지하고, 정작\n * 제목은 잘렸다. 없는 것의 자리를 비워 두는 것이다.\n */\n const thumbnailValue = thumbnailColumn ? record?.[thumbnailColumn.name] : undefined\n const hasThumbnail =\n /*\n * 자기가 그리겠다고 한 renderer 에게는 값이 비어도 자리를 준다. 그림이 없다는 말도, 그림\n * 위에 얹는 것들(상태 표시 · 단추)도 renderer 안에 있고, 그 사정을 아는 것은 renderer 뿐이다.\n */\n thumbnailColumn?.record?.renderEmpty ||\n (Array.isArray(thumbnailValue)\n ? thumbnailValue.length > 0\n : thumbnailValue !== null && thumbnailValue !== undefined && thumbnailValue !== '')\n\n const gutters = (columns || []).filter(column => column.type == 'gutter' && column.forList)\n\n if (this.hasAttribute('dirty')) {\n var dirtyIcon\n\n switch (this.record['__dirty__']) {\n case 'M':\n dirtyIcon = 'done'\n break\n case '+':\n dirtyIcon = 'add'\n break\n case '-':\n dirtyIcon = 'remove'\n break\n }\n }\n\n return html`\n ${dirtyIcon ? html` <md-icon dirty>${dirtyIcon}</md-icon> ` : html``}\n ${thumbnailColumn\n ? hasThumbnail\n ? html` <ox-card-field\n thumbnail\n .rowIndex=${rowIndex}\n .column=${thumbnailColumn}\n .record=${record}\n .value=${record[thumbnailColumn?.name || '']}\n ></ox-card-field>`\n : html`<div thumbnail empty>\n ${emptyThumbnail?.icon ? html`<md-icon>${emptyThumbnail.icon}</md-icon>` : ''}\n ${emptyThumbnail?.label || ''}\n </div>`\n : html``}\n\n <div content>\n <div brief>\n ${briefFields.map(\n (column, idx) => html`\n <ox-card-field\n .rowIndex=${rowIndex}\n .column=${column}\n .record=${record}\n .value=${record[column?.name || '']}\n ?name=${idx == 0}\n ?desc=${idx == 1}\n ></ox-card-field>\n `\n )}\n </div>\n ${detailFields.length > 0\n ? html`\n <div detail>\n ${detailFields.map(\n (column, idx) => html`\n <ox-card-field\n .rowIndex=${rowIndex}\n .column=${column}\n .record=${record}\n .value=${record[column?.name || '']}\n ></ox-card-field>\n `\n )}\n </div>\n `\n : html``}\n </div>\n\n <div gutters>\n ${gutters.map(gutter => {\n return html`\n <ox-card-gutter\n .rowIndex=${rowIndex}\n .column=${gutter}\n .record=${record}\n .value=${record[gutter.name]}\n ></ox-card-gutter>\n `\n })}\n </div>\n `\n }\n\n popupRecordView() {\n var titleField = this.config.list.fields[0] || 'name'\n var title = this.record[titleField]\n\n /* field가 오브젝트형인 경우에는 렌더러를 타이틀로 사용한다. */\n if (typeof title == 'object') {\n var column = this.config.columns.find(column => column.name == titleField)\n title = column?.record.renderer(title, column, this.record, this.rowIndex, this /* cautious */)\n }\n\n this._recordView = RecordViewHandler(\n this.config.columns,\n this.record,\n this.rowIndex,\n this,\n {\n title\n },\n () => {\n delete this._recordView\n }\n )\n }\n}\n"]}
|
package/dist/src/data-grist.d.ts
CHANGED
|
@@ -114,10 +114,7 @@ export declare class DataGrist extends LitElement implements DataConsumer {
|
|
|
114
114
|
private dataProvider?;
|
|
115
115
|
private pulltorefreshHandle?;
|
|
116
116
|
private headroom?;
|
|
117
|
-
private orginPaddingTop?;
|
|
118
|
-
private originMarginTop?;
|
|
119
117
|
private headResizeObserver?;
|
|
120
|
-
private headroomAtTop;
|
|
121
118
|
private lastLocation;
|
|
122
119
|
private pendingFetch?;
|
|
123
120
|
private popstateEventHandler;
|
package/dist/src/data-grist.js
CHANGED
|
@@ -61,7 +61,6 @@ let DataGrist = class DataGrist extends LitElement {
|
|
|
61
61
|
* 둘을 같게 두면 확인하지 않은 사실을 화면이 단정하게 된다.
|
|
62
62
|
*/
|
|
63
63
|
this._fetched = false;
|
|
64
|
-
this.headroomAtTop = true;
|
|
65
64
|
this.lastLocation = {};
|
|
66
65
|
this.popstateEventHandler = ((e) => {
|
|
67
66
|
const { origin, pathname, search } = window.location;
|
|
@@ -281,36 +280,35 @@ let DataGrist = class DataGrist extends LitElement {
|
|
|
281
280
|
/* 머리가 덮고 있는 위쪽 padding. 머리의 기준 상자가 host 의 padding 박스이므로 이 값이다. */
|
|
282
281
|
const overlaid = parseFloat(getComputedStyle(this).paddingTop || '0') || 0;
|
|
283
282
|
const offset = Math.max(0, this.head.clientHeight - overlaid) + 'px';
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
283
|
+
/*
|
|
284
|
+
── 자리는 목록 **안쪽**에 만든다(padding), 목록을 밀어내지 않는다(margin) ──────────
|
|
285
|
+
전에는 맨 위에서 margin-top 으로 목록 상자 자체를 내려놓았다. 그러면 목록이 차지하는 상자가
|
|
286
|
+
머리 높이만큼 작아지고, **머리가 스크롤에 말려 올라가면 그 띠가 빈 채로 남는다.** 머리는
|
|
287
|
+
`headroom--unpinned` 에서 translateY(-100%) 로 사라지는데(HeadroomStyles), 목록은 여전히
|
|
288
|
+
62px 아래에서 시작해 흰 띠가 그대로 보였다.
|
|
289
|
+
|
|
290
|
+
padding 으로 두면 목록 상자는 늘 꽉 차 있고, 위쪽 62px 은 스크롤된 내용이 지나가는 자리가
|
|
291
|
+
된다. 맨 위에서는 그 자리를 머리가 덮으므로(불투명) 보이는 것은 전과 같다. 값이 늘 같아서
|
|
292
|
+
머리가 접히고 펴질 때 내용이 튀지 않는다 — 상태를 나눠 서로 다른 값을 쓰던 것이 원인이었다.
|
|
293
|
+
*/
|
|
294
|
+
this.grist.style.paddingTop = offset;
|
|
295
|
+
this.grist.style.removeProperty('margin-top');
|
|
290
296
|
}
|
|
291
297
|
setHeadroom() {
|
|
292
298
|
var _a, _b;
|
|
293
299
|
(_a = this.headroom) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
294
300
|
if (this.grist && this.head && this.head.style.display !== 'none') {
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
this.applyHeadOffset();
|
|
305
|
-
},
|
|
306
|
-
onNotTop: () => {
|
|
307
|
-
this.grist.style.marginTop = this.originMarginTop;
|
|
308
|
-
this.orginPaddingTop = this.grist.style.paddingTop;
|
|
309
|
-
this.headroomAtTop = false;
|
|
310
|
-
this.applyHeadOffset();
|
|
311
|
-
}
|
|
312
|
-
});
|
|
301
|
+
/*
|
|
302
|
+
**맨 위인지 아닌지로 값을 갈라 두지 않는다.**
|
|
303
|
+
|
|
304
|
+
전에는 onTop·onNotTop 이 서로의 값을 저장했다 되돌리며 margin 과 padding 을 번갈아 썼다.
|
|
305
|
+
그 저장 변수들은 서로가 밀어 놓은 값을 다시 담아 믿을 수 없었고(2026-09-02 에 남은 주석이
|
|
306
|
+
그 사연이다), 상태에 따라 값이 달라지니 머리가 접힐 때 내용이 튀었다. 자리는 한 가지
|
|
307
|
+
방법으로만 만든다 — `applyHeadOffset` 하나가 소유한다.
|
|
308
|
+
*/
|
|
309
|
+
this.headroom = new Headroom(this.head, { scroller: this.grist });
|
|
313
310
|
this.headroom.init();
|
|
311
|
+
this.applyHeadOffset();
|
|
314
312
|
/* 머리가 커지거나 줄면 그때마다 다시 민다 — 한 번 잰 값으로 두면 내용이 겹친다. */
|
|
315
313
|
(_b = this.headResizeObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
316
314
|
this.headResizeObserver = new ResizeObserver(() => this.applyHeadOffset());
|
|
@@ -354,45 +352,45 @@ let DataGrist = class DataGrist extends LitElement {
|
|
|
354
352
|
<div id="wrap" @keydown=${(e) => this.onKeydown(e)}>
|
|
355
353
|
${this.mode == 'GRID'
|
|
356
354
|
? html `
|
|
357
|
-
|
|
358
|
-
id="grist"
|
|
359
|
-
.gridLabel=${this.gridLabel}
|
|
360
|
-
.config=${this.compiledConfig}
|
|
361
|
-
.data=${this._data}
|
|
362
|
-
.sorters=${this.sorters || []}
|
|
363
|
-
.filters=${this.filters || []}
|
|
364
|
-
.pagination=${this.pagination || {}}
|
|
365
|
-
?empty=${empty}
|
|
366
|
-
.emptyNote=${emptyNote}
|
|
367
|
-
>
|
|
368
|
-
<slot name="setting" slot="setting"> </slot>
|
|
369
|
-
</ox-grid>
|
|
370
|
-
`
|
|
371
|
-
: this.mode == 'CARD'
|
|
372
|
-
? html `
|
|
373
|
-
<ox-card
|
|
355
|
+
<ox-grid
|
|
374
356
|
id="grist"
|
|
357
|
+
.gridLabel=${this.gridLabel}
|
|
375
358
|
.config=${this.compiledConfig}
|
|
376
359
|
.data=${this._data}
|
|
377
360
|
.sorters=${this.sorters || []}
|
|
378
361
|
.filters=${this.filters || []}
|
|
362
|
+
.pagination=${this.pagination || {}}
|
|
379
363
|
?empty=${empty}
|
|
380
|
-
|
|
364
|
+
.emptyNote=${emptyNote}
|
|
381
365
|
>
|
|
382
|
-
|
|
366
|
+
<slot name="setting" slot="setting"> </slot>
|
|
367
|
+
</ox-grid>
|
|
383
368
|
`
|
|
369
|
+
: this.mode == 'CARD'
|
|
370
|
+
? html `
|
|
371
|
+
<ox-card
|
|
372
|
+
id="grist"
|
|
373
|
+
.config=${this.compiledConfig}
|
|
374
|
+
.data=${this._data}
|
|
375
|
+
.sorters=${this.sorters || []}
|
|
376
|
+
.filters=${this.filters || []}
|
|
377
|
+
?empty=${empty}
|
|
378
|
+
.emptyNote=${emptyNote}
|
|
379
|
+
>
|
|
380
|
+
</ox-card>
|
|
381
|
+
`
|
|
384
382
|
: html `
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
383
|
+
<ox-list
|
|
384
|
+
id="grist"
|
|
385
|
+
.config=${this.compiledConfig}
|
|
386
|
+
.data=${this._data}
|
|
387
|
+
.sorters=${this.sorters || []}
|
|
388
|
+
.filters=${this.filters || []}
|
|
389
|
+
?empty=${empty}
|
|
390
|
+
.emptyNote=${emptyNote}
|
|
391
|
+
>
|
|
392
|
+
</ox-list>
|
|
393
|
+
`}
|
|
396
394
|
</div>
|
|
397
395
|
|
|
398
396
|
<div id="spinner" ?show=${this._showSpinner}></div>
|
|
@@ -1202,7 +1200,7 @@ DataGrist.styles = [
|
|
|
1202
1200
|
--grid-header-splitter-display: none;
|
|
1203
1201
|
|
|
1204
1202
|
--grid-record-background-color: var(--ui-panel, #ffffff);
|
|
1205
|
-
--grid-record-odd-background-color: var(--ui-panel, #ffffff);
|
|
1203
|
+
--grid-record-odd-background-color: var(--ui-odd-stripe, var(--ui-panel, #ffffff));
|
|
1206
1204
|
--grid-record-padding: 7px 10px;
|
|
1207
1205
|
--grid-record-color: var(--ui-ink, #17242c);
|
|
1208
1206
|
--grid-record-border-bottom: 1px solid var(--ui-line-soft, #e6eaed);
|
|
@@ -1311,6 +1309,25 @@ DataGrist.styles = [
|
|
|
1311
1309
|
border-width: var(--grid-wrap-container-border-width, 0px);
|
|
1312
1310
|
}
|
|
1313
1311
|
|
|
1312
|
+
/*
|
|
1313
|
+
**세 모드가 다 자리를 채운다.** GRID 에만 flex 가 있었다.
|
|
1314
|
+
|
|
1315
|
+
#wrap 은 flex 통이라 늘어나라고 하지 않은 자식은 내용 높이만 갖는다. 줄이 없는 목록에서
|
|
1316
|
+
CARD·LIST 의 내용 높이는 0 이고, 그러면 비었을 때의 안내(ox-empty-note)가 그 안에서
|
|
1317
|
+
잘린다 — 만들어지기는 하는데 8px 짜리 칸에 갇힌다.
|
|
1318
|
+
|
|
1319
|
+
[확인함] plant 레인 실측 2026-09-10 · #wrap 589px · ox-card 8px · 안내 300×77 잘림
|
|
1320
|
+
|
|
1321
|
+
빈 화면은 이 부품이 가장 중요하게 말해야 하는 자리다(그래서 emptyNote 가 있다). 그 자리가
|
|
1322
|
+
모드에 따라 잘리면 화면이 아무 말도 못 한다. min-height: 0 은 함께 둔다 — 없으면 안쪽
|
|
1323
|
+
스크롤이 내용 높이만큼 밀린다.
|
|
1324
|
+
*/
|
|
1325
|
+
ox-card,
|
|
1326
|
+
ox-list {
|
|
1327
|
+
flex: 1;
|
|
1328
|
+
min-height: 0;
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1314
1331
|
slot[name='headroom'] {
|
|
1315
1332
|
display: block;
|
|
1316
1333
|
position: absolute;
|
|
@@ -1319,7 +1336,15 @@ DataGrist.styles = [
|
|
|
1319
1336
|
|
|
1320
1337
|
width: 100%;
|
|
1321
1338
|
box-sizing: border-box;
|
|
1322
|
-
|
|
1339
|
+
/*
|
|
1340
|
+
**머리 뒤는 막혀 있어야 한다.**
|
|
1341
|
+
|
|
1342
|
+
머리는 목록 위에 떠 있고 목록은 그 아래로 지나간다. --grist-background-color 는
|
|
1343
|
+
테마에서 **transparent 로 선언되어 있어**(그리스트가 페이지 바탕을 물려받게 하려고) 그것을
|
|
1344
|
+
그대로 쓰면 머리 글자와 목록 내용이 겹쳐 보인다. 값이 선언돼 있으니 var() 의 기본값도
|
|
1345
|
+
소용없다 — 다른 토큰으로 막고, 화면의 바탕이 surface 가 아니면 그 토큰으로 맞춘다.
|
|
1346
|
+
*/
|
|
1347
|
+
background-color: var(--grist-headroom-background-color, var(--md-sys-color-surface));
|
|
1323
1348
|
|
|
1324
1349
|
z-index: 8;
|
|
1325
1350
|
}
|