@operato/data-grist 2.0.0-alpha.0 → 2.0.0-alpha.3

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.
Files changed (83) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/src/configure/column-builder.js +5 -5
  3. package/dist/src/configure/column-builder.js.map +1 -1
  4. package/dist/src/configure/zero-config.js +3 -1
  5. package/dist/src/configure/zero-config.js.map +1 -1
  6. package/dist/src/data-card/data-card-field.js +1 -1
  7. package/dist/src/data-card/data-card-field.js.map +1 -1
  8. package/dist/src/data-grid/data-grid-accum-field.d.ts +1 -0
  9. package/dist/src/data-grid/data-grid-accum-field.js +8 -0
  10. package/dist/src/data-grid/data-grid-accum-field.js.map +1 -1
  11. package/dist/src/data-grid/data-grid-body.js +24 -3
  12. package/dist/src/data-grid/data-grid-body.js.map +1 -1
  13. package/dist/src/data-grid/data-grid-field.d.ts +1 -0
  14. package/dist/src/data-grid/data-grid-field.js +5 -0
  15. package/dist/src/data-grid/data-grid-field.js.map +1 -1
  16. package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js +2 -2
  17. package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js.map +1 -1
  18. package/dist/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.d.ts +7 -0
  19. package/dist/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.js +25 -0
  20. package/dist/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.js.map +1 -0
  21. package/dist/src/data-grid/event-handlers/data-grid-body-dblclick-handler.js +2 -2
  22. package/dist/src/data-grid/event-handlers/data-grid-body-dblclick-handler.js.map +1 -1
  23. package/dist/src/data-grid/event-handlers/data-grid-body-focus-change-handler.js +2 -2
  24. package/dist/src/data-grid/event-handlers/data-grid-body-focus-change-handler.js.map +1 -1
  25. package/dist/src/data-list/data-list-field.js +1 -1
  26. package/dist/src/data-list/data-list-field.js.map +1 -1
  27. package/dist/src/data-manipulator.d.ts +7 -3
  28. package/dist/src/data-manipulator.js +86 -18
  29. package/dist/src/data-manipulator.js.map +1 -1
  30. package/dist/src/editors/ox-grist-editor-tree.d.ts +6 -0
  31. package/dist/src/editors/ox-grist-editor-tree.js +27 -0
  32. package/dist/src/editors/ox-grist-editor-tree.js.map +1 -0
  33. package/dist/src/editors/ox-grist-editor.d.ts +1 -0
  34. package/dist/src/editors/ox-grist-editor.js +3 -0
  35. package/dist/src/editors/ox-grist-editor.js.map +1 -1
  36. package/dist/src/editors/ox-input-tree.d.ts +20 -0
  37. package/dist/src/editors/ox-input-tree.js +221 -0
  38. package/dist/src/editors/ox-input-tree.js.map +1 -0
  39. package/dist/src/editors/registry.js +3 -1
  40. package/dist/src/editors/registry.js.map +1 -1
  41. package/dist/src/filters/filters-form.js +1 -1
  42. package/dist/src/filters/filters-form.js.map +1 -1
  43. package/dist/src/handlers/contextmenu-tree-mutation.d.ts +3 -0
  44. package/dist/src/handlers/contextmenu-tree-mutation.js +82 -0
  45. package/dist/src/handlers/contextmenu-tree-mutation.js.map +1 -0
  46. package/dist/src/handlers/registry.js +3 -1
  47. package/dist/src/handlers/registry.js.map +1 -1
  48. package/dist/src/renderers/ox-grist-renderer-tree.d.ts +1 -0
  49. package/dist/src/renderers/ox-grist-renderer-tree.js +6 -3
  50. package/dist/src/renderers/ox-grist-renderer-tree.js.map +1 -1
  51. package/dist/src/types.d.ts +437 -6
  52. package/dist/src/types.js +9 -0
  53. package/dist/src/types.js.map +1 -1
  54. package/dist/stories/tree-column-with-checkbox.stories.js +8 -3
  55. package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
  56. package/dist/stories/tree-column.stories.js +8 -3
  57. package/dist/stories/tree-column.stories.js.map +1 -1
  58. package/dist/tsconfig.tsbuildinfo +1 -1
  59. package/docs/gutter/gutter.md +7 -0
  60. package/package.json +4 -4
  61. package/src/configure/column-builder.ts +4 -4
  62. package/src/configure/zero-config.ts +3 -1
  63. package/src/data-card/data-card-field.ts +1 -1
  64. package/src/data-grid/data-grid-accum-field.ts +7 -0
  65. package/src/data-grid/data-grid-body.ts +30 -3
  66. package/src/data-grid/data-grid-field.ts +6 -0
  67. package/src/data-grid/event-handlers/data-grid-body-click-handler.ts +2 -2
  68. package/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.ts +32 -0
  69. package/src/data-grid/event-handlers/data-grid-body-dblclick-handler.ts +2 -2
  70. package/src/data-grid/event-handlers/data-grid-body-focus-change-handler.ts +2 -2
  71. package/src/data-list/data-list-field.ts +1 -1
  72. package/src/data-manipulator.ts +109 -22
  73. package/src/editors/ox-grist-editor-tree.ts +27 -0
  74. package/src/editors/ox-grist-editor.ts +4 -0
  75. package/src/editors/ox-input-tree.ts +226 -0
  76. package/src/editors/registry.ts +3 -1
  77. package/src/filters/filters-form.ts +1 -1
  78. package/src/handlers/contextmenu-tree-mutation.ts +98 -0
  79. package/src/handlers/registry.ts +3 -1
  80. package/src/renderers/ox-grist-renderer-tree.ts +7 -3
  81. package/src/types.ts +446 -6
  82. package/stories/tree-column-with-checkbox.stories.ts +8 -3
  83. package/stories/tree-column.stories.ts +8 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@operato/data-grist",
3
- "version": "2.0.0-alpha.0",
3
+ "version": "2.0.0-alpha.3",
4
4
  "description": "User interface for grid (desktop) and list (mobile)",
5
5
  "author": "heartyoh",
6
6
  "main": "dist/index.js",
@@ -57,8 +57,8 @@
57
57
  "dependencies": {
58
58
  "@material/mwc-icon": "^0.27.0",
59
59
  "@operato/headroom": "^2.0.0-alpha.0",
60
- "@operato/input": "^2.0.0-alpha.0",
61
- "@operato/popup": "^2.0.0-alpha.0",
60
+ "@operato/input": "^2.0.0-alpha.3",
61
+ "@operato/popup": "^2.0.0-alpha.2",
62
62
  "@operato/pull-to-refresh": "^2.0.0-alpha.0",
63
63
  "@operato/styles": "^2.0.0-alpha.0",
64
64
  "@operato/utils": "^2.0.0-alpha.0",
@@ -100,5 +100,5 @@
100
100
  "prettier --write"
101
101
  ]
102
102
  },
103
- "gitHead": "f995e977847947a1ac4043ff7c627a5cf2ada67b"
103
+ "gitHead": "9943c2c54a27be3619920543344c699d3a9a55de"
104
104
  }
@@ -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: () => title
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: 1; /* 고정된 열을 다른 열 위에 표시. */
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
 
@@ -135,7 +140,6 @@ export class DataGridBody extends LitElement {
135
140
  var columns = this.columns.filter(column => !column.hidden)
136
141
  var data = this.data
137
142
  var { records } = data
138
- records = records.filter(record => !record.__parent__ || !record.__parent__.collapsed)
139
143
  var { appendable, classifier, accumulator } = this.config.rows
140
144
  const { start, end } = this._selectBlock || {}
141
145
 
@@ -208,6 +212,7 @@ export class DataGridBody extends LitElement {
208
212
  .column=${column}
209
213
  .record=${accumRecord!}
210
214
  .value=${accumRecord[column.name]}
215
+ fixed=${ifDefined(this.fixedLefts[idxColumn])}
211
216
  ></ox-grid-accum-field>
212
217
  `
213
218
  )}
@@ -261,6 +266,27 @@ export class DataGridBody extends LitElement {
261
266
  this.setSelectBlock(start, end)
262
267
  })
263
268
 
269
+ this.renderRoot.addEventListener('contextmenu', (event: Event) => {
270
+ const e = event as MouseEvent
271
+ this.setSelectBlock()
272
+
273
+ this._draggable = false
274
+
275
+ var target = (e.target as Element).closest('ox-grid-field') as DataGridField
276
+ var { rowIndex, columnIndex } = target || {}
277
+
278
+ this.dispatchEvent(
279
+ new CustomEvent('focus-change', {
280
+ bubbles: true,
281
+ composed: true,
282
+ detail: {
283
+ row: rowIndex,
284
+ column: columnIndex
285
+ }
286
+ })
287
+ )
288
+ })
289
+
264
290
  this.renderRoot.addEventListener('mousedown', (event: Event) => {
265
291
  const e = event as MouseEvent
266
292
  this.setSelectBlock()
@@ -285,7 +311,7 @@ export class DataGridBody extends LitElement {
285
311
  })
286
312
  )
287
313
 
288
- if (!isNaN(rowIndex) && !isNaN(columnIndex)) {
314
+ if (columnIndex >= 0 && target.editableOnClick && !isNaN(rowIndex) && !isNaN(columnIndex)) {
289
315
  this.startEditTarget(rowIndex, columnIndex)
290
316
  }
291
317
  })
@@ -318,6 +344,7 @@ export class DataGridBody extends LitElement {
318
344
 
319
345
  this.renderRoot.addEventListener('click', dataGridBodyClickHandler.bind(this))
320
346
  this.renderRoot.addEventListener('dblclick', dataGridBodyDblclickHandler.bind(this))
347
+ this.renderRoot.addEventListener('contextmenu', dataGridBodyContextMenuHandler.bind(this))
321
348
 
322
349
  this.addEventListener('focus-change', dataGridBodyFocusChangeHandler.bind(this))
323
350
 
@@ -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
  }
@@ -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: Object }) sorters: SortersConfig = []
19
- @property({ type: Object }) filters: FilterValue[] = []
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,16 +64,15 @@ export class DataManipulator extends LitElement {
64
64
  })
65
65
 
66
66
  /* tree processing */
67
- this.addEventListener('collapsed', (e: Event) => this.onCollapsed(e as CustomEvent))
68
- this.addEventListener('expanded', (e: Event) => this.onExpanded(e as CustomEvent))
67
+ this.addEventListener('collapse-all', (e: Event) => this.onCollapseAll(e as CustomEvent))
68
+ this.addEventListener('expand-all', (e: Event) => this.onExpandAll(e as CustomEvent))
69
+ this.addEventListener('collapse-node', (e: Event) => this.onCollapse(e as CustomEvent))
70
+ this.addEventListener('expand-node', (e: Event) => this.onExpand(e as CustomEvent))
69
71
  this.addEventListener('check-in-tree', (e: Event) => this.onCheckInTree(e as CustomEvent))
70
- }
71
72
 
72
- // updated(changes: PropertyValues<this>) {
73
- // if (changes.has('data')) {
74
- // this.refresh()
75
- // }
76
- // }
73
+ this.addEventListener('add-sibling-node', (e: Event) => this.onAddSiblingNode(e as CustomEvent))
74
+ this.addEventListener('add-child-node', (e: Event) => this.onAddChildNode(e as CustomEvent))
75
+ }
77
76
 
78
77
  onFieldChange({
79
78
  after,
@@ -213,23 +212,101 @@ export class DataManipulator extends LitElement {
213
212
  this.requestUpdate()
214
213
  }
215
214
 
216
- onCollapsed(e: CustomEvent) {
217
- const record = e.detail
215
+ onCollapseAll(e: CustomEvent) {
216
+ this.refresh(false)
217
+ }
218
+
219
+ onExpandAll(e: CustomEvent) {
220
+ this.refresh(true)
221
+ }
222
+
223
+ onCollapse(e: CustomEvent) {
224
+ const record = e.detail as GristRecord
218
225
  record.__expanded__ = false
219
226
 
220
227
  this.refresh()
221
228
  }
222
229
 
223
- onExpanded(e: CustomEvent) {
224
- const record = e.detail
230
+ onExpand(e: CustomEvent) {
231
+ const record = e.detail as GristRecord
225
232
  record.__expanded__ = true
226
233
 
227
234
  this.refresh()
228
235
  }
229
236
 
230
- onCheckInTree(e: CustomEvent) {
231
- const self = this
237
+ onAddSiblingNode(e: CustomEvent) {
238
+ const { records } = this.data
239
+ const toplevelRecords = records.filter(
240
+ record => !record.__depth__
241
+ ) /* __depth__ 가 설정되지 않았거나, 0 인 경우만 수집 */
242
+
243
+ const field = e.detail
244
+ const { record } = field
245
+ const { __depth__ } = record as GristRecord
246
+
247
+ function findParent(record: GristRecord, parent?: GristRecord): GristRecord | undefined {
248
+ var children = (parent ? parent.__children__ || [] : toplevelRecords) as GristRecord[]
249
+
250
+ if (children.find(child => child === record)) {
251
+ return parent
252
+ } else {
253
+ for (let child of children) {
254
+ const found = findParent(record, child)
255
+ if (found) {
256
+ return found
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ const parent = findParent(record)
263
+
264
+ const sibling = {
265
+ __depth__,
266
+ __dirty__: '+'
267
+ }
268
+
269
+ if (parent) {
270
+ const { __children__ } = parent as GristRecord
232
271
 
272
+ if (!__children__) {
273
+ parent.__children__ = [sibling]
274
+ } else {
275
+ parent.__children__ = [...__children__, sibling]
276
+ }
277
+
278
+ parent.__expanded__ = true
279
+ } else {
280
+ this.data.records = [...toplevelRecords, sibling]
281
+ }
282
+
283
+ this.refresh()
284
+ }
285
+
286
+ onAddChildNode(e: CustomEvent) {
287
+ const field = e.detail
288
+ const { record } = field
289
+
290
+ const { __children__, __depth__, __seq__ } = record as GristRecord
291
+ const child = {
292
+ __depth__: (__depth__ || 0) + 1,
293
+ __dirty__: '+'
294
+ }
295
+
296
+ if (!__children__) {
297
+ record.__children__ = [child]
298
+ } else {
299
+ record.__children__.push(child)
300
+ }
301
+
302
+ record.__expanded__ = true
303
+
304
+ field.requestUpdate()
305
+
306
+ this.refresh()
307
+ }
308
+
309
+ onCheckInTree(e: CustomEvent) {
233
310
  function walkTreeCheckedUpdate(record: GristRecord, checked: 'checked' | 'unchecked') {
234
311
  const children = record.__children__
235
312
 
@@ -248,7 +325,8 @@ export class DataManipulator extends LitElement {
248
325
 
249
326
  children.forEach(child => updateCheckedAll(child))
250
327
 
251
- var checked: 'checked' | 'half-checked' | 'unchecked' | undefined
328
+ var checked: 'checked' | 'half-checked' | 'unchecked' | undefined =
329
+ record.__check_in_tree__ == 'checked' ? 'checked' : undefined
252
330
 
253
331
  children.forEach(child => {
254
332
  const { __check_in_tree__ } = child
@@ -256,7 +334,7 @@ export class DataManipulator extends LitElement {
256
334
  if (__check_in_tree__ == 'half-checked') {
257
335
  checked = 'half-checked'
258
336
  } else if (__check_in_tree__ == 'checked') {
259
- checked = checked == 'checked' || !checked ? 'checked' : 'half-checked'
337
+ checked = checked == 'checked' ? 'checked' : 'half-checked'
260
338
  } else {
261
339
  checked = checked == 'unchecked' || !checked ? 'unchecked' : 'half-checked'
262
340
  }
@@ -287,7 +365,7 @@ export class DataManipulator extends LitElement {
287
365
  * Therefore, it will be deprecated.
288
366
  * @method
289
367
  */
290
- refresh() {
368
+ refresh(forceExpandOrCollapse?: boolean) {
291
369
  /*
292
370
  - TODO 여기에서 TREE 형태 데이터의 접고, 펴는 것을 재구성한다.
293
371
  - 동적으로 서브항목을 fetch 하는 기능은 제공하지 않는다.
@@ -302,15 +380,24 @@ export class DataManipulator extends LitElement {
302
380
  ) /* __depth__ 가 설정되지 않았거나, 0 인 경우만 수집 */
303
381
  this.data = {
304
382
  ...this.data,
305
- records: ([] as GristRecord[]).concat(...toplevelRecords.map(record => this.traverseRefresh(record)))
383
+ records: ([] as GristRecord[]).concat(
384
+ ...toplevelRecords.map(record => this.traverseRefresh(record, forceExpandOrCollapse))
385
+ )
306
386
  }
307
387
  }
308
388
 
309
- private traverseRefresh(record: GristRecord): GristRecord[] {
389
+ private traverseRefresh(record: GristRecord, forceExpandOrCollapse?: boolean): GristRecord[] {
390
+ if (forceExpandOrCollapse !== undefined) {
391
+ record = {
392
+ ...record,
393
+ __expanded__: forceExpandOrCollapse
394
+ }
395
+ }
396
+
310
397
  const { __expanded__, __children__ = [] } = record
311
398
 
312
399
  if (__expanded__ && __children__.length > 0) {
313
- return [record].concat(...__children__.map(child => this.traverseRefresh(child)))
400
+ return [record].concat(...__children__.map(child => this.traverseRefresh(child, forceExpandOrCollapse)))
314
401
  } else {
315
402
  return [record]
316
403
  }
@@ -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))