@operato/form 2.0.0-alpha.0 → 2.0.0-alpha.103

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 (91) hide show
  1. package/CHANGELOG.md +164 -0
  2. package/demo/index.html +14 -3
  3. package/dist/src/components/ox-custom-input.d.ts +1 -1
  4. package/dist/src/components/ox-custom-select.d.ts +1 -1
  5. package/dist/src/components/ox-file-uploader.d.ts +1 -1
  6. package/dist/src/components/ox-file-uploader.js +7 -7
  7. package/dist/src/components/ox-file-uploader.js.map +1 -1
  8. package/dist/src/components/ox-form-paginator.d.ts +1 -1
  9. package/dist/src/components/ox-search-form.d.ts +10 -25
  10. package/dist/src/components/ox-search-form.js +163 -89
  11. package/dist/src/components/ox-search-form.js.map +1 -1
  12. package/dist/src/filters/filter-checkbox.d.ts +1 -1
  13. package/dist/src/filters/filter-checkbox.js +4 -2
  14. package/dist/src/filters/filter-checkbox.js.map +1 -1
  15. package/dist/src/filters/filter-input-barcode.d.ts +1 -1
  16. package/dist/src/filters/filter-input-barcode.js +2 -2
  17. package/dist/src/filters/filter-input-barcode.js.map +1 -1
  18. package/dist/src/filters/filter-input.d.ts +1 -1
  19. package/dist/src/filters/filter-input.js.map +1 -1
  20. package/dist/src/filters/filter-range-date.d.ts +1 -1
  21. package/dist/src/filters/filter-range-date.js +14 -3
  22. package/dist/src/filters/filter-range-date.js.map +1 -1
  23. package/dist/src/filters/filter-range-number.d.ts +1 -1
  24. package/dist/src/filters/filter-range-number.js.map +1 -1
  25. package/dist/src/filters/filter-select.d.ts +1 -1
  26. package/dist/src/filters/filter-select.js +23 -11
  27. package/dist/src/filters/filter-select.js.map +1 -1
  28. package/dist/src/filters/filter-styles.js +38 -28
  29. package/dist/src/filters/filter-styles.js.map +1 -1
  30. package/dist/src/filters/index.d.ts +1 -1
  31. package/dist/src/filters/index.js +1 -1
  32. package/dist/src/filters/index.js.map +1 -1
  33. package/dist/src/filters/ox-filters-form-base.d.ts +8 -9
  34. package/dist/src/filters/ox-filters-form-base.js +126 -72
  35. package/dist/src/filters/ox-filters-form-base.js.map +1 -1
  36. package/dist/src/filters/registry.d.ts +1 -1
  37. package/dist/src/filters/registry.js.map +1 -1
  38. package/dist/src/styles/search-form-styles.js +1 -1
  39. package/dist/src/styles/search-form-styles.js.map +1 -1
  40. package/dist/src/types.d.ts +59 -0
  41. package/dist/src/types.js.map +1 -0
  42. package/dist/stories/{ox-filter-form-barcode.stories.js → ox-filters-form-barcode.stories.js} +29 -12
  43. package/dist/stories/ox-filters-form-barcode.stories.js.map +1 -0
  44. package/dist/stories/{ox-filter-form-base.stories.d.ts → ox-filters-form-base-bounded.stories.d.ts} +3 -2
  45. package/dist/stories/ox-filters-form-base-bounded.stories.js +182 -0
  46. package/dist/stories/ox-filters-form-base-bounded.stories.js.map +1 -0
  47. package/dist/stories/ox-filters-form-base-change-handler.stories.d.ts +30 -0
  48. package/dist/stories/ox-filters-form-base-change-handler.stories.js +194 -0
  49. package/dist/stories/ox-filters-form-base-change-handler.stories.js.map +1 -0
  50. package/dist/stories/ox-filters-form-base-dependencies.stories.d.ts +30 -0
  51. package/dist/stories/ox-filters-form-base-dependencies.stories.js +182 -0
  52. package/dist/stories/ox-filters-form-base-dependencies.stories.js.map +1 -0
  53. package/dist/stories/ox-filters-form-base.stories.d.ts +30 -0
  54. package/dist/stories/ox-filters-form-base.stories.js +142 -0
  55. package/dist/stories/ox-filters-form-base.stories.js.map +1 -0
  56. package/dist/stories/ox-search-form.stories.d.ts +34 -0
  57. package/dist/stories/ox-search-form.stories.js +219 -0
  58. package/dist/stories/ox-search-form.stories.js.map +1 -0
  59. package/dist/tsconfig.tsbuildinfo +1 -1
  60. package/package.json +17 -16
  61. package/src/components/ox-file-uploader.ts +7 -7
  62. package/src/components/ox-search-form.ts +195 -122
  63. package/src/filters/filter-checkbox.ts +5 -3
  64. package/src/filters/filter-input-barcode.ts +3 -3
  65. package/src/filters/filter-input.ts +1 -1
  66. package/src/filters/filter-range-date.ts +21 -6
  67. package/src/filters/filter-range-number.ts +1 -1
  68. package/src/filters/filter-select.ts +29 -20
  69. package/src/filters/filter-styles.ts +38 -28
  70. package/src/filters/index.ts +1 -1
  71. package/src/filters/ox-filters-form-base.ts +136 -72
  72. package/src/filters/registry.ts +1 -1
  73. package/src/styles/search-form-styles.ts +1 -1
  74. package/src/types.ts +96 -0
  75. package/stories/{ox-filter-form-barcode.stories.ts → ox-filters-form-barcode.stories.ts} +30 -13
  76. package/stories/ox-filters-form-base-bounded.stories.ts +206 -0
  77. package/stories/ox-filters-form-base-change-handler.stories.ts +218 -0
  78. package/stories/ox-filters-form-base.stories.ts +159 -0
  79. package/stories/ox-search-form.stories.ts +244 -0
  80. package/themes/app-theme.css +7 -7
  81. package/themes/form-theme.css +1 -1
  82. package/themes/input-theme.css +32 -0
  83. package/dist/src/filters/types.d.ts +0 -17
  84. package/dist/src/filters/types.js.map +0 -1
  85. package/dist/stories/ox-filter-form-barcode.stories.js.map +0 -1
  86. package/dist/stories/ox-filter-form-base.stories.js +0 -82
  87. package/dist/stories/ox-filter-form-base.stories.js.map +0 -1
  88. package/src/filters/types.ts +0 -47
  89. package/stories/ox-filter-form-base.stories.ts +0 -97
  90. /package/dist/src/{filters/types.js → types.js} +0 -0
  91. /package/dist/stories/{ox-filter-form-barcode.stories.d.ts → ox-filters-form-barcode.stories.d.ts} +0 -0
@@ -1,17 +1,47 @@
1
- import '@material/mwc-icon'
1
+ import '@material/web/icon/icon.js'
2
2
  import './ox-custom-input.js'
3
3
  import './ox-custom-select.js'
4
4
 
5
5
  import gql from 'graphql-tag'
6
- import { css, html, LitElement, PropertyValues } from 'lit'
7
- import { customElement, property, query, queryAll } from 'lit/decorators.js'
6
+ import { css, html, LitElement, nothing, PropertyValues } from 'lit'
7
+ import { customElement, property, query, queryAll, queryAsync } from 'lit/decorators.js'
8
+ import { ifDefined } from 'lit/directives/if-defined.js'
9
+ import { until } from 'lit/directives/until.js'
8
10
 
9
11
  import { buildArgs, client } from '@operato/graphql'
10
12
 
11
13
  import { SearchFormStyles } from '../styles/search-form-styles.js'
14
+ import { SearchFormField, SelectOption, SelectOptionObject } from '../types.js'
15
+
16
+ function buildOptions(field: SearchFormField, options: SelectOption[]) {
17
+ const selectOptionObjects = options.map(option => {
18
+ switch (typeof option) {
19
+ case 'string':
20
+ return {
21
+ name: option,
22
+ value: option
23
+ }
24
+ case 'object':
25
+ return {
26
+ name: option.name || option.display,
27
+ value: option.value
28
+ }
29
+ default:
30
+ return option
31
+ }
32
+ }) as SelectOptionObject[]
33
+
34
+ return html`
35
+ ${selectOptionObjects?.map(
36
+ ({ value, display, name }) => html`
37
+ <option ?selected=${value == field.value} value=${value}>${name || display}</option>
38
+ `
39
+ )}
40
+ `
41
+ }
12
42
 
13
43
  @customElement('ox-search-form')
14
- export class SearchForm extends LitElement {
44
+ export class OxSearchForm extends LitElement {
15
45
  static styles = [
16
46
  SearchFormStyles,
17
47
  css`
@@ -24,33 +54,21 @@ export class SearchForm extends LitElement {
24
54
 
25
55
  ::placeholder {
26
56
  text-transform: capitalize;
27
- color: var(--theme-white-color);
57
+ color: rgba(var(--secondary-color-rgb), 0.5);
28
58
  }
29
59
  `
30
60
  ]
31
61
 
32
- @property({ type: Array }) fields?: {
33
- type: string
34
- hidden: boolean
35
- name: string
36
- id: string
37
- label: string
38
- placeholder: string
39
- value: any
40
- field: string
41
- queryName: string
42
- props: { [prop: string]: string }
43
- attrs: string[]
44
- options: { name: string; value: string }[]
45
- handlers: { [event: string]: EventListener }
46
- }[]
62
+ @property({ type: Array }) fields?: SearchFormField[]
47
63
  @property({ type: Boolean }) hideSearchButton: boolean = false
48
64
  @property({ type: Boolean, attribute: true }) autofocus: boolean = false
49
65
 
50
- @query('form') form!: HTMLFormElement
66
+ @queryAsync('form') form!: HTMLFormElement
51
67
  @query('input[autofocus]') autofocused?: HTMLInputElement
52
68
  @queryAll('input, select') formFields!: ((HTMLInputElement | HTMLSelectElement) & { field: string; _value: any })[]
53
69
 
70
+ private autoUpdateTargetsOnChange: { [name: string]: string[] } = {}
71
+
54
72
  render() {
55
73
  var autofocusConsumed = 0
56
74
 
@@ -63,92 +81,135 @@ export class SearchForm extends LitElement {
63
81
  this.submit()
64
82
  }
65
83
  }}
84
+ @change=${(e: Event) => {
85
+ this.dispatchEvent(
86
+ new CustomEvent('change', {
87
+ detail: (e.target as HTMLInputElement).value
88
+ })
89
+ )
90
+
91
+ const name = (e.target as HTMLElement)?.getAttribute('name')
92
+ if (name && this.autoUpdateTargetsOnChange[name]) {
93
+ ;(this.autoUpdateTargetsOnChange[name] || []).forEach(name => {
94
+ const target = this.renderRoot.querySelector(`[name='${name}']`)
95
+ if (target) {
96
+ ;(target as HTMLInputElement).value = ''
97
+ }
98
+ })
99
+
100
+ this.requestUpdate()
101
+ }
102
+ }}
66
103
  >
67
104
  ${(this.fields || []).map(
68
105
  field => html`
69
106
  ${field.type === 'select'
70
- ? html`
71
- <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
72
- <select
73
- .value=${field.value}
74
- .name=${field.name}
75
- ?hidden=${field.hidden}
76
- .placeholder=${field.placeholder || ''}
77
- >
78
- ${(field.options || []).map(
79
- (option: { name: string; value: string }) => html`
80
- <option ?selected=${option.value == field.value} value=${option.value}>${option.name}</option>
81
- `
82
- )}
83
- </select>
84
- `
107
+ ? this.renderSelect(field)
85
108
  : field.type === 'checkbox'
86
- ? html`
87
- <input
88
- id="ckbx_${field.name}"
89
- type="checkbox"
90
- ?checked="${field.value}"
91
- .name=${field.name}
92
- ?hidden=${field.hidden}
93
- @click=${(e: MouseEvent) => {
94
- const checkbox = e.currentTarget as HTMLInputElement & { _value: any }
95
- if (checkbox.hasAttribute('indeterminate')) {
96
- const values = [undefined, 'on', 'off']
97
- const currentValue = checkbox._value
98
- const newValue =
99
- values.indexOf(currentValue) + 1 > values.length - 1
100
- ? values[0]
101
- : values[values.indexOf(currentValue) + 1]
102
-
103
- if (newValue === 'on') {
104
- checkbox.checked = true
105
- } else if (newValue === 'off') {
106
- checkbox.checked = false
107
- } else {
108
- checkbox.indeterminate = true
109
- }
110
- checkbox._value = newValue
111
- }
112
- }}
113
- />
114
- <label for="ckbx_${field.name}" ?hidden=${field.hidden}
115
- >${field.label || field.name || field.id}</label
116
- >
117
- `
118
- : field.type === 'object'
119
- ? html`
120
- <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
121
- <input
122
- .type=${field.type}
123
- .value=${field.value || ''}
124
- .name=${field.name}
125
- .field=${field.field}
126
- .queryName=${field.queryName}
127
- .placeholder=${field.placeholder || ''}
128
- ?hidden=${field.hidden}
129
- ?autofocus=${!field.hidden && 0 === autofocusConsumed++}
130
- />
131
- `
132
- : html`
133
- <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
134
- <input
135
- .type=${field.type}
136
- .value=${field.value || ''}
137
- .name=${field.name}
138
- .placeholder=${field.placeholder || ''}
139
- ?hidden=${field.hidden}
140
- ?autofocus=${!field.hidden && 0 === autofocusConsumed++}
141
- />
142
- `}
109
+ ? this.renderCheckbox(field)
110
+ : field.type === 'object'
111
+ ? this.renderObject(field, autofocusConsumed++)
112
+ : this.renderElse(field, autofocusConsumed++)}
143
113
  `
144
114
  )}
145
- ${this.hideSearchButton || false
146
- ? ``
147
- : html`<mwc-icon @click=${(e: MouseEvent) => this.submit()} search>search</mwc-icon>`}
115
+ ${!!this.hideSearchButton
116
+ ? nothing
117
+ : html`<md-icon @click=${(e: MouseEvent) => this.submit()} search>search</md-icon>`}
148
118
  </form>
149
119
  `
150
120
  }
151
121
 
122
+ renderSelect(field: SearchFormField) {
123
+ var { options } = field
124
+
125
+ if (typeof options === 'function') {
126
+ options = (options as Function).call(field, this)
127
+
128
+ if (options instanceof Promise) {
129
+ var optionsTemplate = html`${until(options.then(options => buildOptions(field, options)))}`
130
+ } else {
131
+ var optionsTemplate = buildOptions(field, (options || []) as SelectOption[])
132
+ }
133
+ } else {
134
+ var optionsTemplate = buildOptions(field, (options || []) as SelectOption[])
135
+ }
136
+
137
+ return html`
138
+ <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
139
+ <select
140
+ .value=${field.value}
141
+ name=${ifDefined(field.name)}
142
+ placeholder=${ifDefined(field.placeholder)}
143
+ ?hidden=${field.hidden}
144
+ >
145
+ ${optionsTemplate!}
146
+ </select>
147
+ `
148
+ }
149
+
150
+ renderCheckbox(field: SearchFormField) {
151
+ return html`
152
+ <input
153
+ id="ckbx_${field.name}"
154
+ type="checkbox"
155
+ name=${ifDefined(field.name)}
156
+ ?checked=${field.value}
157
+ ?hidden=${field.hidden}
158
+ @click=${(e: MouseEvent) => {
159
+ const checkbox = e.currentTarget as HTMLInputElement & { _value: any }
160
+ if (checkbox.hasAttribute('indeterminate')) {
161
+ const values = [undefined, 'on', 'off']
162
+ const currentValue = checkbox._value
163
+ const newValue =
164
+ values.indexOf(currentValue) + 1 > values.length - 1
165
+ ? values[0]
166
+ : values[values.indexOf(currentValue) + 1]
167
+
168
+ if (newValue === 'on') {
169
+ checkbox.checked = true
170
+ } else if (newValue === 'off') {
171
+ checkbox.checked = false
172
+ } else {
173
+ checkbox.indeterminate = true
174
+ }
175
+ checkbox._value = newValue
176
+ }
177
+ }}
178
+ />
179
+ <label for="ckbx_${field.name}" ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
180
+ `
181
+ }
182
+
183
+ renderObject(field: SearchFormField, autofocusConsumed: number) {
184
+ return html`
185
+ <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
186
+ <input
187
+ .type=${field.type}
188
+ name=${ifDefined(field.name)}
189
+ placeholder=${ifDefined(field.placeholder)}
190
+ .value=${field.value || ''}
191
+ .field=${field.field}
192
+ .queryName=${field.queryName}
193
+ ?hidden=${field.hidden}
194
+ ?autofocus=${!field.hidden && 0 === autofocusConsumed}
195
+ />
196
+ `
197
+ }
198
+
199
+ renderElse(field: SearchFormField, autofocusConsumed: number) {
200
+ return html`
201
+ <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
202
+ <input
203
+ .type=${field.type}
204
+ .value=${field.value || ''}
205
+ name=${ifDefined(field.name)}
206
+ placeholder=${ifDefined(field.placeholder)}
207
+ ?hidden=${field.hidden}
208
+ ?autofocus=${!field.hidden && 0 === autofocusConsumed++}
209
+ />
210
+ `
211
+ }
212
+
152
213
  async updated(changes: PropertyValues<this>) {
153
214
  if (changes.has('fields')) {
154
215
  this._checkInputValidity()
@@ -186,6 +247,18 @@ export class SearchForm extends LitElement {
186
247
  await this.requestUpdate()
187
248
  this.autofocused?.focus()
188
249
  }
250
+
251
+ this.autoUpdateTargetsOnChange = {}
252
+ this.fields
253
+ ?.filter(filter => filter.boundTo && filter.boundTo.length > 0)
254
+ .map(({ name, boundTo }) => {
255
+ boundTo!.forEach(to => {
256
+ const origin = this.autoUpdateTargetsOnChange[to] || []
257
+ if (name && !origin.includes(name)) {
258
+ this.autoUpdateTargetsOnChange[to] = [...origin, name]
259
+ }
260
+ })
261
+ })
189
262
  }
190
263
  }
191
264
 
@@ -224,14 +297,14 @@ export class SearchForm extends LitElement {
224
297
  field.type === 'text'
225
298
  ? value
226
299
  : field.type === 'checkbox'
227
- ? field.hasAttribute('indeterminate')
228
- ? field._value === 'on'
229
- ? true
230
- : false
231
- : (field as HTMLInputElement).checked
232
- : field.type === 'number'
233
- ? parseFloat(value)
234
- : value,
300
+ ? field.hasAttribute('indeterminate')
301
+ ? field._value === 'on'
302
+ ? true
303
+ : false
304
+ : (field as HTMLInputElement).checked
305
+ : field.type === 'number'
306
+ ? parseFloat(value)
307
+ : value,
235
308
  operator
236
309
  }
237
310
  })
@@ -257,16 +330,16 @@ export class SearchForm extends LitElement {
257
330
  field.type === 'text' && field.getAttribute('type') === 'object'
258
331
  ? await this._getResourceIds(field)
259
332
  : field.type === 'text'
260
- ? value
261
- : field.type === 'checkbox'
262
- ? field.hasAttribute('indeterminate')
263
- ? field._value === 'on'
264
- ? true
265
- : false
266
- : (field as HTMLInputElement).checked
267
- : field.type === 'number'
268
- ? parseFloat(value)
269
- : value,
333
+ ? value
334
+ : field.type === 'checkbox'
335
+ ? field.hasAttribute('indeterminate')
336
+ ? field._value === 'on'
337
+ ? true
338
+ : false
339
+ : (field as HTMLInputElement).checked
340
+ : field.type === 'number'
341
+ ? parseFloat(value)
342
+ : value,
270
343
  relation: field.type === 'text' && field.getAttribute('type') === 'object'
271
344
  }
272
345
  return filter
@@ -285,14 +358,14 @@ export class SearchForm extends LitElement {
285
358
  query: gql`
286
359
  query {
287
360
  fetch: ${queryName}(${buildArgs({
288
- filters: [
289
- {
290
- name: field,
291
- operator: 'i_like',
292
- value: `%${value}%`
293
- }
294
- ]
295
- })}) {
361
+ filters: [
362
+ {
363
+ name: field,
364
+ operator: 'i_like',
365
+ value: `%${value}%`
366
+ }
367
+ ]
368
+ })}) {
296
369
  items {
297
370
  id
298
371
  }
@@ -2,10 +2,10 @@ import '@operato/input/ox-checkbox.js'
2
2
 
3
3
  import { html } from 'lit-html'
4
4
 
5
- import { FilterSelectRenderer } from './types.js'
5
+ import { FilterSelectRenderer } from '../types.js'
6
6
 
7
7
  export const FilterCheckbox: FilterSelectRenderer = (filter, value, owner) => {
8
- const { name } = filter
8
+ const { name, label } = filter
9
9
 
10
10
  return html`
11
11
  <ox-checkbox
@@ -13,6 +13,7 @@ export const FilterCheckbox: FilterSelectRenderer = (filter, value, owner) => {
13
13
  ?checked=${value}
14
14
  indeterminatable
15
15
  ?indeterminate=${value === undefined}
16
+ left-label
16
17
  @change=${(e: CustomEvent) => {
17
18
  ;(e.target as HTMLElement).dispatchEvent(
18
19
  new CustomEvent('filter-change', {
@@ -26,6 +27,7 @@ export const FilterCheckbox: FilterSelectRenderer = (filter, value, owner) => {
26
27
  })
27
28
  )
28
29
  }}
29
- />
30
+ ><label><span>${label}</span></label></ox-checkbox
31
+ >
30
32
  `
31
33
  }
@@ -2,11 +2,11 @@ import '@operato/input/ox-input-barcode.js'
2
2
 
3
3
  import { html } from 'lit-html'
4
4
 
5
- import { FilterSelectRenderer } from './types.js'
5
+ import { FilterSelectRenderer } from '../types.js'
6
6
 
7
7
  export const FilterInputBarcode: FilterSelectRenderer = (filter, value, owner) => {
8
- const { name, type } = filter
9
- const { englishOnly, selectAfterChange } = filter.options || {}
8
+ const { name, type, options } = filter
9
+ const { englishOnly, selectAfterChange } = (options || {}) as { [key: string]: any }
10
10
 
11
11
  return html`
12
12
  <ox-input-barcode
@@ -1,6 +1,6 @@
1
1
  import { html } from 'lit-html'
2
2
 
3
- import { FilterSelectRenderer } from './types.js'
3
+ import { FilterSelectRenderer } from '../types.js'
4
4
 
5
5
  export const FilterInput: FilterSelectRenderer = (filter, value, owner) => {
6
6
  const { name, type } = filter
@@ -1,20 +1,35 @@
1
1
  import { html } from 'lit-html'
2
2
 
3
- import { FilterSelectRenderer } from './types.js'
3
+ import { FilterSelectRenderer } from '../types.js'
4
+
5
+ function formatDate(type: string, date: Date) {
6
+ var year = date.getFullYear()
7
+ var month = ('0' + (date.getMonth() + 1)).slice(-2)
8
+ var day = ('0' + date.getDate()).slice(-2)
9
+ var hours = ('0' + date.getHours()).slice(-2)
10
+ var minutes = ('0' + date.getMinutes()).slice(-2)
11
+
12
+ var formatDate = year + '-' + month + '-' + day
13
+
14
+ return type == 'date' ? formatDate : formatDate + 'T' + hours + ':' + minutes
15
+ }
4
16
 
5
17
  export const FilterRangeDate: FilterSelectRenderer = (filter, value, owner) => {
6
18
  var { name, type, operator } = filter
7
- const [from, to] = value instanceof Array ? value : []
19
+ var [from, to] = value instanceof Array ? value : []
8
20
 
9
21
  if (type === 'datetime') {
10
22
  type = 'datetime-local'
11
23
  }
12
24
 
25
+ from = formatDate(type, new Date(from))
26
+ to = formatDate(type, new Date(to))
27
+
13
28
  return html`
14
29
  <input
15
30
  name=${name}
16
- type=${type}
17
- .value=${from}
31
+ type=${type as 'date' | 'datetime-local'}
32
+ value=${from}
18
33
  from
19
34
  @keyup=${(e: KeyboardEvent) => {
20
35
  if (e.key !== 'Enter') {
@@ -38,8 +53,8 @@ export const FilterRangeDate: FilterSelectRenderer = (filter, value, owner) => {
38
53
  ~
39
54
  <input
40
55
  name=${name}
41
- type=${type}
42
- .value=${to}
56
+ type=${type as 'date' | 'datetime-local'}
57
+ value=${to}
43
58
  to
44
59
  @keyup=${(e: KeyboardEvent) => {
45
60
  if (e.key !== 'Enter') {
@@ -1,6 +1,6 @@
1
1
  import { html } from 'lit-html'
2
2
 
3
- import { FilterSelectRenderer } from './types.js'
3
+ import { FilterSelectRenderer } from '../types.js'
4
4
 
5
5
  export const FilterRangeNumber: FilterSelectRenderer = (filter, value, owner) => {
6
6
  const { name, operator } = filter
@@ -1,18 +1,12 @@
1
1
  import '@operato/input/ox-checkbox.js'
2
2
 
3
- import { html } from 'lit-html'
3
+ import { html } from 'lit'
4
+ import { until } from 'lit/directives/until.js'
4
5
 
5
- import { FilterSelectRenderer } from './types.js'
6
+ import { FilterOperator, FilterSelectRenderer, SelectOption, SelectOptionObject } from '../types.js'
6
7
 
7
- export const FilterSelect: FilterSelectRenderer = (filter, value, owner) => {
8
- /* value는 filters-form이나 grid-header에서 처리되므로 이 곳에서는 무시한다. */
9
- var { name, type, operator, options = [] } = filter
10
-
11
- if (typeof options === 'function') {
12
- options = options.call(filter, owner)
13
- }
14
-
15
- options = options.map((option: any) => {
8
+ function buildOptions(options: SelectOption[], operator?: FilterOperator) {
9
+ const selectOptionObjects = options.map(option => {
16
10
  switch (typeof option) {
17
11
  case 'string':
18
12
  return {
@@ -21,27 +15,42 @@ export const FilterSelect: FilterSelectRenderer = (filter, value, owner) => {
21
15
  }
22
16
  case 'object':
23
17
  return {
24
- display: option.display,
18
+ display: option.display || option.name,
25
19
  value: option.value
26
20
  }
27
21
  default:
28
22
  return option
29
23
  }
30
- })
24
+ }) as SelectOptionObject[]
31
25
 
32
26
  return operator === 'in'
33
27
  ? html`
34
- ${options
35
- ?.filter((option: { display: string; value: any }) => !!option)
28
+ ${selectOptionObjects
29
+ ?.filter(option => !!option)
36
30
  .map(
37
- (option: { display: string; value: any }) =>
38
- html` <ox-checkbox option value=${option.value}>${option.display}</ox-checkbox> `
31
+ ({ value, display, name }) => html` <ox-checkbox option value=${value}>${display || name}</ox-checkbox> `
39
32
  )}
40
33
  `
41
34
  : html`
42
- ${options?.map(
43
- (option: { display: string; value: any }) =>
44
- html` <div option value=${option.value}>${option.display}&nbsp;</div> `
35
+ ${selectOptionObjects?.map(
36
+ ({ value, display, name }) => html` <div option value=${value}>${display || name}&nbsp;</div> `
45
37
  )}
46
38
  `
47
39
  }
40
+
41
+ export const FilterSelect: FilterSelectRenderer = (filter, value, owner) => {
42
+ /* value는 filters-form이나 grid-header에서 처리되므로 이 곳에서는 무시한다. */
43
+ var { operator, options } = filter
44
+
45
+ if (typeof options === 'function') {
46
+ options = (options as Function).call(filter, owner)
47
+
48
+ if (options instanceof Promise) {
49
+ return html`${until(options.then(options => buildOptions(options, operator)))}`
50
+ } else {
51
+ return buildOptions((options || []) as SelectOption[], operator)
52
+ }
53
+ } else {
54
+ return buildOptions((options || []) as SelectOption[], operator)
55
+ }
56
+ }