@operato/data-grist 7.1.26 → 7.1.27
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 +11 -0
- package/dist/src/data-grist.d.ts +16 -1
- package/dist/src/data-grist.js +53 -20
- package/dist/src/data-grist.js.map +1 -1
- package/dist/src/record-view/index.d.ts +1 -1
- package/dist/src/record-view/index.js +1 -1
- package/dist/src/record-view/index.js.map +1 -1
- package/dist/src/record-view/ox-record-creator.d.ts +26 -0
- package/dist/src/record-view/ox-record-creator.js +260 -0
- package/dist/src/record-view/ox-record-creator.js.map +1 -0
- package/dist/src/record-view/record-view-body.d.ts +6 -1
- package/dist/src/record-view/record-view-body.js +43 -4
- package/dist/src/record-view/record-view-body.js.map +1 -1
- package/dist/src/record-view/record-view.d.ts +7 -1
- package/dist/src/record-view/record-view.js +7 -1
- package/dist/src/record-view/record-view.js.map +1 -1
- package/dist/src/types.d.ts +6 -0
- package/dist/src/types.js +7 -0
- package/dist/src/types.js.map +1 -1
- package/dist/stories/accumulator-format.stories.d.ts +1 -1
- package/dist/stories/accumulator-format.stories.js +1 -1
- package/dist/stories/accumulator-format.stories.js.map +1 -1
- package/dist/stories/click-event-custom.stories.d.ts +45 -0
- package/dist/stories/click-event-custom.stories.js +247 -0
- package/dist/stories/click-event-custom.stories.js.map +1 -0
- package/dist/stories/click-event.stories.d.ts +1 -1
- package/dist/stories/click-event.stories.js +1 -1
- package/dist/stories/click-event.stories.js.map +1 -1
- package/dist/stories/fixed-column.stories.d.ts +1 -1
- package/dist/stories/fixed-column.stories.js +1 -1
- package/dist/stories/fixed-column.stories.js.map +1 -1
- package/dist/stories/grid-setting.stories.d.ts +1 -1
- package/dist/stories/grid-setting.stories.js +1 -1
- package/dist/stories/grid-setting.stories.js.map +1 -1
- package/dist/stories/grist-modes.stories.d.ts +1 -1
- package/dist/stories/grist-modes.stories.js +1 -1
- package/dist/stories/grist-modes.stories.js.map +1 -1
- package/dist/stories/group-header.stories.d.ts +1 -1
- package/dist/stories/group-header.stories.js +1 -1
- package/dist/stories/group-header.stories.js.map +1 -1
- package/dist/stories/textarea.stories.d.ts +1 -1
- package/dist/stories/textarea.stories.js +1 -1
- package/dist/stories/textarea.stories.js.map +1 -1
- package/dist/stories/tree-column-with-checkbox.stories.d.ts +1 -1
- package/dist/stories/tree-column-with-checkbox.stories.js +1 -1
- package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
- package/dist/stories/tree-column.stories.d.ts +1 -1
- package/dist/stories/tree-column.stories.js +1 -1
- package/dist/stories/tree-column.stories.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +8 -8
- package/src/data-grist.ts +60 -24
- package/src/record-view/index.ts +1 -1
- package/src/record-view/{record-creator.ts → ox-record-creator.ts} +131 -10
- package/src/record-view/record-view-body.ts +50 -4
- package/src/record-view/record-view.ts +10 -2
- package/src/types.ts +8 -0
- package/stories/accumulator-format.stories.ts +1 -1
- package/stories/click-event-custom.stories.ts +287 -0
- package/stories/click-event.stories.ts +1 -1
- package/stories/fixed-column.stories.ts +1 -1
- package/stories/grid-setting.stories.ts +1 -1
- package/stories/grist-modes.stories.ts +1 -1
- package/stories/group-header.stories.ts +1 -1
- package/stories/textarea.stories.ts +1 -1
- package/stories/tree-column-with-checkbox.stories.ts +1 -1
- package/stories/tree-column.stories.ts +1 -1
- package/themes/calendar-theme.css +3 -1
- package/translations/en.json +5 -1
- package/translations/ja.json +5 -1
- package/translations/ko.json +5 -1
- package/translations/ms.json +5 -1
- package/translations/zh.json +5 -1
- package/dist/src/record-view/record-creator.d.ts +0 -17
- package/dist/src/record-view/record-creator.js +0 -148
- package/dist/src/record-view/record-creator.js.map +0 -1
- package/yarn-error.log +0 -16971
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@operato/data-grist",
|
3
|
-
"version": "7.1.
|
3
|
+
"version": "7.1.27",
|
4
4
|
"description": "User interface for grid (desktop) and list (mobile)",
|
5
5
|
"author": "heartyoh",
|
6
6
|
"main": "dist/index.js",
|
@@ -23,7 +23,7 @@
|
|
23
23
|
"./ox-report.js": "./dist/src/data-report.js",
|
24
24
|
"./ox-filters-form.js": "./dist/src/filters/filters-form.js",
|
25
25
|
"./ox-sorters-control.js": "./dist/src/sorters/sorters-control.js",
|
26
|
-
"./ox-record-creator.js": "./dist/src/record-view/record-creator.js",
|
26
|
+
"./ox-record-creator.js": "./dist/src/record-view/ox-record-creator.js",
|
27
27
|
"./ox-grist-personalizer.js": "./dist/src/personalizer/ox-grist-personalizer.js"
|
28
28
|
},
|
29
29
|
"typesVersions": {
|
@@ -41,7 +41,7 @@
|
|
41
41
|
"dist/src/sorters/sorters-control.d.ts"
|
42
42
|
],
|
43
43
|
"ox-record-creator.js": [
|
44
|
-
"dist/src/record-view/record-creator.d.ts"
|
44
|
+
"dist/src/record-view/ox-record-creator.d.ts"
|
45
45
|
],
|
46
46
|
"ox-grist-personalizer.js": [
|
47
47
|
"dist/src/personalizer/ox-grist-personalizer.d.ts"
|
@@ -63,11 +63,11 @@
|
|
63
63
|
"dependencies": {
|
64
64
|
"@material/web": "^2.0.0",
|
65
65
|
"@operato/headroom": "^7.1.1",
|
66
|
-
"@operato/input": "^7.1.
|
67
|
-
"@operato/p13n": "^7.1.
|
68
|
-
"@operato/popup": "^7.1.
|
66
|
+
"@operato/input": "^7.1.27",
|
67
|
+
"@operato/p13n": "^7.1.27",
|
68
|
+
"@operato/popup": "^7.1.27",
|
69
69
|
"@operato/pull-to-refresh": "^7.1.1",
|
70
|
-
"@operato/styles": "^7.1.
|
70
|
+
"@operato/styles": "^7.1.27",
|
71
71
|
"@operato/time-calculator": "^7.1.1",
|
72
72
|
"@operato/utils": "^7.1.1",
|
73
73
|
"i18next": "^23.11.5",
|
@@ -108,5 +108,5 @@
|
|
108
108
|
"prettier --write"
|
109
109
|
]
|
110
110
|
},
|
111
|
-
"gitHead": "
|
111
|
+
"gitHead": "c1c3d738aa1f8462b2483cd1ebdfdfbe95d7e22a"
|
112
112
|
}
|
package/src/data-grist.ts
CHANGED
@@ -31,7 +31,8 @@ import {
|
|
31
31
|
GristSelectFunction,
|
32
32
|
PaginationConfig,
|
33
33
|
PersonalGristPreference,
|
34
|
-
SortersConfig
|
34
|
+
SortersConfig,
|
35
|
+
ValidationReason
|
35
36
|
} from './types'
|
36
37
|
import { convertListParamToSearchString, convertSearchStringToListParam } from './utils'
|
37
38
|
|
@@ -478,28 +479,28 @@ export class DataGrist extends LitElement implements DataConsumer {
|
|
478
479
|
</ox-grid>
|
479
480
|
`
|
480
481
|
: this.mode == 'CARD'
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
482
|
+
? html`
|
483
|
+
<ox-card
|
484
|
+
id="grist"
|
485
|
+
.config=${this.compiledConfig}
|
486
|
+
.data=${this._data}
|
487
|
+
.sorters=${this.sorters || []}
|
488
|
+
.filters=${this.filters || []}
|
489
|
+
?empty=${empty}
|
490
|
+
>
|
491
|
+
</ox-card>
|
492
|
+
`
|
493
|
+
: html`
|
494
|
+
<ox-list
|
495
|
+
id="grist"
|
496
|
+
.config=${this.compiledConfig}
|
497
|
+
.data=${this._data}
|
498
|
+
.sorters=${this.sorters || []}
|
499
|
+
.filters=${this.filters || []}
|
500
|
+
?empty=${empty}
|
501
|
+
>
|
502
|
+
</ox-list>
|
503
|
+
`}
|
503
504
|
</div>
|
504
505
|
|
505
506
|
<div id="spinner" ?show=${this._showSpinner}></div>
|
@@ -1190,8 +1191,43 @@ export class DataGrist extends LitElement implements DataConsumer {
|
|
1190
1191
|
})
|
1191
1192
|
)
|
1192
1193
|
}
|
1193
|
-
|
1194
|
+
/**
|
1195
|
+
* Returns the current pagination limit.
|
1196
|
+
* @returns {number} The current pagination limit value
|
1197
|
+
*/
|
1194
1198
|
getCurrentLimit() {
|
1195
1199
|
return this.dataProvider?.limit || ZERO_PAGINATION.limit
|
1196
1200
|
}
|
1201
|
+
|
1202
|
+
/**
|
1203
|
+
* Checks the validity of dirty records.
|
1204
|
+
* @returns {Array<{record: GristRecord, invalidFields: Array<{field: string, reason: ValidationReason}>}>} List of invalid records and their corresponding invalid fields
|
1205
|
+
*/
|
1206
|
+
checkDirtyRecordsValidity(): { record: GristRecord; invalidFields: { field: string; reason: ValidationReason }[] }[] {
|
1207
|
+
const records = this.dirtyRecords
|
1208
|
+
const validationResults = []
|
1209
|
+
|
1210
|
+
for (const record of records) {
|
1211
|
+
const invalidFields = []
|
1212
|
+
|
1213
|
+
for (const column of this.compiledConfig.columns) {
|
1214
|
+
if (column.record?.mandatory && (record[column.name] === undefined || record[column.name] === null)) {
|
1215
|
+
invalidFields.push({
|
1216
|
+
field: column.name,
|
1217
|
+
reason: ValidationReason.MANDATORY
|
1218
|
+
})
|
1219
|
+
}
|
1220
|
+
// Additional validation rules can be implemented here.
|
1221
|
+
}
|
1222
|
+
|
1223
|
+
if (invalidFields.length > 0) {
|
1224
|
+
validationResults.push({
|
1225
|
+
record,
|
1226
|
+
invalidFields
|
1227
|
+
})
|
1228
|
+
}
|
1229
|
+
}
|
1230
|
+
|
1231
|
+
return validationResults
|
1232
|
+
}
|
1197
1233
|
}
|
package/src/record-view/index.ts
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
export * from './record-view'
|
2
|
-
export * from './record-creator'
|
2
|
+
export * from './ox-record-creator'
|
@@ -1,20 +1,29 @@
|
|
1
1
|
import '@material/web/icon/icon.js'
|
2
2
|
import './record-view'
|
3
3
|
|
4
|
-
import { html, LitElement } from 'lit'
|
4
|
+
import { css, html, LitElement } from 'lit'
|
5
5
|
import { customElement, property, state } from 'lit/decorators.js'
|
6
6
|
|
7
7
|
import { OxPopup } from '@operato/popup'
|
8
8
|
|
9
9
|
import { DataGrist } from '../data-grist'
|
10
|
-
import { ColumnConfig, GristRecord } from '../types'
|
10
|
+
import { ColumnConfig, GristRecord, ValidationReason } from '../types'
|
11
11
|
import { RecordView } from './record-view'
|
12
12
|
|
13
13
|
@customElement('ox-record-creator')
|
14
|
-
export class
|
14
|
+
export class OxRecordCreator extends LitElement {
|
15
|
+
static styles = [
|
16
|
+
css`
|
17
|
+
::slotted([slot='popup']) {
|
18
|
+
display: none;
|
19
|
+
}
|
20
|
+
`
|
21
|
+
]
|
22
|
+
|
15
23
|
@state() grist?: DataGrist
|
16
24
|
|
17
|
-
@property({ type: Object }) callback?: (
|
25
|
+
@property({ type: Object }) callback?: (record: GristRecord) => boolean
|
26
|
+
@property({ type: Object }) customPopupCallback?: (popup: any) => boolean
|
18
27
|
@property({ type: Boolean, attribute: 'light-popup' }) lightPopup: boolean = false
|
19
28
|
@property({ type: Boolean, attribute: 'prevent-close-on-blur' }) preventCloseOnBlur = false
|
20
29
|
|
@@ -26,9 +35,9 @@ export class RecordCreator extends LitElement {
|
|
26
35
|
e.stopPropagation()
|
27
36
|
|
28
37
|
if (this.lightPopup) {
|
29
|
-
this.
|
38
|
+
this.openLightPopup()
|
30
39
|
} else {
|
31
|
-
this.
|
40
|
+
this.openPopup()
|
32
41
|
}
|
33
42
|
})
|
34
43
|
}
|
@@ -40,7 +49,53 @@ export class RecordCreator extends LitElement {
|
|
40
49
|
}
|
41
50
|
|
42
51
|
render() {
|
43
|
-
return html
|
52
|
+
return html`
|
53
|
+
<slot></slot>
|
54
|
+
<slot name="popup"></slot>
|
55
|
+
`
|
56
|
+
}
|
57
|
+
|
58
|
+
validateRecord(record: GristRecord): { field: string; reason: ValidationReason }[] {
|
59
|
+
const columns = this.grist!.compiledConfig.columns
|
60
|
+
const invalidFields: { field: string; reason: ValidationReason }[] = []
|
61
|
+
|
62
|
+
columns.forEach(column => {
|
63
|
+
if (
|
64
|
+
column.record?.mandatory &&
|
65
|
+
(record[column.name] === undefined || record[column.name] === null || record[column.name] === '')
|
66
|
+
) {
|
67
|
+
invalidFields.push({
|
68
|
+
field: column.name,
|
69
|
+
reason: ValidationReason.MANDATORY
|
70
|
+
})
|
71
|
+
}
|
72
|
+
})
|
73
|
+
|
74
|
+
return invalidFields
|
75
|
+
}
|
76
|
+
|
77
|
+
openLightPopup() {
|
78
|
+
const slot = this.renderRoot?.querySelector(`slot[name='popup']`) as HTMLSlotElement
|
79
|
+
const slottedElements = slot?.assignedElements({ flatten: true })
|
80
|
+
const originalContent = slottedElements?.[0] as HTMLElement
|
81
|
+
|
82
|
+
if (originalContent) {
|
83
|
+
this.lightPopupCustomCreator(originalContent)
|
84
|
+
} else {
|
85
|
+
this.lightPopupRecordView()
|
86
|
+
}
|
87
|
+
}
|
88
|
+
|
89
|
+
openPopup() {
|
90
|
+
const slot = this.renderRoot?.querySelector(`slot[name='popup']`) as HTMLSlotElement
|
91
|
+
const slottedElements = slot?.assignedElements({ flatten: true })
|
92
|
+
const originalContent = slottedElements?.[0] as HTMLElement
|
93
|
+
|
94
|
+
if (originalContent) {
|
95
|
+
this.popupCustomCreator(originalContent)
|
96
|
+
} else {
|
97
|
+
this.popupRecordView()
|
98
|
+
}
|
44
99
|
}
|
45
100
|
|
46
101
|
lightPopupRecordView() {
|
@@ -87,11 +142,22 @@ export class RecordCreator extends LitElement {
|
|
87
142
|
@cancel=${(e: Event) => {
|
88
143
|
popup.close()
|
89
144
|
}}
|
90
|
-
@ok=${(e: Event) => {
|
91
|
-
popup.close()
|
92
|
-
|
145
|
+
@ok=${async (e: Event) => {
|
93
146
|
const view = e.currentTarget as RecordView
|
94
147
|
|
148
|
+
// 레코드 밸리데이션 체크
|
149
|
+
const invalidFields = await this.validateRecord(view.record)
|
150
|
+
if (invalidFields.length > 0) {
|
151
|
+
// const firstInvalidField = invalidFields[0];
|
152
|
+
// if (firstInvalidField) {
|
153
|
+
// view.setFocus(firstInvalidField.field)
|
154
|
+
// }
|
155
|
+
view.setFocusOnInvalid(invalidFields)
|
156
|
+
return false
|
157
|
+
}
|
158
|
+
|
159
|
+
popup.close()
|
160
|
+
|
95
161
|
this.dispatchEvent(
|
96
162
|
new CustomEvent('ok', {
|
97
163
|
bubbles: true,
|
@@ -142,8 +208,26 @@ export class RecordCreator extends LitElement {
|
|
142
208
|
|
143
209
|
recordView.addEventListener('ok', async (e: Event) => {
|
144
210
|
const view = e.currentTarget as RecordView
|
211
|
+
|
212
|
+
// 레코드 밸리데이션 체크
|
213
|
+
const invalidFields = await this.validateRecord(view.record)
|
214
|
+
if (invalidFields.length > 0) {
|
215
|
+
const firstInvalidField = invalidFields[0]
|
216
|
+
if (firstInvalidField) {
|
217
|
+
const fieldElement = view.renderRoot?.querySelector(`[name="${firstInvalidField}"]`)
|
218
|
+
if (fieldElement) {
|
219
|
+
;(fieldElement as HTMLElement).focus()
|
220
|
+
}
|
221
|
+
}
|
222
|
+
return false
|
223
|
+
}
|
224
|
+
|
145
225
|
if (await this.callback?.(view.record)) {
|
146
226
|
popup.close()
|
227
|
+
} else {
|
228
|
+
// 밸리데이션 실패 시 처리
|
229
|
+
console.error('레코드 밸리데이션 실패')
|
230
|
+
// 여기에 사용자에게 오류 메시지를 표시하는 로직을 추가할 수 있습니다.
|
147
231
|
}
|
148
232
|
})
|
149
233
|
|
@@ -177,4 +261,41 @@ export class RecordCreator extends LitElement {
|
|
177
261
|
})
|
178
262
|
)
|
179
263
|
}
|
264
|
+
|
265
|
+
lightPopupCustomCreator(originalContent: HTMLElement) {
|
266
|
+
const title = 'create'
|
267
|
+
const popupContent = originalContent.cloneNode(true) as HTMLElement
|
268
|
+
popupContent.removeAttribute('slot')
|
269
|
+
|
270
|
+
OxPopup.open({
|
271
|
+
template: html`
|
272
|
+
<div title>${title}</div>
|
273
|
+
${popupContent}
|
274
|
+
`,
|
275
|
+
parent: document.body,
|
276
|
+
preventCloseOnBlur: this.preventCloseOnBlur
|
277
|
+
})
|
278
|
+
|
279
|
+
this.customPopupCallback?.(popupContent) // 사용자 정의 팝업용 콜백 실행
|
280
|
+
}
|
281
|
+
|
282
|
+
popupCustomCreator(originalContent: HTMLElement) {
|
283
|
+
const title = 'create'
|
284
|
+
const popupContent = originalContent.cloneNode(true) as HTMLElement
|
285
|
+
popupContent.removeAttribute('slot')
|
286
|
+
|
287
|
+
document.dispatchEvent(
|
288
|
+
new CustomEvent('open-popup', {
|
289
|
+
detail: {
|
290
|
+
template: popupContent,
|
291
|
+
options: {
|
292
|
+
backdrop: true,
|
293
|
+
size: 'large',
|
294
|
+
title
|
295
|
+
},
|
296
|
+
callback: this.customPopupCallback
|
297
|
+
}
|
298
|
+
})
|
299
|
+
)
|
300
|
+
}
|
180
301
|
}
|
@@ -5,8 +5,9 @@ import { css, html, LitElement } from 'lit'
|
|
5
5
|
import { customElement, property } from 'lit/decorators.js'
|
6
6
|
|
7
7
|
import { ZERO_RECORD } from '../configure/zero-config'
|
8
|
-
import { ColumnConfig, GristRecord } from '../types'
|
8
|
+
import { ColumnConfig, GristRecord, ValidationReason } from '../types'
|
9
9
|
import { recordViewBodyClickHandler } from './event-handlers/record-view-body-click-handler'
|
10
|
+
import i18next from 'i18next'
|
10
11
|
|
11
12
|
@customElement('ox-record-view-body')
|
12
13
|
export class RecordViewBody extends LitElement {
|
@@ -86,7 +87,21 @@ export class RecordViewBody extends LitElement {
|
|
86
87
|
color: var(--record-view-focus-color);
|
87
88
|
font-weight: bold;
|
88
89
|
}
|
89
|
-
|
90
|
+
|
91
|
+
.highlight-invalid {
|
92
|
+
position: relative;
|
93
|
+
padding: var(--spacing-tiny) var(--spacing-small);
|
94
|
+
}
|
95
|
+
|
96
|
+
.highlight-invalid::after {
|
97
|
+
content: attr(data-reason); /* 콘텐츠를 동적으로 변경하기 위해 data-reason 속성을 사용 */
|
98
|
+
color: red;
|
99
|
+
font-size: 12px;
|
100
|
+
position: absolute;
|
101
|
+
left: 0;
|
102
|
+
bottom: -8px; /* 라벨 아래쪽에 메시지를 표시 */
|
103
|
+
}
|
104
|
+
|
90
105
|
@media only screen and (max-width: 1000px) {
|
91
106
|
div[content] {
|
92
107
|
grid-template-columns: 2fr 3fr;
|
@@ -142,6 +157,36 @@ export class RecordViewBody extends LitElement {
|
|
142
157
|
super.disconnectedCallback()
|
143
158
|
this.removeEventListener('keydown', this._onKeyDown)
|
144
159
|
}
|
160
|
+
|
161
|
+
setFocus(fieldElement: HTMLElement) {
|
162
|
+
fieldElement?.dispatchEvent(new CustomEvent('click', { bubbles: true, composed: true }))
|
163
|
+
}
|
164
|
+
|
165
|
+
setFocusOnInvalid(invalidFields: { field: string; reason: ValidationReason }[]) {
|
166
|
+
const allLabels = this.renderRoot.querySelectorAll('label')
|
167
|
+
allLabels.forEach((label: HTMLLabelElement) => {
|
168
|
+
label.classList.remove('highlight-invalid')
|
169
|
+
label.removeAttribute('data-reason')
|
170
|
+
});
|
171
|
+
|
172
|
+
// 유효성 검사를 통과하지 못한 필드에 대해 처리
|
173
|
+
invalidFields.forEach(({ field, reason }, index) => {
|
174
|
+
const labelElement = this.renderRoot.querySelector(`[data-name="${field}"]`) as HTMLLabelElement
|
175
|
+
const fieldElement = this.renderRoot.querySelector(`[data-name="${field}"] + ox-grid-field`) as HTMLInputElement
|
176
|
+
|
177
|
+
// 동적으로 data-reason 속성을 설정하여 메시지를 변경
|
178
|
+
if (labelElement) {
|
179
|
+
labelElement.classList.add('highlight-invalid');
|
180
|
+
labelElement.setAttribute('data-reason', '(' + i18next.t(`text.validation-reason.${reason}`) + ')')
|
181
|
+
}
|
182
|
+
|
183
|
+
// 첫 번째 필드에 포커스 설정
|
184
|
+
if (index === 0 && fieldElement) {
|
185
|
+
this.setFocus(fieldElement)
|
186
|
+
}
|
187
|
+
});
|
188
|
+
}
|
189
|
+
|
145
190
|
|
146
191
|
_onKeyDown(event: KeyboardEvent) {
|
147
192
|
if (event.key === 'Tab') {
|
@@ -156,7 +201,8 @@ export class RecordViewBody extends LitElement {
|
|
156
201
|
}
|
157
202
|
|
158
203
|
event.preventDefault()
|
159
|
-
fields[nextIndex]
|
204
|
+
const nextField = fields[nextIndex] as HTMLInputElement
|
205
|
+
nextField && this.setFocus(nextField)
|
160
206
|
}
|
161
207
|
}
|
162
208
|
|
@@ -176,7 +222,7 @@ export class RecordViewBody extends LitElement {
|
|
176
222
|
let dirtyFields = record['__dirtyfields__'] || {}
|
177
223
|
|
178
224
|
return html`
|
179
|
-
<label ?editable=${editable} ?wide=${wide}>
|
225
|
+
<label ?editable=${editable} ?wide=${wide} data-name=${column.name}>
|
180
226
|
<span>${mandatory ? '*' : ''}${this._renderLabel(column)}</span>
|
181
227
|
<md-icon>edit</md-icon>
|
182
228
|
</label>
|
@@ -4,12 +4,14 @@ import '@operato/input/ox-input-file.js'
|
|
4
4
|
import '../data-grid/data-grid-field'
|
5
5
|
|
6
6
|
import { css, html, LitElement } from 'lit'
|
7
|
-
import { customElement, property } from 'lit/decorators.js'
|
7
|
+
import { customElement, property, query } from 'lit/decorators.js'
|
8
8
|
|
9
9
|
import { ScrollbarStyles } from '@operato/styles'
|
10
10
|
|
11
11
|
import { ZERO_RECORD } from '../configure/zero-config'
|
12
|
-
import { ColumnConfig, GristRecord } from '../types'
|
12
|
+
import { ColumnConfig, GristRecord, ValidationReason } from '../types'
|
13
|
+
|
14
|
+
import { RecordViewBody } from './record-view-body'
|
13
15
|
|
14
16
|
@customElement('ox-record-view')
|
15
17
|
export class RecordView extends LitElement {
|
@@ -66,6 +68,8 @@ export class RecordView extends LitElement {
|
|
66
68
|
@property({ type: Object }) record: GristRecord = ZERO_RECORD
|
67
69
|
@property({ type: Number }) rowIndex: number = -1
|
68
70
|
|
71
|
+
@query('ox-record-view-body') body!: RecordViewBody
|
72
|
+
|
69
73
|
render() {
|
70
74
|
return html`
|
71
75
|
<ox-record-view-body .columns=${this.columns} .record=${this.record} .rowIndex=${this.rowIndex}>
|
@@ -82,6 +86,10 @@ export class RecordView extends LitElement {
|
|
82
86
|
this.setAttribute('tabindex', '0')
|
83
87
|
}
|
84
88
|
|
89
|
+
setFocusOnInvalid(invalidFields: { field: string; reason: ValidationReason }[]) {
|
90
|
+
this.body.setFocusOnInvalid(invalidFields)
|
91
|
+
}
|
92
|
+
|
85
93
|
onReset() {
|
86
94
|
this.focus()
|
87
95
|
|
package/src/types.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import '../src/index.js'
|
2
2
|
import '../src/filters/filters-form.js'
|
3
3
|
import '../src/sorters/sorters-control.js'
|
4
|
-
import '../src/record-view/record-creator.js'
|
4
|
+
import '../src/record-view/ox-record-creator.js'
|
5
5
|
import '@operato/popup/ox-popup-list.js'
|
6
6
|
import '@material/web/icon/icon.js'
|
7
7
|
|