@operato/data-grist 2.0.0-alpha.0 → 2.0.0-alpha.2
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 +13 -0
- package/dist/src/configure/column-builder.js +5 -5
- package/dist/src/configure/column-builder.js.map +1 -1
- package/dist/src/configure/zero-config.js +3 -1
- package/dist/src/configure/zero-config.js.map +1 -1
- package/dist/src/data-card/data-card-field.js +1 -1
- package/dist/src/data-card/data-card-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-accum-field.d.ts +1 -0
- package/dist/src/data-grid/data-grid-accum-field.js +8 -0
- package/dist/src/data-grid/data-grid-accum-field.js.map +1 -1
- package/dist/src/data-grid/data-grid-body.js +24 -2
- package/dist/src/data-grid/data-grid-body.js.map +1 -1
- package/dist/src/data-grid/data-grid-field.d.ts +1 -0
- package/dist/src/data-grid/data-grid-field.js +5 -0
- package/dist/src/data-grid/data-grid-field.js.map +1 -1
- package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js +2 -2
- package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js.map +1 -1
- package/dist/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.d.ts +7 -0
- package/dist/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.js +25 -0
- package/dist/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.js.map +1 -0
- package/dist/src/data-grid/event-handlers/data-grid-body-dblclick-handler.js +2 -2
- package/dist/src/data-grid/event-handlers/data-grid-body-dblclick-handler.js.map +1 -1
- package/dist/src/data-grid/event-handlers/data-grid-body-focus-change-handler copy.d.ts +7 -0
- package/dist/src/data-grid/event-handlers/data-grid-body-focus-change-handler copy.js +19 -0
- package/dist/src/data-grid/event-handlers/data-grid-body-focus-change-handler copy.js.map +1 -0
- package/dist/src/data-grid/event-handlers/data-grid-body-focus-change-handler.js +2 -2
- package/dist/src/data-grid/event-handlers/data-grid-body-focus-change-handler.js.map +1 -1
- package/dist/src/data-list/data-list-field.js +1 -1
- package/dist/src/data-list/data-list-field.js.map +1 -1
- package/dist/src/data-manipulator.d.ts +3 -1
- package/dist/src/data-manipulator.js +20 -7
- package/dist/src/data-manipulator.js.map +1 -1
- package/dist/src/editors/ox-grist-editor-tree.d.ts +6 -0
- package/dist/src/editors/ox-grist-editor-tree.js +27 -0
- package/dist/src/editors/ox-grist-editor-tree.js.map +1 -0
- package/dist/src/editors/ox-grist-editor.d.ts +1 -0
- package/dist/src/editors/ox-grist-editor.js +3 -0
- package/dist/src/editors/ox-grist-editor.js.map +1 -1
- package/dist/src/editors/ox-input-tree.d.ts +20 -0
- package/dist/src/editors/ox-input-tree.js +221 -0
- package/dist/src/editors/ox-input-tree.js.map +1 -0
- package/dist/src/editors/registry.js +3 -1
- package/dist/src/editors/registry.js.map +1 -1
- package/dist/src/filters/filters-form.js +1 -1
- package/dist/src/filters/filters-form.js.map +1 -1
- package/dist/src/handlers/contextmenu-tree-mutation.d.ts +3 -0
- package/dist/src/handlers/contextmenu-tree-mutation.js +82 -0
- package/dist/src/handlers/contextmenu-tree-mutation.js.map +1 -0
- package/dist/src/handlers/contextmenu-tree.d.ts +3 -0
- package/dist/src/handlers/contextmenu-tree.js +30 -0
- package/dist/src/handlers/contextmenu-tree.js.map +1 -0
- package/dist/src/handlers/move-up copy.d.ts +3 -0
- package/dist/src/handlers/move-up copy.js +26 -0
- package/dist/src/handlers/move-up copy.js.map +1 -0
- package/dist/src/handlers/registry.js +3 -1
- package/dist/src/handlers/registry.js.map +1 -1
- package/dist/src/renderers/ox-grist-renderer-tree.d.ts +1 -0
- package/dist/src/renderers/ox-grist-renderer-tree.js +5 -2
- package/dist/src/renderers/ox-grist-renderer-tree.js.map +1 -1
- package/dist/src/types.d.ts +3 -2
- package/dist/src/types.js.map +1 -1
- package/dist/stories/tree-column-with-checkbox.stories.js +8 -3
- package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
- package/dist/stories/tree-column.stories.js +8 -3
- package/dist/stories/tree-column.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/configure/column-builder.ts +4 -4
- package/src/configure/zero-config.ts +3 -1
- package/src/data-card/data-card-field.ts +1 -1
- package/src/data-grid/data-grid-accum-field.ts +7 -0
- package/src/data-grid/data-grid-body.ts +30 -2
- package/src/data-grid/data-grid-field.ts +6 -0
- package/src/data-grid/event-handlers/data-grid-body-click-handler.ts +2 -2
- package/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.ts +32 -0
- package/src/data-grid/event-handlers/data-grid-body-dblclick-handler.ts +2 -2
- package/src/data-grid/event-handlers/data-grid-body-focus-change-handler.ts +2 -2
- package/src/data-list/data-list-field.ts +1 -1
- package/src/data-manipulator.ts +25 -8
- package/src/editors/ox-grist-editor-tree.ts +27 -0
- package/src/editors/ox-grist-editor.ts +4 -0
- package/src/editors/ox-input-tree.ts +226 -0
- package/src/editors/registry.ts +3 -1
- package/src/filters/filters-form.ts +1 -1
- package/src/handlers/contextmenu-tree-mutation.ts +98 -0
- package/src/handlers/registry.ts +3 -1
- package/src/renderers/ox-grist-renderer-tree.ts +6 -2
- package/src/types.ts +4 -2
- package/stories/tree-column-with-checkbox.stories.ts +8 -3
- package/stories/tree-column.stories.ts +8 -3
@@ -36,9 +36,8 @@ export const buildColumn = (column: any): ColumnConfig => {
|
|
36
36
|
let type = typeof label
|
37
37
|
switch (type) {
|
38
38
|
case 'boolean':
|
39
|
-
let title = typeof header == 'string' ? header : name
|
40
39
|
compiled.label = {
|
41
|
-
renderer: () =>
|
40
|
+
renderer: compiled.header?.renderer || (() => name)
|
42
41
|
}
|
43
42
|
break
|
44
43
|
case 'string':
|
@@ -101,12 +100,13 @@ export const buildColumn = (column: any): ColumnConfig => {
|
|
101
100
|
}
|
102
101
|
|
103
102
|
/* handler */
|
104
|
-
var { click, dblclick, focus } = handlers || {}
|
103
|
+
var { click, dblclick, focus, contextmenu } = handlers || {}
|
105
104
|
|
106
105
|
compiled.handlers = {
|
107
106
|
click: click && getGristEventHandler(click),
|
108
107
|
dblclick: dblclick && getGristEventHandler(dblclick),
|
109
|
-
focus: focus && getGristEventHandler(focus)
|
108
|
+
focus: focus && getGristEventHandler(focus),
|
109
|
+
contextmenu: contextmenu && getGristEventHandler(contextmenu)
|
110
110
|
}
|
111
111
|
|
112
112
|
return compiled
|
@@ -18,7 +18,9 @@ export const ZERO_FIELD_RENDERER: FieldRenderer = (value, column, record, rowInd
|
|
18
18
|
|
19
19
|
export const ZERO_EVENTHANDLERSET: GristEventHandlerSet = {
|
20
20
|
click: undefined,
|
21
|
-
dblclick: undefined
|
21
|
+
dblclick: undefined,
|
22
|
+
focus: undefined,
|
23
|
+
contextmenu: undefined
|
22
24
|
}
|
23
25
|
export const ZERO_COLUMNS: ColumnConfig[] = []
|
24
26
|
export const ZERO_GROUPS: GroupConfig[] = []
|
@@ -89,7 +89,7 @@ export class DataCardField extends LitElement {
|
|
89
89
|
|
90
90
|
if (typeof label == 'object') {
|
91
91
|
let { renderer: labelRenderer } = label
|
92
|
-
return html`<label>${labelRenderer()}</label>${recordRenderer(value, column, record, rowIndex, this)}`
|
92
|
+
return html`<label>${labelRenderer(column)}</label>${recordRenderer(value, column, record, rowIndex, this)}`
|
93
93
|
} else {
|
94
94
|
return html`${recordRenderer(value, column, record, rowIndex, this)}`
|
95
95
|
}
|
@@ -58,6 +58,7 @@ export class DataGridAccumField extends LitElement {
|
|
58
58
|
@property({ type: Boolean }) editing = false
|
59
59
|
@property({ type: Object }) value = {}
|
60
60
|
@property({ attribute: false }) emphasized: any = false
|
61
|
+
@property({ type: String }) fixed?: string
|
61
62
|
|
62
63
|
render(): TemplateResult {
|
63
64
|
if (!this.column || !this.column.accumulator) {
|
@@ -90,5 +91,11 @@ export class DataGridAccumField extends LitElement {
|
|
90
91
|
this.style.setProperty('--data-grid-field-text-align', align)
|
91
92
|
}
|
92
93
|
}
|
94
|
+
|
95
|
+
if (changes.has('fixed')) {
|
96
|
+
if (this.fixed) {
|
97
|
+
this.style.left = this.fixed + 'px'
|
98
|
+
}
|
99
|
+
}
|
93
100
|
}
|
94
101
|
}
|
@@ -18,6 +18,7 @@ import { DataGridField } from './data-grid-field'
|
|
18
18
|
import { dataGridBodyClickHandler } from './event-handlers/data-grid-body-click-handler'
|
19
19
|
import { dataGridBodyDblclickHandler } from './event-handlers/data-grid-body-dblclick-handler'
|
20
20
|
import { dataGridBodyFocusChangeHandler } from './event-handlers/data-grid-body-focus-change-handler'
|
21
|
+
import { dataGridBodyContextMenuHandler } from './event-handlers/data-grid-body-contextmenu-handler'
|
21
22
|
import { dataGridBodyKeydownHandler } from './event-handlers/data-grid-body-keydown-handler'
|
22
23
|
import { accumulate } from '../accumulator/accumulator'
|
23
24
|
|
@@ -75,7 +76,7 @@ export class DataGridBody extends LitElement {
|
|
75
76
|
[fixed] {
|
76
77
|
position: sticky;
|
77
78
|
background-color: var(--grid-record-background-color);
|
78
|
-
z-index:
|
79
|
+
z-index: 2; /* 고정된 열을 다른 열 위에 표시. */
|
79
80
|
}
|
80
81
|
|
81
82
|
:host([raised]) [fixed] {
|
@@ -88,6 +89,10 @@ export class DataGridBody extends LitElement {
|
|
88
89
|
bottom: 0;
|
89
90
|
z-index: 1;
|
90
91
|
}
|
92
|
+
|
93
|
+
ox-grid-accum-field[fixed] {
|
94
|
+
background-color: var(--grid-accum-record-background-color, #ccc);
|
95
|
+
}
|
91
96
|
`
|
92
97
|
]
|
93
98
|
|
@@ -208,6 +213,7 @@ export class DataGridBody extends LitElement {
|
|
208
213
|
.column=${column}
|
209
214
|
.record=${accumRecord!}
|
210
215
|
.value=${accumRecord[column.name]}
|
216
|
+
fixed=${ifDefined(this.fixedLefts[idxColumn])}
|
211
217
|
></ox-grid-accum-field>
|
212
218
|
`
|
213
219
|
)}
|
@@ -261,6 +267,27 @@ export class DataGridBody extends LitElement {
|
|
261
267
|
this.setSelectBlock(start, end)
|
262
268
|
})
|
263
269
|
|
270
|
+
this.renderRoot.addEventListener('contextmenu', (event: Event) => {
|
271
|
+
const e = event as MouseEvent
|
272
|
+
this.setSelectBlock()
|
273
|
+
|
274
|
+
this._draggable = false
|
275
|
+
|
276
|
+
var target = (e.target as Element).closest('ox-grid-field') as DataGridField
|
277
|
+
var { rowIndex, columnIndex } = target || {}
|
278
|
+
|
279
|
+
this.dispatchEvent(
|
280
|
+
new CustomEvent('focus-change', {
|
281
|
+
bubbles: true,
|
282
|
+
composed: true,
|
283
|
+
detail: {
|
284
|
+
row: rowIndex,
|
285
|
+
column: columnIndex
|
286
|
+
}
|
287
|
+
})
|
288
|
+
)
|
289
|
+
})
|
290
|
+
|
264
291
|
this.renderRoot.addEventListener('mousedown', (event: Event) => {
|
265
292
|
const e = event as MouseEvent
|
266
293
|
this.setSelectBlock()
|
@@ -285,7 +312,7 @@ export class DataGridBody extends LitElement {
|
|
285
312
|
})
|
286
313
|
)
|
287
314
|
|
288
|
-
if (!isNaN(rowIndex) && !isNaN(columnIndex)) {
|
315
|
+
if (columnIndex >= 0 && target.editableOnClick && !isNaN(rowIndex) && !isNaN(columnIndex)) {
|
289
316
|
this.startEditTarget(rowIndex, columnIndex)
|
290
317
|
}
|
291
318
|
})
|
@@ -318,6 +345,7 @@ export class DataGridBody extends LitElement {
|
|
318
345
|
|
319
346
|
this.renderRoot.addEventListener('click', dataGridBodyClickHandler.bind(this))
|
320
347
|
this.renderRoot.addEventListener('dblclick', dataGridBodyDblclickHandler.bind(this))
|
348
|
+
this.renderRoot.addEventListener('contextmenu', dataGridBodyContextMenuHandler.bind(this))
|
321
349
|
|
322
350
|
this.addEventListener('focus-change', dataGridBodyFocusChangeHandler.bind(this))
|
323
351
|
|
@@ -173,4 +173,10 @@ export class DataGridField extends LitElement {
|
|
173
173
|
this.removeAttribute('emphasized-row')
|
174
174
|
}
|
175
175
|
}
|
176
|
+
|
177
|
+
get editableOnClick() {
|
178
|
+
const renderer = this.renderRoot.firstElementChild as HTMLElement
|
179
|
+
//@ts-ignore
|
180
|
+
return renderer && 'editableOnClick' in renderer ? renderer.editableOnClick : true
|
181
|
+
}
|
176
182
|
}
|
@@ -56,10 +56,10 @@ export function dataGridBodyClickHandler(this: DataGridBody, e: Event): void {
|
|
56
56
|
/* do column click handler */
|
57
57
|
if (column) {
|
58
58
|
var { click } = column.handlers
|
59
|
-
click && click(this.columns, this.data, column, record, rowIndex, target)
|
59
|
+
click && click(this.columns, this.data, column, record, rowIndex, target, e)
|
60
60
|
}
|
61
61
|
|
62
62
|
/* do rows click handler */
|
63
63
|
var { click: rowsClick } = this.config.rows.handlers
|
64
|
-
rowsClick && rowsClick(this.columns, this.data, column, record, rowIndex, target)
|
64
|
+
rowsClick && rowsClick(this.columns, this.data, column, record, rowIndex, target, e)
|
65
65
|
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { DataGridBody } from '../data-grid-body'
|
2
|
+
import { DataGridField } from '../data-grid-field'
|
3
|
+
|
4
|
+
/**
|
5
|
+
* ox-grid-body 의 focus-change handler
|
6
|
+
*
|
7
|
+
* - handler의 this 는 ox-grid-body임.
|
8
|
+
*/
|
9
|
+
export async function dataGridBodyContextMenuHandler(this: DataGridBody, e: Event): Promise<void> {
|
10
|
+
e.stopPropagation()
|
11
|
+
|
12
|
+
if (this.editTarget) {
|
13
|
+
/* editTarget이 새로 설정되지 않았다면, 이후 기능이 실행된다. */
|
14
|
+
return
|
15
|
+
}
|
16
|
+
|
17
|
+
/* target should be 'ox-grid-field' */
|
18
|
+
var target = (e.target as Element).closest('ox-grid-field') as DataGridField
|
19
|
+
var { column, record, rowIndex, columnIndex } = target || {}
|
20
|
+
|
21
|
+
var { column, record } = target || {}
|
22
|
+
|
23
|
+
/* do column contextmenu handler */
|
24
|
+
if (column) {
|
25
|
+
var { contextmenu } = column.handlers
|
26
|
+
contextmenu && contextmenu(this.columns, this.data, column, record, rowIndex, target, e)
|
27
|
+
}
|
28
|
+
|
29
|
+
/* do rows contextmenu handler */
|
30
|
+
var { contextmenu: rowsContextMenu } = this.config.rows.handlers
|
31
|
+
rowsContextMenu && rowsContextMenu(this.columns, this.data, column, record, rowIndex, target, e)
|
32
|
+
}
|
@@ -33,10 +33,10 @@ export async function dataGridBodyDblclickHandler(this: DataGridBody, e: Event):
|
|
33
33
|
/* do column dblclick handler */
|
34
34
|
if (column) {
|
35
35
|
var { dblclick } = column.handlers
|
36
|
-
dblclick && dblclick(this.columns, this.data, column, record, rowIndex, target)
|
36
|
+
dblclick && dblclick(this.columns, this.data, column, record, rowIndex, target, e)
|
37
37
|
}
|
38
38
|
|
39
39
|
/* do rows dblclick handler */
|
40
40
|
var { dblclick: rowsDblclick } = this.config.rows.handlers
|
41
|
-
rowsDblclick && rowsDblclick(this.columns, this.data, column, record, rowIndex, target)
|
41
|
+
rowsDblclick && rowsDblclick(this.columns, this.data, column, record, rowIndex, target, e)
|
42
42
|
}
|
@@ -15,10 +15,10 @@ export async function dataGridBodyFocusChangeHandler(this: DataGridBody, e: Even
|
|
15
15
|
/* do column focus handler */
|
16
16
|
if (column) {
|
17
17
|
var { focus } = column.handlers
|
18
|
-
focus && focus(this.columns, this.data, column, record, rowIndex, target)
|
18
|
+
focus && focus(this.columns, this.data, column, record, rowIndex, target, e)
|
19
19
|
}
|
20
20
|
|
21
21
|
/* do rows focus handler */
|
22
22
|
var { focus: rowsFocus } = this.config.rows.handlers
|
23
|
-
rowsFocus && rowsFocus(this.columns, this.data, column, record, rowIndex, target)
|
23
|
+
rowsFocus && rowsFocus(this.columns, this.data, column, record, rowIndex, target, e)
|
24
24
|
}
|
@@ -77,7 +77,7 @@ export class DataListField extends LitElement {
|
|
77
77
|
|
78
78
|
if (typeof label == 'object') {
|
79
79
|
let { renderer: labelRenderer } = label
|
80
|
-
return html`<label>${labelRenderer()}</label>${fieldRenderer(value, column, record, rowIndex, this)}`
|
80
|
+
return html`<label>${labelRenderer(column)}</label>${fieldRenderer(value, column, record, rowIndex, this)}`
|
81
81
|
} else {
|
82
82
|
return html`${fieldRenderer(value, column, record, rowIndex, this)}`
|
83
83
|
}
|
package/src/data-manipulator.ts
CHANGED
@@ -15,8 +15,8 @@ import {
|
|
15
15
|
export class DataManipulator extends LitElement {
|
16
16
|
@property({ type: Object }) config: GristConfig = ZERO_CONFIG
|
17
17
|
@property({ type: Object }) data: GristData = ZERO_DATA
|
18
|
-
@property({ type:
|
19
|
-
@property({ type:
|
18
|
+
@property({ type: Array }) sorters: SortersConfig = []
|
19
|
+
@property({ type: Array }) filters: FilterValue[] = []
|
20
20
|
@property({ type: Object }) pagination: PaginationConfig = {}
|
21
21
|
|
22
22
|
constructor() {
|
@@ -64,6 +64,8 @@ export class DataManipulator extends LitElement {
|
|
64
64
|
})
|
65
65
|
|
66
66
|
/* tree processing */
|
67
|
+
this.addEventListener('collapse-all', (e: Event) => this.onCollapseAll(e as CustomEvent))
|
68
|
+
this.addEventListener('expand-all', (e: Event) => this.onExpandAll(e as CustomEvent))
|
67
69
|
this.addEventListener('collapsed', (e: Event) => this.onCollapsed(e as CustomEvent))
|
68
70
|
this.addEventListener('expanded', (e: Event) => this.onExpanded(e as CustomEvent))
|
69
71
|
this.addEventListener('check-in-tree', (e: Event) => this.onCheckInTree(e as CustomEvent))
|
@@ -213,6 +215,14 @@ export class DataManipulator extends LitElement {
|
|
213
215
|
this.requestUpdate()
|
214
216
|
}
|
215
217
|
|
218
|
+
onCollapseAll(e: CustomEvent) {
|
219
|
+
this.refresh(false)
|
220
|
+
}
|
221
|
+
|
222
|
+
onExpandAll(e: CustomEvent) {
|
223
|
+
this.refresh(true)
|
224
|
+
}
|
225
|
+
|
216
226
|
onCollapsed(e: CustomEvent) {
|
217
227
|
const record = e.detail
|
218
228
|
record.__expanded__ = false
|
@@ -228,8 +238,6 @@ export class DataManipulator extends LitElement {
|
|
228
238
|
}
|
229
239
|
|
230
240
|
onCheckInTree(e: CustomEvent) {
|
231
|
-
const self = this
|
232
|
-
|
233
241
|
function walkTreeCheckedUpdate(record: GristRecord, checked: 'checked' | 'unchecked') {
|
234
242
|
const children = record.__children__
|
235
243
|
|
@@ -287,7 +295,7 @@ export class DataManipulator extends LitElement {
|
|
287
295
|
* Therefore, it will be deprecated.
|
288
296
|
* @method
|
289
297
|
*/
|
290
|
-
refresh() {
|
298
|
+
refresh(forceExpandOrCollapse?: boolean) {
|
291
299
|
/*
|
292
300
|
- TODO 여기에서 TREE 형태 데이터의 접고, 펴는 것을 재구성한다.
|
293
301
|
- 동적으로 서브항목을 fetch 하는 기능은 제공하지 않는다.
|
@@ -302,15 +310,24 @@ export class DataManipulator extends LitElement {
|
|
302
310
|
) /* __depth__ 가 설정되지 않았거나, 0 인 경우만 수집 */
|
303
311
|
this.data = {
|
304
312
|
...this.data,
|
305
|
-
records: ([] as GristRecord[]).concat(
|
313
|
+
records: ([] as GristRecord[]).concat(
|
314
|
+
...toplevelRecords.map(record => this.traverseRefresh(record, forceExpandOrCollapse))
|
315
|
+
)
|
306
316
|
}
|
307
317
|
}
|
308
318
|
|
309
|
-
private traverseRefresh(record: GristRecord): GristRecord[] {
|
319
|
+
private traverseRefresh(record: GristRecord, forceExpandOrCollapse?: boolean): GristRecord[] {
|
320
|
+
if (forceExpandOrCollapse !== undefined) {
|
321
|
+
record = {
|
322
|
+
...record,
|
323
|
+
__expanded__: forceExpandOrCollapse
|
324
|
+
}
|
325
|
+
}
|
326
|
+
|
310
327
|
const { __expanded__, __children__ = [] } = record
|
311
328
|
|
312
329
|
if (__expanded__ && __children__.length > 0) {
|
313
|
-
return [record].concat(...__children__.map(child => this.traverseRefresh(child)))
|
330
|
+
return [record].concat(...__children__.map(child => this.traverseRefresh(child, forceExpandOrCollapse)))
|
314
331
|
} else {
|
315
332
|
return [record]
|
316
333
|
}
|
@@ -0,0 +1,27 @@
|
|
1
|
+
import './ox-input-tree'
|
2
|
+
|
3
|
+
import { html, css } from 'lit'
|
4
|
+
import { customElement, query } from 'lit/decorators.js'
|
5
|
+
|
6
|
+
import { OxGristEditor } from './ox-grist-editor.js'
|
7
|
+
|
8
|
+
@customElement('ox-grist-editor-tree')
|
9
|
+
export class OxGristEditorTree extends OxGristEditor {
|
10
|
+
static styles = [
|
11
|
+
css`
|
12
|
+
:host {
|
13
|
+
flex: 1;
|
14
|
+
}
|
15
|
+
|
16
|
+
ox-input-tree {
|
17
|
+
flex: 1;
|
18
|
+
}
|
19
|
+
`
|
20
|
+
]
|
21
|
+
|
22
|
+
get editorTemplate() {
|
23
|
+
var { selectable } = this.column.record.options || {}
|
24
|
+
|
25
|
+
return html`<ox-input-tree .value=${this.value} .record=${this.record} ?selectable=${selectable}></ox-input-tree>`
|
26
|
+
}
|
27
|
+
}
|
@@ -91,6 +91,10 @@ export class OxGristEditor extends LitElement {
|
|
91
91
|
return this.renderRoot.firstElementChild as HTMLElement
|
92
92
|
}
|
93
93
|
|
94
|
+
get directEditable() {
|
95
|
+
return true
|
96
|
+
}
|
97
|
+
|
94
98
|
async firstUpdated() {
|
95
99
|
this.renderRoot.addEventListener('change', this._onchange.bind(this))
|
96
100
|
this.renderRoot.addEventListener('focusout', this._onfocusout.bind(this))
|
@@ -0,0 +1,226 @@
|
|
1
|
+
/**
|
2
|
+
* @license Copyright © HatioLab Inc. All rights reserved.
|
3
|
+
*/
|
4
|
+
|
5
|
+
import { PropertyValues, css, html, nothing } from 'lit'
|
6
|
+
import { customElement, property, query, state } from 'lit/decorators.js'
|
7
|
+
import { ifDefined } from 'lit/directives/if-defined.js'
|
8
|
+
|
9
|
+
import { OxFormField } from '@operato/input'
|
10
|
+
import { GristRecord } from '../types'
|
11
|
+
|
12
|
+
@customElement('ox-input-tree')
|
13
|
+
export class OxInputTree extends OxFormField {
|
14
|
+
static styles = css`
|
15
|
+
:host {
|
16
|
+
overflow: hidden;
|
17
|
+
}
|
18
|
+
|
19
|
+
div[wrap] {
|
20
|
+
flex: 1;
|
21
|
+
|
22
|
+
position: relative;
|
23
|
+
|
24
|
+
display: flex;
|
25
|
+
align-items: center;
|
26
|
+
gap: 6px;
|
27
|
+
|
28
|
+
padding-left: calc(var(--tree-depth, 0) * 18px);
|
29
|
+
}
|
30
|
+
|
31
|
+
span[expander] {
|
32
|
+
display: inline-block;
|
33
|
+
vertical-align: middle;
|
34
|
+
width: 12px;
|
35
|
+
height: 20px;
|
36
|
+
cursor: pointer;
|
37
|
+
position: relative;
|
38
|
+
}
|
39
|
+
|
40
|
+
span[expander][collapsed]::before {
|
41
|
+
position: absolute;
|
42
|
+
top: 50%;
|
43
|
+
left: 50%;
|
44
|
+
transform: translate(-25%, -50%) rotate(-90deg);
|
45
|
+
content: ' ';
|
46
|
+
border: 5px solid transparent;
|
47
|
+
border-top: 5px solid var(--primary-color, #1890ff);
|
48
|
+
}
|
49
|
+
|
50
|
+
span[expander][expanded]::before {
|
51
|
+
position: absolute;
|
52
|
+
top: 50%;
|
53
|
+
left: 50%;
|
54
|
+
transform: translate(-50%, -25%);
|
55
|
+
content: ' ';
|
56
|
+
border: 5px solid transparent;
|
57
|
+
border-top: 5px solid var(--primary-color, #1890ff);
|
58
|
+
}
|
59
|
+
|
60
|
+
span[checkbox] {
|
61
|
+
display: inline-block;
|
62
|
+
vertical-align: middle;
|
63
|
+
width: 12px;
|
64
|
+
height: 20px;
|
65
|
+
cursor: pointer;
|
66
|
+
position: relative;
|
67
|
+
}
|
68
|
+
|
69
|
+
span[checkbox]::before {
|
70
|
+
cursor: pointer;
|
71
|
+
position: absolute;
|
72
|
+
top: 50%;
|
73
|
+
left: 50%;
|
74
|
+
transform: translate(-50%, -50%);
|
75
|
+
content: ' ';
|
76
|
+
display: block;
|
77
|
+
width: 10px;
|
78
|
+
height: 10px;
|
79
|
+
border: 1px solid var(--primary-color, #1890ff);
|
80
|
+
border-radius: 2px;
|
81
|
+
}
|
82
|
+
|
83
|
+
span[checkbox][checked='checked']::before {
|
84
|
+
background-color: var(--primary-color, #1890ff);
|
85
|
+
border-color: var(--primary-color, #1890ff);
|
86
|
+
}
|
87
|
+
|
88
|
+
span[checkbox][checked='checked']::after {
|
89
|
+
position: absolute;
|
90
|
+
content: ' ';
|
91
|
+
display: block;
|
92
|
+
top: 50%;
|
93
|
+
left: 50%;
|
94
|
+
width: 3px;
|
95
|
+
height: 7px;
|
96
|
+
border: 2px solid #fff;
|
97
|
+
border-top: none;
|
98
|
+
border-left: none;
|
99
|
+
-webkit-transform: translate(-50%, -50%) rotate(45deg);
|
100
|
+
-ms-transform: translate(-50%, -50%) rotate(45deg);
|
101
|
+
transform: translate(-50%, -50%) rotate(45deg);
|
102
|
+
}
|
103
|
+
|
104
|
+
span[checkbox][checked='half-checked']::before {
|
105
|
+
background-color: var(--primary-color, #1890ff);
|
106
|
+
border-color: var(--primary-color, #1890ff);
|
107
|
+
}
|
108
|
+
|
109
|
+
span[checkbox][checked='half-checked']::after {
|
110
|
+
position: absolute;
|
111
|
+
content: ' ';
|
112
|
+
display: block;
|
113
|
+
top: 50%;
|
114
|
+
left: 50%;
|
115
|
+
transform: translate(-50%, -50%);
|
116
|
+
width: 10px;
|
117
|
+
height: 2px;
|
118
|
+
background-color: #fff;
|
119
|
+
}
|
120
|
+
|
121
|
+
span[label] {
|
122
|
+
flex: 1;
|
123
|
+
}
|
124
|
+
|
125
|
+
input {
|
126
|
+
width: 100%;
|
127
|
+
height: 100%;
|
128
|
+
border: 0;
|
129
|
+
background-color: transparent;
|
130
|
+
box-sizing: border-box;
|
131
|
+
}
|
132
|
+
|
133
|
+
input:focus {
|
134
|
+
outline: none;
|
135
|
+
}
|
136
|
+
`
|
137
|
+
|
138
|
+
@property({ type: Object }) record!: GristRecord
|
139
|
+
@property({ type: Boolean }) selectable?: boolean
|
140
|
+
|
141
|
+
@state() private checked?: 'checked' | 'half-checked' | 'unchecked'
|
142
|
+
@state() private expanded?: boolean = false
|
143
|
+
|
144
|
+
@query('input') input!: HTMLInputElement
|
145
|
+
|
146
|
+
render() {
|
147
|
+
var { __children__ } = this.record
|
148
|
+
|
149
|
+
const expandable = __children__ && __children__.length > 0
|
150
|
+
|
151
|
+
return html`
|
152
|
+
<div wrap>
|
153
|
+
${expandable
|
154
|
+
? html`
|
155
|
+
<span
|
156
|
+
expander
|
157
|
+
@click=${this.onClickExpander.bind(this)}
|
158
|
+
?expanded=${this.expanded}
|
159
|
+
?collapsed=${!this.expanded}
|
160
|
+
></span>
|
161
|
+
`
|
162
|
+
: html`<span expander></span>`}
|
163
|
+
${this.selectable
|
164
|
+
? html` <span checkbox @click=${this.onClickCheckbox.bind(this)} checked=${ifDefined(this.checked)}></span>`
|
165
|
+
: nothing}
|
166
|
+
|
167
|
+
<span label
|
168
|
+
><input
|
169
|
+
value=${ifDefined(this.value)}
|
170
|
+
@change=${(e: Event) => {
|
171
|
+
e.stopPropagation()
|
172
|
+
this.value = (e.target as HTMLInputElement).value
|
173
|
+
this.dispatchEvent(new CustomEvent('change', { bubbles: true, composed: true }))
|
174
|
+
}}
|
175
|
+
focus
|
176
|
+
/></span>
|
177
|
+
|
178
|
+
<!-- <span label>${this.value}</span> -->
|
179
|
+
</div>
|
180
|
+
`
|
181
|
+
}
|
182
|
+
|
183
|
+
updated(changes: PropertyValues<this>) {
|
184
|
+
var { __depth__, __check_in_tree__, __expanded__ } = this.record
|
185
|
+
this.checked = __check_in_tree__
|
186
|
+
this.expanded = __expanded__
|
187
|
+
|
188
|
+
this.style.setProperty('--tree-depth', String(__depth__))
|
189
|
+
}
|
190
|
+
|
191
|
+
focus() {
|
192
|
+
this.input.focus()
|
193
|
+
}
|
194
|
+
|
195
|
+
select() {
|
196
|
+
this.input.select()
|
197
|
+
}
|
198
|
+
|
199
|
+
onClickCheckbox(e: MouseEvent) {
|
200
|
+
e.stopPropagation()
|
201
|
+
|
202
|
+
this.dispatchEvent(
|
203
|
+
new CustomEvent('check-in-tree', {
|
204
|
+
bubbles: true,
|
205
|
+
composed: true,
|
206
|
+
detail: this.record
|
207
|
+
})
|
208
|
+
)
|
209
|
+
|
210
|
+
this.requestUpdate()
|
211
|
+
}
|
212
|
+
|
213
|
+
onClickExpander(e: MouseEvent) {
|
214
|
+
e.stopPropagation()
|
215
|
+
|
216
|
+
this.dispatchEvent(
|
217
|
+
new CustomEvent(this.record.__expanded__ ? 'collapsed' : 'expanded', {
|
218
|
+
bubbles: true,
|
219
|
+
composed: true,
|
220
|
+
detail: this.record
|
221
|
+
})
|
222
|
+
)
|
223
|
+
|
224
|
+
this.requestUpdate()
|
225
|
+
}
|
226
|
+
}
|
package/src/editors/registry.ts
CHANGED
@@ -17,6 +17,7 @@ import { OxGristEditorTel } from './ox-grist-editor-tel'
|
|
17
17
|
import { OxGristEditorText } from './ox-grist-editor-text'
|
18
18
|
import { OxGristEditorTextarea } from './ox-grist-editor-textarea'
|
19
19
|
import { OxGristEditorTime } from './ox-grist-editor-time'
|
20
|
+
import { OxGristEditorTree } from './ox-grist-editor-tree'
|
20
21
|
import { OxGristEditorWeek } from './ox-grist-editor-week'
|
21
22
|
|
22
23
|
var EDITORS: { [name: string]: { new (): OxGristEditor } } = {
|
@@ -42,7 +43,8 @@ var EDITORS: { [name: string]: { new (): OxGristEditor } } = {
|
|
42
43
|
link: OxGristEditorText,
|
43
44
|
image: OxGristEditorImage,
|
44
45
|
file: OxGristEditorFile,
|
45
|
-
'string[]': OxGristEditorMultipleSelect
|
46
|
+
'string[]': OxGristEditorMultipleSelect,
|
47
|
+
tree: OxGristEditorTree
|
46
48
|
}
|
47
49
|
|
48
50
|
export function registerEditor(type: string, editor: { new (): OxGristEditor }) {
|
@@ -151,7 +151,7 @@ export class FiltersForm extends LitElement {
|
|
151
151
|
filterLabel !== undefined
|
152
152
|
? filterLabel
|
153
153
|
: typeof label === 'object' && label.renderer
|
154
|
-
? label.renderer()
|
154
|
+
? label.renderer(column)
|
155
155
|
: header.renderer(column) || name
|
156
156
|
|
157
157
|
const idx = operator === 'between' ? 1 : 0
|