@operato/data-grist 1.0.0-beta.7 → 1.0.0

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 (180) hide show
  1. package/.storybook/main.js +3 -0
  2. package/.storybook/server.mjs +8 -0
  3. package/CHANGELOG.md +412 -0
  4. package/demo/data-grist-test.html +1 -1
  5. package/demo/index.html +16 -4
  6. package/demo/report-test.html +1 -1
  7. package/dist/src/configure/zero-config.d.ts +2 -0
  8. package/dist/src/configure/zero-config.js +3 -1
  9. package/dist/src/configure/zero-config.js.map +1 -1
  10. package/dist/src/data-card/data-card-field.d.ts +1 -1
  11. package/dist/src/data-card/data-card-field.js +3 -2
  12. package/dist/src/data-card/data-card-field.js.map +1 -1
  13. package/dist/src/data-card/data-card.js +1 -0
  14. package/dist/src/data-card/data-card.js.map +1 -1
  15. package/dist/src/data-grid/data-grid-body.d.ts +4 -2
  16. package/dist/src/data-grid/data-grid-body.js +74 -40
  17. package/dist/src/data-grid/data-grid-body.js.map +1 -1
  18. package/dist/src/data-grid/data-grid-field.d.ts +1 -1
  19. package/dist/src/data-grid/data-grid-field.js +1 -1
  20. package/dist/src/data-grid/data-grid-field.js.map +1 -1
  21. package/dist/src/data-grid/data-grid-footer.d.ts +2 -2
  22. package/dist/src/data-grid/data-grid-footer.js +9 -10
  23. package/dist/src/data-grid/data-grid-footer.js.map +1 -1
  24. package/dist/src/data-grid/data-grid-header.d.ts +4 -6
  25. package/dist/src/data-grid/data-grid-header.js +39 -48
  26. package/dist/src/data-grid/data-grid-header.js.map +1 -1
  27. package/dist/src/data-grid/data-grid.d.ts +2 -2
  28. package/dist/src/data-grid/data-grid.js +4 -3
  29. package/dist/src/data-grid/data-grid.js.map +1 -1
  30. package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js +9 -11
  31. package/dist/src/data-grid/event-handlers/data-grid-body-click-handler.js.map +1 -1
  32. package/dist/src/data-grist.d.ts +7 -5
  33. package/dist/src/data-grist.js +154 -112
  34. package/dist/src/data-grist.js.map +1 -1
  35. package/dist/src/data-list/record-partial.js +1 -5
  36. package/dist/src/data-list/record-partial.js.map +1 -1
  37. package/dist/src/data-manipulator.d.ts +4 -1
  38. package/dist/src/data-manipulator.js +12 -0
  39. package/dist/src/data-manipulator.js.map +1 -1
  40. package/dist/src/data-provider.d.ts +4 -6
  41. package/dist/src/data-provider.js +12 -23
  42. package/dist/src/data-provider.js.map +1 -1
  43. package/dist/src/data-report/data-report-body.d.ts +1 -1
  44. package/dist/src/data-report/data-report-body.js +4 -4
  45. package/dist/src/data-report/data-report-body.js.map +1 -1
  46. package/dist/src/data-report/data-report-header.js +4 -4
  47. package/dist/src/data-report/data-report-header.js.map +1 -1
  48. package/dist/src/editors/ox-grist-editor.d.ts +1 -1
  49. package/dist/src/editors/ox-grist-editor.js +7 -4
  50. package/dist/src/editors/ox-grist-editor.js.map +1 -1
  51. package/dist/src/filters/filter-checkbox.d.ts +1 -1
  52. package/dist/src/filters/filter-checkbox.js +1 -1
  53. package/dist/src/filters/filter-checkbox.js.map +1 -1
  54. package/dist/src/filters/filter-input-barcode.d.ts +3 -0
  55. package/dist/src/filters/filter-input-barcode.js +27 -0
  56. package/dist/src/filters/filter-input-barcode.js.map +1 -0
  57. package/dist/src/filters/filter-input.js +1 -1
  58. package/dist/src/filters/filter-input.js.map +1 -1
  59. package/dist/src/filters/filter-styles.js +65 -17
  60. package/dist/src/filters/filter-styles.js.map +1 -1
  61. package/dist/src/filters/filters-form.js +27 -9
  62. package/dist/src/filters/filters-form.js.map +1 -1
  63. package/dist/src/filters/registry.d.ts +1 -1
  64. package/dist/src/filters/registry.js +10 -7
  65. package/dist/src/filters/registry.js.map +1 -1
  66. package/dist/src/gutters/gutter-button.js +5 -4
  67. package/dist/src/gutters/gutter-button.js.map +1 -1
  68. package/dist/src/gutters/gutter-dirty.d.ts +5 -1
  69. package/dist/src/gutters/gutter-dirty.js +17 -2
  70. package/dist/src/gutters/gutter-dirty.js.map +1 -1
  71. package/dist/src/gutters/gutter-row-selector.js +2 -1
  72. package/dist/src/gutters/gutter-row-selector.js.map +1 -1
  73. package/dist/src/gutters/gutter-sequence.js +15 -0
  74. package/dist/src/gutters/gutter-sequence.js.map +1 -1
  75. package/dist/src/record-view/event-handlers/record-view-body-click-handler.js +2 -4
  76. package/dist/src/record-view/event-handlers/record-view-body-click-handler.js.map +1 -1
  77. package/dist/src/record-view/event-handlers/record-view-body-keydown-handler.js +2 -2
  78. package/dist/src/record-view/event-handlers/record-view-body-keydown-handler.js.map +1 -1
  79. package/dist/src/record-view/record-creator.js +0 -2
  80. package/dist/src/record-view/record-creator.js.map +1 -1
  81. package/dist/src/record-view/record-view-body.d.ts +0 -1
  82. package/dist/src/record-view/record-view-body.js +0 -5
  83. package/dist/src/record-view/record-view-body.js.map +1 -1
  84. package/dist/src/record-view/record-view-handler.d.ts +1 -1
  85. package/dist/src/record-view/record-view.d.ts +0 -1
  86. package/dist/src/record-view/record-view.js +1 -10
  87. package/dist/src/record-view/record-view.js.map +1 -1
  88. package/dist/src/renderers/ox-grist-renderer-color.js +1 -1
  89. package/dist/src/renderers/ox-grist-renderer-color.js.map +1 -1
  90. package/dist/src/renderers/ox-grist-renderer-json5.js +1 -1
  91. package/dist/src/renderers/ox-grist-renderer-json5.js.map +1 -1
  92. package/dist/src/renderers/ox-grist-renderer-link.js +1 -1
  93. package/dist/src/renderers/ox-grist-renderer-link.js.map +1 -1
  94. package/dist/src/renderers/ox-grist-renderer-select.js +2 -2
  95. package/dist/src/renderers/ox-grist-renderer-select.js.map +1 -1
  96. package/dist/src/renderers/ox-grist-renderer-text.js +6 -2
  97. package/dist/src/renderers/ox-grist-renderer-text.js.map +1 -1
  98. package/dist/src/sorters/sorters-control.d.ts +1 -1
  99. package/dist/src/sorters/sorters-control.js +5 -7
  100. package/dist/src/sorters/sorters-control.js.map +1 -1
  101. package/dist/src/types.d.ts +7 -4
  102. package/dist/src/types.js.map +1 -1
  103. package/dist/stories/{index.stories.d.ts → barcode-input-filter.stories.d.ts} +9 -13
  104. package/dist/stories/barcode-input-filter.stories.js +200 -0
  105. package/dist/stories/barcode-input-filter.stories.js.map +1 -0
  106. package/dist/stories/default-filters.stories.d.ts +20 -0
  107. package/dist/stories/default-filters.stories.js +187 -0
  108. package/dist/stories/default-filters.stories.js.map +1 -0
  109. package/dist/stories/empty-sorters.stories.d.ts +20 -0
  110. package/dist/stories/empty-sorters.stories.js +180 -0
  111. package/dist/stories/empty-sorters.stories.js.map +1 -0
  112. package/dist/stories/explicit-fetch.stories.d.ts +25 -0
  113. package/dist/stories/explicit-fetch.stories.js +186 -0
  114. package/dist/stories/explicit-fetch.stories.js.map +1 -0
  115. package/dist/stories/grist-modes.stories.d.ts +36 -0
  116. package/dist/stories/grist-modes.stories.js +448 -0
  117. package/dist/stories/grist-modes.stories.js.map +1 -0
  118. package/dist/tsconfig.tsbuildinfo +1 -1
  119. package/package.json +11 -11
  120. package/src/configure/zero-config.ts +4 -1
  121. package/src/data-card/data-card-field.ts +5 -3
  122. package/src/data-card/data-card.ts +1 -0
  123. package/src/data-grid/data-grid-body.ts +96 -49
  124. package/src/data-grid/data-grid-field.ts +3 -2
  125. package/src/data-grid/data-grid-footer.ts +8 -9
  126. package/src/data-grid/data-grid-header.ts +38 -47
  127. package/src/data-grid/data-grid.ts +8 -6
  128. package/src/data-grid/event-handlers/data-grid-body-click-handler.ts +11 -13
  129. package/src/data-grist.ts +179 -130
  130. package/src/data-list/record-partial.ts +1 -5
  131. package/src/data-manipulator.ts +12 -1
  132. package/src/data-provider.ts +13 -29
  133. package/src/data-report/data-report-body.ts +5 -5
  134. package/src/data-report/data-report-header.ts +5 -5
  135. package/src/editors/ox-grist-editor.ts +8 -5
  136. package/src/filters/filter-checkbox.ts +3 -3
  137. package/src/filters/filter-input-barcode.ts +33 -0
  138. package/src/filters/filter-input.ts +3 -3
  139. package/src/filters/filter-styles.ts +65 -17
  140. package/src/filters/filters-form.ts +30 -9
  141. package/src/filters/registry.ts +11 -8
  142. package/src/gutters/gutter-button.ts +5 -4
  143. package/src/gutters/gutter-dirty.ts +21 -3
  144. package/src/gutters/gutter-row-selector.ts +2 -1
  145. package/src/gutters/gutter-sequence.ts +18 -2
  146. package/src/record-view/event-handlers/record-view-body-click-handler.ts +2 -4
  147. package/src/record-view/event-handlers/record-view-body-keydown-handler.ts +2 -2
  148. package/src/record-view/record-creator.ts +0 -2
  149. package/src/record-view/record-view-body.ts +0 -2
  150. package/src/record-view/record-view.ts +1 -7
  151. package/src/renderers/ox-grist-renderer-color.ts +3 -2
  152. package/src/renderers/ox-grist-renderer-json5.ts +3 -2
  153. package/src/renderers/ox-grist-renderer-link.ts +3 -2
  154. package/src/renderers/ox-grist-renderer-select.ts +2 -2
  155. package/src/renderers/ox-grist-renderer-text.ts +8 -2
  156. package/src/sorters/sorters-control.ts +6 -9
  157. package/src/types.ts +8 -4
  158. package/stories/barcode-input-filter.stories.ts +220 -0
  159. package/stories/default-filters.stories.ts +204 -0
  160. package/stories/empty-sorters.stories.ts +197 -0
  161. package/stories/explicit-fetch.stories.ts +205 -0
  162. package/stories/grist-modes.stories.ts +488 -0
  163. package/themes/form-theme.css +75 -0
  164. package/themes/grist-theme.css +1 -1
  165. package/dist/src/data-grid/event-handlers/data-grid-body-beforeinput-handler.d.ts +0 -7
  166. package/dist/src/data-grid/event-handlers/data-grid-body-beforeinput-handler.js +0 -12
  167. package/dist/src/data-grid/event-handlers/data-grid-body-beforeinput-handler.js.map +0 -1
  168. package/dist/src/data-grid/event-handlers/data-grid-body-input-handler copy.d.ts +0 -7
  169. package/dist/src/data-grid/event-handlers/data-grid-body-input-handler copy.js +0 -88
  170. package/dist/src/data-grid/event-handlers/data-grid-body-input-handler copy.js.map +0 -1
  171. package/dist/src/data-grid/event-handlers/data-grid-body-input-handler.d.ts +0 -7
  172. package/dist/src/data-grid/event-handlers/data-grid-body-input-handler.js +0 -88
  173. package/dist/src/data-grid/event-handlers/data-grid-body-input-handler.js.map +0 -1
  174. package/dist/src/data-grid/event-handlers/data-grid-body-keydown-handler copy.d.ts +0 -7
  175. package/dist/src/data-grid/event-handlers/data-grid-body-keydown-handler copy.js +0 -88
  176. package/dist/src/data-grid/event-handlers/data-grid-body-keydown-handler copy.js.map +0 -1
  177. package/dist/stories/index.stories.js +0 -33
  178. package/dist/stories/index.stories.js.map +0 -1
  179. package/stories/index.stories.ts +0 -52
  180. package/yarn-error.log +0 -17496
package/src/data-grist.ts CHANGED
@@ -15,7 +15,7 @@ import { HeadroomStyles, ScrollbarStyles, SpinnerStyles } from '@operato/styles'
15
15
  import { SnapshotTaker, TimeCapsule } from '@operato/utils'
16
16
 
17
17
  import { buildConfig } from './configure/config-builder'
18
- import { ZERO_CONFIG, ZERO_DATA, ZERO_PAGINATION } from './configure/zero-config'
18
+ import { ZERO_CONFIG, ZERO_DATA, ZERO_PAGES, ZERO_PAGINATION } from './configure/zero-config'
19
19
  import { DataCard } from './data-card/data-card'
20
20
  import { DataConsumer } from './data-consumer'
21
21
  import { DataGrid } from './data-grid/data-grid'
@@ -23,11 +23,13 @@ import { DataList } from './data-list/data-list'
23
23
  import { DataProvider } from './data-provider'
24
24
  import {
25
25
  FetchHandler,
26
+ FilterConfigObject,
26
27
  FilterValue,
27
28
  GristConfig,
28
29
  GristData,
29
30
  GristRecord,
30
31
  GristSelectFunction,
32
+ PaginationConfig,
31
33
  SortersConfig
32
34
  } from './types'
33
35
 
@@ -62,8 +64,7 @@ export class DataGrist extends LitElement implements DataConsumer {
62
64
  overflow: auto;
63
65
  }
64
66
 
65
- ox-grid,
66
- ox-list {
67
+ #grist {
67
68
  flex: 1;
68
69
  }
69
70
 
@@ -92,11 +93,12 @@ export class DataGrist extends LitElement implements DataConsumer {
92
93
  @property() config: any
93
94
  @property() data: GristData = ZERO_DATA
94
95
  @property() selectedRecords?: GristRecord[]
95
- @property({ type: Boolean, attribute: 'auto-fetch' }) autoFetch: boolean = false
96
+ @property({ type: Boolean, attribute: 'explicit-fetch' }) explicitFetch: boolean = false
96
97
  @property() fetchHandler?: FetchHandler
97
98
  @property() fetchOptions: any
98
99
  @property() filters?: FilterValue[]
99
100
  @property() sorters?: SortersConfig
101
+ @property() pagination?: PaginationConfig
100
102
  @property({ type: Boolean, attribute: 'url-params-sensitive' }) urlParamsSensitive?: boolean
101
103
 
102
104
  @state() _data: GristData = ZERO_DATA
@@ -108,9 +110,82 @@ export class DataGrist extends LitElement implements DataConsumer {
108
110
  private _headroom?: Headroom
109
111
  private orginPaddingTop?: string
110
112
  private originMarginTop?: string
111
- private _popstateEventHandler?: EventListener
112
- private _urlSensitiveFiltersHandler?: EventListener
113
- private _urlSensitiveSortersHandler?: EventListener
113
+ private lastLocation: { origin?: string; pathname?: string; search?: string } = {}
114
+
115
+ private _popstateEventHandler: EventListener = ((e: Event) => {
116
+ const { origin, pathname, search } = window.location
117
+ if (
118
+ this.lastLocation.origin &&
119
+ (this.lastLocation.origin !== origin ||
120
+ this.lastLocation.pathname !== pathname ||
121
+ this.lastLocation.search === search)
122
+ ) {
123
+ return
124
+ }
125
+
126
+ this.lastLocation = {
127
+ origin,
128
+ pathname,
129
+ search
130
+ }
131
+
132
+ const queryString = search
133
+ const urlParams = new URLSearchParams(queryString)
134
+ var filters = urlParams.get('filters')
135
+ var sorters = urlParams.get('sorters')
136
+
137
+ try {
138
+ if (!isEqual(filters, this.filters) || !isEqual(sorters, this.sorters)) {
139
+ this.dispatchEvent(
140
+ new CustomEvent('fetch-params-change', {
141
+ bubbles: true,
142
+ composed: true,
143
+ detail: {
144
+ filters: json5.parse(filters || '[]'),
145
+ sorters: json5.parse(sorters || '[]'),
146
+ from: 'url-parameter'
147
+ }
148
+ })
149
+ )
150
+ }
151
+ } catch (e) {
152
+ console.error(`invalid fetch params on URL query string : ${e}`)
153
+ }
154
+ }).bind(this)
155
+
156
+ private _fetchParamsChangeEventHandler: EventListener = ((e: Event) => {
157
+ const urlParams = new URLSearchParams(window.location.search)
158
+ const { sorters, filters, from } = (e as CustomEvent).detail
159
+
160
+ sorters && (this.sorters = sorters)
161
+ filters && (this.filters = filters)
162
+
163
+ if (!this.urlParamsSensitive || from === 'url-parameter') {
164
+ return
165
+ }
166
+
167
+ if (sorters) {
168
+ if (sorters.length > 0) {
169
+ urlParams.set('sorters', json5.stringify(sorters))
170
+ } else {
171
+ urlParams.delete('sorters')
172
+ }
173
+ }
174
+
175
+ if (filters) {
176
+ if (filters.length > 0) {
177
+ urlParams.set('filters', json5.stringify(filters))
178
+ } else {
179
+ urlParams.delete('filters')
180
+ }
181
+ }
182
+
183
+ const queryString = String(urlParams)
184
+ this.lastLocation.search = queryString ? `?${queryString}` : ''
185
+ const url = `${window.location.pathname}${this.lastLocation.search}`
186
+
187
+ history.pushState({}, document.title, url)
188
+ }).bind(this)
114
189
 
115
190
  @query('slot[name=headroom]') head!: HTMLElement
116
191
  @query('#grist') grist!: DataGrid | DataList | DataCard
@@ -127,12 +202,16 @@ export class DataGrist extends LitElement implements DataConsumer {
127
202
  this._timeCapsule = new TimeCapsule(10)
128
203
  this._snapshotTaker = new SnapshotTaker(this, this._timeCapsule!)
129
204
 
205
+ this.addEventListener('fetch-params-change', this._fetchParamsChangeEventHandler)
206
+
130
207
  await this.updateComplete
131
208
  }
132
209
 
133
210
  disconnectedCallback() {
134
211
  super.disconnectedCallback()
135
212
 
213
+ this.removeEventListener('fetch-params-change', this._fetchParamsChangeEventHandler)
214
+
136
215
  this._timeCapsule && this._timeCapsule.dispose()
137
216
  this._snapshotTaker && this._snapshotTaker.dispose()
138
217
 
@@ -172,8 +251,6 @@ export class DataGrist extends LitElement implements DataConsumer {
172
251
  this.orginPaddingTop = style.paddingTop || '0'
173
252
  this.originMarginTop = style.marginTop || '0'
174
253
 
175
- console.log(this.orginPaddingTop, this.originMarginTop)
176
-
177
254
  this._headroom = new Headroom(this.head, {
178
255
  scroller: this.grist,
179
256
  onTop: () => {
@@ -208,10 +285,38 @@ export class DataGrist extends LitElement implements DataConsumer {
208
285
  : html``}
209
286
  <div id="wrap" @keydown=${(e: KeyboardEvent) => this.onKeydown(e)}>
210
287
  ${this.mode == 'GRID'
211
- ? html` <ox-grid id="grist" .config=${this.compiledConfig} .data=${this._data}> </ox-grid> `
288
+ ? html`
289
+ <ox-grid
290
+ id="grist"
291
+ .config=${this.compiledConfig}
292
+ .data=${this._data}
293
+ .sorters=${this.sorters}
294
+ .filters=${this.filters}
295
+ .pagination=${this.pagination}
296
+ >
297
+ </ox-grid>
298
+ `
212
299
  : this.mode == 'CARD'
213
- ? html` <ox-card id="grist" .config=${this.compiledConfig} .data=${this._data}> </ox-card> `
214
- : html` <ox-list id="grist" .config=${this.compiledConfig} .data=${this._data}> </ox-list> `}
300
+ ? html`
301
+ <ox-card
302
+ id="grist"
303
+ .config=${this.compiledConfig}
304
+ .data=${this._data}
305
+ .sorters=${this.sorters}
306
+ .filters=${this.filters}
307
+ >
308
+ </ox-card>
309
+ `
310
+ : html`
311
+ <ox-list
312
+ id="grist"
313
+ .config=${this.compiledConfig}
314
+ .data=${this._data}
315
+ .sorters=${this.sorters}
316
+ .filters=${this.filters}
317
+ >
318
+ </ox-list>
319
+ `}
215
320
  </div>
216
321
 
217
322
  <div id="spinner" ?show=${this._showSpinner}></div>
@@ -283,127 +388,12 @@ export class DataGrist extends LitElement implements DataConsumer {
283
388
  async updated(changes: PropertyValues<this>) {
284
389
  var needToSetPullToRefresh = false
285
390
 
286
- if (changes.has('urlParamsSensitive')) {
287
- if (this.urlParamsSensitive) {
288
- this._popstateEventHandler = () => {
289
- const queryString = window.location.search
290
- const urlParams = new URLSearchParams(queryString)
291
- var filters = urlParams.get('filters')
292
- var sorters = urlParams.get('sorters')
293
-
294
- if (filters) {
295
- try {
296
- this.filters = json5.parse(filters)
297
- this.dispatchEvent(
298
- new CustomEvent('filters-change', {
299
- bubbles: true,
300
- composed: true,
301
- detail: {
302
- filters: json5.parse(filters),
303
- from: 'url-parameter'
304
- }
305
- })
306
- )
307
- } catch (e) {
308
- console.error(`invalid filters params on URL query string : ${e}`)
309
- }
310
- }
311
- if (sorters) {
312
- try {
313
- this.sorters = json5.parse(sorters)
314
- } catch (e) {
315
- console.error(`invalid sorters params on URL query string : ${e}`)
316
- }
317
- }
318
- }
319
-
320
- //@ts-ignore
321
- this._popstateEventHandler() // call for the first time
322
-
323
- window.addEventListener('popstate', this._popstateEventHandler)
324
-
325
- this._urlSensitiveFiltersHandler = (e: Event) => {
326
- const urlParams = new URLSearchParams(window.location.search)
327
- const { filters, from } = (e as CustomEvent).detail || {}
328
-
329
- if (from === 'url-parameter') {
330
- return
331
- }
332
-
333
- if (filters.length > 0) {
334
- urlParams.set('filters', json5.stringify(filters))
335
- } else {
336
- urlParams.delete('filters')
337
- }
338
- const queryString = String(urlParams)
339
- const url = `${window.location.pathname}${queryString ? `?${queryString}` : ''}`
340
-
341
- history.pushState({}, document.title, url)
342
- }
343
-
344
- this.addEventListener('filters-change', this._urlSensitiveFiltersHandler)
345
-
346
- this._urlSensitiveSortersHandler = (e: Event) => {
347
- const urlParams = new URLSearchParams(window.location.search)
348
- const { sorters, from } = (e as CustomEvent).detail
349
-
350
- if (from === 'url-parameter') {
351
- return
352
- }
353
-
354
- if (sorters.length > 0) {
355
- urlParams.set('sorters', json5.stringify(sorters))
356
- } else {
357
- urlParams.delete('sorters')
358
- }
359
- const queryString = String(urlParams)
360
- const url = `${window.location.pathname}${queryString ? `?${queryString}` : ''}`
361
-
362
- history.pushState({}, document.title, url)
363
- }
364
-
365
- this.addEventListener('sorters-change', this._urlSensitiveSortersHandler)
366
- } else {
367
- if (this._popstateEventHandler) {
368
- window.removeEventListener('popstate', this._popstateEventHandler)
369
- }
370
- if (this._urlSensitiveFiltersHandler) {
371
- this.removeEventListener('popstate', this._urlSensitiveFiltersHandler)
372
- }
373
- if (this._urlSensitiveSortersHandler) {
374
- this.removeEventListener('popstate', this._urlSensitiveSortersHandler)
375
- }
376
- }
377
- }
378
-
379
391
  if (changes.has('filters')) {
380
392
  await this.requestUpdate()
381
-
382
- this.dispatchEvent(
383
- new CustomEvent('filters-change', {
384
- bubbles: true,
385
- composed: true,
386
- detail: {
387
- filters: this.filters,
388
- from: 'url-parameter'
389
- }
390
- })
391
- )
392
393
  }
393
394
 
394
395
  if (changes.has('sorters')) {
395
396
  await this.requestUpdate()
396
-
397
- this.dispatchEvent(
398
- new CustomEvent('sorters-change', {
399
- bubbles: true,
400
- composed: true,
401
- detail: {
402
- sorters: this.sorters,
403
- from: 'url-parameter'
404
- }
405
- })
406
- )
407
397
  }
408
398
 
409
399
  if (changes.has('config')) {
@@ -419,12 +409,44 @@ export class DataGrist extends LitElement implements DataConsumer {
419
409
  })
420
410
  )
421
411
 
412
+ this.pagination = this.compiledConfig.pagination || {}
413
+
414
+ if (!this.urlParamsSensitive) {
415
+ const sorters = this.compiledConfig?.sorters
416
+ const filters = this.compiledConfig?.columns
417
+ .filter(
418
+ column =>
419
+ column.filter &&
420
+ 'value' in (column.filter as FilterConfigObject) &&
421
+ (column.filter as FilterConfigObject).value
422
+ )
423
+ .map(column => {
424
+ const filter = column.filter as FilterConfigObject
425
+ return { name: column.name, operator: filter.operator, value: filter.value } as FilterValue
426
+ })
427
+
428
+ this.dispatchEvent(
429
+ new CustomEvent('fetch-params-change', {
430
+ bubbles: true,
431
+ composed: true,
432
+ detail: {
433
+ filters,
434
+ sorters,
435
+ from: 'config'
436
+ }
437
+ })
438
+ )
439
+ }
440
+
422
441
  if (this.dataProvider) {
423
- this.dataProvider.sorters = this.sorters || this.compiledConfig?.sorters
424
- this.dataProvider.filters = this.filters
442
+ const { limit, pages = ZERO_PAGES } = this._config.pagination || ZERO_PAGINATION
443
+ this.dataProvider.page = 1
444
+ this.dataProvider.limit = limit || pages[0] || ZERO_PAGES[0]
425
445
  }
426
446
 
427
- this.fetch()
447
+ if (!this.urlParamsSensitive && !this.explicitFetch) {
448
+ this.fetch()
449
+ }
428
450
  }
429
451
 
430
452
  if (changes.has('fetchHandler')) {
@@ -470,6 +492,17 @@ export class DataGrist extends LitElement implements DataConsumer {
470
492
  this.refresh()
471
493
  }
472
494
 
495
+ if (changes.has('urlParamsSensitive')) {
496
+ if (this.urlParamsSensitive) {
497
+ //@ts-ignore
498
+ this._popstateEventHandler() // call for the first time
499
+
500
+ window.addEventListener('popstate', this._popstateEventHandler)
501
+ } else {
502
+ window.removeEventListener('popstate', this._popstateEventHandler)
503
+ }
504
+ }
505
+
473
506
  if (needToSetPullToRefresh) {
474
507
  await this._setPullToRefresh()
475
508
  }
@@ -690,4 +723,20 @@ export class DataGrist extends LitElement implements DataConsumer {
690
723
 
691
724
  this.checkDirties()
692
725
  }
726
+
727
+ deleteSelectedRecords(dirty = true) {
728
+ const records = this.selected || ([] as GristRecord[])
729
+
730
+ records.forEach(record => {
731
+ if (dirty) {
732
+ record.__dirty__ = '-'
733
+ } else {
734
+ }
735
+
736
+ const rowIndex = this._data.records.findIndex(rec => rec === record)
737
+ this._data.records.splice(rowIndex, 1)
738
+ })
739
+
740
+ this.checkDirties()
741
+ }
693
742
  }
@@ -41,10 +41,6 @@ export class RecordPartial extends LitElement {
41
41
  min-height: 42px;
42
42
  }
43
43
 
44
- ox-list-gutter {
45
- flex: 0 0 14px;
46
- }
47
-
48
44
  :host([dirty])::before {
49
45
  content: '';
50
46
  position: absolute;
@@ -59,7 +55,7 @@ export class RecordPartial extends LitElement {
59
55
 
60
56
  :host > * {
61
57
  margin: var(--data-list-item-margin);
62
- zoom: 1.4;
58
+ zoom: var(--grist-input-zoom);
63
59
  }
64
60
 
65
61
  :host [dirty] {
@@ -2,11 +2,22 @@ import { LitElement } from 'lit'
2
2
  import { property } from 'lit/decorators.js'
3
3
 
4
4
  import { ZERO_CONFIG, ZERO_DATA } from './configure/zero-config'
5
- import { ColumnConfig, GristConfig, GristData, GristRecord } from './types'
5
+ import {
6
+ ColumnConfig,
7
+ FilterValue,
8
+ GristConfig,
9
+ GristData,
10
+ GristRecord,
11
+ PaginationConfig,
12
+ SortersConfig
13
+ } from './types'
6
14
 
7
15
  export class DataManipulator extends LitElement {
8
16
  @property({ type: Object }) config: GristConfig = ZERO_CONFIG
9
17
  @property({ type: Object }) data: GristData = ZERO_DATA
18
+ @property({ type: Object }) sorters: SortersConfig = []
19
+ @property({ type: Object }) filters: FilterValue[] = []
20
+ @property({ type: Object }) pagination: PaginationConfig = {}
10
21
 
11
22
  constructor() {
12
23
  super()
@@ -1,9 +1,6 @@
1
- import { FetchHandler, FetchOption, FilterValue, GristRecord, SorterConfig, SortersConfig } from './types'
2
- import { SnapshotTaker, TimeCapsule } from '@operato/utils'
3
-
4
- import { DataConsumer } from './data-consumer'
5
- import { ZERO_RECORDS } from './configure/zero-config'
6
- import deepEquals from 'lodash-es/isEqual'
1
+ import { ZERO_RECORDS } from './configure/zero-config.js'
2
+ import { DataConsumer } from './data-consumer.js'
3
+ import { FetchHandler, FetchOption, FilterValue, GristRecord, SorterConfig, SortersConfig } from './types.js'
7
4
 
8
5
  function EMPTY_FETCHHANDLER() {
9
6
  return {
@@ -33,8 +30,7 @@ export class DataProvider {
33
30
 
34
31
  private _pageChangeHandler: EventListener = this.onPageChange.bind(this)
35
32
  private _limitChangeHandler = this.onLimitChange.bind(this)
36
- private _sortersChangeHandler = this.onSortersChange.bind(this)
37
- private _filtersChangeHandler = this.onFiltersChange.bind(this)
33
+ private _fetchParamsChangeHandler = this.onFetchParamsChange.bind(this)
38
34
  private _recordChangeHandler = this.onRecordChange.bind(this)
39
35
  private _attachPageHandler: EventListener = this.onAttachPage.bind(this)
40
36
 
@@ -49,8 +45,7 @@ export class DataProvider {
49
45
  this.consumer.addEventListener('attach-page', this._attachPageHandler)
50
46
  this.consumer.addEventListener('page-change', this._pageChangeHandler)
51
47
  this.consumer.addEventListener('limit-change', this._limitChangeHandler)
52
- this.consumer.addEventListener('sorters-change', this._sortersChangeHandler)
53
- this.consumer.addEventListener('filters-change', this._filtersChangeHandler)
48
+ this.consumer.addEventListener('fetch-params-change', this._fetchParamsChangeHandler)
54
49
  this.consumer.addEventListener('record-change', this._recordChangeHandler)
55
50
  }
56
51
 
@@ -58,8 +53,7 @@ export class DataProvider {
58
53
  this.consumer?.removeEventListener('attach-page', this._attachPageHandler)
59
54
  this.consumer?.removeEventListener('page-change', this._pageChangeHandler)
60
55
  this.consumer?.removeEventListener('limit-change', this._limitChangeHandler)
61
- this.consumer?.removeEventListener('sorters-change', this._sortersChangeHandler)
62
- this.consumer?.removeEventListener('filters-change', this._filtersChangeHandler)
56
+ this.consumer?.removeEventListener('fetch-params-change', this._fetchParamsChangeHandler)
63
57
  this.consumer?.removeEventListener('record-change', this._recordChangeHandler)
64
58
  }
65
59
 
@@ -77,21 +71,17 @@ export class DataProvider {
77
71
  this.fetch({ limit })
78
72
  }
79
73
 
80
- onSortersChange(e: Event) {
81
- const { sorters } = (e as CustomEvent).detail || {}
82
- this.sorters = sorters
74
+ onFetchParamsChange(e: Event) {
75
+ const { sorters, filters, from } = (e as CustomEvent).detail || {}
76
+
77
+ sorters && (this.sorters = sorters)
78
+ filters && (this.filters = filters)
83
79
 
84
80
  if (this.consumer?.mode !== 'GRID') {
85
81
  this.page = 0
86
82
  }
87
83
 
88
- this.fetch()
89
- }
90
-
91
- onFiltersChange(e: Event) {
92
- const { filters } = (e as CustomEvent).detail || {}
93
-
94
- this.filters = filters
84
+ from !== 'config' && this.fetch()
95
85
  }
96
86
 
97
87
  onRecordChange(e: Event) {
@@ -154,13 +144,7 @@ export class DataProvider {
154
144
  }
155
145
 
156
146
  set filters(filters) {
157
- if (this._filters === filters || deepEquals(this._filters, filters)) {
158
- return
159
- }
160
-
161
147
  this._filters = filters
162
-
163
- this.fetch()
164
148
  }
165
149
 
166
150
  async attach(reset = false) {
@@ -188,6 +172,7 @@ export class DataProvider {
188
172
  page,
189
173
  limit,
190
174
  sorters: this.sorters,
175
+ filters: this.filters,
191
176
  options: this.fetchOptions
192
177
  }))
193
178
  },
@@ -251,7 +236,6 @@ export class DataProvider {
251
236
  if (maxpage < page) {
252
237
  return await this.fetch({ page: maxpage, limit })
253
238
  }
254
- // CONFIRM-ME 위 코드에 대한 설명이 필요함!!!.
255
239
 
256
240
  // page와 limit이 없는 경우 records 검사 전에 초기화
257
241
  this.page = this.page || page
@@ -1,14 +1,14 @@
1
1
  import './data-report-field'
2
2
 
3
- import { ColumnConfig, GristConfig, GristData } from '../types'
4
- import { LitElement, PropertyValues, html } from 'lit'
5
- import { ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
3
+ import { html, LitElement, PropertyValues } from 'lit'
6
4
  import { customElement, property } from 'lit/decorators.js'
7
5
 
6
+ import { ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
7
+ import { ColumnConfig, GristConfig, GristData } from '../types'
8
+ import { dataReportBodyStyle } from './data-report-body-style'
8
9
  import { dataReportBodyClickHandler } from './event-handlers/data-report-body-click-handler'
9
10
  import { dataReportBodyDblclickHandler } from './event-handlers/data-report-body-dblclick-handler'
10
11
  import { dataReportBodyKeydownHandler } from './event-handlers/data-report-body-keydown-handler'
11
- import { dataReportBodyStyle } from './data-report-body-style'
12
12
 
13
13
  function calcScrollPos(parent: DataReportBody, child: Element) {
14
14
  /* getBoundingClientRect는 safari에서 스크롤 상태에서 다른 브라우저와는 다른 값을 리턴함 - 사파리는 약간 이상 작동함. */
@@ -182,7 +182,7 @@ export class DataReportBody extends LitElement {
182
182
  focus() {
183
183
  super.focus()
184
184
 
185
- if (!this.focused || this.focused.row === undefined) {
185
+ if (!this.focused || this.focused.row == null) {
186
186
  this.focused = { row: 0, column: 0 }
187
187
  }
188
188
  }
@@ -1,10 +1,10 @@
1
- import { ColumnConfig, GristConfig, GristData, SortersConfig } from '../types'
2
- import { LitElement, css, html } from 'lit'
3
- import { ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
1
+ import { css, html, LitElement } from 'lit'
4
2
  import { customElement, property } from 'lit/decorators.js'
3
+ import throttle from 'lodash-es/throttle'
5
4
 
5
+ import { ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
6
+ import { ColumnConfig, GristConfig, GristData, SortersConfig } from '../types'
6
7
  import { supportsPassive } from '../utils'
7
- import throttle from 'lodash-es/throttle'
8
8
 
9
9
  @customElement('ox-report-header')
10
10
  class DataReportHeader extends LitElement {
@@ -170,7 +170,7 @@ class DataReportHeader extends LitElement {
170
170
  this._sorters = sorters
171
171
 
172
172
  this.dispatchEvent(
173
- new CustomEvent('sorters-change', {
173
+ new CustomEvent('fetch-params-change', {
174
174
  bubbles: true,
175
175
  composed: true,
176
176
  detail: {
@@ -1,9 +1,9 @@
1
- import { ColumnConfig, GristRecord } from '../types'
2
- import { LitElement, css, html } from 'lit'
3
- import { ZERO_COLUMN, ZERO_RECORD } from '../configure/zero-config'
1
+ import { css, html, LitElement } from 'lit'
4
2
  import { customElement, property } from 'lit/decorators.js'
5
3
 
4
+ import { ZERO_COLUMN, ZERO_RECORD } from '../configure/zero-config'
6
5
  import { DataGridField } from '../data-grid/data-grid-field'
6
+ import { ColumnConfig, GristRecord } from '../types'
7
7
 
8
8
  const STYLE = css`
9
9
  :host {
@@ -16,13 +16,14 @@ const STYLE = css`
16
16
 
17
17
  border: 0;
18
18
  background-color: transparent;
19
+
20
+ overflow: hidden;
19
21
  }
20
22
 
21
23
  :host > * {
22
24
  display: flex;
23
25
 
24
26
  width: 100%;
25
- height: 100%;
26
27
 
27
28
  border: 0;
28
29
  background-color: transparent;
@@ -31,6 +32,8 @@ const STYLE = css`
31
32
 
32
33
  font-size: inherit;
33
34
  font-family: inherit;
35
+
36
+ align-items: center;
34
37
  }
35
38
 
36
39
  :host > style {
@@ -116,7 +119,7 @@ export class OxGristEditor extends LitElement {
116
119
  }
117
120
 
118
121
  formatForEditor(value: any): any {
119
- return value === undefined ? '' : value
122
+ return value == null ? '' : value
120
123
  }
121
124
 
122
125
  formatFromEditor(e: Event): any {
@@ -1,9 +1,9 @@
1
1
  import '@operato/input/ox-checkbox.js'
2
2
 
3
- import { FilterConfigObject, FilterSelectRenderer } from '../types'
4
-
5
3
  import { html } from 'lit-html'
6
4
 
5
+ import { FilterConfigObject, FilterSelectRenderer } from '../types.js'
6
+
7
7
  export const FilterCheckbox: FilterSelectRenderer = (column, value, owner) => {
8
8
  const filter = column.filter as FilterConfigObject
9
9
  const options = filter?.options
@@ -13,7 +13,7 @@ export const FilterCheckbox: FilterSelectRenderer = (column, value, owner) => {
13
13
  name=${column.name}
14
14
  ?checked=${value}
15
15
  indeterminatable
16
- ?indeterminate=${value === undefined}
16
+ ?indeterminate=${value == null}
17
17
  @change=${(e: CustomEvent) => {
18
18
  ;(e.target as HTMLElement).dispatchEvent(
19
19
  new CustomEvent('filter-change', {