@operato/data-grist 8.0.0-alpha.8 → 8.0.0-beta.1

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 (218) hide show
  1. package/CHANGELOG.md +186 -0
  2. package/dist/src/data-grid/data-grid-body.js +21 -7
  3. package/dist/src/data-grid/data-grid-body.js.map +1 -1
  4. package/dist/src/data-grid/data-grid-footer.js +2 -0
  5. package/dist/src/data-grid/data-grid-footer.js.map +1 -1
  6. package/dist/src/data-grid/data-grid-header.d.ts +1 -1
  7. package/dist/src/data-grid/data-grid-header.js +13 -9
  8. package/dist/src/data-grid/data-grid-header.js.map +1 -1
  9. package/dist/src/editors/ox-grist-editor-varname.d.ts +6 -0
  10. package/dist/src/editors/ox-grist-editor-varname.js +36 -0
  11. package/dist/src/editors/ox-grist-editor-varname.js.map +1 -0
  12. package/dist/src/editors/ox-grist-editor.js +3 -3
  13. package/dist/src/editors/ox-grist-editor.js.map +1 -1
  14. package/dist/src/editors/registry.js +3 -1
  15. package/dist/src/editors/registry.js.map +1 -1
  16. package/dist/src/gutters/gutter-sequence.d.ts +1 -1
  17. package/dist/src/record-view/index.d.ts +1 -1
  18. package/dist/src/record-view/index.js +1 -1
  19. package/dist/src/record-view/index.js.map +1 -1
  20. package/dist/src/record-view/{record-creator.d.ts → ox-record-creator.d.ts} +8 -4
  21. package/dist/src/record-view/{record-creator.js → ox-record-creator.js} +90 -34
  22. package/dist/src/record-view/ox-record-creator.js.map +1 -0
  23. package/dist/src/renderers/ox-grist-renderer-boolean.js +1 -1
  24. package/dist/src/renderers/ox-grist-renderer-boolean.js.map +1 -1
  25. package/dist/stories/accumulator-format.stories.d.ts +1 -1
  26. package/dist/stories/accumulator-format.stories.js +1 -1
  27. package/dist/stories/accumulator-format.stories.js.map +1 -1
  28. package/dist/stories/click-event-custom.stories.d.ts +45 -0
  29. package/dist/stories/click-event-custom.stories.js +247 -0
  30. package/dist/stories/click-event-custom.stories.js.map +1 -0
  31. package/dist/stories/click-event.stories.d.ts +1 -1
  32. package/dist/stories/click-event.stories.js +1 -1
  33. package/dist/stories/click-event.stories.js.map +1 -1
  34. package/dist/stories/fixed-column.stories.d.ts +1 -1
  35. package/dist/stories/fixed-column.stories.js +1 -1
  36. package/dist/stories/fixed-column.stories.js.map +1 -1
  37. package/dist/stories/grid-setting.stories.d.ts +1 -1
  38. package/dist/stories/grid-setting.stories.js +1 -1
  39. package/dist/stories/grid-setting.stories.js.map +1 -1
  40. package/dist/stories/grist-modes.stories.d.ts +1 -1
  41. package/dist/stories/grist-modes.stories.js +1 -1
  42. package/dist/stories/grist-modes.stories.js.map +1 -1
  43. package/dist/stories/group-header.stories.d.ts +1 -1
  44. package/dist/stories/group-header.stories.js +1 -1
  45. package/dist/stories/group-header.stories.js.map +1 -1
  46. package/dist/stories/textarea.stories.d.ts +1 -1
  47. package/dist/stories/textarea.stories.js +1 -1
  48. package/dist/stories/textarea.stories.js.map +1 -1
  49. package/dist/stories/tree-column-with-checkbox.stories.d.ts +1 -1
  50. package/dist/stories/tree-column-with-checkbox.stories.js +1 -1
  51. package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
  52. package/dist/stories/tree-column.stories.d.ts +1 -1
  53. package/dist/stories/tree-column.stories.js +1 -1
  54. package/dist/stories/tree-column.stories.js.map +1 -1
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +20 -20
  57. package/themes/calendar-theme.css +3 -1
  58. package/.storybook/main.js +0 -3
  59. package/.storybook/preview.js +0 -52
  60. package/.storybook/server.mjs +0 -8
  61. package/dist/src/record-view/record-creator.js.map +0 -1
  62. package/src/accumulator/accumulator.ts +0 -63
  63. package/src/configure/column-builder.ts +0 -114
  64. package/src/configure/config-builder.ts +0 -40
  65. package/src/configure/filters-option-builder.ts +0 -8
  66. package/src/configure/imex-option-builder.ts +0 -5
  67. package/src/configure/list-option-builder.ts +0 -9
  68. package/src/configure/rows-option-builder.ts +0 -38
  69. package/src/configure/tree-option-builder.ts +0 -22
  70. package/src/configure/zero-config.ts +0 -83
  71. package/src/const.ts +0 -1
  72. package/src/data-card/data-card-field.ts +0 -94
  73. package/src/data-card/data-card-gutter-menu.ts +0 -94
  74. package/src/data-card/data-card-gutter.ts +0 -103
  75. package/src/data-card/data-card.ts +0 -154
  76. package/src/data-card/event-handlers/record-card-click-handler.ts +0 -34
  77. package/src/data-card/event-handlers/record-card-dblclick-handler.ts +0 -34
  78. package/src/data-card/record-card.ts +0 -298
  79. package/src/data-consumer.ts +0 -11
  80. package/src/data-grid/data-grid-accum-field.ts +0 -109
  81. package/src/data-grid/data-grid-body-style.ts +0 -85
  82. package/src/data-grid/data-grid-body.ts +0 -749
  83. package/src/data-grid/data-grid-field.ts +0 -227
  84. package/src/data-grid/data-grid-footer.ts +0 -117
  85. package/src/data-grid/data-grid-header.ts +0 -574
  86. package/src/data-grid/data-grid.ts +0 -293
  87. package/src/data-grid/event-handlers/data-grid-body-click-handler.ts +0 -69
  88. package/src/data-grid/event-handlers/data-grid-body-contextmenu-handler.ts +0 -32
  89. package/src/data-grid/event-handlers/data-grid-body-dblclick-handler.ts +0 -42
  90. package/src/data-grid/event-handlers/data-grid-body-focus-change-handler.ts +0 -24
  91. package/src/data-grid/event-handlers/data-grid-body-keydown-handler.ts +0 -234
  92. package/src/data-grist.ts +0 -1233
  93. package/src/data-list/data-list-field.ts +0 -82
  94. package/src/data-list/data-list-gutter.ts +0 -108
  95. package/src/data-list/data-list.ts +0 -145
  96. package/src/data-list/event-handlers/record-partial-click-handler.ts +0 -34
  97. package/src/data-list/event-handlers/record-partial-dblclick-handler.ts +0 -33
  98. package/src/data-list/event-handlers/record-partial-long-press-handler.ts +0 -33
  99. package/src/data-list/record-partial.ts +0 -264
  100. package/src/data-manipulator.ts +0 -426
  101. package/src/data-provider.ts +0 -271
  102. package/src/data-report/data-report-body-style.ts +0 -58
  103. package/src/data-report/data-report-body.ts +0 -189
  104. package/src/data-report/data-report-component.ts +0 -138
  105. package/src/data-report/data-report-field.ts +0 -83
  106. package/src/data-report/data-report-header.ts +0 -242
  107. package/src/data-report/event-handlers/data-report-body-click-handler.ts +0 -38
  108. package/src/data-report/event-handlers/data-report-body-dblclick-handler.ts +0 -25
  109. package/src/data-report/event-handlers/data-report-body-keydown-handler.ts +0 -68
  110. package/src/data-report.ts +0 -424
  111. package/src/editors/index.ts +0 -4
  112. package/src/editors/ox-grist-editor-checkbox.ts +0 -28
  113. package/src/editors/ox-grist-editor-color.ts +0 -10
  114. package/src/editors/ox-grist-editor-date.ts +0 -10
  115. package/src/editors/ox-grist-editor-datetime.ts +0 -27
  116. package/src/editors/ox-grist-editor-email.ts +0 -10
  117. package/src/editors/ox-grist-editor-file.ts +0 -28
  118. package/src/editors/ox-grist-editor-image.ts +0 -31
  119. package/src/editors/ox-grist-editor-month.ts +0 -10
  120. package/src/editors/ox-grist-editor-multiple-select.ts +0 -57
  121. package/src/editors/ox-grist-editor-number.ts +0 -27
  122. package/src/editors/ox-grist-editor-password.ts +0 -10
  123. package/src/editors/ox-grist-editor-select.ts +0 -55
  124. package/src/editors/ox-grist-editor-tel.ts +0 -10
  125. package/src/editors/ox-grist-editor-text.ts +0 -14
  126. package/src/editors/ox-grist-editor-textarea.ts +0 -16
  127. package/src/editors/ox-grist-editor-time.ts +0 -10
  128. package/src/editors/ox-grist-editor-tree.ts +0 -27
  129. package/src/editors/ox-grist-editor-week.ts +0 -10
  130. package/src/editors/ox-grist-editor.ts +0 -207
  131. package/src/editors/ox-input-tree.ts +0 -226
  132. package/src/editors/registry.ts +0 -80
  133. package/src/empty-note.ts +0 -46
  134. package/src/filters/filter-checkbox.ts +0 -49
  135. package/src/filters/filter-input-barcode.ts +0 -34
  136. package/src/filters/filter-input.ts +0 -30
  137. package/src/filters/filter-range-date.ts +0 -81
  138. package/src/filters/filter-range-number.ts +0 -64
  139. package/src/filters/filter-select-buttons.ts +0 -60
  140. package/src/filters/filter-select.ts +0 -68
  141. package/src/filters/filter-styles.ts +0 -119
  142. package/src/filters/filters-form.ts +0 -476
  143. package/src/filters/index.ts +0 -10
  144. package/src/filters/registry.ts +0 -56
  145. package/src/formatters/date-formatter.ts +0 -3
  146. package/src/formatters/index.ts +0 -1
  147. package/src/formatters/number-formatter.ts +0 -3
  148. package/src/formatters/registry.ts +0 -30
  149. package/src/formatters/text-formatter.ts +0 -3
  150. package/src/gutters/gutter-button.ts +0 -51
  151. package/src/gutters/gutter-dirty.ts +0 -96
  152. package/src/gutters/gutter-row-selector.ts +0 -89
  153. package/src/gutters/gutter-sequence.ts +0 -54
  154. package/src/gutters/index.ts +0 -1
  155. package/src/gutters/registry.ts +0 -32
  156. package/src/handlers/contextmenu-tree-mutation.ts +0 -80
  157. package/src/handlers/index.ts +0 -1
  158. package/src/handlers/move-down.ts +0 -44
  159. package/src/handlers/move-up.ts +0 -44
  160. package/src/handlers/record-copy.ts +0 -38
  161. package/src/handlers/record-delete.ts +0 -30
  162. package/src/handlers/record-view-handler.ts +0 -27
  163. package/src/handlers/registry.ts +0 -42
  164. package/src/handlers/select-row-toggle.ts +0 -30
  165. package/src/handlers/select-row.ts +0 -27
  166. package/src/index.ts +0 -17
  167. package/src/personalizer/index.ts +0 -1
  168. package/src/personalizer/ox-grist-filter-personalizer.ts +0 -192
  169. package/src/personalizer/ox-grist-personalizer.ts +0 -226
  170. package/src/record-view/event-handlers/record-view-body-click-handler.ts +0 -33
  171. package/src/record-view/event-handlers/record-view-body-keydown-handler.ts +0 -26
  172. package/src/record-view/index.ts +0 -2
  173. package/src/record-view/record-creator.ts +0 -226
  174. package/src/record-view/record-view-body.ts +0 -257
  175. package/src/record-view/record-view-handler.ts +0 -86
  176. package/src/record-view/record-view.ts +0 -122
  177. package/src/renderers/index.ts +0 -14
  178. package/src/renderers/ox-grist-renderer-boolean.ts +0 -43
  179. package/src/renderers/ox-grist-renderer-color.ts +0 -15
  180. package/src/renderers/ox-grist-renderer-date.ts +0 -62
  181. package/src/renderers/ox-grist-renderer-file.ts +0 -31
  182. package/src/renderers/ox-grist-renderer-image.ts +0 -27
  183. package/src/renderers/ox-grist-renderer-json5.ts +0 -36
  184. package/src/renderers/ox-grist-renderer-link.ts +0 -17
  185. package/src/renderers/ox-grist-renderer-password.ts +0 -7
  186. package/src/renderers/ox-grist-renderer-progress.ts +0 -45
  187. package/src/renderers/ox-grist-renderer-select.ts +0 -58
  188. package/src/renderers/ox-grist-renderer-text.ts +0 -16
  189. package/src/renderers/ox-grist-renderer-textarea.ts +0 -7
  190. package/src/renderers/ox-grist-renderer-tree.ts +0 -189
  191. package/src/renderers/ox-grist-renderer.ts +0 -35
  192. package/src/renderers/registry.ts +0 -111
  193. package/src/sorters/sorters-control.ts +0 -143
  194. package/src/types.ts +0 -813
  195. package/src/utils/index.ts +0 -2
  196. package/src/utils/list-param.ts +0 -72
  197. package/src/utils/supports-passive.ts +0 -13
  198. package/stories/accumulator-format.stories.ts +0 -276
  199. package/stories/barcode-input-filter.stories.ts +0 -216
  200. package/stories/bounded-select-filters.stories.ts +0 -333
  201. package/stories/bounded-select-record.stories.ts +0 -336
  202. package/stories/click-event.stories.ts +0 -283
  203. package/stories/creatable-only-column.stories.ts +0 -253
  204. package/stories/default-filters.stories.ts +0 -241
  205. package/stories/dynamic-editable.stories.ts +0 -313
  206. package/stories/empty-sorters.stories.ts +0 -180
  207. package/stories/explicit-fetch.stories.ts +0 -186
  208. package/stories/fixed-column.stories.ts +0 -416
  209. package/stories/grid-setting.stories.ts +0 -501
  210. package/stories/grist-modes.stories.ts +0 -451
  211. package/stories/group-header.stories.ts +0 -442
  212. package/stories/record-view.stories.ts +0 -143
  213. package/stories/textarea.stories.ts +0 -261
  214. package/stories/tree-column-with-checkbox.stories.ts +0 -297
  215. package/stories/tree-column.stories.ts +0 -296
  216. package/tsconfig.json +0 -26
  217. package/web-dev-server.config.mjs +0 -27
  218. package/web-test-runner.config.mjs +0 -45
@@ -1,68 +0,0 @@
1
- import '@operato/input/ox-checkbox.js'
2
-
3
- import { html } from 'lit'
4
- import { until } from 'lit/directives/until.js'
5
-
6
- import { FilterConfigObject, FilterOperator, FilterSelectRenderer, SelectOption, SelectOptionObject } from '../types'
7
- import { OxFiltersForm } from './filters-form'
8
- import { DataGridHeader } from '../data-grid/data-grid-header'
9
-
10
- function buildOptions(options: SelectOption[], operator?: FilterOperator) {
11
- const selectOptionObjects = options.map(option => {
12
- switch (typeof option) {
13
- case 'string':
14
- return {
15
- display: option,
16
- value: option
17
- }
18
- case 'object':
19
- return {
20
- display: option.display || option.name,
21
- value: option.value
22
- }
23
- default:
24
- return option
25
- }
26
- }) as SelectOptionObject[]
27
-
28
- return operator === 'in'
29
- ? html`
30
- ${selectOptionObjects
31
- ?.filter(option => !!option)
32
- .map(
33
- ({ value, display, name }) => html` <ox-checkbox option value=${value}>${display || name}</ox-checkbox> `
34
- )}
35
- `
36
- : html`
37
- ${selectOptionObjects?.map(
38
- ({ value, display, name }) => html` <div option value=${value}>${display || name}&nbsp;</div> `
39
- )}
40
- `
41
- }
42
-
43
- export const FilterSelect: FilterSelectRenderer = (column, value, owner) => {
44
- /* value는 filters-form이나 grid-header에서 처리되므로 이 곳에서는 무시한다. */
45
- const filter = column.filter as FilterConfigObject
46
- const operator = filter?.operator
47
- const form = owner as OxFiltersForm | DataGridHeader
48
-
49
- var options = filter?.options || column.record.options || []
50
-
51
- if (typeof options === 'function') {
52
- if (!filter?.options) {
53
- console.warn(
54
- 'ox-grist의 column.filter 속성에서는 column.record.options의 함수형 options을 사용할 수 없으므로, filter 속성에서 재지정해야한다.'
55
- )
56
- }
57
-
58
- options = options.call(null, value, column, form instanceof OxFiltersForm ? form.getFormObjectValue() : {}, owner)
59
-
60
- if (options instanceof Promise) {
61
- return html`${until(options.then(options => buildOptions(options, operator)))}`
62
- } else {
63
- return buildOptions((options || []) as SelectOption[], operator)
64
- }
65
- } else {
66
- return buildOptions((options || []) as SelectOption[], operator)
67
- }
68
- }
@@ -1,119 +0,0 @@
1
- import { css } from 'lit'
2
-
3
- export const FilterStyles = css`
4
- :host {
5
- --ox-filters-input-placeholder-color: var(--input-placeholder-color, var(--md-sys-color-on-surface));
6
-
7
- --ox-filters-input-border: var(--input-border, 1px solid rgba(0, 0, 0, 0.2));
8
- --ox-filters-input-focus-border: var(--input-focus-border, 1px solid var(--md-sys-color-outline-variant));
9
- --ox-filters-input-font: var(--input-font, normal 14px var(--theme-font));
10
- --ox-filters-input-color: var(--input-color, var(--md-sys-color-on-surface));
11
- --ox-filters-input-focus-color: var(--input-focus-color, var(--md-sys-color-on-surface-variant));
12
- --ox-filters-label-font: var(--label-font, normal 14px var(--theme-font));
13
- --ox-filters-label-color: var(--label-color, var(--md-sys-color-on-surface));
14
- --ox-filters-input-background-color: transparent;
15
-
16
- --ox-filters-form-gap: var(--input-gap-vertical, 8px) var(--input-gap-horizontal, 16px);
17
- --ox-filters-input-padding: var(--spacing-small, 4px);
18
-
19
- --ox-select-padding: var(--ox-filters-input-padding);
20
- --ox-checkbox-background-color: var(--ox-filters-input-background-color, transparent);
21
- }
22
-
23
- label {
24
- color: var(--ox-filters-label-color, var(--md-sys-color-on-primary-container));
25
- }
26
-
27
- span {
28
- font-weight: var(--md-sys-typescale-label-medium-weight);
29
- text-transform: capitalize;
30
- }
31
-
32
- input::placeholder {
33
- color: var(--ox-filters-input-placeholder-color, var(--md-sys-color-surface-dim));
34
- opacity: 0.6;
35
- }
36
-
37
- input,
38
- ox-input-search,
39
- [filter-input] {
40
- padding: var(--ox-filters-input-padding);
41
- }
42
-
43
- ox-select,
44
- ox-input-search,
45
- input,
46
- [filter-input] {
47
- border: none;
48
- border-bottom: var(--ox-filters-input-border, var(--md-sys-color-outline));
49
- font: var(--ox-filters-input-font);
50
- color: var(--ox-filters-input-color, var(--md-sys-color-on-surface));
51
- background-color: var(--ox-filters-input-background-color, transparent);
52
- vertical-align: middle;
53
- }
54
-
55
- ox-select:focus,
56
- input:focus,
57
- [filter-input]:focus {
58
- outline: none;
59
- border-bottom: var(--ox-filters-input-focus-border, var(--md-sys-color-outline-variant));
60
- color: var(--ox-filters-input-focus-color, var(--md-sys-color-on-surface-variant));
61
- }
62
-
63
- ox-select {
64
- min-width: 90px;
65
- max-width: 170px;
66
- }
67
-
68
- ox-input-search {
69
- max-width: 150px;
70
- }
71
-
72
- input[type='number'] {
73
- max-width: 90px;
74
- }
75
-
76
- input[type*='date'],
77
- input[type*='time'],
78
- input[type='week'],
79
- input[type='month'] {
80
- max-width: 170px;
81
- }
82
-
83
- [filter-input] {
84
- min-width: 140px;
85
- max-width: 170px;
86
- }
87
-
88
- @media only screen and (max-width: 460px) {
89
- :host {
90
- --ox-filters-form-label-font: bold 13px var(--theme-font);
91
- --ox-filters-input-font: normal 16px var(--theme-font);
92
- }
93
-
94
- ox-input-barcode {
95
- max-width: unset;
96
- flex: 1;
97
- }
98
-
99
- ox-input-search {
100
- max-width: unset;
101
- }
102
-
103
- ox-select {
104
- max-width: unset;
105
- }
106
-
107
- ox-checkbox {
108
- max-width: unset;
109
- }
110
-
111
- input[type='number'] {
112
- max-width: unset;
113
- }
114
-
115
- input {
116
- flex: 1;
117
- }
118
- }
119
- `
@@ -1,476 +0,0 @@
1
- import '@operato/input/ox-checkbox.js'
2
- import '@operato/input/ox-select.js'
3
- import '@operato/popup/ox-popup-list.js'
4
- import '@operato/input/ox-input-search.js'
5
-
6
- import { css, html, LitElement, PropertyValues, TemplateResult, nothing } from 'lit'
7
- import { customElement, property, queryAsync, state } from 'lit/decorators.js'
8
- import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
9
-
10
- import { PagePreferenceProvider } from '@operato/p13n'
11
- import { getDefaultValue } from '@operato/time-calculator'
12
-
13
- import { FilterConfigObject, FilterPreference } from '../types.js'
14
- import { DataGrist } from '../data-grist'
15
- import { ColumnConfig, FilterOperator, FilterValue, GristConfig, PersonalGristPreference } from '../types'
16
- import { FilterStyles } from './filter-styles'
17
- import { getFilterRenderer } from './registry'
18
-
19
- export type QueryFilterRangeValue = [from: number, to: number]
20
-
21
- export type QueryFilter = {
22
- name: string
23
- operator: FilterOperator
24
- value: any
25
- }
26
-
27
- @customElement('ox-filters-form')
28
- export class OxFiltersForm extends LitElement {
29
- static styles = [
30
- MDTypeScaleStyles,
31
- FilterStyles,
32
- css`
33
- :host {
34
- display: flex;
35
- padding: var(--spacing-small);
36
- }
37
-
38
- form {
39
- flex: 1;
40
-
41
- display: flex;
42
- flex-flow: row wrap;
43
- gap: var(--ox-filters-form-gap);
44
- }
45
-
46
- form > * {
47
- display: flex;
48
- align-items: center;
49
- gap: var(--input-intra-gap, 7px);
50
- }
51
-
52
- label span {
53
- display: block;
54
- }
55
-
56
- @media only screen and (max-width: 460px) {
57
- form {
58
- flex-direction: column;
59
- flex-flow: column;
60
- }
61
- }
62
- `
63
- ]
64
-
65
- @property({ type: Array }) value: FilterValue[] = []
66
- @property({ type: Boolean, attribute: 'without-search' }) withoutSearch: boolean = false
67
- @property({ type: Boolean, attribute: 'autofocus' }) autofocus: boolean = true
68
- @property({ type: Boolean, attribute: 'empty', reflect: true }) empty: boolean = true
69
-
70
- @state() personalConfigProvider?: PagePreferenceProvider
71
- @state() personalConfig?: PersonalGristPreference
72
- @state() personalFilters?: FilterPreference[]
73
-
74
- @state() config!: GristConfig
75
- @state() filterColumns: ColumnConfig[] = []
76
- @state() searchColumns: ColumnConfig[] = []
77
-
78
- @queryAsync('form') form!: HTMLFormElement
79
-
80
- private autoUpdateTargetsOnChange: { [name: string]: string[] } = {}
81
- private objectValue?: object
82
-
83
- connectedCallback(): void {
84
- super.connectedCallback()
85
-
86
- const grist = this.closest('ox-grist') as DataGrist
87
-
88
- if (grist) {
89
- this.config = grist.compiledConfig
90
- this.personalConfigProvider = grist.personalConfigProvider
91
-
92
- grist.addEventListener('config-change', (e: Event) => {
93
- this.config = (e as CustomEvent).detail
94
- })
95
-
96
- grist.addEventListener('fetch-params-change', (e: Event) => {
97
- const { filters, from } = (e as CustomEvent).detail || {}
98
- if (from === 'filters-form') {
99
- return
100
- }
101
-
102
- this.value = filters
103
- })
104
-
105
- this.renderRoot.addEventListener('change', async (e: Event) => {
106
- const { target, detail: value } = e as CustomEvent
107
- const name = (target as HTMLInputElement).name
108
- const { filter } = this.filterColumns.find(filter => filter.name == name) || {}
109
-
110
- if (this.autoUpdateTargetsOnChange[name]) {
111
- /* 일단은 심플하게, boundTo로 연결된 필터값이 바뀌면, 폼 전체를 update하도록 함. */
112
- ;(this.autoUpdateTargetsOnChange[name] || []).forEach(name => {
113
- const target = this.renderRoot.querySelector(`[name='${name}']`)
114
- if (target) {
115
- ;(target as HTMLInputElement).value = ''
116
- }
117
- })
118
-
119
- await this.updateObjectValues()
120
- this.requestUpdate()
121
- }
122
-
123
- const onchange = typeof filter == 'object' ? filter.onchange : null
124
- const keepGoing = onchange ? await onchange.call(null, value ?? (target as HTMLInputElement).value, this) : true
125
-
126
- keepGoing &&
127
- this.dispatchEvent(
128
- new CustomEvent('fetch-params-change', {
129
- bubbles: true,
130
- composed: true,
131
- detail: {
132
- filters: await this.getQueryFilters(),
133
- from: 'filters-form'
134
- }
135
- })
136
- )
137
- })
138
- }
139
- }
140
-
141
- buildDefaultValue(operator: FilterOperator, defaultValue: any) {
142
- if (defaultValue === undefined) {
143
- return
144
- }
145
- if (operator == 'between') {
146
- return (defaultValue as Array<any>).map(v => getDefaultValue(v, this))
147
- } else {
148
- return getDefaultValue(defaultValue, this)
149
- }
150
- }
151
-
152
- async updated(changes: PropertyValues<this>) {
153
- if (changes.has('personalConfigProvider') && this.personalConfigProvider) {
154
- this.personalConfig = await this.personalConfigProvider.load()
155
- } else if (changes.has('config') || changes.has('personalConfig')) {
156
- this.applyUpdatedConfiguration()
157
- }
158
- }
159
-
160
- render(): TemplateResult {
161
- const searchValue =
162
- (this.value?.find(filter => filter.operator === 'search')?.value as string)?.match(/^\%(.*)\%$/)?.[1] || ''
163
-
164
- return this.empty
165
- ? html``
166
- : html`
167
- <form
168
- class="md-typescale-body-medium-prominent"
169
- @submit=${(e: Event) => {
170
- e.stopPropagation()
171
- e.preventDefault()
172
-
173
- const grist = this.closest('ox-grist') as DataGrist
174
-
175
- grist && grist.fetch()
176
- }}
177
- >
178
- ${this.filterColumns
179
- .filter(column => !(column.filter as FilterConfigObject).hidden)
180
- .map((column: ColumnConfig) => {
181
- const { name, header, label, filter } = column
182
-
183
- const type = (filter as FilterConfigObject).type
184
-
185
- if (type == 'search') {
186
- return html`
187
- <ox-input-search name="search" .value=${searchValue} ?autofocus=${this.autofocus}></ox-input-search>
188
- `
189
- }
190
-
191
- const operator = (filter as FilterConfigObject).operator
192
- const filterLabel = (filter as FilterConfigObject).label
193
-
194
- const labelText =
195
- filterLabel !== undefined
196
- ? filterLabel
197
- : typeof label === 'object' && label.renderer
198
- ? label.renderer(column)
199
- : header.renderer(column) || name
200
-
201
- const idx = operator === 'between' ? 1 : 0
202
- const renderer = getFilterRenderer(
203
- operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'
204
- ? 'text'
205
- : type
206
- )[idx]
207
- const value =
208
- this.value?.find(filter => filter.name == name)?.value ??
209
- this.buildDefaultValue(operator!, (filter as FilterConfigObject)?.value)
210
-
211
- if (!renderer) {
212
- return html``
213
- }
214
-
215
- return type === 'boolean' || type === 'checkbox'
216
- ? renderer(column, value, this)
217
- : type !== 'select' && labelText
218
- ? html`<label filter-title ?between=${operator === 'between'}
219
- ><span>${labelText}</span> ${renderer(column, value, this)}
220
- </label> `
221
- : type !== 'select' && !labelText
222
- ? renderer(column, value, this)
223
- : operator === 'in'
224
- ? html`
225
- <ox-select
226
- name=${name}
227
- placeholder=${labelText}
228
- .value=${value}
229
- @change=${(e: CustomEvent) =>
230
- e.target?.dispatchEvent(
231
- new CustomEvent('filter-change', {
232
- detail: {
233
- name,
234
- operator,
235
- value: e.detail
236
- }
237
- })
238
- )}
239
- >
240
- <ox-popup-list multiple attr-selected="checked" with-search>
241
- ${renderer(column, value, this)}
242
- </ox-popup-list>
243
- </ox-select>
244
- `
245
- : html`
246
- <ox-select
247
- name=${name}
248
- placeholder=${labelText}
249
- .value=${value}
250
- @change=${(e: CustomEvent) =>
251
- e.target?.dispatchEvent(
252
- new CustomEvent('filter-change', {
253
- detail: {
254
- name,
255
- operator,
256
- value: e.detail
257
- }
258
- })
259
- )}
260
- >
261
- <ox-popup-list with-search> ${renderer(column, value, this)} </ox-popup-list>
262
- </ox-select>
263
- `
264
- })}
265
- </form>
266
- <slot name="setting"></slot>
267
- `
268
- }
269
-
270
- applyUpdatedConfiguration() {
271
- if (!this.config) {
272
- return
273
- }
274
-
275
- const filters = this.config.columns.filter(columnConfig => !!columnConfig.filter)
276
-
277
- this.filterColumns = filters.filter((columnConfig: ColumnConfig) => {
278
- const filter = columnConfig.filter as FilterConfigObject
279
- return filter!.operator !== 'search'
280
- })
281
- this.searchColumns = filters.filter(columnConfig => {
282
- const filter = columnConfig.filter as FilterConfigObject
283
- return filter!.operator === 'search'
284
- })
285
-
286
- if (this.searchColumns.length > 0 && !this.withoutSearch) {
287
- this.filterColumns.unshift({ name: 'search', filter: { type: 'search' } } as any)
288
- }
289
-
290
- if (!this.personalConfig) {
291
- this.personalFilters = this.filterColumns.map(column => {
292
- return { name: column.name }
293
- })
294
- } else {
295
- const { filters: personalFilters = [] } = this.personalConfig
296
-
297
- if (personalFilters) {
298
- const xfilters = this.filterColumns.map(column => {
299
- return personalFilters.find(pFilter => pFilter.name == column.name) || { name: column.name }
300
- })
301
-
302
- function reorderList(a: FilterPreference[], b: FilterPreference[]): FilterPreference[] {
303
- // 결과 배열 초기화, a 배열 길이만큼 undefined로 채움
304
- const result = new Array(a.length)
305
-
306
- // b 배열에 없는 아이템은 원래 위치로 채움
307
- a.forEach((item, index) => {
308
- if (!item.name || !b.find(bi => bi.name == item.name)) {
309
- result[index] = item
310
- }
311
- })
312
-
313
- b.forEach(item => {
314
- const ai = a.find(ai => ai.name == item.name)
315
- if (ai) {
316
- result[result.findIndex(slot => slot === undefined)] = ai
317
- }
318
- })
319
-
320
- return result
321
- }
322
-
323
- // 배열 재정렬 실행
324
- this.personalFilters = reorderList(xfilters as any, personalFilters as any) as FilterPreference[]
325
-
326
- this.filterColumns = this.personalFilters
327
- .map(filter => {
328
- const column = this.filterColumns.find(column => column.name == filter.name)
329
- if (column?.filter) {
330
- ;(column.filter as FilterConfigObject)!.hidden = filter.hidden
331
- }
332
- return column
333
- })
334
- .filter(Boolean) as ColumnConfig[]
335
- }
336
- }
337
-
338
- const grist = this.closest('ox-grist') as DataGrist
339
-
340
- this.value = (grist?.filters || []).map(filter => {
341
- return {
342
- ...filter,
343
- value: this.buildDefaultValue(filter!.operator, filter!.value)
344
- }
345
- })
346
-
347
- this.empty = (this.searchColumns.length === 0 || this.withoutSearch) && this.filterColumns.length === 0
348
-
349
- this.autoUpdateTargetsOnChange = {}
350
- this.filterColumns
351
- ?.filter(({ filter }) => {
352
- return typeof filter == 'object' && filter.boundTo && filter.boundTo.length > 0
353
- })
354
- .map(({ name, filter }) => {
355
- const boundTo = (filter as FilterConfigObject).boundTo
356
-
357
- boundTo!.forEach(to => {
358
- const origin = this.autoUpdateTargetsOnChange[to] || []
359
- if (name && !origin.includes(name)) {
360
- this.autoUpdateTargetsOnChange[to] = [...origin, name]
361
- }
362
- })
363
- })
364
- }
365
-
366
- async getQueryFilters(): Promise<QueryFilter[]> {
367
- const form = await this.form
368
- if (!form) return []
369
-
370
- const formData = new FormData(form)
371
- const search: string | undefined = formData.get('search')?.toString()
372
-
373
- var filters = this.filterColumns
374
- .filter(column => column.name !== 'search' && !(column.filter as FilterConfigObject)!.hidden)
375
- .map((column: ColumnConfig) => {
376
- const { name, type, filter } = column
377
- const operator = (filter as FilterConfigObject).operator
378
-
379
- var value = formData.getAll(name)
380
- if (value.length == 0) {
381
- return
382
- }
383
-
384
- if (-1 === value.findIndex(v => v !== '')) {
385
- return
386
- }
387
-
388
- const filterValue = value.map(v => {
389
- const value = v.toString()
390
-
391
- /* TODO registry에서 타입별로 parsing 방법을 지정할 수 있도록 해야한다. */
392
- switch (type) {
393
- case 'integer':
394
- case 'float':
395
- case 'number':
396
- case 'progress':
397
- case 'checkbox':
398
- case 'boolean':
399
- return !value ? undefined : JSON.parse(value)
400
- default:
401
- return value
402
- }
403
- })
404
-
405
- return {
406
- name,
407
- operator,
408
- value: filterValue.length === 1 ? filterValue[0] : filterValue
409
- }
410
- })
411
- .filter(result => result !== undefined) as QueryFilter[]
412
-
413
- if (search) {
414
- filters = filters.concat(
415
- this.searchColumns.map((column: ColumnConfig) => {
416
- const { name } = column
417
-
418
- return {
419
- name,
420
- operator: 'search',
421
- value: `%${search}%`
422
- }
423
- })
424
- )
425
- }
426
-
427
- return filters
428
- }
429
-
430
- public setInputValue(name: string, value: any) {
431
- const input = this.renderRoot.querySelector(`form [name="${name}"]`) as HTMLInputElement
432
- if (input) {
433
- input.value = value
434
- input.dispatchEvent(new Event('change', { bubbles: true }))
435
- }
436
- }
437
-
438
- public getInputValue(name: string): any {
439
- const input = this.renderRoot.querySelector(`form [name="${name}"]`) as HTMLInputElement
440
- return input?.value
441
- }
442
-
443
- private async updateObjectValues() {
444
- const form = await this.form
445
- if (!form) return []
446
-
447
- const formData = new FormData(form)
448
-
449
- const object = {} as any
450
- formData.forEach((value, key) => {
451
- const prev = object[key]
452
-
453
- if (key in object) {
454
- object[key] = prev instanceof Array ? [...prev, value] : [prev, value]
455
- } else {
456
- object[key] = value
457
- }
458
- })
459
-
460
- this.objectValue = object
461
- }
462
-
463
- public getFormObjectValue() {
464
- return this.objectValue
465
- }
466
-
467
- reset() {
468
- this.form
469
- .then((form: HTMLFormElement) => {
470
- form.reset()
471
- })
472
- .catch((error: any) => {
473
- console.error('Error resetting the form:', error)
474
- })
475
- }
476
- }
@@ -1,10 +0,0 @@
1
- export * from './registry'
2
-
3
- export * from './filter-select'
4
- export * from './filter-input'
5
- export * from './filter-checkbox'
6
- export * from './filter-range-date'
7
- export * from './filter-range-number'
8
- export * from './filter-select-buttons'
9
-
10
- export * from './filters-form'