@operato/form 2.0.0-alpha.92 → 2.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/CHANGELOG.md +281 -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 +197 -61
  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
@@ -4,24 +4,28 @@ import '@operato/popup/ox-popup-list.js'
4
4
  import '@operato/input/ox-input-search.js'
5
5
 
6
6
  import json5 from 'json5'
7
- import { css, html, LitElement, PropertyValues, TemplateResult } from 'lit'
8
- import { customElement, property, queryAsync } from 'lit/decorators.js'
7
+ import { css, html, LitElement, nothing, PropertyValues, TemplateResult } from 'lit'
8
+ import { customElement, property, queryAsync, state } from 'lit/decorators.js'
9
+ import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
9
10
 
10
11
  import { getDefaultValue } from '@operato/time-calculator'
12
+ import { PagePreferenceProvider } from '@operato/p13n'
11
13
 
12
14
  import { FilterStyles } from './filter-styles.js'
13
15
  import { getFilterRenderer } from './registry.js'
14
- import { FilterConfig, FilterOperator, FilterValue } from '../types.js'
16
+ import { FilterConfig, FilterOperator, FilterSelectRenderer, FilterValue, PersonalFilterPreference } from '../types.js'
15
17
 
16
18
  export type QueryFilterRangeValue = [from: number, to: number]
17
19
 
18
20
  @customElement('ox-filters-form-base')
19
21
  export class OxFiltersFormBase extends LitElement {
20
22
  static styles = [
23
+ MDTypeScaleStyles,
21
24
  FilterStyles,
22
25
  css`
23
26
  :host {
24
27
  display: flex;
28
+ padding: var(--spacing-small);
25
29
  }
26
30
 
27
31
  form {
@@ -29,13 +33,13 @@ export class OxFiltersFormBase extends LitElement {
29
33
 
30
34
  display: flex;
31
35
  flex-flow: row wrap;
32
- gap: var(--ox-filters-form-gap);
36
+ gap: var(--spacing-medium) var(--spacing-large);
33
37
  }
34
38
 
35
39
  form > * {
36
40
  display: flex;
37
41
  align-items: center;
38
- gap: var(--input-intra-gap, 7px);
42
+ gap: var(--spacing-small, 4px);
39
43
  }
40
44
 
41
45
  label span {
@@ -43,8 +47,9 @@ export class OxFiltersFormBase extends LitElement {
43
47
  }
44
48
 
45
49
  @media only screen and (max-width: 460px) {
46
- label[between] {
47
- display: block;
50
+ form {
51
+ flex-direction: column;
52
+ flex-flow: column;
48
53
  }
49
54
  }
50
55
  `
@@ -54,11 +59,16 @@ export class OxFiltersFormBase extends LitElement {
54
59
  @property({ type: Array }) filters: FilterConfig[] = []
55
60
  @property({ type: Boolean, attribute: 'url-params-sensitive' }) urlParamsSensitive?: boolean
56
61
  @property({ type: Boolean, attribute: 'autofocus' }) autofocus: boolean = true
62
+ @property({ type: Object }) personalConfigProvider?: PagePreferenceProvider
63
+
64
+ @state() personalConfig?: PersonalFilterPreference
65
+ @state() personalFilters?: FilterConfig[]
57
66
 
58
67
  @queryAsync('form') form!: HTMLFormElement
59
68
 
60
69
  private _popstateEventHandler?: EventListener
61
70
  private _filtersChangeHandler?: EventListener
71
+ private autoUpdateTargetsOnChange: { [name: string]: string[] } = {}
62
72
 
63
73
  connectedCallback(): void {
64
74
  super.connectedCallback()
@@ -72,9 +82,25 @@ export class OxFiltersFormBase extends LitElement {
72
82
  operator,
73
83
  value: defaultValue,
74
84
  onchange
75
- } = this.filters.find(filter => filter.name == name) || {}
85
+ } = (this.personalFilters || []).find(filter => filter.name == name) || {}
86
+
87
+ if (this.autoUpdateTargetsOnChange[name]) {
88
+ /*
89
+ 일단은 심플하게, boundTo로 연결된 필터값이 바뀌면, 폼 전체를 update하도록 함.
90
+ */
91
+ ;(this.autoUpdateTargetsOnChange[name] || []).forEach(name => {
92
+ const target = this.renderRoot.querySelector(`[name='${name}']`)
93
+ if (target) {
94
+ ;(target as HTMLInputElement).value = ''
95
+ }
96
+ })
97
+
98
+ this.requestUpdate()
99
+ }
100
+
101
+ const keepGoing = onchange ? await onchange.call(null, value ?? (target as HTMLInputElement).value, this) : true
76
102
 
77
- const keepGoing = onchange ? onchange.call(null, value ?? (target as HTMLInputElement).value, this) : true
103
+ this.value = await this.getQueryFilters()
78
104
 
79
105
  keepGoing &&
80
106
  this.dispatchEvent(
@@ -90,12 +116,12 @@ export class OxFiltersFormBase extends LitElement {
90
116
  })
91
117
  }
92
118
 
93
- buildDefaultValue(operator: string, defaultValue: any) {
119
+ buildDefaultValue(operator: FilterOperator, defaultValue: any) {
94
120
  if (defaultValue === undefined) {
95
121
  return
96
122
  }
97
123
  if (operator == 'between') {
98
- return (defaultValue as Array<any>).map(v => getDefaultValue(v, this))
124
+ return defaultValue instanceof Array && (defaultValue as Array<any>).map(v => getDefaultValue(v, this))
99
125
  } else {
100
126
  return getDefaultValue(defaultValue, this)
101
127
  }
@@ -104,84 +130,98 @@ export class OxFiltersFormBase extends LitElement {
104
130
  render(): TemplateResult {
105
131
  return html`
106
132
  <form
133
+ class="md-typescale-body-medium-prominent"
107
134
  @submit=${(e: Event) => {
108
135
  e.preventDefault()
109
136
  }}
110
137
  >
111
- ${this.filters.map((filter: FilterConfig) => {
112
- const { name, label, type, operator, value: defaultValue } = filter
113
- const idx = operator === 'between' ? 1 : 0
114
- const renderer = getFilterRenderer(
115
- operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'
116
- ? 'text'
117
- : type
118
- )[idx]
119
-
120
- const value =
121
- this.value?.find(filter => filter.name == name)?.value ?? this.buildDefaultValue(operator!, defaultValue)
122
-
123
- if (!renderer) {
124
- return html``
125
- }
138
+ ${(this.personalFilters || [])
139
+ .filter(filter => !filter.hidden)
140
+ .map((filter: FilterConfig) => {
141
+ const { name, label, type, operator, readonly, value: defaultValue } = filter
142
+ const idx = operator === 'between' ? 1 : 0
143
+ const renderer = getFilterRenderer(
144
+ operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'
145
+ ? 'text'
146
+ : type
147
+ )[idx]
148
+
149
+ const value =
150
+ this.value?.find(filter => filter.name == name)?.value ?? this.buildDefaultValue(operator!, defaultValue)
151
+
152
+ if (!renderer) {
153
+ return nothing
154
+ }
126
155
 
127
- return type === 'search'
128
- ? html`<ox-input-search name="search" .value=${value} ?autofocus=${this.autofocus}></ox-input-search>`
129
- : type === 'boolean'
130
- ? renderer(filter, value, this)
131
- : type !== 'select'
132
- ? html`
133
- <label filter-title ?between=${operator == 'between'}
134
- ><span>${label}</span> ${renderer(filter, value, this)}
135
- </label>
136
- `
137
- : operator === 'in'
156
+ return type === 'search'
157
+ ? html`<ox-input-search
158
+ name="search"
159
+ .value=${value}
160
+ ?autofocus=${this.autofocus}
161
+ ?readonly=${readonly}
162
+ ></ox-input-search>`
163
+ : type === 'boolean' || type === 'checkbox'
164
+ ? renderer(filter, value, this)
165
+ : type !== 'select'
138
166
  ? html`
139
- <ox-select
140
- name=${name}
141
- placeholder=${label}
142
- .value=${value}
143
- @change=${(e: CustomEvent) =>
144
- e.target?.dispatchEvent(
145
- new CustomEvent('filter-change', {
146
- detail: {
147
- name,
148
- operator,
149
- value: e.detail
150
- }
151
- })
152
- )}
153
- >
154
- <ox-popup-list multiple attr-selected="checked" with-search>
155
- ${renderer(filter, value, this)}
156
- </ox-popup-list>
157
- </ox-select>
167
+ <label filter-title ?between=${operator == 'between'}
168
+ ><span>${label}</span> ${renderer(filter, value, this)}
169
+ </label>
158
170
  `
159
- : html`
160
- <ox-select
161
- name=${name}
162
- placeholder=${label}
163
- .value=${value}
164
- @change=${(e: CustomEvent) =>
165
- e.target?.dispatchEvent(
166
- new CustomEvent('filter-change', {
167
- detail: {
168
- name,
169
- operator,
170
- value: e.detail
171
- }
172
- })
173
- )}
174
- >
175
- <ox-popup-list with-search> ${renderer(filter, value, this)} </ox-popup-list>
176
- </ox-select>
177
- `
178
- })}
171
+ : this.renderSelect(filter, value, renderer)
172
+ })}
179
173
  </form>
174
+
175
+ <slot name="setting"></slot>
180
176
  `
181
177
  }
182
178
 
183
- getFieldByName(name: string) {
184
- return this.renderRoot.querySelector(`[name=${name}]`)
179
+ renderSelect(filter: FilterConfig, value: any, renderer: FilterSelectRenderer) {
180
+ const { name, label, operator, readonly, value: defaultValue } = filter
181
+
182
+ return operator === 'in'
183
+ ? html`
184
+ <ox-select
185
+ name=${name}
186
+ placeholder=${label}
187
+ .value=${value ?? defaultValue}
188
+ @change=${(e: CustomEvent) =>
189
+ e.target?.dispatchEvent(
190
+ new CustomEvent('filter-change', {
191
+ detail: {
192
+ name,
193
+ operator,
194
+ value: e.detail
195
+ }
196
+ })
197
+ )}
198
+ ?readonly=${readonly}
199
+ >
200
+ <ox-popup-list multiple attr-selected="checked" with-search>
201
+ ${renderer(filter, value, this)}
202
+ </ox-popup-list>
203
+ </ox-select>
204
+ `
205
+ : html`
206
+ <ox-select
207
+ name=${name}
208
+ placeholder=${label}
209
+ .value=${value ?? defaultValue}
210
+ @change=${(e: CustomEvent) =>
211
+ e.target?.dispatchEvent(
212
+ new CustomEvent('filter-change', {
213
+ detail: {
214
+ name,
215
+ operator,
216
+ value: e.detail
217
+ }
218
+ })
219
+ )}
220
+ ?readonly=${readonly}
221
+ >
222
+ <ox-popup-list with-search> ${renderer(filter, value, this)} </ox-popup-list>
223
+ </ox-select>
224
+ `
185
225
  }
186
226
 
187
227
  async updated(changes: PropertyValues<this>) {
@@ -245,12 +285,82 @@ export class OxFiltersFormBase extends LitElement {
245
285
  }
246
286
  }
247
287
  }
288
+
289
+ if (changes.has('personalConfigProvider') && this.personalConfigProvider) {
290
+ this.personalConfig = await this.personalConfigProvider.load()
291
+ } else if (changes.has('filters') || changes.has('personalConfig')) {
292
+ this.applyUpdatedConfiguration()
293
+ }
294
+ }
295
+
296
+ async applyUpdatedConfiguration() {
297
+ if (!this.filters) {
298
+ return
299
+ }
300
+
301
+ if (!this.personalConfig) {
302
+ this.personalFilters = [...this.filters]
303
+ } else {
304
+ const { filters: personalFilters } = this.personalConfig
305
+
306
+ if (personalFilters) {
307
+ const xfilters = this.filters.map((filter: Partial<FilterConfig>) => {
308
+ const personalFilter = personalFilters.find(pFilter => pFilter.name == filter.name)
309
+ return personalFilter ? { ...filter, ...personalFilter } : filter
310
+ })
311
+
312
+ function reorderList(a: Partial<FilterConfig>[], b: Partial<FilterConfig>[]): Partial<FilterConfig>[] {
313
+ // 결과 배열 초기화, a 배열 길이만큼 undefined로 채움
314
+ const result = new Array(a.length)
315
+
316
+ // b 배열에 없는 아이템은 원래 위치로 채움
317
+ a.forEach((item, index) => {
318
+ if (!item.name || !b.find(bi => bi.name == item.name)) {
319
+ result[index] = item
320
+ }
321
+ })
322
+
323
+ b.forEach(item => {
324
+ const ai = a.find(ai => ai.name == item.name)
325
+ if (ai) {
326
+ result[result.findIndex(slot => slot === undefined)] = ai
327
+ }
328
+ })
329
+
330
+ return result
331
+ }
332
+
333
+ // 배열 재정렬 실행
334
+ this.personalFilters = reorderList(xfilters as any, personalFilters as any) as FilterConfig[]
335
+ }
336
+ }
337
+
338
+ this.autoUpdateTargetsOnChange = {}
339
+
340
+ this.personalFilters
341
+ ?.filter(filter => filter.boundTo && filter.boundTo.length > 0)
342
+ .map(({ name, boundTo }) => {
343
+ boundTo!.forEach(to => {
344
+ const origin = this.autoUpdateTargetsOnChange[to] || []
345
+ if (name && !origin.includes(name)) {
346
+ this.autoUpdateTargetsOnChange[to] = [...origin, name]
347
+ }
348
+ })
349
+ })
350
+
351
+ if (!this.urlParamsSensitive) {
352
+ this.value = await this.getQueryFilters()
353
+ }
354
+ }
355
+
356
+ getFieldByName(name: string) {
357
+ return this.renderRoot.querySelector(`[name=${name}]`)
248
358
  }
249
359
 
250
360
  async getQueryFilters(): Promise<FilterValue[]> {
251
361
  const formData = new FormData(await this.form)
252
362
 
253
- var filters = this.filters
363
+ var filters = (this.personalFilters || [])
254
364
  .map((filter: FilterConfig) => {
255
365
  const { name, type, operator } = filter
256
366
 
@@ -290,4 +400,37 @@ export class OxFiltersFormBase extends LitElement {
290
400
 
291
401
  return filters
292
402
  }
403
+
404
+ reset(value?: string[] | { [field: string]: any }) {
405
+ this.form
406
+ .then((form: HTMLFormElement) => {
407
+ if (value) {
408
+ if (value instanceof Array) {
409
+ value
410
+ .filter(item => typeof item == 'string')
411
+ .forEach(item => {
412
+ const field = this.getFieldByName(item)
413
+ if (field) {
414
+ ;(field as HTMLInputElement).value = ''
415
+ }
416
+ })
417
+ } else {
418
+ const keys = Object.keys(value)
419
+ keys
420
+ .filter(key => typeof key == 'string')
421
+ .forEach(key => {
422
+ const field = this.getFieldByName(key)
423
+ if (field) {
424
+ ;(field as HTMLInputElement).value = value[key]
425
+ }
426
+ })
427
+ }
428
+ } else {
429
+ form.reset()
430
+ }
431
+ })
432
+ .catch((error: any) => {
433
+ console.error('Error resetting the form:', error)
434
+ })
435
+ }
293
436
  }
@@ -23,7 +23,7 @@ export const MultiColumnFormStyles = css`
23
23
 
24
24
  padding: var(--legend-padding);
25
25
  font: var(--legend-font);
26
- color: var(--legend-text-color);
26
+ color: var(--legend-text-color, var(--md-sys-color-on-surface-variant));
27
27
  border-bottom: var(--legend-border-bottom);
28
28
  }
29
29
 
@@ -33,7 +33,7 @@ export const MultiColumnFormStyles = css`
33
33
  text-transform: capitalize;
34
34
  align-self: center;
35
35
 
36
- color: var(--label-color);
36
+ color: var(--label-color, var(--md-sys-color-on-surface));
37
37
  font: var(--label-font);
38
38
  }
39
39
 
@@ -72,7 +72,7 @@ export const MultiColumnFormStyles = css`
72
72
  grid-column: span 9 / auto;
73
73
 
74
74
  font: var(--form-sublabel-font);
75
- color: var(--form-sublabel-color);
75
+ color: var(--form-sublabel-color, var(--md-sys-color-on-surface));
76
76
  }
77
77
  .multi-column-form [options-wrap] {
78
78
  grid-column: span 21 / auto;
@@ -80,7 +80,7 @@ export const MultiColumnFormStyles = css`
80
80
 
81
81
  input:focus {
82
82
  outline: none;
83
- border: 1px solid var(--focus-background-color);
83
+ border: 1px solid var(--focus-background-color, var(--md-sys-color-surface-variant));
84
84
  }
85
85
  input[type='checkbox'] {
86
86
  margin: 0;
@@ -109,7 +109,7 @@ export const MultiColumnFormStyles = css`
109
109
  .multi-column-form [custom-input] {
110
110
  grid-column: span 8 / auto;
111
111
  max-width: initial;
112
- padding: var(--padding-default);
112
+ padding: var(--padding-default, var(--spacing-medium));
113
113
  font: normal 15px var(--theme-font);
114
114
  }
115
115
  .multi-column-form input[type='checkbox'],
@@ -131,7 +131,7 @@ export const MultiColumnFormStyles = css`
131
131
  .multi-column-form [options-wrap] {
132
132
  grid-column: span 12 / auto;
133
133
  display: grid;
134
- grid-gap: var(--padding-default) var(--padding-narrow);
134
+ grid-gap: var(--padding-default, var(--spacing-small)) var(--padding-narrow, var(--spacing-small));
135
135
  grid-template-columns: repeat(12, 1fr);
136
136
  }
137
137
  .multi-column-form [options-wrap] input[type='checkbox'] + label,
@@ -3,17 +3,16 @@ import { css } from 'lit'
3
3
  export const SearchFormStyles = css`
4
4
  :host {
5
5
  overflow: auto;
6
- background-color: var(--search-form-background-color);
6
+ background-color: transparent;
7
7
  }
8
8
 
9
9
  .search-form {
10
10
  position: relative;
11
11
  display: grid;
12
12
  grid-template-columns: repeat(24, 1fr);
13
- grid-gap: var(--form-grid-gap);
13
+ grid-gap: var(--form-grid-gap, var(--spacing-medium));
14
14
  grid-auto-rows: minmax(24px, auto);
15
- padding: var(--search-form-box-padding);
16
- border-bottom: 1px solid rgba(0, 0, 0, 0.1);
15
+ background-color: var(--search-form-background-color, var(--md-sys-color-surface));
17
16
  }
18
17
  .search-form label {
19
18
  grid-column: span 3;
@@ -21,8 +20,8 @@ export const SearchFormStyles = css`
21
20
  align-self: center;
22
21
  text-transform: capitalize;
23
22
 
24
- color: var(--label-color);
25
- font: var(--label-font);
23
+ font-size: var(--md-sys-typescale-label-large-size, 0.875rem);
24
+ color: var(--md-sys-color-on-primary-container);
26
25
  }
27
26
 
28
27
  .search-form input,
@@ -30,12 +29,13 @@ export const SearchFormStyles = css`
30
29
  grid-column: span 9;
31
30
 
32
31
  border: var(--input-field-border);
32
+ border-bottom: 1px solid rgba(0, 0, 0, 0.2);
33
33
  border-radius: var(--input-field-border-radius);
34
- padding: var(--input-field-padding);
34
+ padding: var(--input-field-padding, var(--spacing-tiny));
35
35
  font: var(--input-field-font);
36
36
  max-width: 85%;
37
- color: var(--input-field-color);
38
- background-color: var(--input-field-background-color);
37
+ color: var(--input-field-color, var(--md-sys-color-on-surface-variant));
38
+ background-color: transparent;
39
39
  }
40
40
 
41
41
  .search-form select {
@@ -60,13 +60,13 @@ export const SearchFormStyles = css`
60
60
  grid-column: span 9 / auto;
61
61
 
62
62
  font: var(--form-sublabel-font);
63
- color: var(--form-sublabel-color);
63
+ color: var(--form-sublabel-color, var(--md-sys-color-on-surface-variant));
64
64
  }
65
65
 
66
66
  input:focus {
67
67
  outline: none;
68
- border: 1px solid var(--focus-background-color);
69
68
  }
69
+
70
70
  input[type='checkbox'] {
71
71
  margin: 0;
72
72
  }
@@ -75,14 +75,19 @@ export const SearchFormStyles = css`
75
75
  position: absolute;
76
76
  right: 1%;
77
77
  bottom: 15px;
78
- color: var(--search-form-icon-color);
78
+ color: var(--search-form-icon-color, var(--md-sys-color-on-surface-variant));
79
+ }
80
+
81
+ input[readonly],
82
+ select[readonly] {
83
+ background-color: #f0f0f0;
79
84
  }
80
85
 
81
86
  @media screen and (max-width: 460px) {
82
87
  .search-form {
83
88
  grid-template-columns: repeat(12, 1fr);
84
- grid-gap: 10px 5px;
85
- background-color: var(--search-form-narrow-background-color);
89
+ grid-gap: var(--spacing-medium) var(--spacing-medium);
90
+ background-color: transparent;
86
91
 
87
92
  max-height: 100%;
88
93
  overflow-y: auto;
@@ -91,13 +96,13 @@ export const SearchFormStyles = css`
91
96
  grid-column: span 3;
92
97
  padding-right: 5px;
93
98
  align-self: center;
94
- color: var(--search-form-narrow-text-color);
99
+ color: var(--search-form-narrow-text-color, var(--md-sys-color-on-surface));
95
100
  }
96
101
  .search-form input,
97
102
  .search-form select {
98
103
  grid-column: span 8;
99
104
  max-width: 100%;
100
- color: var(--theme-white-color);
105
+ color: var(--md-sys-color-surface, var(--md-sys-color-on-surface));
101
106
  }
102
107
  .search-form input[type='checkbox'],
103
108
  .search-form input[type='radio'] {
@@ -112,12 +117,12 @@ export const SearchFormStyles = css`
112
117
  align-self: center;
113
118
  position: relative;
114
119
  left: 5px;
115
- color: var(--search-form-narrow-text-color);
120
+ color: var(--search-form-narrow-text-color, var(--md-sys-color-on-surface));
116
121
  }
117
122
 
118
123
  [search] {
119
124
  right: 3%;
120
- color: var(--search-form-narrow-text-color);
125
+ color: var(--search-form-narrow-text-color, var(--md-sys-color-on-surface));
121
126
  }
122
127
  }
123
128
  @media (min-width: 461px) and (max-width: 1024px) {
@@ -24,7 +24,7 @@ export const SingleColumnFormStyles = css`
24
24
 
25
25
  padding: var(--legend-padding);
26
26
  font: var(--legend-font);
27
- color: var(--legend-text-color);
27
+ color: var(--legend-text-color, var(--md-sys-color-on-surface-variant));
28
28
  border-bottom: var(--legend-border-bottom);
29
29
  }
30
30
 
@@ -33,7 +33,7 @@ export const SingleColumnFormStyles = css`
33
33
  text-align: right;
34
34
  text-transform: capitalize;
35
35
 
36
- color: var(--label-color);
36
+ color: var(--label-color, var(--md-sys-color-on-surface));
37
37
  font: var(--label-font);
38
38
  }
39
39
 
@@ -66,12 +66,12 @@ export const SingleColumnFormStyles = css`
66
66
  grid-column: span 9 / auto;
67
67
 
68
68
  font: var(--form-sublabel-font);
69
- color: var(--form-sublabel-color);
69
+ color: var(--form-sublabel-color, var(--md-sys-color-on-surface));
70
70
  }
71
71
 
72
72
  input:focus {
73
73
  outline: none;
74
- border: 1px solid var(--focus-background-color);
74
+ border: 1px solid var(--focus-background-color, var(--md-sys-color-surface-variant));
75
75
  }
76
76
  input[type='checkbox'] {
77
77
  margin: 0;
@@ -94,7 +94,7 @@ export const SingleColumnFormStyles = css`
94
94
  .single-column-form [custom-input] {
95
95
  grid-column: span 12;
96
96
 
97
- padding: var(--padding-default);
97
+ padding: var(--padding-default, var(--spacing-medium));
98
98
  font: normal 15px var(--theme-font);
99
99
  }
100
100
  .single-column-form input[type='checkbox'],
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { TemplateResult } from 'lit-html'
2
2
  import { OxFiltersFormBase } from './filters/ox-filters-form-base'
3
+ import { OxSearchForm } from './components/ox-search-form'
3
4
 
4
5
  export type FilterOperator =
5
6
  | 'search'
@@ -27,12 +28,31 @@ export type FilterOperator =
27
28
  | 'i_nlike'
28
29
  | 'nlike'
29
30
 
31
+ export type SelectOptionObject =
32
+ | {
33
+ name: string
34
+ display?: never
35
+ value: string
36
+ }
37
+ | {
38
+ display: string
39
+ name?: never
40
+ value: string
41
+ }
42
+
43
+ export type SelectOption = SelectOptionObject | string
44
+
45
+ export type FilterChangedCallback = (value: any, form: OxFiltersFormBase) => boolean | Promise<boolean>
46
+
30
47
  export type FilterConfig = {
31
48
  name: string
32
49
  label: string
33
50
  type: string
34
51
  operator?: FilterOperator
35
- options?: { [key: string]: any }
52
+ options?:
53
+ | { [key: string]: any }
54
+ | SelectOption[]
55
+ | ((form: OxFiltersFormBase) => SelectOption[] | Promise<SelectOption[]>)
36
56
  value?:
37
57
  | string
38
58
  | number
@@ -42,6 +62,9 @@ export type FilterConfig = {
42
62
  | number[]
43
63
  | { name: string; [params: string]: any }[]
44
64
  | undefined
65
+ boundTo?: string[]
66
+ hidden?: boolean
67
+ readonly?: boolean
45
68
  onchange?: FilterChangedCallback
46
69
  }
47
70
 
@@ -57,4 +80,27 @@ export type FilterSelectRenderer = (
57
80
  owner: Element
58
81
  ) => TemplateResult | string | void
59
82
 
60
- export type FilterChangedCallback = (value: any, form: OxFiltersFormBase) => boolean
83
+ export type SearchFilterChangedCallback = (value: any, form: OxSearchForm) => boolean | Promise<boolean>
84
+
85
+ export type SearchFormField = {
86
+ type: string
87
+ hidden?: boolean
88
+ name?: string
89
+ id?: string
90
+ label?: string
91
+ placeholder?: string
92
+ value?: any
93
+ field?: string
94
+ queryName?: string
95
+ props?: { [prop: string]: string }
96
+ attrs?: string[]
97
+ options?: SelectOption[] | ((form: OxSearchForm) => SelectOption[] | Promise<SelectOption[]>)
98
+ boundTo?: string[]
99
+ readonly?: boolean
100
+ handlers?: { [event: string]: EventListener }
101
+ onchange?: SearchFilterChangedCallback
102
+ }
103
+
104
+ export type PersonalFilterPreference = {
105
+ filters?: Partial<FilterConfig>[]
106
+ }