@operato/data-grist 8.0.0-alpha.51 → 8.0.0-alpha.54

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 (52) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/src/record-view/index.d.ts +1 -1
  3. package/dist/src/record-view/index.js +1 -1
  4. package/dist/src/record-view/index.js.map +1 -1
  5. package/dist/src/record-view/{record-creator.d.ts → ox-record-creator.d.ts} +8 -4
  6. package/dist/src/record-view/{record-creator.js → ox-record-creator.js} +90 -34
  7. package/dist/src/record-view/ox-record-creator.js.map +1 -0
  8. package/dist/stories/accumulator-format.stories.d.ts +1 -1
  9. package/dist/stories/accumulator-format.stories.js +1 -1
  10. package/dist/stories/accumulator-format.stories.js.map +1 -1
  11. package/dist/stories/click-event-custom.stories.d.ts +45 -0
  12. package/dist/stories/click-event-custom.stories.js +247 -0
  13. package/dist/stories/click-event-custom.stories.js.map +1 -0
  14. package/dist/stories/click-event.stories.d.ts +1 -1
  15. package/dist/stories/click-event.stories.js +1 -1
  16. package/dist/stories/click-event.stories.js.map +1 -1
  17. package/dist/stories/fixed-column.stories.d.ts +1 -1
  18. package/dist/stories/fixed-column.stories.js +1 -1
  19. package/dist/stories/fixed-column.stories.js.map +1 -1
  20. package/dist/stories/grid-setting.stories.d.ts +1 -1
  21. package/dist/stories/grid-setting.stories.js +1 -1
  22. package/dist/stories/grid-setting.stories.js.map +1 -1
  23. package/dist/stories/grist-modes.stories.d.ts +1 -1
  24. package/dist/stories/grist-modes.stories.js +1 -1
  25. package/dist/stories/grist-modes.stories.js.map +1 -1
  26. package/dist/stories/group-header.stories.d.ts +1 -1
  27. package/dist/stories/group-header.stories.js +1 -1
  28. package/dist/stories/group-header.stories.js.map +1 -1
  29. package/dist/stories/textarea.stories.d.ts +1 -1
  30. package/dist/stories/textarea.stories.js +1 -1
  31. package/dist/stories/textarea.stories.js.map +1 -1
  32. package/dist/stories/tree-column-with-checkbox.stories.d.ts +1 -1
  33. package/dist/stories/tree-column-with-checkbox.stories.js +1 -1
  34. package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
  35. package/dist/stories/tree-column.stories.d.ts +1 -1
  36. package/dist/stories/tree-column.stories.js +1 -1
  37. package/dist/stories/tree-column.stories.js.map +1 -1
  38. package/dist/tsconfig.tsbuildinfo +1 -1
  39. package/package.json +4 -4
  40. package/src/record-view/index.ts +1 -1
  41. package/src/record-view/{record-creator.ts → ox-record-creator.ts} +104 -41
  42. package/stories/accumulator-format.stories.ts +1 -1
  43. package/stories/click-event-custom.stories.ts +287 -0
  44. package/stories/click-event.stories.ts +1 -1
  45. package/stories/fixed-column.stories.ts +1 -1
  46. package/stories/grid-setting.stories.ts +1 -1
  47. package/stories/grist-modes.stories.ts +1 -1
  48. package/stories/group-header.stories.ts +1 -1
  49. package/stories/textarea.stories.ts +1 -1
  50. package/stories/tree-column-with-checkbox.stories.ts +1 -1
  51. package/stories/tree-column.stories.ts +1 -1
  52. package/dist/src/record-view/record-creator.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@operato/data-grist",
3
- "version": "8.0.0-alpha.51",
3
+ "version": "8.0.0-alpha.54",
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"
@@ -108,5 +108,5 @@
108
108
  "prettier --write"
109
109
  ]
110
110
  },
111
- "gitHead": "ac94e729e3647d45c921be99f96f4c2e65cef797"
111
+ "gitHead": "a2e227ba9bb0a2be069abffff97c9e1e2ee62339"
112
112
  }
@@ -1,2 +1,2 @@
1
1
  export * from './record-view'
2
- export * from './record-creator'
2
+ export * from './ox-record-creator'
@@ -1,7 +1,7 @@
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'
@@ -11,10 +11,19 @@ import { ColumnConfig, GristRecord, ValidationReason } from '../types'
11
11
  import { RecordView } from './record-view'
12
12
 
13
13
  @customElement('ox-record-creator')
14
- export class RecordCreator extends LitElement {
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?: (operation: { [key: string]: any }) => boolean
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.lightPopupRecordView()
38
+ this.openLightPopup()
30
39
  } else {
31
- this.popupRecordView()
40
+ this.openPopup()
32
41
  }
33
42
  })
34
43
  }
@@ -40,26 +49,57 @@ export class RecordCreator extends LitElement {
40
49
  }
41
50
 
42
51
  render() {
43
- return html`<slot></slot>`
52
+ return html`
53
+ <slot></slot>
54
+ <slot name="popup"></slot>
55
+ `
44
56
  }
45
57
 
46
58
  validateRecord(record: GristRecord): { field: string; reason: ValidationReason }[] {
47
- const columns = this.grist!.compiledConfig.columns;
48
- const invalidFields: { field: string; reason: ValidationReason }[] = [];
49
-
50
- columns.forEach(column => {
51
- if (column.record?.mandatory && (record[column.name] === undefined || record[column.name] === null || record[column.name] === '')) {
52
- invalidFields.push({
53
- field: column.name,
54
- reason: ValidationReason.MANDATORY
55
- });
56
- }
57
- // 여기에 추가적인 유효성 검사 규칙을 구현할 수 있습니다.
58
- });
59
+ const columns = this.grist!.compiledConfig.columns
60
+ const invalidFields: { field: string; reason: ValidationReason }[] = []
61
+
62
+ columns
63
+ .filter(column => !column.hidden)
64
+ .forEach(column => {
65
+ if (
66
+ column.record?.mandatory &&
67
+ (record[column.name] === undefined || record[column.name] === null || record[column.name] === '')
68
+ ) {
69
+ invalidFields.push({
70
+ field: column.name,
71
+ reason: ValidationReason.MANDATORY
72
+ })
73
+ }
74
+ })
59
75
 
60
76
  return invalidFields
61
77
  }
62
78
 
79
+ openLightPopup() {
80
+ const slot = this.renderRoot?.querySelector(`slot[name='popup']`) as HTMLSlotElement
81
+ const slottedElements = slot?.assignedElements({ flatten: true })
82
+ const originalContent = slottedElements?.[0] as HTMLElement
83
+
84
+ if (originalContent) {
85
+ this.lightPopupCustomCreator(originalContent)
86
+ } else {
87
+ this.lightPopupRecordView()
88
+ }
89
+ }
90
+
91
+ openPopup() {
92
+ const slot = this.renderRoot?.querySelector(`slot[name='popup']`) as HTMLSlotElement
93
+ const slottedElements = slot?.assignedElements({ flatten: true })
94
+ const originalContent = slottedElements?.[0] as HTMLElement
95
+
96
+ if (originalContent) {
97
+ this.popupCustomCreator(originalContent)
98
+ } else {
99
+ this.popupRecordView()
100
+ }
101
+ }
102
+
63
103
  lightPopupRecordView() {
64
104
  const config = this.grist!.compiledConfig
65
105
  var title = 'create'
@@ -105,17 +145,12 @@ export class RecordCreator extends LitElement {
105
145
  popup.close()
106
146
  }}
107
147
  @ok=${async (e: Event) => {
108
- const view = e.currentTarget as RecordView
148
+ const view = e.currentTarget as RecordView
109
149
 
110
- // 레코드 밸리데이션 체크
111
- const invalidFields = await this.validateRecord(view.record);
150
+ const invalidFields = await this.validateRecord(view.record)
112
151
  if (invalidFields.length > 0) {
113
- // const firstInvalidField = invalidFields[0];
114
- // if (firstInvalidField) {
115
- // view.setFocus(firstInvalidField.field)
116
- // }
117
- view.setFocusOnInvalid(invalidFields);
118
- return false;
152
+ view.setFocusOnInvalid(invalidFields)
153
+ return false
119
154
  }
120
155
 
121
156
  popup.close()
@@ -171,25 +206,16 @@ export class RecordCreator extends LitElement {
171
206
  recordView.addEventListener('ok', async (e: Event) => {
172
207
  const view = e.currentTarget as RecordView
173
208
 
174
- // 레코드 밸리데이션 체크
175
- const invalidFields = await this.validateRecord(view.record);
209
+ const invalidFields = await this.validateRecord(view.record)
176
210
  if (invalidFields.length > 0) {
177
- const firstInvalidField = invalidFields[0];
178
- if (firstInvalidField) {
179
- const fieldElement = view.renderRoot?.querySelector(`[name="${firstInvalidField}"]`);
180
- if (fieldElement) {
181
- (fieldElement as HTMLElement).focus();
182
- }
183
- }
184
- return false;
211
+ view.setFocusOnInvalid(invalidFields)
212
+ return false
185
213
  }
186
-
214
+
187
215
  if (await this.callback?.(view.record)) {
188
216
  popup.close()
189
217
  } else {
190
- // 밸리데이션 실패 시 처리
191
- console.error('레코드 밸리데이션 실패');
192
- // 여기에 사용자에게 오류 메시지를 표시하는 로직을 추가할 수 있습니다.
218
+ console.error('validation failed')
193
219
  }
194
220
  })
195
221
 
@@ -223,4 +249,41 @@ export class RecordCreator extends LitElement {
223
249
  })
224
250
  )
225
251
  }
252
+
253
+ lightPopupCustomCreator(originalContent: HTMLElement) {
254
+ const title = 'create'
255
+ const popupContent = originalContent.cloneNode(true) as HTMLElement
256
+ popupContent.removeAttribute('slot')
257
+
258
+ OxPopup.open({
259
+ template: html`
260
+ <div title>${title}</div>
261
+ ${popupContent}
262
+ `,
263
+ parent: document.body,
264
+ preventCloseOnBlur: this.preventCloseOnBlur
265
+ })
266
+
267
+ this.customPopupCallback?.(popupContent) // 사용자 정의 팝업용 콜백 실행
268
+ }
269
+
270
+ popupCustomCreator(originalContent: HTMLElement) {
271
+ const title = 'create'
272
+ const popupContent = originalContent.cloneNode(true) as HTMLElement
273
+ popupContent.removeAttribute('slot')
274
+
275
+ document.dispatchEvent(
276
+ new CustomEvent('open-popup', {
277
+ detail: {
278
+ template: popupContent,
279
+ options: {
280
+ backdrop: true,
281
+ size: 'large',
282
+ title
283
+ },
284
+ callback: this.customPopupCallback
285
+ }
286
+ })
287
+ )
288
+ }
226
289
  }
@@ -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
 
@@ -0,0 +1,287 @@
1
+ import '../src/index.js'
2
+ import '../src/filters/filters-form.js'
3
+ import '../src/sorters/sorters-control.js'
4
+ import '../src/record-view/ox-record-creator.js'
5
+ import '@operato/popup/ox-popup-list.js'
6
+ import '@material/web/icon/icon.js'
7
+
8
+ import { html, TemplateResult } from 'lit'
9
+ import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'
10
+
11
+ import { FetchHandler, FetchOption, GristEventHandler } from '../src/types.js'
12
+
13
+ import { CommonHeaderStyles, CommonGristStyles } from '@operato/styles'
14
+
15
+ const fetchHandler: FetchHandler = async ({ page, limit }: FetchOption) => {
16
+ var total = 25
17
+ var start = (page! - 1) * limit!
18
+
19
+ await new Promise(resolve => setTimeout(resolve, 500))
20
+
21
+ return {
22
+ total,
23
+ records: Array(limit! * page! > total ? total % limit! : limit)
24
+ .fill('')
25
+ .map((item, idx) => {
26
+ return {
27
+ id: String(idx),
28
+ name: idx % 2 ? `shnam-${start + idx + 1}` : `heartyoh-${start + idx + 1}`,
29
+ description: idx % 2 ? `hatiolabmanager${start + idx + 1}1234567890` : `hatiosea manager-${start + idx + 1}`,
30
+ accval: Math.random(),
31
+ accval2: Math.round(Math.random() * 15),
32
+ createdAt: Date.now(),
33
+ updatedAt: Date.now()
34
+ }
35
+ })
36
+ }
37
+ }
38
+
39
+ const config = {
40
+ columns: [
41
+ {
42
+ type: 'gutter',
43
+ gutterName: 'dirty'
44
+ },
45
+ {
46
+ type: 'gutter',
47
+ gutterName: 'sequence'
48
+ },
49
+ {
50
+ type: 'gutter',
51
+ gutterName: 'row-selector',
52
+ multiple: true
53
+ },
54
+ {
55
+ type: 'gutter',
56
+ gutterName: 'button',
57
+ icon: 'add',
58
+ title: 'add',
59
+ handlers: {
60
+ click: ((columns, data, column, record, rowIndex, target, e) =>
61
+ console.log('column - clicked')) as GristEventHandler,
62
+ dblclick: ((columns, data, column, record, rowIndex, target, e) =>
63
+ console.log('column - dblclicked')) as GristEventHandler,
64
+ contextmenu: ((columns, data, column, record, rowIndex, target, e) =>
65
+ console.log('column - contextmenued')) as GristEventHandler,
66
+ focus: ((columns, data, column, record, rowIndex, target, e) =>
67
+ console.log('column - focused')) as GristEventHandler
68
+ }
69
+ },
70
+ {
71
+ type: 'string',
72
+ name: 'id',
73
+ hidden: true
74
+ },
75
+ {
76
+ type: 'string',
77
+ name: 'name',
78
+ label: true,
79
+ header: 'name',
80
+ record: {
81
+ editable: true
82
+ },
83
+ filter: 'search',
84
+ sortable: true,
85
+ width: 120,
86
+ fixed: true
87
+ },
88
+ {
89
+ type: 'string',
90
+ name: 'description',
91
+ header: {
92
+ renderer: () => 'description',
93
+ style: 'text-transform: none;'
94
+ },
95
+ filter: 'search',
96
+ record: {
97
+ editable: true,
98
+ align: 'left'
99
+ },
100
+ width: 200
101
+ },
102
+ {
103
+ type: 'number',
104
+ name: 'accval',
105
+ label: true,
106
+ header: 'accval',
107
+ record: {
108
+ editable: true,
109
+ align: 'right',
110
+ defaultValue: 100,
111
+ format: '+$#,##0.00'
112
+ },
113
+ accumulator: 'avg',
114
+ sortable: true,
115
+ width: 130
116
+ },
117
+ {
118
+ type: 'number',
119
+ name: 'accval2',
120
+ label: true,
121
+ header: 'accval2',
122
+ record: {
123
+ editable: true,
124
+ align: 'right',
125
+ renderer: (value: any, column: any, record: any) => {
126
+ return value && Intl.NumberFormat('en-US').format(value)
127
+ }
128
+ },
129
+ accumulator: {
130
+ type: 'sum',
131
+ tag: true
132
+ },
133
+ sortable: true,
134
+ width: 130
135
+ },
136
+ {
137
+ type: 'datetime',
138
+ name: 'updatedAt',
139
+ header: 'updated at',
140
+ record: {
141
+ editable: true,
142
+ defaultValue: {
143
+ name: 'now'
144
+ }
145
+ },
146
+ filter: 'between',
147
+ sortable: true,
148
+ width: 180
149
+ },
150
+ {
151
+ type: 'datetime',
152
+ name: 'createdAt',
153
+ header: 'created at',
154
+ record: {
155
+ editable: false
156
+ },
157
+ sortable: true,
158
+ width: 180
159
+ }
160
+ ],
161
+ rows: {
162
+ selectable: {
163
+ multiple: false
164
+ },
165
+ handlers: {
166
+ click: ((columns, data, column, record, rowIndex, target, e) =>
167
+ console.log('row - clicked')) as GristEventHandler,
168
+ dblclick: ((columns, data, column, record, rowIndex, target, e) =>
169
+ console.log('row - dblclicked')) as GristEventHandler,
170
+ contextmenu: ((columns, data, column, record, rowIndex, target, e) =>
171
+ console.log('row - contextmenued')) as GristEventHandler,
172
+ focus: ((columns, data, column, record, rowIndex, target, e) => console.log('row - focused')) as GristEventHandler
173
+ },
174
+ accumulator: true
175
+ },
176
+ sorters: [
177
+ {
178
+ name: 'name',
179
+ desc: true
180
+ }
181
+ ],
182
+ pagination: {
183
+ pages: [20, 30, 50, 100, 200]
184
+ }
185
+ }
186
+
187
+ export default {
188
+ title: 'click events for custom popup in ox-grist',
189
+ component: 'ox-grist',
190
+ argTypes: {
191
+ config: { control: 'object' },
192
+ mode: { control: 'select', options: ['GRID', 'LIST', 'CARD'] },
193
+ urlParamsSensitive: { control: 'boolean' },
194
+ withoutSearch: { control: 'boolean' },
195
+ preventCloseOnBlur: { control: 'boolean' }
196
+ }
197
+ }
198
+
199
+ interface Story<T> {
200
+ (args: T): TemplateResult
201
+ args?: Partial<T>
202
+ argTypes?: Record<string, unknown>
203
+ }
204
+
205
+ interface ArgTypes {
206
+ config: object
207
+ mode: 'GRID' | 'LIST' | 'CARD'
208
+ urlParamsSensitive: boolean
209
+ withoutSearch: boolean
210
+ preventCloseOnBlur: boolean
211
+ fetchHandler: FetchHandler
212
+ }
213
+
214
+ const Template: Story<ArgTypes> = ({
215
+ config,
216
+ mode = 'GRID',
217
+ urlParamsSensitive = false,
218
+ withoutSearch = false,
219
+ preventCloseOnBlur = false,
220
+ fetchHandler
221
+ }: ArgTypes) =>
222
+ html` <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;500;700&display=swap" rel="stylesheet" />
223
+
224
+ <link href="/themes/light.css" rel="stylesheet" />
225
+ <link href="/themes/dark.css" rel="stylesheet" />
226
+ <link href="/themes/spacing.css" rel="stylesheet" />
227
+ <link href="/themes/grist-theme.css" rel="stylesheet" />
228
+
229
+ <link
230
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL@20..48,100..700,0..1"
231
+ rel="stylesheet"
232
+ />
233
+ <link
234
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Rounded:opsz,wght,FILL@20..48,100..700,0..1"
235
+ rel="stylesheet"
236
+ />
237
+ <link
238
+ href="https://fonts.googleapis.com/css2?family=Material+Symbols+Sharp:opsz,wght,FILL@20..48,100..700,0..1"
239
+ rel="stylesheet"
240
+ />
241
+
242
+ <style>
243
+ ${MDTypeScaleStyles.cssText}
244
+ </style>
245
+
246
+ <style>
247
+ ${CommonGristStyles.cssText}
248
+ ${CommonHeaderStyles.cssText}
249
+ </style>
250
+
251
+ <style>
252
+ ox-grist {
253
+ height: 600px;
254
+ }
255
+
256
+ ox-filters-form {
257
+ flex: 1;
258
+ }
259
+ </style>
260
+
261
+ <ox-grist
262
+ mode=${mode}
263
+ .config=${config}
264
+ .fetchHandler=${fetchHandler}
265
+ ?url-params-sensitive=${urlParamsSensitive}
266
+ @filters-change=${(e: Event) => console.log('filters', (e.target as any).filters)}
267
+ >
268
+ <div slot="headroom" class="header">
269
+ <div class="filters">
270
+ <ox-filters-form ?without-search=${withoutSearch} autofocus></ox-filters-form>
271
+ <ox-record-creator id="add" light-popup ?prevent-close-on-blur=${preventCloseOnBlur}>
272
+ <button><md-icon>add</md-icon></button>
273
+ <div slot="popup">
274
+ <label>Test</label>
275
+ <input />
276
+ </div>
277
+ </ox-record-creator>
278
+ </div>
279
+ </div>
280
+ </ox-grist>`
281
+
282
+ export const Regular = Template.bind({})
283
+ Regular.args = {
284
+ config,
285
+ fetchHandler,
286
+ mode: 'GRID'
287
+ }
@@ -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
 
@@ -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
 
@@ -6,7 +6,7 @@ import { sleep } from '@operato/utils'
6
6
  import '../src/index.js'
7
7
  import '../src/filters/filters-form.js'
8
8
  import '../src/sorters/sorters-control.js'
9
- import '../src/record-view/record-creator.js'
9
+ import '../src/record-view/ox-record-creator.js'
10
10
  import '../src/personalizer/ox-grist-personalizer.js'
11
11
  import '../src/personalizer/ox-grist-filter-personalizer.js'
12
12
 
@@ -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
 
@@ -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
 
@@ -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
 
@@ -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
 
@@ -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
 
@@ -1 +0,0 @@
1
- {"version":3,"file":"record-creator.js","sourceRoot":"","sources":["../../../src/record-view/record-creator.ts"],"names":[],"mappings":"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","sourcesContent":["import '@material/web/icon/icon.js'\nimport './record-view'\n\nimport { html, LitElement } from 'lit'\nimport { customElement, property, state } from 'lit/decorators.js'\n\nimport { OxPopup } from '@operato/popup'\n\nimport { DataGrist } from '../data-grist'\nimport { ColumnConfig, GristRecord, ValidationReason } from '../types'\nimport { RecordView } from './record-view'\n\n@customElement('ox-record-creator')\nexport class RecordCreator extends LitElement {\n @state() grist?: DataGrist\n\n @property({ type: Object }) callback?: (operation: { [key: string]: any }) => boolean\n @property({ type: Boolean, attribute: 'light-popup' }) lightPopup: boolean = false\n @property({ type: Boolean, attribute: 'prevent-close-on-blur' }) preventCloseOnBlur = false\n\n constructor() {\n super()\n\n this.addEventListener('click', (e: Event) => {\n e.preventDefault()\n e.stopPropagation()\n\n if (this.lightPopup) {\n this.lightPopupRecordView()\n } else {\n this.popupRecordView()\n }\n })\n }\n\n connectedCallback(): void {\n super.connectedCallback()\n\n this.grist = this.closest('ox-grist') as DataGrist\n }\n\n render() {\n return html`<slot></slot>`\n }\n\n validateRecord(record: GristRecord): { field: string; reason: ValidationReason }[] {\n const columns = this.grist!.compiledConfig.columns;\n const invalidFields: { field: string; reason: ValidationReason }[] = [];\n\n columns.forEach(column => {\n if (column.record?.mandatory && (record[column.name] === undefined || record[column.name] === null || record[column.name] === '')) {\n invalidFields.push({\n field: column.name,\n reason: ValidationReason.MANDATORY\n });\n }\n // 여기에 추가적인 유효성 검사 규칙을 구현할 수 있습니다.\n });\n\n return invalidFields\n }\n\n lightPopupRecordView() {\n const config = this.grist!.compiledConfig\n var title = 'create'\n const rowIndex = -1\n var record: GristRecord = {}\n const columns = config.columns\n\n var popup = OxPopup.open({\n template: html`\n <div title>${title}</div>\n <ox-record-view\n @field-change=${(e: CustomEvent) => {\n const view = e.currentTarget as RecordView\n\n var { after, before, column, record, row } = (e as CustomEvent).detail as {\n after: any\n before: any\n column: ColumnConfig\n record: GristRecord\n row: number\n }\n\n var validation = column.validation\n if (validation && typeof validation == 'function') {\n if (!validation.call(this, after, before, record, column)) {\n return\n }\n }\n\n view.record = {\n ...record,\n [column.name]: after\n }\n }}\n .columns=${columns}\n .record=${record}\n .rowIndex=${rowIndex}\n @reset=${(e: Event) => {\n const view = e.currentTarget as RecordView\n view.record = {}\n }}\n @cancel=${(e: Event) => {\n popup.close()\n }}\n @ok=${async (e: Event) => {\n const view = e.currentTarget as RecordView\n\n // 레코드 밸리데이션 체크\n const invalidFields = await this.validateRecord(view.record);\n if (invalidFields.length > 0) {\n // const firstInvalidField = invalidFields[0];\n // if (firstInvalidField) {\n // view.setFocus(firstInvalidField.field)\n // }\n view.setFocusOnInvalid(invalidFields);\n return false;\n }\n\n popup.close()\n\n this.dispatchEvent(\n new CustomEvent('ok', {\n bubbles: true,\n composed: true,\n detail: view.record\n })\n )\n }}\n ></ox-record-view>\n `,\n parent: document.body,\n preventCloseOnBlur: this.preventCloseOnBlur\n })\n }\n\n popupRecordView() {\n const config = this.grist!.compiledConfig\n const rowIndex = -1\n var record: GristRecord = {}\n const columns = config.columns\n\n var title = 'create'\n\n var recordView = document.createElement('ox-record-view') as RecordView\n\n recordView.columns = columns\n recordView.record = record\n recordView.rowIndex = rowIndex\n\n document.dispatchEvent(\n new CustomEvent('open-popup', {\n detail: {\n template: recordView,\n options: {\n backdrop: true,\n size: 'large',\n title\n },\n callback: (popup: any) => {\n recordView.addEventListener('reset', (e: Event) => {\n const view = e.currentTarget as RecordView\n view.record = {}\n })\n\n recordView.addEventListener('cancel', (e: Event) => {\n popup.close()\n })\n\n recordView.addEventListener('ok', async (e: Event) => {\n const view = e.currentTarget as RecordView\n\n // 레코드 밸리데이션 체크\n const invalidFields = await this.validateRecord(view.record);\n if (invalidFields.length > 0) {\n const firstInvalidField = invalidFields[0];\n if (firstInvalidField) {\n const fieldElement = view.renderRoot?.querySelector(`[name=\"${firstInvalidField}\"]`);\n if (fieldElement) {\n (fieldElement as HTMLElement).focus();\n }\n }\n return false;\n }\n \n if (await this.callback?.(view.record)) {\n popup.close()\n } else {\n // 밸리데이션 실패 시 처리\n console.error('레코드 밸리데이션 실패');\n // 여기에 사용자에게 오류 메시지를 표시하는 로직을 추가할 수 있습니다.\n }\n })\n\n recordView.addEventListener('field-change', async (e: Event) => {\n const view = e.currentTarget as RecordView\n\n var { after, before, column, record, row } = (e as CustomEvent).detail as {\n after: any\n before: any\n column: ColumnConfig\n record: GristRecord\n row: number\n }\n\n var validation = column.validation\n if (validation && typeof validation == 'function') {\n if (!(await validation.call(this, after, before, record, column))) {\n return\n }\n }\n\n view.record = {\n ...record,\n [column.name]: after\n }\n })\n\n popup.onclosed = () => {}\n }\n }\n })\n )\n }\n}\n"]}