@operato/form 2.0.0-alpha.94 → 2.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 (97) hide show
  1. package/CHANGELOG.md +280 -0
  2. package/dist/src/components/ox-custom-input.js +5 -5
  3. package/dist/src/components/ox-custom-input.js.map +1 -1
  4. package/dist/src/components/ox-custom-select.js +2 -1
  5. package/dist/src/components/ox-custom-select.js.map +1 -1
  6. package/dist/src/components/ox-file-uploader.js +1 -1
  7. package/dist/src/components/ox-file-uploader.js.map +1 -1
  8. package/dist/src/components/ox-search-form.d.ts +12 -23
  9. package/dist/src/components/ox-search-form.js +227 -91
  10. package/dist/src/components/ox-search-form.js.map +1 -1
  11. package/dist/src/filters/filter-checkbox.js +2 -1
  12. package/dist/src/filters/filter-checkbox.js.map +1 -1
  13. package/dist/src/filters/filter-input-barcode.js +5 -3
  14. package/dist/src/filters/filter-input-barcode.js.map +1 -1
  15. package/dist/src/filters/filter-input.js +2 -1
  16. package/dist/src/filters/filter-input.js.map +1 -1
  17. package/dist/src/filters/filter-range-date.js +3 -1
  18. package/dist/src/filters/filter-range-date.js.map +1 -1
  19. package/dist/src/filters/filter-range-number.js +3 -1
  20. package/dist/src/filters/filter-range-number.js.map +1 -1
  21. package/dist/src/filters/filter-select.js +23 -11
  22. package/dist/src/filters/filter-select.js.map +1 -1
  23. package/dist/src/filters/filter-styles.js +56 -24
  24. package/dist/src/filters/filter-styles.js.map +1 -1
  25. package/dist/src/filters/ox-filter-personalizer.d.ts +8 -0
  26. package/dist/src/filters/ox-filter-personalizer.js +175 -0
  27. package/dist/src/filters/ox-filter-personalizer.js.map +1 -0
  28. package/dist/src/filters/ox-filters-form-base.d.ts +13 -3
  29. package/dist/src/filters/ox-filters-form-base.js +196 -60
  30. package/dist/src/filters/ox-filters-form-base.js.map +1 -1
  31. package/dist/src/styles/multi-column-form-styles.js +6 -6
  32. package/dist/src/styles/multi-column-form-styles.js.map +1 -1
  33. package/dist/src/styles/search-form-styles.js +23 -18
  34. package/dist/src/styles/search-form-styles.js.map +1 -1
  35. package/dist/src/styles/single-column-form-styles.js +5 -5
  36. package/dist/src/styles/single-column-form-styles.js.map +1 -1
  37. package/dist/src/types.d.ts +42 -2
  38. package/dist/src/types.js.map +1 -1
  39. package/dist/stories/ox-filters-form-barcode.stories.d.ts +5 -0
  40. package/dist/stories/ox-filters-form-barcode.stories.js +51 -12
  41. package/dist/stories/ox-filters-form-barcode.stories.js.map +1 -1
  42. package/dist/stories/ox-filters-form-base-bounded.stories.d.ts +35 -0
  43. package/dist/stories/ox-filters-form-base-bounded.stories.js +187 -0
  44. package/dist/stories/ox-filters-form-base-bounded.stories.js.map +1 -0
  45. package/dist/stories/ox-filters-form-base-change-handler.stories.d.ts +35 -0
  46. package/dist/stories/ox-filters-form-base-change-handler.stories.js +199 -0
  47. package/dist/stories/ox-filters-form-base-change-handler.stories.js.map +1 -0
  48. package/dist/stories/ox-filters-form-base-page-preference.stories.d.ts +31 -0
  49. package/dist/stories/ox-filters-form-base-page-preference.stories.js +173 -0
  50. package/dist/stories/ox-filters-form-base-page-preference.stories.js.map +1 -0
  51. package/dist/stories/ox-filters-form-base.stories.d.ts +5 -0
  52. package/dist/stories/ox-filters-form-base.stories.js +57 -27
  53. package/dist/stories/ox-filters-form-base.stories.js.map +1 -1
  54. package/dist/stories/ox-search-form-change-handler.stories.d.ts +34 -0
  55. package/dist/stories/ox-search-form-change-handler.stories.js +227 -0
  56. package/dist/stories/ox-search-form-change-handler.stories.js.map +1 -0
  57. package/dist/stories/ox-search-form.stories.d.ts +45 -0
  58. package/dist/stories/ox-search-form.stories.js +235 -0
  59. package/dist/stories/ox-search-form.stories.js.map +1 -0
  60. package/dist/tsconfig.tsbuildinfo +1 -1
  61. package/package.json +7 -5
  62. package/src/components/ox-custom-input.ts +5 -5
  63. package/src/components/ox-custom-select.ts +2 -1
  64. package/src/components/ox-file-uploader.ts +1 -1
  65. package/src/components/ox-search-form.ts +231 -97
  66. package/src/filters/filter-checkbox.ts +2 -1
  67. package/src/filters/filter-input-barcode.ts +5 -3
  68. package/src/filters/filter-input.ts +2 -1
  69. package/src/filters/filter-range-date.ts +3 -1
  70. package/src/filters/filter-range-number.ts +3 -1
  71. package/src/filters/filter-select.ts +29 -20
  72. package/src/filters/filter-styles.ts +56 -24
  73. package/src/filters/ox-filter-personalizer.ts +188 -0
  74. package/src/filters/ox-filters-form-base.ts +222 -79
  75. package/src/styles/multi-column-form-styles.ts +6 -6
  76. package/src/styles/search-form-styles.ts +23 -18
  77. package/src/styles/single-column-form-styles.ts +5 -5
  78. package/src/types.ts +48 -2
  79. package/stories/ox-filters-form-barcode.stories.ts +54 -14
  80. package/stories/ox-filters-form-base-bounded.stories.ts +213 -0
  81. package/stories/ox-filters-form-base-change-handler.stories.ts +225 -0
  82. package/stories/ox-filters-form-base-page-preference.stories.ts +192 -0
  83. package/stories/ox-filters-form-base.stories.ts +63 -31
  84. package/stories/ox-search-form-change-handler.stories.ts +252 -0
  85. package/stories/ox-search-form.stories.ts +269 -0
  86. package/themes/dark-hc.css +151 -0
  87. package/themes/dark-mc.css +151 -0
  88. package/themes/dark.css +151 -0
  89. package/themes/grist-theme.css +169 -0
  90. package/themes/light-hc.css +151 -0
  91. package/themes/light-mc.css +151 -0
  92. package/themes/light.css +151 -0
  93. package/themes/md-typescale-styles.css +100 -0
  94. package/themes/spacing.css +43 -0
  95. package/themes/state-color.css +6 -0
  96. package/themes/app-theme.css +0 -145
  97. package/themes/form-theme.css +0 -75
@@ -3,63 +3,120 @@ 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'
10
+ import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
8
11
 
9
12
  import { buildArgs, client } from '@operato/graphql'
10
13
 
11
14
  import { SearchFormStyles } from '../styles/search-form-styles.js'
15
+ import { SearchFormField, SelectOption, SelectOptionObject } from '../types.js'
16
+
17
+ function buildOptions(field: SearchFormField, options: SelectOption[]) {
18
+ const selectOptionObjects = options.map(option => {
19
+ switch (typeof option) {
20
+ case 'string':
21
+ return {
22
+ name: option,
23
+ value: option
24
+ }
25
+ case 'object':
26
+ return {
27
+ name: option.name || option.display,
28
+ value: option.value
29
+ }
30
+ default:
31
+ return option
32
+ }
33
+ }) as SelectOptionObject[]
34
+
35
+ return html`
36
+ ${selectOptionObjects?.map(
37
+ ({ value, display, name }) => html`
38
+ <option ?selected=${value == field.value} value=${value}>${name || display}</option>
39
+ `
40
+ )}
41
+ `
42
+ }
12
43
 
13
44
  @customElement('ox-search-form')
14
- export class SearchForm extends LitElement {
45
+ export class OxSearchForm extends LitElement {
15
46
  static styles = [
47
+ MDTypeScaleStyles,
16
48
  SearchFormStyles,
17
49
  css`
18
50
  :host {
19
51
  display: flex;
20
52
  flex-direction: column;
53
+ padding: var(--spacing-small);
21
54
 
22
55
  position: relative;
23
56
  }
24
57
 
25
58
  ::placeholder {
26
59
  text-transform: capitalize;
27
- color: var(--theme-white-color);
60
+ color: rgba(var(--secondary-color-rgb), 0.5);
61
+ }
62
+ label {
63
+ font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
64
+ color: var(--md-sys-color-primary);
65
+ }
66
+ select,
67
+ input {
68
+ border: none;
69
+ border-bottom: var(--ox-filters-input-border, 1px solid var(--md-sys-color-outline));
70
+ font: var(--ox-filters-input-font);
71
+ }
72
+
73
+ select:focus,
74
+ input:focus {
75
+ outline: none;
76
+ border-bottom: var(--ox-filters-input-focus-border, 1px solid var(--md-ref-palette-primary50));
77
+ color: var(--ox-filters-input-focus-color, var(--md-sys-color-primary));
28
78
  }
29
79
  `
30
80
  ]
31
81
 
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
- }[]
82
+ @property({ type: Array }) fields?: SearchFormField[]
47
83
  @property({ type: Boolean }) hideSearchButton: boolean = false
48
84
  @property({ type: Boolean, attribute: true }) autofocus: boolean = false
49
85
 
50
- @query('form') form!: HTMLFormElement
86
+ @queryAsync('form') form!: HTMLFormElement
51
87
  @query('input[autofocus]') autofocused?: HTMLInputElement
52
88
  @queryAll('input, select') formFields!: ((HTMLInputElement | HTMLSelectElement) & { field: string; _value: any })[]
53
89
 
90
+ private autoUpdateTargetsOnChange: { [name: string]: string[] } = {}
91
+
54
92
  render() {
55
93
  var autofocusConsumed = 0
56
94
 
57
95
  return html`
58
96
  <form
59
- class="search-form"
60
- @keypress=${(e: KeyboardEvent) => {
61
- if (e.key === 'Enter') {
62
- e.preventDefault()
97
+ class="search-form md-typescale-body-medium-prominent"
98
+ @change=${async (e: Event) => {
99
+ const field = e.target as HTMLInputElement
100
+ const name = field?.getAttribute('name')
101
+ const value = field.value
102
+
103
+ if (name && this.autoUpdateTargetsOnChange[name]) {
104
+ ;(this.autoUpdateTargetsOnChange[name] || []).forEach(name => {
105
+ const target = this.renderRoot.querySelector(`[name='${name}']`)
106
+ if (target) {
107
+ ;(target as HTMLInputElement).value = ''
108
+ }
109
+ })
110
+
111
+ this.requestUpdate()
112
+ }
113
+
114
+ const { onchange } = this.fields?.find(field => field.name == name) || {}
115
+
116
+ const keepGoing = onchange ? await onchange.call(null, value, this) : true
117
+
118
+ if (keepGoing) {
119
+ this.dispatchEvent(new CustomEvent('change', { detail: value }))
63
120
  this.submit()
64
121
  }
65
122
  }}
@@ -67,88 +124,116 @@ export class SearchForm extends LitElement {
67
124
  ${(this.fields || []).map(
68
125
  field => html`
69
126
  ${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
- `
127
+ ? this.renderSelect(field)
85
128
  : 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
- `
129
+ ? this.renderCheckbox(field)
118
130
  : 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
- `}
131
+ ? this.renderObject(field, autofocusConsumed++)
132
+ : this.renderElse(field, autofocusConsumed++)}
143
133
  `
144
134
  )}
145
- ${this.hideSearchButton || false
146
- ? ``
135
+ ${!!this.hideSearchButton
136
+ ? nothing
147
137
  : html`<md-icon @click=${(e: MouseEvent) => this.submit()} search>search</md-icon>`}
148
138
  </form>
149
139
  `
150
140
  }
151
141
 
142
+ renderSelect(field: SearchFormField) {
143
+ var { id, options, readonly, label, name, value, placeholder, hidden } = field
144
+
145
+ if (typeof options === 'function') {
146
+ options = (options as Function).call(field, this)
147
+
148
+ if (options instanceof Promise) {
149
+ var optionsTemplate = html`${until(options.then(options => buildOptions(field, options)))}`
150
+ } else {
151
+ var optionsTemplate = buildOptions(field, (options || []) as SelectOption[])
152
+ }
153
+ } else {
154
+ var optionsTemplate = buildOptions(field, (options || []) as SelectOption[])
155
+ }
156
+
157
+ return html`
158
+ <label ?hidden=${hidden}>${label || name || id}</label>
159
+ <select
160
+ .value=${value}
161
+ name=${ifDefined(name)}
162
+ placeholder=${ifDefined(placeholder)}
163
+ ?hidden=${hidden}
164
+ ?readonly=${readonly}
165
+ >
166
+ ${optionsTemplate!}
167
+ </select>
168
+ `
169
+ }
170
+
171
+ renderCheckbox(field: SearchFormField) {
172
+ return html`
173
+ <input
174
+ id="ckbx_${field.name}"
175
+ type="checkbox"
176
+ name=${ifDefined(field.name)}
177
+ ?checked=${field.value}
178
+ ?hidden=${field.hidden}
179
+ ?readonly=${field.readonly}
180
+ @click=${(e: MouseEvent) => {
181
+ const checkbox = e.currentTarget as HTMLInputElement & { _value: any }
182
+ if (checkbox.hasAttribute('indeterminate')) {
183
+ const values = [undefined, 'on', 'off']
184
+ const currentValue = checkbox._value
185
+ const newValue =
186
+ values.indexOf(currentValue) + 1 > values.length - 1
187
+ ? values[0]
188
+ : values[values.indexOf(currentValue) + 1]
189
+
190
+ if (newValue === 'on') {
191
+ checkbox.checked = true
192
+ } else if (newValue === 'off') {
193
+ checkbox.checked = false
194
+ } else {
195
+ checkbox.indeterminate = true
196
+ }
197
+ checkbox._value = newValue
198
+ }
199
+ }}
200
+ />
201
+ <label for="ckbx_${field.name}" ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
202
+ `
203
+ }
204
+
205
+ renderObject(field: SearchFormField, autofocusConsumed: number) {
206
+ return html`
207
+ <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
208
+ <input
209
+ .type=${field.type}
210
+ name=${ifDefined(field.name)}
211
+ placeholder=${ifDefined(field.placeholder)}
212
+ .value=${field.value || ''}
213
+ .field=${field.field}
214
+ .queryName=${field.queryName}
215
+ ?hidden=${field.hidden}
216
+ ?readonly=${field.readonly}
217
+ ?autofocus=${!field.hidden && 0 === autofocusConsumed}
218
+ />
219
+ `
220
+ }
221
+
222
+ renderElse(field: SearchFormField, autofocusConsumed: number) {
223
+ return html`
224
+ <label ?hidden=${field.hidden}>${field.label || field.name || field.id}</label>
225
+ <input
226
+ .type=${field.type}
227
+ .value=${field.value || ''}
228
+ name=${ifDefined(field.name)}
229
+ placeholder=${ifDefined(field.placeholder)}
230
+ ?hidden=${field.hidden}
231
+ ?readonly=${field.readonly}
232
+ ?autofocus=${!field.hidden && 0 === autofocusConsumed++}
233
+ />
234
+ `
235
+ }
236
+
152
237
  async updated(changes: PropertyValues<this>) {
153
238
  if (changes.has('fields')) {
154
239
  this._checkInputValidity()
@@ -186,9 +271,25 @@ export class SearchForm extends LitElement {
186
271
  await this.requestUpdate()
187
272
  this.autofocused?.focus()
188
273
  }
274
+
275
+ this.autoUpdateTargetsOnChange = {}
276
+ this.fields
277
+ ?.filter(filter => filter.boundTo && filter.boundTo.length > 0)
278
+ .map(({ name, boundTo }) => {
279
+ boundTo!.forEach(to => {
280
+ const origin = this.autoUpdateTargetsOnChange[to] || []
281
+ if (name && !origin.includes(name)) {
282
+ this.autoUpdateTargetsOnChange[to] = [...origin, name]
283
+ }
284
+ })
285
+ })
189
286
  }
190
287
  }
191
288
 
289
+ getFieldByName(name: string) {
290
+ return this.renderRoot.querySelector(`[name=${name}]`)
291
+ }
292
+
192
293
  _checkInputValidity() {
193
294
  const names = this.fields?.map(i => i.name) || []
194
295
  const result = names.every(name => {
@@ -324,6 +425,39 @@ export class SearchForm extends LitElement {
324
425
  return data
325
426
  }
326
427
 
428
+ reset(value?: string[] | { [field: string]: any }) {
429
+ this.form
430
+ .then((form: HTMLFormElement) => {
431
+ if (value) {
432
+ if (value instanceof Array) {
433
+ value
434
+ .filter(item => typeof item == 'string')
435
+ .forEach(item => {
436
+ const field = this.getFieldByName(item)
437
+ if (field) {
438
+ ;(field as HTMLInputElement).value = ''
439
+ }
440
+ })
441
+ } else {
442
+ const keys = Object.keys(value)
443
+ keys
444
+ .filter(key => typeof key == 'string')
445
+ .forEach(key => {
446
+ const field = this.getFieldByName(key)
447
+ if (field) {
448
+ ;(field as HTMLInputElement).value = value[key]
449
+ }
450
+ })
451
+ }
452
+ } else {
453
+ form.reset()
454
+ }
455
+ })
456
+ .catch((error: any) => {
457
+ console.error('Error resetting the form:', error)
458
+ })
459
+ }
460
+
327
461
  submit() {
328
462
  this.dispatchEvent(new CustomEvent('submit'))
329
463
  }
@@ -5,7 +5,7 @@ import { html } from 'lit-html'
5
5
  import { FilterSelectRenderer } from '../types.js'
6
6
 
7
7
  export const FilterCheckbox: FilterSelectRenderer = (filter, value, owner) => {
8
- const { name, label } = filter
8
+ const { name, label, readonly } = filter
9
9
 
10
10
  return html`
11
11
  <ox-checkbox
@@ -27,6 +27,7 @@ export const FilterCheckbox: FilterSelectRenderer = (filter, value, owner) => {
27
27
  })
28
28
  )
29
29
  }}
30
+ ?readonly=${readonly}
30
31
  ><label><span>${label}</span></label></ox-checkbox
31
32
  >
32
33
  `
@@ -5,8 +5,8 @@ import { html } from 'lit-html'
5
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, readonly, options } = filter
9
+ const { englishOnly, selectAfterChange } = (options || {}) as { [key: string]: any }
10
10
 
11
11
  return html`
12
12
  <ox-input-barcode
@@ -28,6 +28,8 @@ export const FilterInputBarcode: FilterSelectRenderer = (filter, value, owner) =
28
28
  })
29
29
  )
30
30
  }}
31
- />
31
+ filter-input
32
+ ?readonly=${readonly}
33
+ ></ox-input-barcode>
32
34
  `
33
35
  }
@@ -3,7 +3,7 @@ import { html } from 'lit-html'
3
3
  import { FilterSelectRenderer } from '../types.js'
4
4
 
5
5
  export const FilterInput: FilterSelectRenderer = (filter, value, owner) => {
6
- const { name, type } = filter
6
+ const { name, type, readonly } = filter
7
7
 
8
8
  return html`
9
9
  <input
@@ -24,6 +24,7 @@ export const FilterInput: FilterSelectRenderer = (filter, value, owner) => {
24
24
  })
25
25
  )
26
26
  }}
27
+ ?readonly=${readonly}
27
28
  />
28
29
  `
29
30
  }
@@ -15,7 +15,7 @@ function formatDate(type: string, date: Date) {
15
15
  }
16
16
 
17
17
  export const FilterRangeDate: FilterSelectRenderer = (filter, value, owner) => {
18
- var { name, type, operator } = filter
18
+ var { name, type, operator, readonly } = filter
19
19
  var [from, to] = value instanceof Array ? value : []
20
20
 
21
21
  if (type === 'datetime') {
@@ -49,6 +49,7 @@ export const FilterRangeDate: FilterSelectRenderer = (filter, value, owner) => {
49
49
  })
50
50
  )
51
51
  }}
52
+ ?readonly=${readonly}
52
53
  />
53
54
  ~
54
55
  <input
@@ -74,6 +75,7 @@ export const FilterRangeDate: FilterSelectRenderer = (filter, value, owner) => {
74
75
  })
75
76
  )
76
77
  }}
78
+ ?readonly=${readonly}
77
79
  />
78
80
  `
79
81
  }
@@ -3,7 +3,7 @@ import { html } from 'lit-html'
3
3
  import { FilterSelectRenderer } from '../types.js'
4
4
 
5
5
  export const FilterRangeNumber: FilterSelectRenderer = (filter, value, owner) => {
6
- const { name, operator } = filter
6
+ const { name, operator, readonly } = filter
7
7
  const [from, to] = value instanceof Array ? value : []
8
8
 
9
9
  return html`
@@ -31,6 +31,7 @@ export const FilterRangeNumber: FilterSelectRenderer = (filter, value, owner) =>
31
31
  })
32
32
  )
33
33
  }}
34
+ ?readonly=${readonly}
34
35
  />
35
36
  ~
36
37
  <input
@@ -57,6 +58,7 @@ export const FilterRangeNumber: FilterSelectRenderer = (filter, value, owner) =>
57
58
  })
58
59
  )
59
60
  }}
61
+ ?readonly=${readonly}
60
62
  />
61
63
  `
62
64
  }
@@ -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
+ }