@operato/data-grist 1.11.6 → 1.11.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 +21 -0
- package/demo/data-grist-test.html +2 -1
- package/dist/src/configure/column-builder.js +8 -0
- package/dist/src/configure/column-builder.js.map +1 -1
- package/dist/src/data-grid/data-grid-accum-field.js +2 -15
- package/dist/src/data-grid/data-grid-accum-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-body.js +0 -1
- package/dist/src/data-grid/data-grid-body.js.map +1 -1
- package/dist/src/data-grid/data-grid-header.d.ts +8 -5
- package/dist/src/data-grid/data-grid-header.js +131 -47
- package/dist/src/data-grid/data-grid-header.js.map +1 -1
- package/dist/src/editors/ox-grist-editor.js +1 -1
- package/dist/src/editors/ox-grist-editor.js.map +1 -1
- package/dist/src/types.d.ts +2 -0
- package/dist/src/types.js.map +1 -1
- package/dist/stories/dynamic-editable.stories.js +22 -7
- package/dist/stories/dynamic-editable.stories.js.map +1 -1
- package/dist/stories/fixed-column.stories.js +2 -1
- package/dist/stories/fixed-column.stories.js.map +1 -1
- package/dist/stories/grist-modes.stories.js +2 -1
- package/dist/stories/grist-modes.stories.js.map +1 -1
- package/dist/stories/group-header.stories.d.ts +26 -0
- package/dist/stories/group-header.stories.js +473 -0
- package/dist/stories/group-header.stories.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/configure/column-builder.ts +8 -0
- package/src/data-grid/data-grid-accum-field.ts +2 -15
- package/src/data-grid/data-grid-body.ts +0 -2
- package/src/data-grid/data-grid-header.ts +148 -47
- package/src/editors/ox-grist-editor.ts +1 -1
- package/src/types.ts +2 -0
- package/stories/dynamic-editable.stories.ts +22 -7
- package/stories/fixed-column.stories.ts +2 -1
- package/stories/grist-modes.stories.ts +2 -1
- package/stories/group-header.stories.ts +505 -0
- package/dist/src/data-grid/data-grid-field-header.d.ts +0 -24
- package/dist/src/data-grid/data-grid-field-header.js +0 -381
- package/dist/src/data-grid/data-grid-field-header.js.map +0 -1
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import '@operato/popup/ox-popup.js'
|
|
2
2
|
import '@material/mwc-icon'
|
|
3
3
|
|
|
4
|
-
import { css, html, LitElement, PropertyValues, nothing } from 'lit'
|
|
4
|
+
import { css, html, LitElement, PropertyValues, nothing, TemplateResult } from 'lit'
|
|
5
5
|
import { customElement, property, state } from 'lit/decorators.js'
|
|
6
|
+
import { ifDefined } from 'lit/directives/if-defined.js'
|
|
6
7
|
import throttle from 'lodash-es/throttle'
|
|
7
8
|
|
|
8
9
|
import { OxPopup } from '@operato/popup'
|
|
@@ -24,6 +25,7 @@ export class DataGridHeader extends LitElement {
|
|
|
24
25
|
display: grid;
|
|
25
26
|
grid-template-columns: var(--grid-template-columns);
|
|
26
27
|
|
|
28
|
+
border-top: var(--grid-header-top-border);
|
|
27
29
|
overflow: hidden;
|
|
28
30
|
}
|
|
29
31
|
|
|
@@ -33,7 +35,6 @@ export class DataGridHeader extends LitElement {
|
|
|
33
35
|
white-space: nowrap;
|
|
34
36
|
overflow: hidden;
|
|
35
37
|
background-color: var(--grist-background-color);
|
|
36
|
-
border-top: var(--grid-header-top-border);
|
|
37
38
|
border-bottom: var(--grid-header-bottom-border);
|
|
38
39
|
padding: var(--grid-header-padding);
|
|
39
40
|
|
|
@@ -58,6 +59,7 @@ export class DataGridHeader extends LitElement {
|
|
|
58
59
|
text-overflow: ellipsis;
|
|
59
60
|
line-height: 1.6;
|
|
60
61
|
text-transform: capitalize;
|
|
62
|
+
align-self: center;
|
|
61
63
|
}
|
|
62
64
|
|
|
63
65
|
span[for-title] mwc-icon {
|
|
@@ -66,6 +68,9 @@ export class DataGridHeader extends LitElement {
|
|
|
66
68
|
|
|
67
69
|
span[sorter],
|
|
68
70
|
span[filter] {
|
|
71
|
+
display: flex;
|
|
72
|
+
align-self: center;
|
|
73
|
+
|
|
69
74
|
padding: 0;
|
|
70
75
|
border: 0;
|
|
71
76
|
}
|
|
@@ -120,6 +125,15 @@ export class DataGridHeader extends LitElement {
|
|
|
120
125
|
z-index: 1;
|
|
121
126
|
}
|
|
122
127
|
|
|
128
|
+
.span-both {
|
|
129
|
+
grid-row: 1 / span 2; /* 1단과 2단에 걸쳐 표시 */
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.group-header {
|
|
133
|
+
grid-row: 1; /* 1행에 배치 */
|
|
134
|
+
grid-column: var(--group-start) / span var(--group-size); /* 2열부터 시작하여 2열에 걸쳐 표시 */
|
|
135
|
+
}
|
|
136
|
+
|
|
123
137
|
@media print {
|
|
124
138
|
:host {
|
|
125
139
|
grid-template-columns: var(--grid-template-print-columns);
|
|
@@ -134,6 +148,21 @@ export class DataGridHeader extends LitElement {
|
|
|
134
148
|
@property({ type: Array }) filters: FilterValue[] = []
|
|
135
149
|
@property({ type: Boolean, attribute: 'filtering-feature' }) filteringFeature: boolean = false
|
|
136
150
|
|
|
151
|
+
@state() private row1: {
|
|
152
|
+
index: number
|
|
153
|
+
column: ColumnConfig
|
|
154
|
+
clazz?: string
|
|
155
|
+
start?: number
|
|
156
|
+
size?: number
|
|
157
|
+
align?: string
|
|
158
|
+
group?: string
|
|
159
|
+
}[] = []
|
|
160
|
+
|
|
161
|
+
@state() private row2: {
|
|
162
|
+
index: number
|
|
163
|
+
column: ColumnConfig
|
|
164
|
+
}[] = []
|
|
165
|
+
|
|
137
166
|
private _lastAccVal?: number
|
|
138
167
|
private _throttledNotifier?: any
|
|
139
168
|
|
|
@@ -176,54 +205,71 @@ export class DataGridHeader extends LitElement {
|
|
|
176
205
|
}
|
|
177
206
|
|
|
178
207
|
render() {
|
|
179
|
-
|
|
208
|
+
const clazz = this.row2.length > 0 ? 'span-both' : undefined
|
|
180
209
|
|
|
181
210
|
return html`
|
|
182
|
-
${
|
|
183
|
-
|
|
184
|
-
? html`
|
|
185
|
-
<div ?gutter=${column.type == 'gutter'} ?fixed=${column.fixed} column>
|
|
186
|
-
<span
|
|
187
|
-
for-title
|
|
188
|
-
style="text-align:${column.record.align || 'left'};${column.header?.style || ''}"
|
|
189
|
-
@click=${(e: MouseEvent) => this._changeSort(column)}
|
|
190
|
-
@mouseover=${(e: MouseEvent) => {
|
|
191
|
-
const element = e.target as HTMLSpanElement
|
|
192
|
-
|
|
193
|
-
if (detectOverflow(element)) {
|
|
194
|
-
element.setAttribute('data-tooltip', element.textContent!.trim())
|
|
195
|
-
}
|
|
196
|
-
}}
|
|
197
|
-
@mouseout=${(e: MouseEvent) => {
|
|
198
|
-
const element = e.target as HTMLSpanElement
|
|
199
|
-
element.removeAttribute('data-tooltip')
|
|
200
|
-
}}
|
|
201
|
-
>${this._renderHeader(column)}
|
|
202
|
-
</span>
|
|
203
|
-
|
|
204
|
-
${column.sortable
|
|
205
|
-
? html`
|
|
206
|
-
<span sorter @click=${(e: MouseEvent) => this._changeSort(column)}>
|
|
207
|
-
${this._renderSortHeader(column)}
|
|
208
|
-
</span>
|
|
209
|
-
`
|
|
210
|
-
: nothing}
|
|
211
|
-
${this.filteringFeature && column.filter && (column.filter as FilterConfigObject).operator !== 'search'
|
|
212
|
-
? html` <span filter> ${this._renderFilterHeader(column)} </span> `
|
|
213
|
-
: nothing}
|
|
214
|
-
${column.resizable !== false
|
|
215
|
-
? html`
|
|
216
|
-
<span splitter draggable="false" @mousedown=${(e: MouseEvent) => this._mousedown(e, idx)}
|
|
217
|
-
> </span
|
|
218
|
-
>
|
|
219
|
-
`
|
|
220
|
-
: nothing}
|
|
221
|
-
</div>
|
|
222
|
-
`
|
|
223
|
-
: nothing
|
|
211
|
+
${this.row1.map(({ column, clazz, start, size, align, index, group }) =>
|
|
212
|
+
this.renderHeaderColumn({ column, clazz, start, size, align, index, group })
|
|
224
213
|
)}
|
|
225
214
|
|
|
226
|
-
<div column></div>
|
|
215
|
+
<div column class=${ifDefined(clazz)}></div>
|
|
216
|
+
|
|
217
|
+
${this.row2.map(({ column, index }) => this.renderHeaderColumn({ column, index }))}
|
|
218
|
+
`
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
renderHeaderColumn({ column, clazz, start, size, align, index, group }: any): TemplateResult {
|
|
222
|
+
if (column.hidden) {
|
|
223
|
+
return html`${nothing}`
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return html`
|
|
227
|
+
<div
|
|
228
|
+
?gutter=${column.type == 'gutter'}
|
|
229
|
+
?fixed=${column.fixed}
|
|
230
|
+
column
|
|
231
|
+
class=${ifDefined(clazz)}
|
|
232
|
+
style=${group
|
|
233
|
+
? `--group-start:${start};--group-size:${size};${column.header?.style || ''}`
|
|
234
|
+
: `${column.header?.style || ''}`}
|
|
235
|
+
>
|
|
236
|
+
<span
|
|
237
|
+
for-title
|
|
238
|
+
style="text-align:${align || column.record.align || 'left'};"
|
|
239
|
+
@click=${(e: MouseEvent) => this._changeSort(column)}
|
|
240
|
+
@mouseover=${(e: MouseEvent) => {
|
|
241
|
+
const element = e.target as HTMLSpanElement
|
|
242
|
+
|
|
243
|
+
if (detectOverflow(element)) {
|
|
244
|
+
element.setAttribute('data-tooltip', element.textContent!.trim())
|
|
245
|
+
}
|
|
246
|
+
}}
|
|
247
|
+
@mouseout=${(e: MouseEvent) => {
|
|
248
|
+
const element = e.target as HTMLSpanElement
|
|
249
|
+
element.removeAttribute('data-tooltip')
|
|
250
|
+
}}
|
|
251
|
+
>${this._renderHeader(column)}
|
|
252
|
+
</span>
|
|
253
|
+
|
|
254
|
+
${!group && column.sortable
|
|
255
|
+
? html`
|
|
256
|
+
<span sorter @click=${(e: MouseEvent) => this._changeSort(column)}>
|
|
257
|
+
${this._renderSortHeader(column)}
|
|
258
|
+
</span>
|
|
259
|
+
`
|
|
260
|
+
: nothing}
|
|
261
|
+
${!group &&
|
|
262
|
+
this.filteringFeature &&
|
|
263
|
+
column.filter &&
|
|
264
|
+
(column.filter as FilterConfigObject).operator !== 'search'
|
|
265
|
+
? html` <span filter> ${this._renderFilterHeader(column)} </span> `
|
|
266
|
+
: nothing}
|
|
267
|
+
${column.resizable !== false
|
|
268
|
+
? html`
|
|
269
|
+
<span splitter draggable="false" @mousedown=${(e: MouseEvent) => this._mousedown(e, index)}> </span>
|
|
270
|
+
`
|
|
271
|
+
: nothing}
|
|
272
|
+
</div>
|
|
227
273
|
`
|
|
228
274
|
}
|
|
229
275
|
|
|
@@ -246,6 +292,61 @@ export class DataGridHeader extends LitElement {
|
|
|
246
292
|
})
|
|
247
293
|
)
|
|
248
294
|
}
|
|
295
|
+
|
|
296
|
+
if (changes.has('columns')) {
|
|
297
|
+
this.row2 = this.columns.reduce((row2, column, index) => {
|
|
298
|
+
if (column.hidden || !column.header?.group) {
|
|
299
|
+
return row2
|
|
300
|
+
}
|
|
301
|
+
return row2.concat({
|
|
302
|
+
index,
|
|
303
|
+
column
|
|
304
|
+
} as any)
|
|
305
|
+
}, [] as any[])
|
|
306
|
+
|
|
307
|
+
const clazz = this.row2.length > 0 ? 'span-both' : undefined
|
|
308
|
+
|
|
309
|
+
var columnNo = 0
|
|
310
|
+
|
|
311
|
+
this.row1 = this.columns.reduce((row1, column, index) => {
|
|
312
|
+
if (column.hidden) {
|
|
313
|
+
return row1
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
columnNo++
|
|
317
|
+
if (!column.header?.group) {
|
|
318
|
+
return row1.concat({
|
|
319
|
+
index,
|
|
320
|
+
column,
|
|
321
|
+
clazz
|
|
322
|
+
} as any)
|
|
323
|
+
}
|
|
324
|
+
const { group, groupStyle } = column.header
|
|
325
|
+
const last = row1[row1.length - 1] as any
|
|
326
|
+
|
|
327
|
+
if (!last || group !== last.group) {
|
|
328
|
+
return row1.concat({
|
|
329
|
+
index,
|
|
330
|
+
column: {
|
|
331
|
+
...column,
|
|
332
|
+
header: {
|
|
333
|
+
renderer: () => group,
|
|
334
|
+
style: groupStyle
|
|
335
|
+
}
|
|
336
|
+
},
|
|
337
|
+
group,
|
|
338
|
+
align: 'center',
|
|
339
|
+
clazz: 'group-header',
|
|
340
|
+
start: columnNo,
|
|
341
|
+
size: 1
|
|
342
|
+
} as any)
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
last.size++
|
|
346
|
+
|
|
347
|
+
return row1
|
|
348
|
+
}, [] as any[])
|
|
349
|
+
}
|
|
249
350
|
}
|
|
250
351
|
|
|
251
352
|
_renderHeader(column: ColumnConfig) {
|
|
@@ -433,7 +534,7 @@ export class DataGridHeader extends LitElement {
|
|
|
433
534
|
e.preventDefault()
|
|
434
535
|
let column = this.columns[idx]
|
|
435
536
|
|
|
436
|
-
let width = Math.max(0, Number(column.width) + this._accumalate(e.movementX))
|
|
537
|
+
let width = Math.max(0, Number(column.width || 100) + this._accumalate(e.movementX))
|
|
437
538
|
if (width == 0) {
|
|
438
539
|
/* CLARIFY-ME 왜 마지막 이벤트의 offsetX로 음수 값이 오는가 */
|
|
439
540
|
return
|
|
@@ -123,7 +123,7 @@ export class OxGristEditor extends LitElement {
|
|
|
123
123
|
|
|
124
124
|
// 입력을 위한 키를 누르면서 편집모드가 될때는 누른 키가 처음에 입력되도록, enter 같은 것을 눌러서 편집모드가 되면 현재 값으로 편집모드 전환
|
|
125
125
|
const editorValue = this.field?.valueWithEdit ? this.field.valueWithEdit : this.formatForEditor(currentValue)
|
|
126
|
-
this.value = this._dirtyValue = editorValue
|
|
126
|
+
this.value = this._dirtyValue = isFinite(editorValue) ? Number(editorValue) : editorValue
|
|
127
127
|
|
|
128
128
|
requestAnimationFrame(() => {
|
|
129
129
|
this.focus()
|
package/src/types.ts
CHANGED
|
@@ -159,6 +159,8 @@ export type ColumnWidthCallback = (column: ColumnConfig) => string
|
|
|
159
159
|
export type HeaderConfig = {
|
|
160
160
|
renderer: HeaderRenderer
|
|
161
161
|
style?: string
|
|
162
|
+
group?: string
|
|
163
|
+
groupStyle?: string
|
|
162
164
|
}
|
|
163
165
|
export type HeaderRenderer = (column: ColumnConfig) => any
|
|
164
166
|
|
|
@@ -24,7 +24,10 @@ const fetchHandler: FetchHandler = async ({ sorters = [], filters, page, limit }
|
|
|
24
24
|
name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
|
|
25
25
|
description: idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
|
|
26
26
|
date: '2023-09-20',
|
|
27
|
-
|
|
27
|
+
routing: {
|
|
28
|
+
id: '006dc64d-4fb9-4afc-a9ea-962bd1b9e110',
|
|
29
|
+
name: '조림>세척'
|
|
30
|
+
},
|
|
28
31
|
updatedAt: Date.now()
|
|
29
32
|
}
|
|
30
33
|
})
|
|
@@ -104,19 +107,31 @@ function buildConfig({ headerFilter }: { headerFilter: boolean }) {
|
|
|
104
107
|
width: 120
|
|
105
108
|
},
|
|
106
109
|
{
|
|
107
|
-
type: '
|
|
108
|
-
name: '
|
|
109
|
-
header: '
|
|
110
|
+
type: 'object',
|
|
111
|
+
name: 'routing',
|
|
112
|
+
header: 'routing',
|
|
113
|
+
record: { editable: true, options: { queryName: 'routings' }, mandatory: true },
|
|
110
114
|
width: 180
|
|
111
115
|
},
|
|
112
116
|
{
|
|
113
117
|
type: 'datetime',
|
|
114
|
-
name: '
|
|
115
|
-
header: '
|
|
118
|
+
name: 'updatedAt',
|
|
119
|
+
header: 'updated at',
|
|
116
120
|
width: 180
|
|
117
121
|
}
|
|
118
122
|
],
|
|
119
|
-
rows: {
|
|
123
|
+
rows: {
|
|
124
|
+
selectable: {
|
|
125
|
+
multiple: false
|
|
126
|
+
},
|
|
127
|
+
handlers: {
|
|
128
|
+
click: 'select-row',
|
|
129
|
+
dblclick: () => {
|
|
130
|
+
console.log('dblclick333')
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
appendable: false
|
|
134
|
+
},
|
|
120
135
|
sorters: [
|
|
121
136
|
{
|
|
122
137
|
name: 'name',
|