@operato/data-grist 8.0.0-alpha.8 → 8.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 (77) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/dist/src/data-grid/data-grid-body.js +21 -7
  3. package/dist/src/data-grid/data-grid-body.js.map +1 -1
  4. package/dist/src/data-grid/data-grid-footer.js +2 -0
  5. package/dist/src/data-grid/data-grid-footer.js.map +1 -1
  6. package/dist/src/data-grid/data-grid-header.d.ts +1 -1
  7. package/dist/src/data-grid/data-grid-header.js +13 -9
  8. package/dist/src/data-grid/data-grid-header.js.map +1 -1
  9. package/dist/src/editors/ox-grist-editor-varname.d.ts +6 -0
  10. package/dist/src/editors/ox-grist-editor-varname.js +36 -0
  11. package/dist/src/editors/ox-grist-editor-varname.js.map +1 -0
  12. package/dist/src/editors/ox-grist-editor.js +3 -3
  13. package/dist/src/editors/ox-grist-editor.js.map +1 -1
  14. package/dist/src/editors/registry.js +3 -1
  15. package/dist/src/editors/registry.js.map +1 -1
  16. package/dist/src/gutters/gutter-sequence.d.ts +1 -1
  17. package/dist/src/record-view/index.d.ts +1 -1
  18. package/dist/src/record-view/index.js +1 -1
  19. package/dist/src/record-view/index.js.map +1 -1
  20. package/dist/src/record-view/{record-creator.d.ts → ox-record-creator.d.ts} +8 -4
  21. package/dist/src/record-view/{record-creator.js → ox-record-creator.js} +90 -34
  22. package/dist/src/record-view/ox-record-creator.js.map +1 -0
  23. package/dist/src/renderers/ox-grist-renderer-boolean.js +1 -1
  24. package/dist/src/renderers/ox-grist-renderer-boolean.js.map +1 -1
  25. package/dist/stories/accumulator-format.stories.d.ts +1 -1
  26. package/dist/stories/accumulator-format.stories.js +1 -1
  27. package/dist/stories/accumulator-format.stories.js.map +1 -1
  28. package/dist/stories/click-event-custom.stories.d.ts +45 -0
  29. package/dist/stories/click-event-custom.stories.js +247 -0
  30. package/dist/stories/click-event-custom.stories.js.map +1 -0
  31. package/dist/stories/click-event.stories.d.ts +1 -1
  32. package/dist/stories/click-event.stories.js +1 -1
  33. package/dist/stories/click-event.stories.js.map +1 -1
  34. package/dist/stories/fixed-column.stories.d.ts +1 -1
  35. package/dist/stories/fixed-column.stories.js +1 -1
  36. package/dist/stories/fixed-column.stories.js.map +1 -1
  37. package/dist/stories/grid-setting.stories.d.ts +1 -1
  38. package/dist/stories/grid-setting.stories.js +1 -1
  39. package/dist/stories/grid-setting.stories.js.map +1 -1
  40. package/dist/stories/grist-modes.stories.d.ts +1 -1
  41. package/dist/stories/grist-modes.stories.js +1 -1
  42. package/dist/stories/grist-modes.stories.js.map +1 -1
  43. package/dist/stories/group-header.stories.d.ts +1 -1
  44. package/dist/stories/group-header.stories.js +1 -1
  45. package/dist/stories/group-header.stories.js.map +1 -1
  46. package/dist/stories/textarea.stories.d.ts +1 -1
  47. package/dist/stories/textarea.stories.js +1 -1
  48. package/dist/stories/textarea.stories.js.map +1 -1
  49. package/dist/stories/tree-column-with-checkbox.stories.d.ts +1 -1
  50. package/dist/stories/tree-column-with-checkbox.stories.js +1 -1
  51. package/dist/stories/tree-column-with-checkbox.stories.js.map +1 -1
  52. package/dist/stories/tree-column.stories.d.ts +1 -1
  53. package/dist/stories/tree-column.stories.js +1 -1
  54. package/dist/stories/tree-column.stories.js.map +1 -1
  55. package/dist/tsconfig.tsbuildinfo +1 -1
  56. package/package.json +20 -20
  57. package/src/data-grid/data-grid-body.ts +23 -7
  58. package/src/data-grid/data-grid-footer.ts +2 -0
  59. package/src/data-grid/data-grid-header.ts +13 -9
  60. package/src/editors/ox-grist-editor-varname.ts +36 -0
  61. package/src/editors/ox-grist-editor.ts +3 -3
  62. package/src/editors/registry.ts +3 -1
  63. package/src/record-view/index.ts +1 -1
  64. package/src/record-view/{record-creator.ts → ox-record-creator.ts} +104 -41
  65. package/src/renderers/ox-grist-renderer-boolean.ts +1 -1
  66. package/stories/accumulator-format.stories.ts +1 -1
  67. package/stories/click-event-custom.stories.ts +287 -0
  68. package/stories/click-event.stories.ts +1 -1
  69. package/stories/fixed-column.stories.ts +1 -1
  70. package/stories/grid-setting.stories.ts +1 -1
  71. package/stories/grist-modes.stories.ts +1 -1
  72. package/stories/group-header.stories.ts +1 -1
  73. package/stories/textarea.stories.ts +1 -1
  74. package/stories/tree-column-with-checkbox.stories.ts +1 -1
  75. package/stories/tree-column.stories.ts +1 -1
  76. package/themes/calendar-theme.css +3 -1
  77. 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.8",
3
+ "version": "8.0.0-beta.0",
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"
@@ -62,32 +62,32 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@material/web": "^2.0.0",
65
- "@operato/headroom": "^8.0.0-alpha.0",
66
- "@operato/input": "^8.0.0-alpha.4",
67
- "@operato/p13n": "^8.0.0-alpha.4",
68
- "@operato/popup": "^8.0.0-alpha.4",
69
- "@operato/pull-to-refresh": "^8.0.0-alpha.0",
70
- "@operato/styles": "^8.0.0-alpha.4",
71
- "@operato/time-calculator": "^8.0.0-alpha.6",
72
- "@operato/utils": "^8.0.0-alpha.0",
65
+ "@operato/headroom": "^8.0.0-beta.0",
66
+ "@operato/input": "^8.0.0-beta.0",
67
+ "@operato/p13n": "^8.0.0-beta.0",
68
+ "@operato/popup": "^8.0.0-beta.0",
69
+ "@operato/pull-to-refresh": "^8.0.0-beta.0",
70
+ "@operato/styles": "^8.0.0-beta.0",
71
+ "@operato/time-calculator": "^8.0.0-beta.0",
72
+ "@operato/utils": "^8.0.0-beta.0",
73
73
  "i18next": "^23.11.5",
74
74
  "json5": "^2.2.0",
75
75
  "lit": "^3.1.2",
76
76
  "lodash-es": "^4.17.21"
77
77
  },
78
78
  "devDependencies": {
79
- "@custom-elements-manifest/analyzer": "^0.9.2",
79
+ "@custom-elements-manifest/analyzer": "^0.10.0",
80
80
  "@hatiolab/prettier-config": "^1.0.0",
81
81
  "@open-wc/eslint-config": "^12.0.3",
82
- "@open-wc/testing": "^3.1.6",
82
+ "@open-wc/testing": "^4.0.0",
83
83
  "@types/lodash-es": "^4.17.5",
84
- "@typescript-eslint/eslint-plugin": "^7.0.1",
85
- "@typescript-eslint/parser": "^7.0.1",
86
- "@web/dev-server": "^0.3.0",
84
+ "@typescript-eslint/eslint-plugin": "^8.0.0",
85
+ "@typescript-eslint/parser": "^8.0.0",
86
+ "@web/dev-server": "^0.4.0",
87
87
  "@web/dev-server-storybook": "^2.0.1",
88
- "@web/test-runner": "^0.18.0",
89
- "concurrently": "^8.0.1",
90
- "eslint": "^8.39.0",
88
+ "@web/test-runner": "^0.19.0",
89
+ "concurrently": "^9.0.0",
90
+ "eslint": "^9.0.0",
91
91
  "eslint-config-prettier": "^9.1.0",
92
92
  "husky": "^9.0.11",
93
93
  "lint-staged": "^15.2.2",
@@ -108,5 +108,5 @@
108
108
  "prettier --write"
109
109
  ]
110
110
  },
111
- "gitHead": "f495fb42a98844182ac2db30d7c2aea815488d62"
111
+ "gitHead": "c4e9cc245659d050a9ffd66542083a6daad4bcb9"
112
112
  }
@@ -61,6 +61,9 @@ export class DataGridBody extends LitElement {
61
61
  css`
62
62
  :host {
63
63
  font-variation-settings: 'FILL' 1;
64
+
65
+ overscroll-behavior: none;
66
+ user-select: none;
64
67
  }
65
68
 
66
69
  [select-block] {
@@ -72,6 +75,7 @@ export class DataGridBody extends LitElement {
72
75
  border: var(--grid-record-focused-cell-border);
73
76
  background-image: var(--focused-background-image);
74
77
  pointer-events: none;
78
+
75
79
  z-index: 5;
76
80
  }
77
81
 
@@ -289,14 +293,16 @@ export class DataGridBody extends LitElement {
289
293
  )
290
294
  })
291
295
 
292
- this.renderRoot.addEventListener('mousedown', (event: Event) => {
293
- const e = event as MouseEvent
296
+ this.renderRoot.addEventListener('pointerdown', (e: Event) => {
294
297
  this.setSelectBlock()
295
298
 
296
- if (e.buttons !== 1) {
299
+ if ('buttons' in e && e.buttons !== 1) {
297
300
  return
298
301
  }
299
302
 
303
+ e.preventDefault()
304
+ e.stopPropagation()
305
+
300
306
  this._draggable = true
301
307
 
302
308
  var target = (e.target as Element).closest('ox-grid-field') as DataGridField
@@ -318,12 +324,15 @@ export class DataGridBody extends LitElement {
318
324
  }
319
325
  })
320
326
 
321
- this.renderRoot.addEventListener('mousemove', (event: Event) => {
327
+ this.renderRoot.addEventListener('pointermove', (event: Event) => {
322
328
  const e = event as MouseEvent
323
- if (e.buttons !== 1 || !this._draggable) {
329
+ if (('buttons' in e && e.buttons !== 1) || !this._draggable) {
324
330
  return
325
331
  }
326
332
 
333
+ e.preventDefault()
334
+ e.stopPropagation()
335
+
327
336
  const field = e.target as DataGridField
328
337
  if (!this._selectBlock) {
329
338
  this.setSelectBlock(this.focusedField || field, this.focusedField || field)
@@ -340,7 +349,10 @@ export class DataGridBody extends LitElement {
340
349
  }
341
350
  })
342
351
 
343
- this.renderRoot.addEventListener('mouseup', (event: Event) => {
352
+ this.renderRoot.addEventListener('pointerup', (event: Event) => {
353
+ event.preventDefault()
354
+ event.stopPropagation()
355
+
344
356
  this._draggable = false
345
357
  })
346
358
 
@@ -650,7 +662,11 @@ export class DataGridBody extends LitElement {
650
662
  value = parseToNumberOrNull(value)
651
663
  break
652
664
  default:
653
- value = value
665
+ try {
666
+ value = JSON.parse(value)
667
+ } catch (err) {
668
+ value = value
669
+ }
654
670
  }
655
671
 
656
672
  if (targetColumn && !targetColumn.gutterName && editable) {
@@ -21,6 +21,8 @@ export class DataGridFooter extends LitElement {
21
21
  background-color: var(--grid-footer-background-color);
22
22
  font-size: var(--grid-footer-font-size);
23
23
  align-items: center;
24
+
25
+ user-select: none;
24
26
  }
25
27
 
26
28
  :host * {
@@ -28,6 +28,8 @@ export class DataGridHeader extends LitElement {
28
28
  overflow: hidden;
29
29
 
30
30
  font-variation-settings: 'FILL' 1;
31
+
32
+ user-select: none;
31
33
  }
32
34
 
33
35
  :host([raised]) [fixed] {
@@ -266,7 +268,9 @@ export class DataGridHeader extends LitElement {
266
268
  : nothing}
267
269
  ${column.resizable !== false
268
270
  ? html`
269
- <span splitter draggable="false" @mousedown=${(e: MouseEvent) => this._mousedown(e, index)}>&nbsp;</span>
271
+ <span splitter draggable="false" @pointerdown=${(e: PointerEvent) => this._pointerdown(e, index)}
272
+ >&nbsp;</span
273
+ >
270
274
  `
271
275
  : nothing}
272
276
  </div>
@@ -543,11 +547,11 @@ export class DataGridHeader extends LitElement {
543
547
  this._throttledNotifier(idx, width)
544
548
  }
545
549
 
546
- _mousedown(e: MouseEvent, idx: number) {
550
+ _pointerdown(e: MouseEvent, idx: number) {
547
551
  e.stopPropagation()
548
552
  e.preventDefault()
549
553
 
550
- var mousemoveHandler = ((e: MouseEvent) => {
554
+ var pointermoveHandler = ((e: MouseEvent) => {
551
555
  e.stopPropagation()
552
556
  e.preventDefault()
553
557
  let column = this.columns[idx]
@@ -561,14 +565,14 @@ export class DataGridHeader extends LitElement {
561
565
  this._notifyWidthChange(idx, width)
562
566
  }).bind(this)
563
567
 
564
- var mouseupHandler = ((e: MouseEvent) => {
565
- document.removeEventListener('mousemove', mousemoveHandler)
566
- document.removeEventListener('mouseup', mouseupHandler)
568
+ var pointerupHandler = ((e: MouseEvent) => {
569
+ document.removeEventListener('pointermove', pointermoveHandler)
570
+ document.removeEventListener('pointerup', pointerupHandler)
567
571
 
568
- mousemoveHandler(e)
572
+ pointermoveHandler(e)
569
573
  }).bind(this)
570
574
 
571
- document.addEventListener('mousemove', mousemoveHandler)
572
- document.addEventListener('mouseup', mouseupHandler)
575
+ document.addEventListener('pointermove', pointermoveHandler)
576
+ document.addEventListener('pointerup', pointerupHandler)
573
577
  }
574
578
  }
@@ -0,0 +1,36 @@
1
+ import { OxGristEditor } from './ox-grist-editor.js'
2
+ import { customElement } from 'lit/decorators.js'
3
+ import { html } from 'lit'
4
+
5
+ @customElement('ox-grist-editor-varname')
6
+ export class OxGristEditorVarname extends OxGristEditor {
7
+ get inlineEditable() {
8
+ return true
9
+ }
10
+
11
+ get editorTemplate() {
12
+ return html`
13
+ <input
14
+ type="text"
15
+ .value=${this.value}
16
+ @input=${this.handleInput}
17
+ pattern="^[A-Za-z_][A-Za-z0-9_]*$"
18
+ title="Variable names must start with a letter or underscore and contain only letters, numbers, or underscores."
19
+ />
20
+ `
21
+ }
22
+
23
+ handleInput(event: KeyboardEvent) {
24
+ const input = event.target as HTMLInputElement
25
+ const regex = /^[A-Za-z_][A-Za-z0-9_]*$/
26
+
27
+ // Only allow valid characters as the user types
28
+ if (!regex.test(input.value)) {
29
+ // Keep only valid characters and start with a letter or underscore
30
+ input.value = input.value.replace(/[^A-Za-z0-9_]/g, '').replace(/^[^A-Za-z_]+/, '')
31
+ }
32
+
33
+ // Update the component's internal value state
34
+ this.value = input.value
35
+ }
36
+ }
@@ -107,9 +107,9 @@ export class OxGristEditor extends LitElement {
107
107
  this.addEventListener('keydown', this._onkeydown.bind(this))
108
108
 
109
109
  /* editor mode 인 경우의 마우스 움직임이, grist-body의 이벤트 처리에 의해서 에디터를 리셋시킬 수 있으므로, 이벤트 전파를 막는다. */
110
- this.addEventListener('mousedown', (e: Event) => e.stopPropagation())
111
- this.addEventListener('mousemove', (e: Event) => e.stopPropagation())
112
- this.addEventListener('mouseup', (e: Event) => e.stopPropagation())
110
+ this.addEventListener('pointerdown', (e: Event) => e.stopPropagation())
111
+ this.addEventListener('pointermove', (e: Event) => e.stopPropagation())
112
+ this.addEventListener('pointerup', (e: Event) => e.stopPropagation())
113
113
 
114
114
  const { name = '' } = this.column
115
115
  const { align, defaultValue } = this.column.record
@@ -19,6 +19,7 @@ import { OxGristEditorTextarea } from './ox-grist-editor-textarea'
19
19
  import { OxGristEditorTime } from './ox-grist-editor-time'
20
20
  import { OxGristEditorTree } from './ox-grist-editor-tree'
21
21
  import { OxGristEditorWeek } from './ox-grist-editor-week'
22
+ import { OxGristEditorVarname } from './ox-grist-editor-varname'
22
23
 
23
24
  var EDITORS: { [name: string]: { new (): OxGristEditor } } = {
24
25
  string: OxGristEditorText,
@@ -44,7 +45,8 @@ var EDITORS: { [name: string]: { new (): OxGristEditor } } = {
44
45
  image: OxGristEditorImage,
45
46
  file: OxGristEditorFile,
46
47
  'string[]': OxGristEditorMultipleSelect,
47
- tree: OxGristEditorTree
48
+ tree: OxGristEditorTree,
49
+ varname: OxGristEditorVarname
48
50
  }
49
51
 
50
52
  export function registerEditor(type: string, editor: { new (): OxGristEditor }) {
@@ -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
  }
@@ -12,7 +12,7 @@ export const OxGristRendererBoolean: FieldRenderer = (value, column, record, row
12
12
  type="checkbox"
13
13
  .checked=${!!value && !!String(value).match(/true/i)}
14
14
  ?disabled=${!editable}
15
- @mousedown=${(e: Event) => {
15
+ @pointerdown=${(e: Event) => {
16
16
  /* edit mode로 전환되지 않도록 차단함. 체크박스인풋은 렌더러 모드에서도 처리가능하므로. */
17
17
  e.stopPropagation()
18
18
  }}
@@ -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