@operato/data-grist 0.2.35 → 0.2.39

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 (113) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/custom-elements.json +1702 -5
  3. package/demo/data-grist-test.html +1 -1
  4. package/demo/index.html +18 -1
  5. package/dist/src/data-card/data-card-gutter-menu.js +2 -2
  6. package/dist/src/data-card/data-card-gutter-menu.js.map +1 -1
  7. package/dist/src/data-card/data-card-gutter.d.ts +13 -1
  8. package/dist/src/data-card/data-card-gutter.js +1 -0
  9. package/dist/src/data-card/data-card-gutter.js.map +1 -1
  10. package/dist/src/data-card/data-card.d.ts +1 -1
  11. package/dist/src/data-card/data-card.js +2 -8
  12. package/dist/src/data-card/data-card.js.map +1 -1
  13. package/dist/src/data-consumer.d.ts +1 -10
  14. package/dist/src/data-consumer.js.map +1 -1
  15. package/dist/src/data-grid/data-grid-field.d.ts +2 -2
  16. package/dist/src/data-grid/data-grid-field.js.map +1 -1
  17. package/dist/src/data-grid/data-grid-header.d.ts +3 -0
  18. package/dist/src/data-grid/data-grid-header.js +38 -10
  19. package/dist/src/data-grid/data-grid-header.js.map +1 -1
  20. package/dist/src/data-grist.d.ts +11 -9
  21. package/dist/src/data-grist.js +38 -25
  22. package/dist/src/data-grist.js.map +1 -1
  23. package/dist/src/data-list/data-list-field.d.ts +2 -2
  24. package/dist/src/data-list/data-list-field.js +5 -5
  25. package/dist/src/data-list/data-list-field.js.map +1 -1
  26. package/dist/src/data-list/data-list-gutter.d.ts +13 -1
  27. package/dist/src/data-list/data-list-gutter.js +1 -0
  28. package/dist/src/data-list/data-list-gutter.js.map +1 -1
  29. package/dist/src/data-list/data-list.d.ts +1 -1
  30. package/dist/src/data-list/data-list.js +2 -8
  31. package/dist/src/data-list/data-list.js.map +1 -1
  32. package/dist/src/data-provider.js +2 -2
  33. package/dist/src/data-provider.js.map +1 -1
  34. package/dist/src/data-report/data-report-field.d.ts +2 -2
  35. package/dist/src/data-report/data-report-field.js.map +1 -1
  36. package/dist/src/filters/index.d.ts +2 -0
  37. package/dist/src/filters/index.js +3 -0
  38. package/dist/src/filters/index.js.map +1 -0
  39. package/dist/src/filters/list-select.d.ts +3 -0
  40. package/dist/src/filters/list-select.js +12 -0
  41. package/dist/src/filters/list-select.js.map +1 -0
  42. package/dist/src/filters/registry.d.ts +7 -0
  43. package/dist/src/filters/registry.js +40 -0
  44. package/dist/src/filters/registry.js.map +1 -0
  45. package/dist/src/index.d.ts +2 -0
  46. package/dist/src/index.js +2 -0
  47. package/dist/src/index.js.map +1 -1
  48. package/dist/src/interfaces/index.d.ts +2 -0
  49. package/dist/src/interfaces/index.js +3 -0
  50. package/dist/src/interfaces/index.js.map +1 -0
  51. package/dist/src/interfaces/ox-grist-search-form.d.ts +6 -0
  52. package/dist/src/interfaces/ox-grist-search-form.js +2 -0
  53. package/dist/src/interfaces/ox-grist-search-form.js.map +1 -0
  54. package/dist/src/interfaces/ox-search-field.d.ts +39 -0
  55. package/dist/src/interfaces/ox-search-field.js +2 -0
  56. package/dist/src/interfaces/ox-search-field.js.map +1 -0
  57. package/dist/src/search-form/index.d.ts +7 -0
  58. package/dist/src/search-form/index.js +8 -0
  59. package/dist/src/search-form/index.js.map +1 -0
  60. package/dist/src/search-form/ox-basic-field.d.ts +18 -0
  61. package/dist/src/search-form/ox-basic-field.js +75 -0
  62. package/dist/src/search-form/ox-basic-field.js.map +1 -0
  63. package/dist/src/search-form/ox-checkbox-field.d.ts +11 -0
  64. package/dist/src/search-form/ox-checkbox-field.js +60 -0
  65. package/dist/src/search-form/ox-checkbox-field.js.map +1 -0
  66. package/dist/src/search-form/ox-grist-search-form.d.ts +11 -0
  67. package/dist/src/search-form/ox-grist-search-form.js +177 -0
  68. package/dist/src/search-form/ox-grist-search-form.js.map +1 -0
  69. package/dist/src/search-form/ox-number-field.d.ts +14 -0
  70. package/dist/src/search-form/ox-number-field.js +112 -0
  71. package/dist/src/search-form/ox-number-field.js.map +1 -0
  72. package/dist/src/search-form/ox-search-form.d.ts +15 -0
  73. package/dist/src/search-form/ox-search-form.js +53 -0
  74. package/dist/src/search-form/ox-search-form.js.map +1 -0
  75. package/dist/src/search-form/ox-select-field.d.ts +21 -0
  76. package/dist/src/search-form/ox-select-field.js +181 -0
  77. package/dist/src/search-form/ox-select-field.js.map +1 -0
  78. package/dist/src/search-form/ox-text-field.d.ts +11 -0
  79. package/dist/src/search-form/ox-text-field.js +60 -0
  80. package/dist/src/search-form/ox-text-field.js.map +1 -0
  81. package/dist/src/types.d.ts +32 -3
  82. package/dist/src/types.js.map +1 -1
  83. package/dist/tsconfig.tsbuildinfo +1 -1
  84. package/package.json +7 -6
  85. package/src/data-card/data-card-gutter-menu.ts +2 -2
  86. package/src/data-card/data-card-gutter.ts +3 -3
  87. package/src/data-card/data-card.ts +3 -9
  88. package/src/data-consumer.ts +1 -6
  89. package/src/data-grid/data-grid-field.ts +2 -2
  90. package/src/data-grid/data-grid-header.ts +42 -11
  91. package/src/data-grist.ts +52 -31
  92. package/src/data-list/data-list-field.ts +8 -7
  93. package/src/data-list/data-list-gutter.ts +3 -3
  94. package/src/data-list/data-list.ts +3 -9
  95. package/src/data-provider.ts +4 -5
  96. package/src/data-report/data-report-field.ts +2 -2
  97. package/src/filters/index.ts +3 -0
  98. package/src/filters/list-select.ts +14 -0
  99. package/src/filters/registry.ts +48 -0
  100. package/src/index.ts +3 -0
  101. package/src/interfaces/index.ts +2 -0
  102. package/src/interfaces/ox-grist-search-form.ts +7 -0
  103. package/src/interfaces/ox-search-field.ts +52 -0
  104. package/src/search-form/index.ts +7 -0
  105. package/src/search-form/ox-basic-field.ts +86 -0
  106. package/src/search-form/ox-checkbox-field.ts +57 -0
  107. package/src/search-form/ox-grist-search-form.ts +200 -0
  108. package/src/search-form/ox-number-field.ts +113 -0
  109. package/src/search-form/ox-search-form.ts +71 -0
  110. package/src/search-form/ox-select-field.ts +188 -0
  111. package/src/search-form/ox-text-field.ts +55 -0
  112. package/src/types.ts +37 -3
  113. package/yarn-error.log +2427 -3205
package/src/data-grist.ts CHANGED
@@ -3,22 +3,23 @@ import './data-list/data-list'
3
3
  import './data-card/data-card'
4
4
  import './empty-note'
5
5
 
6
- import { DataConsumer, FetchHandler } from './data-consumer'
7
- import { GristConfig, GristData, GristRecord } from './types'
8
- import { HeadroomStyles, ScrollbarStyles, SpinnerStyles } from '@operato/styles'
9
- import { LitElement, PropertyValues, css, html } from 'lit'
10
- import { ZERO_CONFIG, ZERO_DATA, ZERO_PAGINATION } from './configure/zero-config'
6
+ import { css, html, LitElement, PropertyValues } from 'lit'
11
7
  import { customElement, property, query, queryAsync, state } from 'lit/decorators.js'
8
+ import isEmpty from 'lodash-es/isEmpty'
9
+ import isEqual from 'lodash-es/isEqual'
12
10
 
11
+ import Headroom from '@operato/headroom'
12
+ import { pulltorefresh } from '@operato/pull-to-refresh'
13
+ import { HeadroomStyles, ScrollbarStyles, SpinnerStyles } from '@operato/styles'
14
+
15
+ import { buildConfig } from './configure/config-builder'
16
+ import { ZERO_CONFIG, ZERO_DATA, ZERO_PAGINATION } from './configure/zero-config'
13
17
  import { DataCard } from './data-card/data-card'
18
+ import { DataConsumer } from './data-consumer'
14
19
  import { DataGrid } from './data-grid/data-grid'
15
20
  import { DataList } from './data-list/data-list'
16
21
  import { DataProvider } from './data-provider'
17
- import Headroom from '@operato/headroom'
18
- import { buildConfig } from './configure/config-builder'
19
- import isEmpty from 'lodash-es/isEmpty'
20
- import isEqual from 'lodash-es/isEqual'
21
- import { pulltorefresh } from '@operato/pull-to-refresh'
22
+ import { FetchHandler, GristConfig, GristData, GristRecord } from './types'
22
23
 
23
24
  @customElement('ox-grist')
24
25
  export class DataGrist extends LitElement implements DataConsumer {
@@ -88,37 +89,41 @@ export class DataGrist extends LitElement implements DataConsumer {
88
89
  @state() private _showSpinner: boolean = false
89
90
 
90
91
  private dataProvider?: DataProvider
91
- private pulltorefreshHandle?: any
92
- private headroom?: Headroom
92
+ private _pulltorefreshHandle?: any
93
+ private _headroom?: Headroom
94
+ private orginPaddingTop?: string
95
+ private originMarginTop?: string
93
96
 
94
97
  @query('slot[name=headroom]') head!: HTMLElement
95
98
  @query('#grist') grist!: DataGrid | DataList | DataCard
96
99
  @queryAsync('#wrap') private wrap!: Promise<HTMLElement>
97
100
 
98
- connectedCallback() {
101
+ async connectedCallback() {
99
102
  super.connectedCallback()
100
103
 
101
104
  this.dataProvider = new DataProvider(this)
105
+
106
+ await this.updateComplete
102
107
  }
103
108
 
104
109
  disconnectedCallback() {
105
110
  super.disconnectedCallback()
106
111
 
107
112
  this.dataProvider?.dispose()
108
- this.resetPullToRefresh()
113
+ this._resetPullToRefresh()
109
114
  }
110
115
 
111
- private resetPullToRefresh() {
112
- if (this.pulltorefreshHandle) {
113
- this.pulltorefreshHandle()
114
- delete this.pulltorefreshHandle
116
+ private _resetPullToRefresh() {
117
+ if (this._pulltorefreshHandle) {
118
+ this._pulltorefreshHandle()
119
+ delete this._pulltorefreshHandle
115
120
  }
116
121
  }
117
122
 
118
- private async setPullToRefresh() {
119
- this.resetPullToRefresh()
123
+ private async _setPullToRefresh() {
124
+ this._resetPullToRefresh()
120
125
  if (this.fetchHandler) {
121
- this.pulltorefreshHandle = pulltorefresh({
126
+ this._pulltorefreshHandle = pulltorefresh({
122
127
  container: await this.wrap,
123
128
  scrollable: this.grist.pullToRefreshTarget,
124
129
  refresh: () => {
@@ -128,17 +133,33 @@ export class DataGrist extends LitElement implements DataConsumer {
128
133
  }
129
134
  }
130
135
 
131
- setHeadroom() {
132
- this.headroom?.destroy()
136
+ private _setHeadroom() {
137
+ this._headroom?.destroy()
133
138
 
134
139
  if (this.grist && this.head) {
135
- var originPaddingTop = parseFloat(getComputedStyle(this.grist, null).getPropertyValue('padding-top'))
136
- this.grist.style.paddingTop = this.head.clientHeight + originPaddingTop + 'px'
140
+ const style = getComputedStyle(this.grist)
137
141
 
138
- this.headroom = new Headroom(this.head, {
139
- scroller: this.grist
142
+ this.orginPaddingTop = style.paddingTop || '0'
143
+ this.originMarginTop = style.marginTop || '0'
144
+
145
+ console.log(this.orginPaddingTop, this.originMarginTop)
146
+
147
+ this._headroom = new Headroom(this.head, {
148
+ scroller: this.grist,
149
+ onTop: () => {
150
+ this.grist.style.paddingTop = this.orginPaddingTop!
151
+
152
+ this.originMarginTop = this.grist.style.marginTop
153
+ this.grist.style.marginTop = this.head.clientHeight + 'px'
154
+ },
155
+ onNotTop: () => {
156
+ this.grist.style.marginTop = this.originMarginTop!
157
+
158
+ this.orginPaddingTop = this.grist.style.paddingTop
159
+ this.grist.style.paddingTop = this.head.clientHeight + 'px'
160
+ }
140
161
  })
141
- this.headroom.init()
162
+ this._headroom.init()
142
163
  }
143
164
  }
144
165
 
@@ -228,7 +249,7 @@ export class DataGrist extends LitElement implements DataConsumer {
228
249
 
229
250
  if (changes.has('mode')) {
230
251
  needToSetPullToRefresh = true
231
- this.setHeadroom()
252
+ this._setHeadroom()
232
253
  }
233
254
 
234
255
  if (changes.has('selectedRecords')) {
@@ -251,7 +272,7 @@ export class DataGrist extends LitElement implements DataConsumer {
251
272
  }
252
273
 
253
274
  if (needToSetPullToRefresh) {
254
- await this.setPullToRefresh()
275
+ await this._setPullToRefresh()
255
276
  }
256
277
  }
257
278
 
@@ -355,7 +376,7 @@ export class DataGrist extends LitElement implements DataConsumer {
355
376
  /**
356
377
  * Forced internal data to be reflected on the screen
357
378
  * Data changing through a normal method is automatically reflected on the screen, so it is a method that does not need to be used in general.
358
- Therefore, it will be deprecated.
379
+ * Therefore, it will be deprecated.
359
380
  * @deprecated
360
381
  * @method
361
382
  */
@@ -1,8 +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, TemplateResult } from 'lit'
4
2
  import { customElement, property } from 'lit/decorators.js'
5
3
 
4
+ import { ZERO_COLUMN, ZERO_RECORD } from '../configure/zero-config'
5
+ import { ColumnConfig, GristRecord } from '../types'
6
+
6
7
  @customElement('ox-list-field')
7
8
  export class DataListField extends LitElement {
8
9
  static styles = [
@@ -56,19 +57,19 @@ export class DataListField extends LitElement {
56
57
  @property({ type: Number }) rowIndex: number = -1
57
58
  @property({ type: Object }) value?: object
58
59
 
59
- render() {
60
+ render(): TemplateResult {
60
61
  var { value, column, record, rowIndex } = this
61
62
 
62
63
  var {
63
64
  label,
64
- record: { renderer: recordRenderer }
65
+ record: { renderer: fieldRenderer }
65
66
  } = column
66
67
 
67
68
  if (typeof label == 'object') {
68
69
  let { renderer: labelRenderer } = label
69
- return html`<label>${labelRenderer()}</label>${recordRenderer(value, column, record, rowIndex, this)}`
70
+ return html`<label>${labelRenderer()}</label>${fieldRenderer(value, column, record, rowIndex, this)}`
70
71
  } else {
71
- return html`${recordRenderer(value, column, record, rowIndex, this)}`
72
+ return html`${fieldRenderer(value, column, record, rowIndex, this)}`
72
73
  }
73
74
  }
74
75
  }
@@ -1,12 +1,12 @@
1
1
  import { ColumnConfig, GristRecord } from '../types'
2
- import { LitElement, PropertyValues, css, html } from 'lit'
2
+ import { LitElement, PropertyValues, TemplateResult, css, html } from 'lit'
3
3
  import { ZERO_COLUMN, ZERO_RECORD } from '../configure/zero-config'
4
4
  import { customElement, property } from 'lit/decorators.js'
5
5
 
6
6
  const DEFAULT_TEXT_ALIGN = 'left'
7
7
 
8
8
  @customElement('ox-list-gutter')
9
- class DataListGutter extends LitElement {
9
+ export class DataListGutter extends LitElement {
10
10
  static styles = [
11
11
  css`
12
12
  :host {
@@ -46,7 +46,7 @@ class DataListGutter extends LitElement {
46
46
  return this.hasAttribute('editing')
47
47
  }
48
48
 
49
- render() {
49
+ render(): TemplateResult {
50
50
  if (!this.column) {
51
51
  return html``
52
52
  }
@@ -1,11 +1,11 @@
1
1
  import '@material/mwc-icon'
2
2
  import './record-partial'
3
3
 
4
- import { ColumnConfig, GristConfig, GristData, GristRecord } from '../types'
5
- import { LitElement, PropertyValues, css, html } from 'lit'
6
- import { ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
4
+ import { css, html, LitElement, PropertyValues } from 'lit'
7
5
  import { customElement, property } from 'lit/decorators.js'
8
6
 
7
+ import { ZERO_CONFIG, ZERO_DATA } from '../configure/zero-config'
8
+ import { ColumnConfig, GristConfig, GristData, GristRecord } from '../types'
9
9
  import { dataListClickHandler } from './event-handlers/data-list-click-handler'
10
10
  import { dataListDblclickHandler } from './event-handlers/data-list-dblclick-handler'
11
11
 
@@ -41,12 +41,6 @@ export class DataList extends LitElement {
41
41
  slot {
42
42
  width: 100%;
43
43
  }
44
-
45
- slot[name='headroom'] {
46
- display: flex;
47
- position: absolute;
48
- top: 0;
49
- }
50
44
  `
51
45
  ]
52
46
 
@@ -1,7 +1,6 @@
1
- import { DataConsumer, FetchHandler } from './data-consumer'
2
- import { GristRecord, SorterConfig } from './types'
3
-
4
1
  import { ZERO_RECORDS } from './configure/zero-config'
2
+ import { DataConsumer } from './data-consumer'
3
+ import { FetchHandler, FetchOption, GristRecord, SorterConfig } from './types'
5
4
 
6
5
  function EMPTY_FETCHHANDLER() {
7
6
  return {
@@ -92,14 +91,14 @@ export class DataProvider {
92
91
 
93
92
  get fetchHandler() {
94
93
  if (!this._fetchHandlerWrap) {
95
- this._fetchHandlerWrap = async (...args: any[]) => {
94
+ this._fetchHandlerWrap = async (options: FetchOption) => {
96
95
  if (!this._fetchHandler) {
97
96
  return
98
97
  }
99
98
 
100
99
  try {
101
100
  this.consumer?.showSpinner()
102
- return await (this._fetchHandler || EMPTY_FETCHHANDLER)(...args)
101
+ return await (this._fetchHandler || EMPTY_FETCHHANDLER)(options)
103
102
  } finally {
104
103
  this.consumer?.hideSpinner()
105
104
  }
@@ -1,5 +1,5 @@
1
1
  import { ColumnConfig, GristRecord } from '../types'
2
- import { LitElement, PropertyValues, css, html } from 'lit'
2
+ import { LitElement, PropertyValues, TemplateResult, css, html } from 'lit'
3
3
  import { ZERO_COLUMN, ZERO_RECORD } from '../configure/zero-config'
4
4
  import { customElement, property } from 'lit/decorators.js'
5
5
 
@@ -52,7 +52,7 @@ export class DataReportField extends LitElement {
52
52
  @property({ type: Number }) columnIndex: number = -1
53
53
  @property({ type: Object }) value: any
54
54
 
55
- render() {
55
+ render(): TemplateResult {
56
56
  if (!this.column) {
57
57
  return html``
58
58
  }
@@ -0,0 +1,3 @@
1
+ export * from './registry'
2
+
3
+ export * from './list-select'
@@ -0,0 +1,14 @@
1
+ import '@operato/popup'
2
+
3
+ import { FilterSelectRenderer } from '../types'
4
+ import { html } from 'lit-html'
5
+
6
+ export const ListSelect: FilterSelectRenderer = (column, owner) => {
7
+ const options = column.filter?.options
8
+
9
+ return html`
10
+ <ox-popup-list .config=${column} multiple attr-selected="checked" popup>
11
+ ${options?.map((option: string) => html` <ox-checkbox option value="${option}">${option}</ox-checkbox> `)}
12
+ </ox-popup-list>
13
+ `
14
+ }
@@ -0,0 +1,48 @@
1
+ import { FilterSelectRenderer } from '../types'
2
+ import { ListSelect } from './list-select'
3
+
4
+ var RENDERERS: {
5
+ [name: string]: FilterSelectRenderer
6
+ } = {
7
+ string: ListSelect,
8
+ text: ListSelect,
9
+ email: ListSelect,
10
+ tel: ListSelect,
11
+ password: ListSelect,
12
+ integer: ListSelect,
13
+ float: ListSelect,
14
+ number: ListSelect,
15
+ select: ListSelect,
16
+ boolean: ListSelect,
17
+ checkbox: ListSelect,
18
+ month: ListSelect,
19
+ week: ListSelect,
20
+ date: ListSelect,
21
+ time: ListSelect,
22
+ datetime: ListSelect,
23
+ color: ListSelect,
24
+ progress: ListSelect,
25
+ link: ListSelect,
26
+ image: ListSelect,
27
+ json5: ListSelect
28
+ }
29
+
30
+ export function registerRenderer(type: string, renderer: FilterSelectRenderer) {
31
+ RENDERERS[type] = renderer
32
+ }
33
+
34
+ export function unregisterRenderer(type: string): void {
35
+ delete RENDERERS[type]
36
+ }
37
+
38
+ export function getRenderers(): { [name: string]: FilterSelectRenderer } {
39
+ return { ...RENDERERS }
40
+ }
41
+
42
+ export function getRenderer(type: string | FilterSelectRenderer): FilterSelectRenderer {
43
+ if (typeof type == 'function') {
44
+ return type
45
+ }
46
+
47
+ return RENDERERS[type || 'text'] || ListSelect
48
+ }
package/src/index.ts CHANGED
@@ -7,3 +7,6 @@ export * from './renderers'
7
7
  export * from './handlers'
8
8
  export * from './formatters'
9
9
  export * from './gutters'
10
+
11
+ export * from './interfaces'
12
+ export * from './search-form'
@@ -0,0 +1,2 @@
1
+ export * from './ox-search-field'
2
+ export * from './ox-grist-search-form'
@@ -0,0 +1,7 @@
1
+ export type QueryFilterRangeValue = [from: number, to: number]
2
+
3
+ export type QueryFilter = {
4
+ name: string
5
+ operator?: string
6
+ value: any
7
+ }
@@ -0,0 +1,52 @@
1
+ export type OXSearchFieldType = 'select' | 'checkbox' | 'text' | 'number'
2
+
3
+ export interface OXFieldOptionProps {
4
+ name?: string
5
+ value: string
6
+ }
7
+
8
+ export interface OXBasicFieldProps {
9
+ name: string
10
+ type?: OXSearchFieldType
11
+ hidden?: boolean
12
+ id?: string
13
+ placeholder?: string
14
+ handlers?: Record<string, (event: Event) => void>
15
+ defaultValue?: any
16
+ operator?: string
17
+ }
18
+
19
+ export interface OXTextFieldProps extends OXBasicFieldProps {
20
+ defaultValue?: string
21
+ }
22
+
23
+ export interface OXNumberFieldProps extends OXBasicFieldProps {
24
+ min?: number
25
+ max?: number
26
+ step: number
27
+ defaultValue?: number
28
+ }
29
+
30
+ export interface OXObjectFieldProps extends OXBasicFieldProps {
31
+ field: string
32
+ queryName: string
33
+ defaultValue?: Record<string, any>
34
+ }
35
+
36
+ export interface OXSelectFieldProps extends OXBasicFieldProps {
37
+ searchEnable?: boolean
38
+ options: OXFieldOptionProps[]
39
+ defaultValue?: any
40
+ }
41
+
42
+ export interface OXCheckboxFieldProps extends OXBasicFieldProps {
43
+ indeterminate?: boolean
44
+ defaultValue?: boolean
45
+ }
46
+
47
+ export type OXSearchFieldProps =
48
+ | OXTextFieldProps
49
+ | OXNumberFieldProps
50
+ | OXObjectFieldProps
51
+ | OXSelectFieldProps
52
+ | OXCheckboxFieldProps
@@ -0,0 +1,7 @@
1
+ export * from './ox-search-form'
2
+ export * from './ox-grist-search-form'
3
+ export * from './ox-basic-field'
4
+ export * from './ox-checkbox-field'
5
+ export * from './ox-number-field'
6
+ export * from './ox-select-field'
7
+ export * from './ox-text-field'
@@ -0,0 +1,86 @@
1
+ import { css, LitElement } from 'lit-element'
2
+
3
+ import { OXBasicFieldProps } from '../interfaces/ox-search-field'
4
+
5
+ export abstract class OXBasicField extends LitElement {
6
+ static styles = [
7
+ css`
8
+ input,
9
+ select {
10
+ background-color: transparent;
11
+ border: none;
12
+ box-sizing: border-box;
13
+ outline: none;
14
+ padding: 4px 9px;
15
+ font-size: var(--fontsize-default, 14px);
16
+ color: var(--primary-text-color, #476172);
17
+ font-weight: bold;
18
+ }
19
+ `
20
+ ]
21
+
22
+ field!: OXBasicFieldProps
23
+
24
+ private form: HTMLFormElement | null = null
25
+ value?: any
26
+
27
+ abstract setDefaultValue(defaultValue: unknown): void
28
+
29
+ get input(): HTMLInputElement | HTMLSelectElement {
30
+ if (!this.field.name) throw new Error('No name property provided')
31
+ const input: HTMLInputElement | null = this.renderRoot.querySelector(
32
+ `input[name=${this.field.name}],select[name=${this.field.name}]`
33
+ )
34
+ if (!input) throw new Error('Failed to find input element')
35
+
36
+ return input
37
+ }
38
+
39
+ override connectedCallback(): void {
40
+ super.connectedCallback()
41
+ this.form = this.findFormElement()
42
+ this.form?.addEventListener('formdata', this.appendFormData.bind(this))
43
+ }
44
+
45
+ override disconnectedCallback(): void {
46
+ super.disconnectedCallback()
47
+ this.form?.removeEventListener('formdata', this.appendFormData.bind(this))
48
+ this.form = null
49
+ }
50
+
51
+ override firstUpdated(): void {
52
+ const { handlers } = this.field || {}
53
+
54
+ this.registerBasicEventHandlers()
55
+ if (handlers) this.registerCustomEventHandlers(handlers)
56
+ if (this.field.defaultValue !== undefined) this.setDefaultValue(this.field.defaultValue)
57
+ }
58
+
59
+ private findFormElement(): HTMLFormElement | null {
60
+ const rootNode: HTMLElement = this.getRootNode() as HTMLElement
61
+ const forms: HTMLFormElement[] = Array.from(rootNode.querySelectorAll('form'))
62
+
63
+ return forms.find((form: HTMLFormElement) => form.contains(this)) || null
64
+ }
65
+
66
+ private registerCustomEventHandlers(handlers: Record<string, (event: Event) => void>): void {
67
+ const eventNames: string[] = Object.keys(handlers)
68
+ if (!eventNames.length) return
69
+
70
+ eventNames.forEach((eventName: string) => this.input.addEventListener(eventName, handlers[eventName]))
71
+ }
72
+
73
+ private registerBasicEventHandlers(): void {
74
+ this.input.onkeydown = (event: KeyboardEvent) => {
75
+ if (event.key === 'Enter') this.submit()
76
+ }
77
+ }
78
+
79
+ private appendFormData({ formData }: FormDataEvent): void {
80
+ formData.append(this.field.name, this.value)
81
+ }
82
+
83
+ private submit(): void {
84
+ if (this.form) this.dispatchEvent(new CustomEvent('submit-field', { composed: true, bubbles: true }))
85
+ }
86
+ }
@@ -0,0 +1,57 @@
1
+ import { css, html, TemplateResult } from 'lit'
2
+ import { ifDefined } from 'lit-html/directives/if-defined.js'
3
+ import { customElement, property } from 'lit/decorators.js'
4
+
5
+ import { OXCheckboxFieldProps } from '..'
6
+ import { OXBasicField } from './ox-basic-field'
7
+
8
+ @customElement('ox-checkbox-field')
9
+ export class OXCheckboxField extends OXBasicField {
10
+ @property({ type: Object }) field!: OXCheckboxFieldProps
11
+ @property({ type: Boolean }) value?: boolean
12
+
13
+ static styles = [
14
+ css`
15
+ label {
16
+ font-size: var(--fontsize-default, 14px);
17
+ color: var(--primary-text-color, #476172);
18
+ }
19
+ `
20
+ ]
21
+
22
+ setDefaultValue(defaultValue: boolean): void {
23
+ this.value = defaultValue
24
+ }
25
+
26
+ render(): TemplateResult {
27
+ const { name, hidden, placeholder, id } = this.field
28
+
29
+ return html`<label ?hidden=${hidden}>
30
+ <input
31
+ id=${ifDefined(id)}
32
+ type="checkbox"
33
+ name=${name}
34
+ .checked=${Boolean(this.value)}
35
+ @click=${this.onClickHandler.bind(this)}
36
+ />
37
+ ${placeholder || name}
38
+ </label>`
39
+ }
40
+
41
+ private onClickHandler(): void {
42
+ const checkbox: HTMLInputElement = this.input as HTMLInputElement
43
+
44
+ if (!this.field.indeterminate) {
45
+ this.value = !this.value
46
+ } else {
47
+ if (this.value === false) {
48
+ this.value = undefined
49
+ checkbox.indeterminate = true
50
+ } else if (this.value === undefined) {
51
+ this.value = true
52
+ } else {
53
+ this.value = false
54
+ }
55
+ }
56
+ }
57
+ }