@operato/form 8.0.0-beta.0 → 8.0.0-beta.2
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.
- package/CHANGELOG.md +18 -0
- package/package.json +7 -7
- package/.editorconfig +0 -29
- package/.storybook/main.js +0 -3
- package/.storybook/preview.js +0 -52
- package/.storybook/server.mjs +0 -8
- package/demo/index.html +0 -110
- package/src/components/ox-custom-input.ts +0 -102
- package/src/components/ox-custom-select.ts +0 -91
- package/src/components/ox-file-uploader.ts +0 -164
- package/src/components/ox-form-master.ts +0 -246
- package/src/components/ox-form-paginator.ts +0 -60
- package/src/components/ox-search-form-paginator.ts +0 -46
- package/src/components/ox-search-form.ts +0 -467
- package/src/filters/filter-checkbox.ts +0 -34
- package/src/filters/filter-input-barcode.ts +0 -35
- package/src/filters/filter-input.ts +0 -30
- package/src/filters/filter-range-date.ts +0 -81
- package/src/filters/filter-range-number.ts +0 -64
- package/src/filters/filter-select.ts +0 -56
- package/src/filters/filter-styles.ts +0 -127
- package/src/filters/index.ts +0 -10
- package/src/filters/ox-filter-personalizer.ts +0 -188
- package/src/filters/ox-filters-form-base.ts +0 -437
- package/src/filters/registry.ts +0 -54
- package/src/index.ts +0 -4
- package/src/styles/index.ts +0 -3
- package/src/styles/multi-column-form-styles.ts +0 -192
- package/src/styles/search-form-styles.ts +0 -160
- package/src/styles/single-column-form-styles.ts +0 -114
- package/src/types.ts +0 -106
- package/stories/ox-filters-form-barcode.stories.ts +0 -140
- package/stories/ox-filters-form-base-bounded.stories.ts +0 -208
- package/stories/ox-filters-form-base-change-handler.stories.ts +0 -220
- package/stories/ox-filters-form-base-page-preference.stories.ts +0 -177
- package/stories/ox-filters-form-base.stories.ts +0 -179
- package/stories/ox-search-form-change-handler.stories.ts +0 -253
- package/stories/ox-search-form.stories.ts +0 -258
- package/tsconfig.json +0 -24
- package/web-dev-server.config.mjs +0 -27
- package/web-test-runner.config.mjs +0 -41
|
@@ -1,437 +0,0 @@
|
|
|
1
|
-
import '@operato/input/ox-checkbox.js'
|
|
2
|
-
import '@operato/input/ox-select.js'
|
|
3
|
-
import '@operato/popup/ox-popup-list.js'
|
|
4
|
-
import '@operato/input/ox-input-search.js'
|
|
5
|
-
|
|
6
|
-
import json5 from 'json5'
|
|
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'
|
|
10
|
-
|
|
11
|
-
import { getDefaultValue } from '@operato/time-calculator'
|
|
12
|
-
import { PagePreferenceProvider } from '@operato/p13n'
|
|
13
|
-
|
|
14
|
-
import { FilterStyles } from './filter-styles.js'
|
|
15
|
-
import { getFilterRenderer } from './registry.js'
|
|
16
|
-
import { FilterConfig, FilterOperator, FilterSelectRenderer, FilterValue, PersonalFilterPreference } from '../types.js'
|
|
17
|
-
|
|
18
|
-
export type QueryFilterRangeValue = [from: number, to: number]
|
|
19
|
-
|
|
20
|
-
@customElement('ox-filters-form-base')
|
|
21
|
-
export class OxFiltersFormBase extends LitElement {
|
|
22
|
-
static styles = [
|
|
23
|
-
MDTypeScaleStyles,
|
|
24
|
-
FilterStyles,
|
|
25
|
-
css`
|
|
26
|
-
:host {
|
|
27
|
-
display: flex;
|
|
28
|
-
padding: var(--spacing-small);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
form {
|
|
32
|
-
flex: 1;
|
|
33
|
-
|
|
34
|
-
display: flex;
|
|
35
|
-
flex-flow: row wrap;
|
|
36
|
-
gap: var(--spacing-medium) var(--spacing-large);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
form > * {
|
|
40
|
-
display: flex;
|
|
41
|
-
align-items: center;
|
|
42
|
-
gap: var(--spacing-small, 4px);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
label span {
|
|
46
|
-
display: block;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
@media only screen and (max-width: 460px) {
|
|
50
|
-
form {
|
|
51
|
-
flex-direction: column;
|
|
52
|
-
flex-flow: column;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
`
|
|
56
|
-
]
|
|
57
|
-
|
|
58
|
-
@property({ type: Array }) value: FilterValue[] = []
|
|
59
|
-
@property({ type: Array }) filters: FilterConfig[] = []
|
|
60
|
-
@property({ type: Boolean, attribute: 'url-params-sensitive' }) urlParamsSensitive?: boolean
|
|
61
|
-
@property({ type: Boolean, attribute: 'autofocus' }) autofocus: boolean = true
|
|
62
|
-
@property({ type: Object }) personalConfigProvider?: PagePreferenceProvider
|
|
63
|
-
|
|
64
|
-
@state() personalConfig?: PersonalFilterPreference
|
|
65
|
-
@state() personalFilters?: FilterConfig[]
|
|
66
|
-
|
|
67
|
-
@queryAsync('form') form!: HTMLFormElement
|
|
68
|
-
|
|
69
|
-
private _popstateEventHandler?: EventListener
|
|
70
|
-
private _filtersChangeHandler?: EventListener
|
|
71
|
-
private autoUpdateTargetsOnChange: { [name: string]: string[] } = {}
|
|
72
|
-
|
|
73
|
-
connectedCallback(): void {
|
|
74
|
-
super.connectedCallback()
|
|
75
|
-
|
|
76
|
-
this.renderRoot.addEventListener('change', async (e: Event) => {
|
|
77
|
-
const { target, detail: value } = e as CustomEvent
|
|
78
|
-
const name = (target as HTMLInputElement).name
|
|
79
|
-
const {
|
|
80
|
-
label,
|
|
81
|
-
type,
|
|
82
|
-
operator,
|
|
83
|
-
value: defaultValue,
|
|
84
|
-
onchange
|
|
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
|
|
102
|
-
|
|
103
|
-
// filters-form과 동일하게 value 세팅 X (셋팅후 다시 셋팅하여 랜더링을 다시하면서 값이 깨짐)
|
|
104
|
-
// this.value = await this.getQueryFilters()
|
|
105
|
-
|
|
106
|
-
keepGoing &&
|
|
107
|
-
this.dispatchEvent(
|
|
108
|
-
new CustomEvent('filters-change', {
|
|
109
|
-
bubbles: true,
|
|
110
|
-
composed: true,
|
|
111
|
-
detail: {
|
|
112
|
-
filters: this.value,
|
|
113
|
-
from: 'filters-form'
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
)
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
buildDefaultValue(operator: FilterOperator, defaultValue: any) {
|
|
121
|
-
if (defaultValue === undefined) {
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
if (operator == 'between') {
|
|
125
|
-
return defaultValue instanceof Array && (defaultValue as Array<any>).map(v => getDefaultValue(v, this))
|
|
126
|
-
} else {
|
|
127
|
-
return getDefaultValue(defaultValue, this)
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
render(): TemplateResult {
|
|
132
|
-
return html`
|
|
133
|
-
<form
|
|
134
|
-
class="md-typescale-body-medium-prominent"
|
|
135
|
-
@submit=${(e: Event) => {
|
|
136
|
-
e.preventDefault()
|
|
137
|
-
}}
|
|
138
|
-
>
|
|
139
|
-
${(this.personalFilters || [])
|
|
140
|
-
.filter(filter => !filter.hidden)
|
|
141
|
-
.map((filter: FilterConfig) => {
|
|
142
|
-
const { name, label, type, operator, readonly, value: defaultValue } = filter
|
|
143
|
-
const idx = operator === 'between' ? 1 : 0
|
|
144
|
-
const renderer = getFilterRenderer(
|
|
145
|
-
operator === 'like' || operator === 'i_like' || operator === 'i_nlike' || operator === 'nlike'
|
|
146
|
-
? 'text'
|
|
147
|
-
: type
|
|
148
|
-
)[idx]
|
|
149
|
-
|
|
150
|
-
const value =
|
|
151
|
-
this.value?.find(filter => filter.name == name)?.value ?? this.buildDefaultValue(operator!, defaultValue)
|
|
152
|
-
|
|
153
|
-
if (!renderer) {
|
|
154
|
-
return nothing
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return type === 'search'
|
|
158
|
-
? html`<ox-input-search
|
|
159
|
-
name="search"
|
|
160
|
-
.value=${value}
|
|
161
|
-
?autofocus=${this.autofocus}
|
|
162
|
-
?readonly=${readonly}
|
|
163
|
-
></ox-input-search>`
|
|
164
|
-
: type === 'boolean' || type === 'checkbox'
|
|
165
|
-
? renderer(filter, value, this)
|
|
166
|
-
: type !== 'select'
|
|
167
|
-
? html`
|
|
168
|
-
<label filter-title ?between=${operator == 'between'}
|
|
169
|
-
><span>${label}</span> ${renderer(filter, value, this)}
|
|
170
|
-
</label>
|
|
171
|
-
`
|
|
172
|
-
: this.renderSelect(filter, value, renderer)
|
|
173
|
-
})}
|
|
174
|
-
</form>
|
|
175
|
-
|
|
176
|
-
<slot name="setting"></slot>
|
|
177
|
-
`
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
renderSelect(filter: FilterConfig, value: any, renderer: FilterSelectRenderer) {
|
|
181
|
-
const { name, label, operator, readonly, value: defaultValue } = filter
|
|
182
|
-
|
|
183
|
-
return operator === 'in'
|
|
184
|
-
? html`
|
|
185
|
-
<ox-select
|
|
186
|
-
name=${name}
|
|
187
|
-
placeholder=${label}
|
|
188
|
-
.value=${value ?? defaultValue}
|
|
189
|
-
@change=${(e: CustomEvent) =>
|
|
190
|
-
e.target?.dispatchEvent(
|
|
191
|
-
new CustomEvent('filter-change', {
|
|
192
|
-
detail: {
|
|
193
|
-
name,
|
|
194
|
-
operator,
|
|
195
|
-
value: e.detail
|
|
196
|
-
}
|
|
197
|
-
})
|
|
198
|
-
)}
|
|
199
|
-
?readonly=${readonly}
|
|
200
|
-
>
|
|
201
|
-
<ox-popup-list multiple attr-selected="checked" with-search>
|
|
202
|
-
${renderer(filter, value, this)}
|
|
203
|
-
</ox-popup-list>
|
|
204
|
-
</ox-select>
|
|
205
|
-
`
|
|
206
|
-
: html`
|
|
207
|
-
<ox-select
|
|
208
|
-
name=${name}
|
|
209
|
-
placeholder=${label}
|
|
210
|
-
.value=${value ?? defaultValue}
|
|
211
|
-
@change=${(e: CustomEvent) =>
|
|
212
|
-
e.target?.dispatchEvent(
|
|
213
|
-
new CustomEvent('filter-change', {
|
|
214
|
-
detail: {
|
|
215
|
-
name,
|
|
216
|
-
operator,
|
|
217
|
-
value: e.detail
|
|
218
|
-
}
|
|
219
|
-
})
|
|
220
|
-
)}
|
|
221
|
-
?readonly=${readonly}
|
|
222
|
-
>
|
|
223
|
-
<ox-popup-list with-search> ${renderer(filter, value, this)} </ox-popup-list>
|
|
224
|
-
</ox-select>
|
|
225
|
-
`
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
async updated(changes: PropertyValues<this>) {
|
|
229
|
-
if (changes.has('urlParamsSensitive')) {
|
|
230
|
-
if (this.urlParamsSensitive) {
|
|
231
|
-
this._popstateEventHandler = () => {
|
|
232
|
-
const queryString = window.location.search
|
|
233
|
-
const urlParams = new URLSearchParams(queryString)
|
|
234
|
-
var filters = urlParams.get('filters')
|
|
235
|
-
|
|
236
|
-
if (filters) {
|
|
237
|
-
try {
|
|
238
|
-
this.value = json5.parse(filters)
|
|
239
|
-
this.dispatchEvent(
|
|
240
|
-
new CustomEvent('filters-change', {
|
|
241
|
-
bubbles: true,
|
|
242
|
-
composed: true,
|
|
243
|
-
detail: {
|
|
244
|
-
filters: json5.parse(filters),
|
|
245
|
-
from: 'url-parameter'
|
|
246
|
-
}
|
|
247
|
-
})
|
|
248
|
-
)
|
|
249
|
-
} catch (e) {
|
|
250
|
-
console.error(`invalid filters params on URL query string : ${e}`)
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
//@ts-ignore
|
|
256
|
-
this._popstateEventHandler() // call for the first time
|
|
257
|
-
|
|
258
|
-
window.addEventListener('popstate', this._popstateEventHandler)
|
|
259
|
-
|
|
260
|
-
this._filtersChangeHandler = (e: Event) => {
|
|
261
|
-
const urlParams = new URLSearchParams(window.location.search)
|
|
262
|
-
const { filters, from } = (e as CustomEvent).detail || {}
|
|
263
|
-
|
|
264
|
-
if (from === 'url-parameter') {
|
|
265
|
-
return
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
if (filters.length > 0) {
|
|
269
|
-
urlParams.set('filters', json5.stringify(filters))
|
|
270
|
-
} else {
|
|
271
|
-
urlParams.delete('filters')
|
|
272
|
-
}
|
|
273
|
-
const queryString = String(urlParams)
|
|
274
|
-
const url = `${window.location.pathname}${queryString ? `?${queryString}` : ''}`
|
|
275
|
-
|
|
276
|
-
history.pushState({}, document.title, url)
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
this.addEventListener('filters-change', this._filtersChangeHandler)
|
|
280
|
-
} else {
|
|
281
|
-
if (this._popstateEventHandler) {
|
|
282
|
-
window.removeEventListener('popstate', this._popstateEventHandler)
|
|
283
|
-
}
|
|
284
|
-
if (this._filtersChangeHandler) {
|
|
285
|
-
this.removeEventListener('popstate', this._filtersChangeHandler)
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
if (changes.has('personalConfigProvider') && this.personalConfigProvider) {
|
|
291
|
-
this.personalConfig = await this.personalConfigProvider.load()
|
|
292
|
-
} else if (changes.has('filters') || changes.has('personalConfig')) {
|
|
293
|
-
this.applyUpdatedConfiguration()
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
async applyUpdatedConfiguration() {
|
|
298
|
-
if (!this.filters) {
|
|
299
|
-
return
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
if (!this.personalConfig) {
|
|
303
|
-
this.personalFilters = [...this.filters]
|
|
304
|
-
} else {
|
|
305
|
-
const { filters: personalFilters } = this.personalConfig
|
|
306
|
-
|
|
307
|
-
if (personalFilters) {
|
|
308
|
-
const xfilters = this.filters.map((filter: Partial<FilterConfig>) => {
|
|
309
|
-
const personalFilter = personalFilters.find(pFilter => pFilter.name == filter.name)
|
|
310
|
-
return personalFilter ? { ...filter, ...personalFilter } : filter
|
|
311
|
-
})
|
|
312
|
-
|
|
313
|
-
function reorderList(a: Partial<FilterConfig>[], b: Partial<FilterConfig>[]): Partial<FilterConfig>[] {
|
|
314
|
-
// 결과 배열 초기화, a 배열 길이만큼 undefined로 채움
|
|
315
|
-
const result = new Array(a.length)
|
|
316
|
-
|
|
317
|
-
// b 배열에 없는 아이템은 원래 위치로 채움
|
|
318
|
-
a.forEach((item, index) => {
|
|
319
|
-
if (!item.name || !b.find(bi => bi.name == item.name)) {
|
|
320
|
-
result[index] = item
|
|
321
|
-
}
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
b.forEach(item => {
|
|
325
|
-
const ai = a.find(ai => ai.name == item.name)
|
|
326
|
-
if (ai) {
|
|
327
|
-
result[result.findIndex(slot => slot === undefined)] = ai
|
|
328
|
-
}
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
return result
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// 배열 재정렬 실행
|
|
335
|
-
this.personalFilters = reorderList(xfilters as any, personalFilters as any) as FilterConfig[]
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
this.autoUpdateTargetsOnChange = {}
|
|
340
|
-
|
|
341
|
-
this.personalFilters
|
|
342
|
-
?.filter(filter => filter.boundTo && filter.boundTo.length > 0)
|
|
343
|
-
.map(({ name, boundTo }) => {
|
|
344
|
-
boundTo!.forEach(to => {
|
|
345
|
-
const origin = this.autoUpdateTargetsOnChange[to] || []
|
|
346
|
-
if (name && !origin.includes(name)) {
|
|
347
|
-
this.autoUpdateTargetsOnChange[to] = [...origin, name]
|
|
348
|
-
}
|
|
349
|
-
})
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
if (!this.urlParamsSensitive) {
|
|
353
|
-
this.value = await this.getQueryFilters()
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
getFieldByName(name: string) {
|
|
358
|
-
return this.renderRoot.querySelector(`[name=${name}]`)
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
async getQueryFilters(): Promise<FilterValue[]> {
|
|
362
|
-
const formData = new FormData(await this.form)
|
|
363
|
-
|
|
364
|
-
var filters = (this.personalFilters || [])
|
|
365
|
-
.map((filter: FilterConfig) => {
|
|
366
|
-
const { name, type, operator } = filter
|
|
367
|
-
|
|
368
|
-
var value = formData.getAll(name)
|
|
369
|
-
if (value.length == 0) {
|
|
370
|
-
return
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (-1 === value.findIndex(v => v !== '')) {
|
|
374
|
-
return
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const filterValue = value.map(v => {
|
|
378
|
-
const value = v.toString()
|
|
379
|
-
|
|
380
|
-
/* TODO registry에서 타입별로 parsing 방법을 지정할 수 있도록 해야한다. */
|
|
381
|
-
switch (type) {
|
|
382
|
-
case 'integer':
|
|
383
|
-
case 'float':
|
|
384
|
-
case 'number':
|
|
385
|
-
case 'progress':
|
|
386
|
-
case 'checkbox':
|
|
387
|
-
case 'boolean':
|
|
388
|
-
return !value ? undefined : JSON.parse(value)
|
|
389
|
-
default:
|
|
390
|
-
return value
|
|
391
|
-
}
|
|
392
|
-
})
|
|
393
|
-
|
|
394
|
-
return {
|
|
395
|
-
name,
|
|
396
|
-
operator,
|
|
397
|
-
value: filterValue.length === 1 ? filterValue[0] : filterValue
|
|
398
|
-
}
|
|
399
|
-
})
|
|
400
|
-
.filter(result => result !== undefined) as FilterValue[]
|
|
401
|
-
|
|
402
|
-
return filters
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
reset(value?: string[] | { [field: string]: any }) {
|
|
406
|
-
this.form
|
|
407
|
-
.then((form: HTMLFormElement) => {
|
|
408
|
-
if (value) {
|
|
409
|
-
if (value instanceof Array) {
|
|
410
|
-
value
|
|
411
|
-
.filter(item => typeof item == 'string')
|
|
412
|
-
.forEach(item => {
|
|
413
|
-
const field = this.getFieldByName(item)
|
|
414
|
-
if (field) {
|
|
415
|
-
;(field as HTMLInputElement).value = ''
|
|
416
|
-
}
|
|
417
|
-
})
|
|
418
|
-
} else {
|
|
419
|
-
const keys = Object.keys(value)
|
|
420
|
-
keys
|
|
421
|
-
.filter(key => typeof key == 'string')
|
|
422
|
-
.forEach(key => {
|
|
423
|
-
const field = this.getFieldByName(key)
|
|
424
|
-
if (field) {
|
|
425
|
-
;(field as HTMLInputElement).value = value[key]
|
|
426
|
-
}
|
|
427
|
-
})
|
|
428
|
-
}
|
|
429
|
-
} else {
|
|
430
|
-
form.reset()
|
|
431
|
-
}
|
|
432
|
-
})
|
|
433
|
-
.catch((error: any) => {
|
|
434
|
-
console.error('Error resetting the form:', error)
|
|
435
|
-
})
|
|
436
|
-
}
|
|
437
|
-
}
|
package/src/filters/registry.ts
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { FilterCheckbox } from './filter-checkbox.js'
|
|
2
|
-
import { FilterInputBarcode } from './filter-input-barcode.js'
|
|
3
|
-
import { FilterInput } from './filter-input.js'
|
|
4
|
-
import { FilterRangeDate } from './filter-range-date.js'
|
|
5
|
-
import { FilterRangeNumber } from './filter-range-number.js'
|
|
6
|
-
import { FilterSelect } from './filter-select.js'
|
|
7
|
-
import { FilterSelectRenderer } from '../types.js'
|
|
8
|
-
|
|
9
|
-
var RENDERERS: {
|
|
10
|
-
[name: string]: FilterSelectRenderer[]
|
|
11
|
-
} = {
|
|
12
|
-
string: [FilterInput],
|
|
13
|
-
text: [FilterInput],
|
|
14
|
-
email: [FilterInput],
|
|
15
|
-
tel: [FilterInput],
|
|
16
|
-
integer: [FilterInput, FilterRangeNumber],
|
|
17
|
-
float: [FilterInput, FilterRangeNumber],
|
|
18
|
-
number: [FilterInput, FilterRangeNumber],
|
|
19
|
-
select: [FilterSelect],
|
|
20
|
-
boolean: [FilterCheckbox],
|
|
21
|
-
checkbox: [FilterCheckbox],
|
|
22
|
-
month: [FilterInput, FilterRangeDate],
|
|
23
|
-
week: [FilterInput, FilterRangeDate],
|
|
24
|
-
date: [FilterInput, FilterRangeDate],
|
|
25
|
-
time: [FilterInput, FilterRangeDate],
|
|
26
|
-
datetime: [FilterInput, FilterRangeDate],
|
|
27
|
-
color: [FilterInput],
|
|
28
|
-
progress: [FilterInput, FilterRangeNumber],
|
|
29
|
-
link: [FilterInput],
|
|
30
|
-
image: [FilterInput],
|
|
31
|
-
json5: [FilterInput],
|
|
32
|
-
scanner: [FilterInputBarcode],
|
|
33
|
-
barcode: [FilterInputBarcode]
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function registerFilterRenderer(type: string, renderer: FilterSelectRenderer[]) {
|
|
37
|
-
RENDERERS[type] = renderer
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export function unregisterFilterRenderer(type: string): void {
|
|
41
|
-
delete RENDERERS[type]
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function getFilterRenderers(): { [name: string]: FilterSelectRenderer[] } {
|
|
45
|
-
return { ...RENDERERS }
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
export function getFilterRenderer(type: string): FilterSelectRenderer[] {
|
|
49
|
-
if (typeof type == 'function') {
|
|
50
|
-
return type
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
return RENDERERS[type || 'text'] || [FilterInput]
|
|
54
|
-
}
|
package/src/index.ts
DELETED
package/src/styles/index.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import { css } from 'lit'
|
|
2
|
-
|
|
3
|
-
export const MultiColumnFormStyles = css`
|
|
4
|
-
:host {
|
|
5
|
-
overflow: auto;
|
|
6
|
-
padding: var(--form-container-padding);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
.multi-column-form {
|
|
10
|
-
display: grid;
|
|
11
|
-
grid-template-columns: repeat(24, 1fr);
|
|
12
|
-
grid-gap: var(--form-grid-gap);
|
|
13
|
-
grid-auto-rows: minmax(24px, auto);
|
|
14
|
-
max-width: var(--form-multi-column-max-width);
|
|
15
|
-
margin: var(--form-margin);
|
|
16
|
-
}
|
|
17
|
-
.multi-column-form fieldset {
|
|
18
|
-
display: contents;
|
|
19
|
-
}
|
|
20
|
-
.multi-column-form legend {
|
|
21
|
-
grid-column: span 24;
|
|
22
|
-
text-transform: capitalize;
|
|
23
|
-
|
|
24
|
-
padding: var(--legend-padding);
|
|
25
|
-
font: var(--legend-font);
|
|
26
|
-
color: var(--legend-text-color, var(--md-sys-color-on-surface-variant));
|
|
27
|
-
border-bottom: var(--legend-border-bottom);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
.multi-column-form label {
|
|
31
|
-
grid-column: span 3;
|
|
32
|
-
text-align: right;
|
|
33
|
-
text-transform: capitalize;
|
|
34
|
-
align-self: center;
|
|
35
|
-
|
|
36
|
-
color: var(--label-color, var(--md-sys-color-on-surface));
|
|
37
|
-
font: var(--label-font);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
.multi-column-form input,
|
|
41
|
-
.multi-column-form table,
|
|
42
|
-
.multi-column-form select,
|
|
43
|
-
.multi-column-form textarea,
|
|
44
|
-
.multi-column-form [custom-input] {
|
|
45
|
-
grid-column: span 9;
|
|
46
|
-
|
|
47
|
-
border: var(--input-field-border);
|
|
48
|
-
border-radius: var(--input-field-border-radius);
|
|
49
|
-
padding: var(--input-field-padding);
|
|
50
|
-
font: var(--input-field-font);
|
|
51
|
-
max-width: 85%;
|
|
52
|
-
}
|
|
53
|
-
.multi-column-form select {
|
|
54
|
-
min-height: 25px;
|
|
55
|
-
max-width: calc(85% + 18px);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
.multi-column-form input[type='checkbox'],
|
|
59
|
-
.multi-column-form input[type='radio'] {
|
|
60
|
-
justify-self: end;
|
|
61
|
-
align-self: center;
|
|
62
|
-
grid-column: span 3 / auto;
|
|
63
|
-
position: relative;
|
|
64
|
-
left: 17px;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
.multi-column-form input[type='checkbox'] + label,
|
|
68
|
-
.multi-column-form input[type='radio'] + label {
|
|
69
|
-
padding-left: 17px;
|
|
70
|
-
text-align: left;
|
|
71
|
-
align-self: center;
|
|
72
|
-
grid-column: span 9 / auto;
|
|
73
|
-
|
|
74
|
-
font: var(--form-sublabel-font);
|
|
75
|
-
color: var(--form-sublabel-color, var(--md-sys-color-secondary));
|
|
76
|
-
}
|
|
77
|
-
.multi-column-form [options-wrap] {
|
|
78
|
-
grid-column: span 21 / auto;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
input:focus {
|
|
82
|
-
outline: none;
|
|
83
|
-
border: 1px solid var(--focus-background-color, var(--md-sys-color-surface-variant));
|
|
84
|
-
}
|
|
85
|
-
input[type='checkbox'] {
|
|
86
|
-
margin: 0;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
@media screen and (max-width: 460px) {
|
|
90
|
-
.multi-column-form {
|
|
91
|
-
max-width: 100%;
|
|
92
|
-
grid-template-columns: repeat(12, 1fr);
|
|
93
|
-
grid-gap: 5px;
|
|
94
|
-
}
|
|
95
|
-
.multi-column-form legend {
|
|
96
|
-
grid-column: span 12;
|
|
97
|
-
}
|
|
98
|
-
.multi-column-form label {
|
|
99
|
-
grid-column: span 4 / auto;
|
|
100
|
-
text-align: left;
|
|
101
|
-
text-overflow: ellipsis;
|
|
102
|
-
white-space: nowrap;
|
|
103
|
-
overflow: hidden;
|
|
104
|
-
}
|
|
105
|
-
.multi-column-form input,
|
|
106
|
-
.multi-column-form table,
|
|
107
|
-
.multi-column-form select,
|
|
108
|
-
.multi-column-form textarea,
|
|
109
|
-
.multi-column-form [custom-input] {
|
|
110
|
-
grid-column: span 8 / auto;
|
|
111
|
-
max-width: initial;
|
|
112
|
-
padding: var(--padding-default, var(--spacing-medium));
|
|
113
|
-
font: normal 15px var(--theme-font);
|
|
114
|
-
}
|
|
115
|
-
.multi-column-form input[type='checkbox'],
|
|
116
|
-
.multi-column-form input[type='radio'] {
|
|
117
|
-
justify-self: left;
|
|
118
|
-
align-self: center;
|
|
119
|
-
grid-column: span 1 / auto;
|
|
120
|
-
left: 0;
|
|
121
|
-
zoom: 1.4;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
.multi-column-form input[type='checkbox'] + label,
|
|
125
|
-
.multi-column-form input[type='radio'] + label {
|
|
126
|
-
grid-column: span 11 / auto;
|
|
127
|
-
align-self: center;
|
|
128
|
-
position: relative;
|
|
129
|
-
left: -25px;
|
|
130
|
-
}
|
|
131
|
-
.multi-column-form [options-wrap] {
|
|
132
|
-
grid-column: span 12 / auto;
|
|
133
|
-
display: grid;
|
|
134
|
-
grid-gap: var(--padding-default, var(--spacing-small)) var(--spacing-small, var(--spacing-small));
|
|
135
|
-
grid-template-columns: repeat(12, 1fr);
|
|
136
|
-
}
|
|
137
|
-
.multi-column-form [options-wrap] input[type='checkbox'] + label,
|
|
138
|
-
.multi-column-form [options-wrap] input[type='radio'] + label {
|
|
139
|
-
grid-column: span 5 / auto;
|
|
140
|
-
align-self: left;
|
|
141
|
-
left: -4%;
|
|
142
|
-
margin-right: 0;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
@media (min-width: 481px) and (max-width: 1024px) {
|
|
146
|
-
.multi-column-form select {
|
|
147
|
-
max-width: calc(85% + 10px);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
@media screen and (min-width: 1201px) and (max-width: 2000px) {
|
|
151
|
-
.multi-column-form {
|
|
152
|
-
grid-template-columns: repeat(36, 1fr);
|
|
153
|
-
}
|
|
154
|
-
.multi-column-form legend {
|
|
155
|
-
grid-column: span 36;
|
|
156
|
-
}
|
|
157
|
-
.multi-column-form input,
|
|
158
|
-
.multi-column-form table,
|
|
159
|
-
.multi-column-form select,
|
|
160
|
-
.multi-column-form textarea,
|
|
161
|
-
.multi-column-form [custom-input] {
|
|
162
|
-
max-width: 90%;
|
|
163
|
-
}
|
|
164
|
-
.multi-column-form select {
|
|
165
|
-
max-width: calc(90% + 18px);
|
|
166
|
-
}
|
|
167
|
-
.multi-column-form [options-wrap] {
|
|
168
|
-
grid-column: span 33 / auto;
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
@media screen and (min-width: 2001px) {
|
|
172
|
-
.multi-column-form {
|
|
173
|
-
grid-template-columns: repeat(48, 1fr);
|
|
174
|
-
}
|
|
175
|
-
.multi-column-form legend {
|
|
176
|
-
grid-column: span 48;
|
|
177
|
-
}
|
|
178
|
-
.multi-column-form input,
|
|
179
|
-
.multi-column-form table,
|
|
180
|
-
.multi-column-form select,
|
|
181
|
-
.multi-column-form textarea,
|
|
182
|
-
.multi-column-form [custom-input] {
|
|
183
|
-
max-width: 90%;
|
|
184
|
-
}
|
|
185
|
-
.multi-column-form select {
|
|
186
|
-
max-width: calc(90% + 18px);
|
|
187
|
-
}
|
|
188
|
-
.multi-column-form [options-wrap] {
|
|
189
|
-
grid-column: span 45 / auto;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
`
|