@ai-table/grid 0.0.4 → 0.0.6

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 (73) hide show
  1. package/components/cell-editors/cell-editor.scss +20 -0
  2. package/components/cell-editors/number/number-editor.component.d.ts.map +1 -1
  3. package/components/cell-editors/progress/progress-editor.component.d.ts +22 -0
  4. package/components/cell-editors/progress/progress-editor.component.d.ts.map +1 -0
  5. package/components/cell-editors/progress/progress-editor.component.scss +21 -0
  6. package/components/cell-editors/rating/rating-editor.component.d.ts.map +1 -1
  7. package/components/cell-editors/text/text-editor.component.d.ts +9 -1
  8. package/components/cell-editors/text/text-editor.component.d.ts.map +1 -1
  9. package/components/field-property-editor/field-property-editor.component.d.ts.map +1 -1
  10. package/components/index.d.ts +6 -0
  11. package/components/index.d.ts.map +1 -1
  12. package/constants/editor.d.ts.map +1 -1
  13. package/constants/field.d.ts +3 -3
  14. package/constants/grid.d.ts +1 -0
  15. package/constants/grid.d.ts.map +1 -1
  16. package/core/constants/field.d.ts.map +1 -1
  17. package/core/types/core.d.ts +14 -8
  18. package/core/types/core.d.ts.map +1 -1
  19. package/core/utils/field.d.ts +3 -3
  20. package/core/utils/field.d.ts.map +1 -1
  21. package/esm2022/components/cell-editors/abstract-cell-editor.component.mjs +2 -2
  22. package/esm2022/components/cell-editors/number/number-editor.component.mjs +7 -6
  23. package/esm2022/components/cell-editors/progress/progress-editor.component.mjs +75 -0
  24. package/esm2022/components/cell-editors/rating/rating-editor.component.mjs +7 -6
  25. package/esm2022/components/cell-editors/select/select-editor.component.mjs +3 -3
  26. package/esm2022/components/cell-editors/text/text-editor.component.mjs +54 -21
  27. package/esm2022/components/field-menu/field-menu.component.mjs +3 -3
  28. package/esm2022/components/field-property-editor/field-property-editor.component.mjs +5 -5
  29. package/esm2022/components/index.mjs +7 -1
  30. package/esm2022/constants/editor.mjs +6 -8
  31. package/esm2022/constants/field.mjs +4 -4
  32. package/esm2022/constants/grid.mjs +4 -2
  33. package/esm2022/core/action/general.mjs +4 -4
  34. package/esm2022/core/constants/field.mjs +43 -3
  35. package/esm2022/core/types/core.mjs +6 -2
  36. package/esm2022/core/utils/field.mjs +6 -3
  37. package/esm2022/core/utils/queries.mjs +2 -2
  38. package/esm2022/core/utils/record.mjs +3 -3
  39. package/esm2022/grid.component.mjs +94 -50
  40. package/esm2022/pipes/grid.pipe.mjs +31 -0
  41. package/esm2022/pipes/index.mjs +2 -2
  42. package/esm2022/services/event.service.mjs +37 -24
  43. package/esm2022/services/selection.service.mjs +72 -0
  44. package/esm2022/types/field.mjs +1 -1
  45. package/esm2022/types/grid.mjs +2 -8
  46. package/esm2022/utils/build.mjs +35 -13
  47. package/esm2022/utils/cell.mjs +3 -3
  48. package/fesm2022/ai-table-grid.mjs +649 -397
  49. package/fesm2022/ai-table-grid.mjs.map +1 -1
  50. package/grid.component.d.ts +19 -16
  51. package/grid.component.d.ts.map +1 -1
  52. package/package.json +1 -1
  53. package/pipes/grid.pipe.d.ts +15 -0
  54. package/pipes/grid.pipe.d.ts.map +1 -0
  55. package/pipes/index.d.ts +1 -1
  56. package/pipes/index.d.ts.map +1 -1
  57. package/services/event.service.d.ts +7 -6
  58. package/services/event.service.d.ts.map +1 -1
  59. package/services/{selection.servive.d.ts → selection.service.d.ts} +1 -1
  60. package/services/{selection.servive.d.ts.map → selection.service.d.ts.map} +1 -1
  61. package/styles/styles.scss +6 -10
  62. package/types/field.d.ts +1 -1
  63. package/types/field.d.ts.map +1 -1
  64. package/types/grid.d.ts +8 -6
  65. package/types/grid.d.ts.map +1 -1
  66. package/utils/build.d.ts +3 -2
  67. package/utils/build.d.ts.map +1 -1
  68. package/utils/cell.d.ts +1 -1
  69. package/utils/cell.d.ts.map +1 -1
  70. package/esm2022/pipes/grid.mjs +0 -17
  71. package/esm2022/services/selection.servive.mjs +0 -64
  72. package/pipes/grid.d.ts +0 -9
  73. package/pipes/grid.d.ts.map +0 -1
@@ -1,50 +1,39 @@
1
- import * as i0 from '@angular/core';
2
- import { Pipe, signal, computed, model, inject, booleanAttribute, Component, ChangeDetectionStrategy, Input, Injectable, input, output } from '@angular/core';
3
- import * as i4 from '@angular/common';
1
+ import * as i1$2 from '@angular/common';
4
2
  import { NgIf, NgTemplateOutlet, NgForOf, NgClass, CommonModule, NgComponentOutlet } from '@angular/common';
5
- import { ThyTag } from 'ngx-tethys/tag';
6
- import * as i1$1 from 'ngx-tethys/popover';
7
- import { ThyPopoverRef, ThyPopoverModule } from 'ngx-tethys/popover';
3
+ import * as i0 from '@angular/core';
4
+ import { signal, input, inject, computed, Component, ChangeDetectionStrategy, Input, HostListener, ElementRef, Renderer2, model, booleanAttribute, Injectable, Pipe, DestroyRef, output, NgZone } from '@angular/core';
8
5
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
9
- import { helpers, isUndefinedOrNull } from 'ngx-tethys/util';
10
- import { createDraft, finishDraft } from 'immer';
11
- import { ThyIcon } from 'ngx-tethys/icon';
12
- import { of, Subject, fromEvent } from 'rxjs';
13
6
  import * as i1 from '@angular/forms';
14
7
  import { FormsModule } from '@angular/forms';
15
- import { ThyInputGroup, ThyInputCount, ThyInputDirective, ThyInput } from 'ngx-tethys/input';
8
+ import { ThyAction } from 'ngx-tethys/action';
9
+ import * as i3 from 'ngx-tethys/checkbox';
10
+ import { ThyCheckboxModule } from 'ngx-tethys/checkbox';
11
+ import { ThyDatePicker, ThyDatePickerFormatPipe } from 'ngx-tethys/date-picker';
12
+ import { ThyDropdownDirective, ThyDropdownMenuComponent, ThyDropdownMenuItemDirective, ThyDropdownMenuItemNameDirective, ThyDropdownMenuItemIconDirective } from 'ngx-tethys/dropdown';
13
+ import { ThyFlexibleText } from 'ngx-tethys/flexible-text';
14
+ import { ThyIcon } from 'ngx-tethys/icon';
15
+ import * as i1$1 from 'ngx-tethys/popover';
16
+ import { ThyPopoverRef, ThyPopover, ThyPopoverModule } from 'ngx-tethys/popover';
17
+ import { ThyProgress } from 'ngx-tethys/progress';
18
+ import { ThyRate } from 'ngx-tethys/rate';
19
+ import { ThyAutofocusDirective, ThyEnterDirective, ThyOption, ThyStopPropagationDirective } from 'ngx-tethys/shared';
20
+ import { ThyTag } from 'ngx-tethys/tag';
21
+ import { mergeWith } from 'rxjs/operators';
22
+ import { helpers, isUndefinedOrNull } from 'ngx-tethys/util';
23
+ import { createDraft, finishDraft } from 'immer';
24
+ import { ThyTimePickerModule } from 'ngx-tethys/time-picker';
25
+ import { ThyInputNumber } from 'ngx-tethys/input-number';
26
+ import { ThySlider } from 'ngx-tethys/slider';
27
+ import { ThyInputDirective, ThyInputGroup, ThyInputCount, ThyInput } from 'ngx-tethys/input';
16
28
  import * as i2 from 'ngx-tethys/form';
17
29
  import { ThyUniqueCheckValidator, ThyFormModule, ThyConfirmValidatorDirective } from 'ngx-tethys/form';
18
- import { ThyDropdownDirective, ThyDropdownMenuComponent, ThyDropdownMenuItemDirective, ThyDropdownMenuItemNameDirective, ThyDropdownMenuItemIconDirective } from 'ngx-tethys/dropdown';
19
30
  import { ThyButton } from 'ngx-tethys/button';
20
31
  import { ThyListItem } from 'ngx-tethys/list';
21
- import { ThyAutofocusDirective, ThyEnterDirective, ThyOption, ThyStopPropagationDirective } from 'ngx-tethys/shared';
22
- import { ThyInputNumber } from 'ngx-tethys/input-number';
23
- import { ThyDatePicker, ThyDatePickerFormatPipe } from 'ngx-tethys/date-picker';
24
- import { ThyTimePickerModule } from 'ngx-tethys/time-picker';
25
- import { ThyRate } from 'ngx-tethys/rate';
26
- import { ThyTooltipModule, ThyTooltipService } from 'ngx-tethys/tooltip';
27
- import { ThySelect } from 'ngx-tethys/select';
28
- import { ThyFlexibleText } from 'ngx-tethys/flexible-text';
29
- import * as i6 from 'ngx-tethys/checkbox';
30
- import { ThyCheckboxModule } from 'ngx-tethys/checkbox';
32
+ import { of, Subject, fromEvent, debounceTime } from 'rxjs';
31
33
  import { ThyDivider } from 'ngx-tethys/divider';
32
- import { ThyAction } from 'ngx-tethys/action';
33
-
34
- class SelectOptionPipe {
35
- transform(id, options) {
36
- return options.find((item) => item.id === id);
37
- }
38
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
39
- static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, isStandalone: true, name: "selectOption" }); }
40
- }
41
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, decorators: [{
42
- type: Pipe,
43
- args: [{
44
- name: 'selectOption',
45
- standalone: true
46
- }]
47
- }] });
34
+ import { ThySelect } from 'ngx-tethys/select';
35
+ import * as i4 from 'ngx-tethys/avatar';
36
+ import { ThyAvatarModule } from 'ngx-tethys/avatar';
48
37
 
49
38
  var AITableFieldType;
50
39
  (function (AITableFieldType) {
@@ -54,10 +43,14 @@ var AITableFieldType;
54
43
  AITableFieldType["number"] = "number";
55
44
  AITableFieldType["date"] = "date";
56
45
  AITableFieldType["member"] = "member";
57
- // cascadeSelect = "cascade_select", // 包含单选和多选,参数复杂后续再进行设计
46
+ // cascadeSelect = 'cascade_select', // 包含单选和多选,参数复杂后续再进行设计
58
47
  AITableFieldType["progress"] = "progress";
59
48
  AITableFieldType["rate"] = "rate";
60
49
  AITableFieldType["link"] = "link";
50
+ AITableFieldType["createdAt"] = "created_at";
51
+ AITableFieldType["updatedAt"] = "updated_at";
52
+ AITableFieldType["createdBy"] = "created_by";
53
+ AITableFieldType["updatedBy"] = "updated_by";
61
54
  })(AITableFieldType || (AITableFieldType = {}));
62
55
  var AITableStatType;
63
56
  (function (AITableStatType) {
@@ -113,16 +106,18 @@ function idCreator(length = 5) {
113
106
  const BasicFields = [
114
107
  {
115
108
  type: AITableFieldType.text,
116
- name: '文本',
109
+ name: '单行文本',
117
110
  icon: 'font',
118
111
  width: 300
119
112
  },
113
+ // 多行文本
120
114
  {
121
115
  type: AITableFieldType.select,
122
116
  name: '单选',
123
117
  icon: 'check-circle',
124
118
  width: 200
125
119
  },
120
+ // 多选
126
121
  {
127
122
  type: AITableFieldType.number,
128
123
  name: '数字',
@@ -135,6 +130,20 @@ const BasicFields = [
135
130
  icon: 'calendar',
136
131
  width: 200
137
132
  },
133
+ {
134
+ type: AITableFieldType.member,
135
+ name: '成员',
136
+ icon: 'user',
137
+ width: 200
138
+ },
139
+ // 级联单选
140
+ // 级联多选
141
+ {
142
+ type: AITableFieldType.progress,
143
+ name: '进度',
144
+ icon: 'progress',
145
+ width: 200
146
+ },
138
147
  {
139
148
  type: AITableFieldType.rate,
140
149
  name: '评分',
@@ -146,12 +155,39 @@ const BasicFields = [
146
155
  name: '链接',
147
156
  icon: 'link-insert',
148
157
  width: 300
158
+ },
159
+ {
160
+ type: AITableFieldType.createdBy,
161
+ name: '创建人',
162
+ icon: 'user',
163
+ width: 200
164
+ },
165
+ {
166
+ type: AITableFieldType.createdAt,
167
+ name: '创建时间',
168
+ icon: 'calendar',
169
+ width: 200
170
+ },
171
+ {
172
+ type: AITableFieldType.updatedBy,
173
+ name: '更新人',
174
+ icon: 'user',
175
+ width: 200
176
+ },
177
+ {
178
+ type: AITableFieldType.updatedAt,
179
+ name: '更新时间',
180
+ icon: 'calendar',
181
+ width: 200
149
182
  }
150
183
  ];
151
184
  const Fields = [...BasicFields];
152
185
  const FieldsMap = helpers.keyBy([...BasicFields], 'type');
153
186
 
154
- function getDefaultFieldValue(type) {
187
+ function getDefaultFieldValue(field) {
188
+ if ([AITableFieldType.member, AITableFieldType.createdBy, AITableFieldType.updatedBy].includes(field.type)) {
189
+ return [];
190
+ }
155
191
  return '';
156
192
  }
157
193
  function createDefaultFieldName(aiTable, type = AITableFieldType.text) {
@@ -160,7 +196,7 @@ function createDefaultFieldName(aiTable, type = AITableFieldType.text) {
160
196
  return count === 0 ? FieldsMap[type].name : FieldsMap[type].name + count;
161
197
  }
162
198
  function createDefaultField(aiTable, type = AITableFieldType.text) {
163
- return { id: idCreator(), type, name: createDefaultFieldName(aiTable, type) };
199
+ return { _id: idCreator(), type, name: createDefaultFieldName(aiTable, type) };
164
200
  }
165
201
 
166
202
  const FLUSHING = new WeakMap();
@@ -197,11 +233,11 @@ function isPathEqual(path, another) {
197
233
 
198
234
  function getDefaultRecord(fields) {
199
235
  const newRow = {
200
- id: idCreator(),
236
+ _id: idCreator(),
201
237
  values: {}
202
238
  };
203
239
  fields.map((item) => {
204
- newRow.values[item.id] = getDefaultFieldValue(item.type);
240
+ newRow.values[item._id] = getDefaultFieldValue(item);
205
241
  });
206
242
  return newRow;
207
243
  }
@@ -238,7 +274,7 @@ const AITableQueries = {
238
274
  if (!field) {
239
275
  throw new Error(`can not find field at path [${path}]`);
240
276
  }
241
- return aiTable.records()[path[0]].values[field.id];
277
+ return aiTable.records()[path[0]].values[field._id];
242
278
  },
243
279
  getField(aiTable, path) {
244
280
  if (!aiTable) {
@@ -317,7 +353,7 @@ const apply = (aiTable, records, fields, options) => {
317
353
  case ActionName.UpdateFieldValue: {
318
354
  const [recordIndex, fieldIndex] = options.path;
319
355
  if (fieldIndex > -1 && recordIndex > -1) {
320
- const fieldId = aiTable.fields()[fieldIndex].id;
356
+ const fieldId = aiTable.fields()[fieldIndex]._id;
321
357
  records[recordIndex].values[fieldId] = options.newFieldValue;
322
358
  }
323
359
  break;
@@ -335,7 +371,7 @@ const apply = (aiTable, records, fields, options) => {
335
371
  const newField = options.field;
336
372
  fields.splice(fieldIndex, 0, newField);
337
373
  const newRecord = {
338
- [newField.id]: ''
374
+ [newField._id]: ''
339
375
  };
340
376
  records.forEach((item) => {
341
377
  item.values = {
@@ -367,7 +403,7 @@ const apply = (aiTable, records, fields, options) => {
367
403
  case ActionName.RemoveField: {
368
404
  const [fieldIndex] = options.path;
369
405
  if (fieldIndex > -1) {
370
- const fieldId = aiTable.fields()[fieldIndex].id;
406
+ const fieldId = aiTable.fields()[fieldIndex]._id;
371
407
  fields.splice(fieldIndex, 1);
372
408
  records.forEach((item) => {
373
409
  delete item.values[fieldId];
@@ -460,173 +496,6 @@ const Actions = {
460
496
  ...FieldActions
461
497
  };
462
498
 
463
- const buildGridData = (recordValue, fieldsValue, selection) => {
464
- return {
465
- type: 'grid',
466
- fields: fieldsValue.map(item => {
467
- return {
468
- ...item,
469
- icon: item.icon || FieldsMap[item.type].icon,
470
- width: item.width || FieldsMap[item.type].width
471
- };
472
- }),
473
- records: recordValue.map((item) => {
474
- return { ...item, checked: selection.selectedRecords.has(item.id) };
475
- })
476
- };
477
- };
478
-
479
- function getRecordOrField(value, id) {
480
- return computed(() => {
481
- return value().find((item) => item.id === id);
482
- });
483
- }
484
-
485
- const DEFAULT_COLUMN_WIDTH = 200;
486
- const MIN_COLUMN_WIDTH = 80;
487
- const DBL_CLICK_EDIT_TYPE = [
488
- AITableFieldType.text,
489
- AITableFieldType.number,
490
- AITableFieldType.select,
491
- AITableFieldType.date
492
- ];
493
- const RowHeight = {
494
- Short: 32,
495
- Medium: 57,
496
- Tall: 104,
497
- ExtraTall: 152
498
- };
499
-
500
- class AITableFieldPropertyEditor {
501
- constructor() {
502
- this.aiField = model.required();
503
- this.aiExternalTemplate = null;
504
- this.fieldType = computed(() => {
505
- return FieldsMap[this.aiField().type];
506
- });
507
- this.fieldMaxLength = 32;
508
- this.validatorConfig = {
509
- validationMessages: {
510
- fieldName: {
511
- required: '列名不能为空',
512
- thyUniqueCheck: '列名已存在'
513
- }
514
- }
515
- };
516
- this.selectableFields = Fields;
517
- this.thyPopoverRef = inject((ThyPopoverRef));
518
- this.checkUniqueName = (fieldName) => {
519
- fieldName = fieldName?.trim();
520
- return of(!!this.aiTable.fields()?.find((field) => field.name === fieldName && this.aiField()?.id !== field.id));
521
- };
522
- }
523
- selectFieldType(fieldType) {
524
- this.aiField.update((item) => ({ ...item, type: fieldType, name: createDefaultFieldName(this.aiTable, fieldType) }));
525
- }
526
- editFieldProperty() {
527
- if (this.isUpdate) {
528
- const path = this.aiTable.fields().findIndex((item) => item.id === this.aiField().id);
529
- Actions.setField(this.aiTable, this.aiField(), [path]);
530
- }
531
- else {
532
- Actions.addField(this.aiTable, this.aiField(), [this.aiTable.fields().length]);
533
- }
534
- this.thyPopoverRef.close();
535
- }
536
- cancel() {
537
- this.thyPopoverRef.close();
538
- }
539
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
540
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableFieldPropertyEditor, isStandalone: true, selector: "ai-table-field-property-editor", inputs: { aiField: { classPropertyName: "aiField", publicName: "aiField", isSignal: true, isRequired: true, transformFunction: null }, aiTable: { classPropertyName: "aiTable", publicName: "aiTable", isSignal: false, isRequired: true, transformFunction: null }, aiExternalTemplate: { classPropertyName: "aiExternalTemplate", publicName: "aiExternalTemplate", isSignal: false, isRequired: false, transformFunction: null }, isUpdate: { classPropertyName: "isUpdate", publicName: "isUpdate", isSignal: false, isRequired: false, transformFunction: booleanAttribute } }, outputs: { aiField: "aiFieldChange" }, host: { classAttribute: "field-property-editor d-block pl-5 pr-5 pb-5 pt-4" }, ngImport: i0, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track item.type) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyInputGroup, selector: "thy-input-group", inputs: ["thyAppendText", "thyAppendTextTranslateKey", "thyPrependText", "thyPrependTextTranslateKey", "thySize"] }, { kind: "component", type: ThyInputCount, selector: "thy-input-count", inputs: ["thyInput"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyUniqueCheckValidator, selector: "[thyUniqueCheck]", inputs: ["thyUniqueCheck"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }, { kind: "directive", type: ThyDropdownMenuItemNameDirective, selector: "[thyDropdownMenuItemName]" }, { kind: "component", type: ThyButton, selector: "thy-button,[thy-button],[thyButton]", inputs: ["thyButton", "thyType", "thyLoading", "thyLoadingText", "thySize", "thyIcon", "thyBlock"] }, { kind: "ngmodule", type: ThyFormModule }, { kind: "directive", type: i2.ThyFormDirective, selector: "[thyForm],[thy-form]", inputs: ["thyLayout", "thyEnterKeyMode", "thyFormValidatorConfig"], exportAs: ["thyForm"] }, { kind: "component", type: i2.ThyFormGroup, selector: "thy-form-group", inputs: ["thyLabelText", "thyLabelTextTranslateKey", "thyLabelRequired", "thyLabelPaddingTopClear", "thyFeedbackIcon", "thyTipsMode", "thyTips", "thyTipsTranslateKey", "thyRowFill"] }, { kind: "directive", type: i2.ThyFormSubmitDirective, selector: "[thyFormSubmit],[thy-form-submit]", outputs: ["thyFormSubmit"] }, { kind: "component", type: i2.ThyFormGroupFooter, selector: "thy-form-group-footer", inputs: ["thyAlign"] }, { kind: "component", type: ThyListItem, selector: "thy-list-item,[thy-list-item]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
541
- }
542
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, decorators: [{
543
- type: Component,
544
- args: [{ selector: 'ai-table-field-property-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
545
- NgIf,
546
- NgForOf,
547
- FormsModule,
548
- ThyIcon,
549
- ThyInput,
550
- ThyInputGroup,
551
- ThyInputCount,
552
- ThyInputDirective,
553
- ThyConfirmValidatorDirective,
554
- ThyUniqueCheckValidator,
555
- ThyDropdownDirective,
556
- ThyDropdownMenuComponent,
557
- ThyDropdownMenuItemDirective,
558
- ThyDropdownMenuItemNameDirective,
559
- ThyDropdownMenuItemIconDirective,
560
- ThyButton,
561
- ThyFormModule,
562
- ThyListItem,
563
- NgTemplateOutlet,
564
- ThyAutofocusDirective
565
- ], host: {
566
- class: 'field-property-editor d-block pl-5 pr-5 pb-5 pt-4'
567
- }, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track item.type) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"] }]
568
- }], ctorParameters: () => [], propDecorators: { aiTable: [{
569
- type: Input,
570
- args: [{ required: true }]
571
- }], aiExternalTemplate: [{
572
- type: Input
573
- }], isUpdate: [{
574
- type: Input,
575
- args: [{ transform: booleanAttribute }]
576
- }] } });
577
-
578
- const AI_TABLE_GRID_FIELD_SERVICE_MAP = new WeakMap();
579
- class AITableGridFieldService {
580
- constructor(thyPopover) {
581
- this.thyPopover = thyPopover;
582
- }
583
- initAIFieldConfig(aiFieldConfig) {
584
- this.aiFieldConfig = aiFieldConfig;
585
- }
586
- editFieldProperty(origin, aiTable, aiField, isUpdate) {
587
- const component = this.aiFieldConfig?.fieldPropertyEditor ?? AITableFieldPropertyEditor;
588
- this.thyPopover.open(component, {
589
- origin: origin,
590
- manualClosure: true,
591
- placement: 'bottomLeft',
592
- initialState: {
593
- aiTable,
594
- aiField,
595
- isUpdate
596
- }
597
- });
598
- }
599
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, deps: [{ token: i1$1.ThyPopover }], target: i0.ɵɵFactoryTarget.Injectable }); }
600
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService }); }
601
- }
602
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, decorators: [{
603
- type: Injectable
604
- }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
605
-
606
- const DividerMenuItem = {
607
- id: 'divider'
608
- };
609
- const EditFieldPropertyItem = {
610
- id: 'editFieldProperty',
611
- name: '编辑列',
612
- icon: 'edit',
613
- exec: (aiTable, field, origin) => {
614
- const fieldService = AI_TABLE_GRID_FIELD_SERVICE_MAP.get(aiTable);
615
- const copyField = signal(JSON.parse(JSON.stringify(field())));
616
- origin && fieldService?.editFieldProperty(origin, aiTable, copyField, true);
617
- }
618
- };
619
- const RemoveFieldItem = {
620
- id: 'removeField',
621
- name: '删除列',
622
- icon: 'trash',
623
- exec: (aiTable, field) => {
624
- const path = AITableQueries.findPath(aiTable, field());
625
- Actions.removeField(aiTable, path);
626
- }
627
- };
628
- const DefaultFieldMenus = [EditFieldPropertyItem, RemoveFieldItem];
629
-
630
499
  class AbstractEditCellEditor {
631
500
  constructor() {
632
501
  this.field = input.required();
@@ -644,7 +513,7 @@ class AbstractEditCellEditor {
644
513
  Actions.updateFieldValue(this.aiTable, this.modelValue, path);
645
514
  }
646
515
  closePopover() {
647
- this.thyPopoverRef.close();
516
+ this.thyPopoverRef?.close();
648
517
  }
649
518
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AbstractEditCellEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
650
519
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.0.2", type: AbstractEditCellEditor, isStandalone: true, selector: "abstract-edit-cell", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, record: { classPropertyName: "record", publicName: "record", isSignal: true, isRequired: true, transformFunction: null }, aiTable: { classPropertyName: "aiTable", publicName: "aiTable", isSignal: false, isRequired: true, transformFunction: null } }, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
@@ -662,88 +531,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
662
531
  args: [{ required: true }]
663
532
  }] } });
664
533
 
665
- class TextCellEditorComponent extends AbstractEditCellEditor {
666
- updateValue() {
667
- this.updateFieldValue();
668
- this.closePopover();
669
- }
670
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
671
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: TextCellEditorComponent, isStandalone: true, selector: "text-cell-editor", usesInheritance: true, ngImport: i0, template: `<input
672
- thyInput
673
- [thyAutofocus]="true"
674
- [(ngModel)]="modelValue"
675
- (thyEnter)="updateValue()"
676
- (blur)="updateValue()"
677
- placeholder=""
678
- /> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
679
- }
680
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, decorators: [{
681
- type: Component,
682
- args: [{
683
- selector: 'text-cell-editor',
684
- template: `<input
685
- thyInput
686
- [thyAutofocus]="true"
687
- [(ngModel)]="modelValue"
688
- (thyEnter)="updateValue()"
689
- (blur)="updateValue()"
690
- placeholder=""
691
- /> `,
692
- standalone: true,
693
- changeDetection: ChangeDetectionStrategy.OnPush,
694
- imports: [NgIf, FormsModule, ThyAutofocusDirective, ThyInputDirective, ThyEnterDirective]
695
- }]
696
- }] });
697
-
698
- class NumberCellEditorComponent extends AbstractEditCellEditor {
699
- updateValue() {
700
- this.updateFieldValue();
701
- this.closePopover();
702
- }
703
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
704
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: NumberCellEditorComponent, isStandalone: true, selector: "number-cell-editor", usesInheritance: true, ngImport: i0, template: `<thy-input-number
705
- class="h-100"
706
- [thyAutoFocus]="true"
707
- [(ngModel)]="modelValue"
708
- (thyEnter)="updateValue()"
709
- (thyBlur)="updateValue()"
710
- placeholder=""
711
- /> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }, { kind: "component", type: ThyInputNumber, selector: "thy-input-number", inputs: ["thyAutoFocus", "thyPlaceholder", "thyDisabled", "thyMax", "thyMin", "thyStep", "thyStepDelay", "thySize", "thyPrecision", "thySuffix"], outputs: ["thyBlur", "thyFocus"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
712
- }
713
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, decorators: [{
714
- type: Component,
715
- args: [{
716
- selector: 'number-cell-editor',
717
- template: `<thy-input-number
718
- class="h-100"
719
- [thyAutoFocus]="true"
720
- [(ngModel)]="modelValue"
721
- (thyEnter)="updateValue()"
722
- (thyBlur)="updateValue()"
723
- placeholder=""
724
- /> `,
725
- standalone: true,
726
- changeDetection: ChangeDetectionStrategy.OnPush,
727
- imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber]
728
- }]
729
- }] });
730
-
731
- class DateTimeCellEditorComponent extends AbstractEditCellEditor {
732
- constructor() {
733
- super(...arguments);
734
- this.dateShowTime = input(false);
735
- this.dateFormat = computed(() => {
736
- return this.dateShowTime() ? 'yyyy-MM-dd HH:mm' : 'yyyy-MM-dd';
737
- })();
738
- }
739
- ngOnInit() {
740
- super.ngOnInit();
741
- if (!this.modelValue && this.dateShowTime()) {
742
- this.modelValue = {
743
- date: 0,
744
- with_time: 1
745
- };
746
- }
534
+ class DateTimeCellEditorComponent extends AbstractEditCellEditor {
535
+ constructor() {
536
+ super(...arguments);
537
+ this.dateShowTime = input(false);
538
+ this.dateFormat = computed(() => {
539
+ return this.dateShowTime() ? 'yyyy-MM-dd HH:mm' : 'yyyy-MM-dd';
540
+ })();
541
+ }
542
+ ngOnInit() {
543
+ super.ngOnInit();
544
+ if (!this.modelValue && this.dateShowTime()) {
545
+ this.modelValue = {
546
+ date: 0,
547
+ with_time: 1
548
+ };
549
+ }
747
550
  }
748
551
  updateValue() {
749
552
  this.updateFieldValue();
@@ -803,13 +606,134 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
803
606
  }]
804
607
  }] });
805
608
 
806
- class RatingCellEditorComponent extends AbstractEditCellEditor {
609
+ class LinkCellEditorComponent extends AbstractEditCellEditor {
807
610
  updateValue() {
808
611
  this.updateFieldValue();
809
612
  this.closePopover();
810
613
  }
614
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
615
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: LinkCellEditorComponent, isStandalone: true, selector: "link-cell-editor", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
616
+ }
617
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, decorators: [{
618
+ type: Component,
619
+ args: [{
620
+ selector: 'link-cell-editor',
621
+ template: ``,
622
+ standalone: true,
623
+ changeDetection: ChangeDetectionStrategy.OnPush,
624
+ imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber]
625
+ }]
626
+ }] });
627
+
628
+ class NumberCellEditorComponent extends AbstractEditCellEditor {
629
+ updateValue() {
630
+ this.updateFieldValue();
631
+ this.closePopover();
632
+ }
633
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
634
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: NumberCellEditorComponent, isStandalone: true, selector: "number-cell-editor", host: { classAttribute: "number-cell-editor" }, usesInheritance: true, ngImport: i0, template: `<thy-input-number
635
+ class="h-100"
636
+ [thyAutoFocus]="true"
637
+ [(ngModel)]="modelValue"
638
+ (thyEnter)="updateValue()"
639
+ (thyBlur)="updateValue()"
640
+ /> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }, { kind: "component", type: ThyInputNumber, selector: "thy-input-number", inputs: ["thyAutoFocus", "thyPlaceholder", "thyDisabled", "thyMax", "thyMin", "thyStep", "thyStepDelay", "thySize", "thyPrecision", "thySuffix"], outputs: ["thyBlur", "thyFocus", "thyStepChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
641
+ }
642
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, decorators: [{
643
+ type: Component,
644
+ args: [{
645
+ selector: 'number-cell-editor',
646
+ template: `<thy-input-number
647
+ class="h-100"
648
+ [thyAutoFocus]="true"
649
+ [(ngModel)]="modelValue"
650
+ (thyEnter)="updateValue()"
651
+ (thyBlur)="updateValue()"
652
+ /> `,
653
+ standalone: true,
654
+ changeDetection: ChangeDetectionStrategy.OnPush,
655
+ imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber],
656
+ host: {
657
+ class: 'number-cell-editor'
658
+ }
659
+ }]
660
+ }] });
661
+
662
+ class ProgressEditorComponent extends AbstractEditCellEditor {
663
+ mousedownHandler(event) {
664
+ event.preventDefault();
665
+ }
666
+ constructor() {
667
+ super();
668
+ this.config = {
669
+ max: 100,
670
+ min: 0,
671
+ step: 1,
672
+ progressType: 'success',
673
+ suffix: '%',
674
+ size: 'md'
675
+ };
676
+ }
677
+ sliderMousedownHandler(event) {
678
+ event.preventDefault();
679
+ event.stopPropagation();
680
+ }
681
+ updateValue(value) {
682
+ this.updateFieldValue();
683
+ }
684
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ProgressEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
685
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: ProgressEditorComponent, isStandalone: true, selector: "progress-editor", host: { listeners: { "mousedown": "mousedownHandler($event)" }, properties: { "attr.type": "field().type", "attr.fieldId": "field()._id", "attr.recordId": "record()._id" }, classAttribute: "grid-cell progress-editor" }, usesInheritance: true, ngImport: i0, template: `
686
+ <thy-slider
687
+ [(ngModel)]="modelValue"
688
+ [thyMax]="config?.max || 100"
689
+ [thyMin]="config?.min || 0"
690
+ [thyStep]="config?.step || 1"
691
+ [thyType]="config?.progressType || 'success'"
692
+ [thySize]="config?.size || 'md'"
693
+ (ngModelChange)="updateValue($event)"
694
+ (mousedown)="sliderMousedownHandler($event)"
695
+ ></thy-slider>
696
+ <span class="progress-text">{{ modelValue }}{{ config?.suffix || '%' }}</span>
697
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThySlider, selector: "thy-slider", inputs: ["thyVertical", "thyDisabled", "thyMax", "thyMin", "thyStep", "thyType", "thyColor", "thySize"], outputs: ["thyAfterChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
698
+ }
699
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: ProgressEditorComponent, decorators: [{
700
+ type: Component,
701
+ args: [{
702
+ selector: 'progress-editor',
703
+ template: `
704
+ <thy-slider
705
+ [(ngModel)]="modelValue"
706
+ [thyMax]="config?.max || 100"
707
+ [thyMin]="config?.min || 0"
708
+ [thyStep]="config?.step || 1"
709
+ [thyType]="config?.progressType || 'success'"
710
+ [thySize]="config?.size || 'md'"
711
+ (ngModelChange)="updateValue($event)"
712
+ (mousedown)="sliderMousedownHandler($event)"
713
+ ></thy-slider>
714
+ <span class="progress-text">{{ modelValue }}{{ config?.suffix || '%' }}</span>
715
+ `,
716
+ standalone: true,
717
+ changeDetection: ChangeDetectionStrategy.OnPush,
718
+ imports: [FormsModule, ThySlider],
719
+ host: {
720
+ class: 'grid-cell progress-editor',
721
+ '[attr.type]': 'field().type',
722
+ '[attr.fieldId]': 'field()._id',
723
+ '[attr.recordId]': 'record()._id'
724
+ }
725
+ }]
726
+ }], ctorParameters: () => [], propDecorators: { mousedownHandler: [{
727
+ type: HostListener,
728
+ args: ['mousedown', ['$event']]
729
+ }] } });
730
+
731
+ class RatingCellEditorComponent extends AbstractEditCellEditor {
732
+ updateValue() {
733
+ this.updateFieldValue();
734
+ }
811
735
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: RatingCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
812
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: RatingCellEditorComponent, isStandalone: true, selector: "rating-cell-editor", usesInheritance: true, ngImport: i0, template: ` <thy-rate [(ngModel)]="modelValue" (ngModelChange)="updateValue()"></thy-rate> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }, { kind: "ngmodule", type: ThyTooltipModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
736
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: RatingCellEditorComponent, isStandalone: true, selector: "rating-cell-editor", host: { classAttribute: "d-flex align-items-center h-100 px-3" }, usesInheritance: true, ngImport: i0, template: ` <thy-rate [(ngModel)]="modelValue" (ngModelChange)="updateValue()"></thy-rate> `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
813
737
  }
814
738
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: RatingCellEditorComponent, decorators: [{
815
739
  type: Component,
@@ -818,26 +742,326 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
818
742
  template: ` <thy-rate [(ngModel)]="modelValue" (ngModelChange)="updateValue()"></thy-rate> `,
819
743
  standalone: true,
820
744
  changeDetection: ChangeDetectionStrategy.OnPush,
821
- imports: [FormsModule, ThyRate, ThyTooltipModule]
745
+ imports: [FormsModule, ThyRate],
746
+ host: {
747
+ class: 'd-flex align-items-center h-100 px-3'
748
+ }
822
749
  }]
823
750
  }] });
824
751
 
825
- class LinkCellEditorComponent extends AbstractEditCellEditor {
752
+ class TextCellEditorComponent extends AbstractEditCellEditor {
753
+ constructor() {
754
+ super();
755
+ this.elementRef = inject(ElementRef);
756
+ this.render2 = inject(Renderer2);
757
+ this.maxHeight = 148;
758
+ }
759
+ ngAfterViewInit() {
760
+ setTimeout(() => {
761
+ this.updateStyle();
762
+ });
763
+ }
764
+ updateStyle() {
765
+ const textarea = this.elementRef.nativeElement.querySelector('textarea');
766
+ const height = textarea.scrollHeight < this.maxHeight ? textarea.scrollHeight : this.maxHeight;
767
+ this.render2.setStyle(textarea, 'height', `${height}px`);
768
+ this.render2.setStyle(textarea, 'min-height', `44px`);
769
+ this.render2.setStyle(textarea, 'max-height', `${this.maxHeight}px`);
770
+ this.render2.setStyle(textarea, 'resize', 'none');
771
+ }
772
+ valueChange() {
773
+ this.updateStyle();
774
+ }
826
775
  updateValue() {
827
776
  this.updateFieldValue();
828
777
  this.closePopover();
829
778
  }
830
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
831
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: LinkCellEditorComponent, isStandalone: true, selector: "link-cell-editor", usesInheritance: true, ngImport: i0, template: ``, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
779
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
780
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: TextCellEditorComponent, isStandalone: true, selector: "text-cell-editor", host: { classAttribute: "text-cell-editor" }, usesInheritance: true, ngImport: i0, template: `
781
+ <textarea
782
+ placeholder=""
783
+ rows="1"
784
+ thyInput
785
+ [thyAutofocus]="true"
786
+ [(ngModel)]="modelValue"
787
+ (ngModelChange)="valueChange()"
788
+ (thyEnter)="updateValue()"
789
+ (blur)="updateValue()"
790
+ ></textarea>
791
+ `, isInline: true, dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyEnterDirective, selector: "[thyEnter]", outputs: ["thyEnter"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
832
792
  }
833
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: LinkCellEditorComponent, decorators: [{
793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: TextCellEditorComponent, decorators: [{
834
794
  type: Component,
835
795
  args: [{
836
- selector: 'link-cell-editor',
837
- template: ``,
796
+ selector: 'text-cell-editor',
797
+ template: `
798
+ <textarea
799
+ placeholder=""
800
+ rows="1"
801
+ thyInput
802
+ [thyAutofocus]="true"
803
+ [(ngModel)]="modelValue"
804
+ (ngModelChange)="valueChange()"
805
+ (thyEnter)="updateValue()"
806
+ (blur)="updateValue()"
807
+ ></textarea>
808
+ `,
838
809
  standalone: true,
839
810
  changeDetection: ChangeDetectionStrategy.OnPush,
840
- imports: [FormsModule, ThyAutofocusDirective, ThyEnterDirective, ThyInputNumber]
811
+ imports: [NgIf, FormsModule, ThyAutofocusDirective, ThyInputDirective, ThyEnterDirective],
812
+ host: {
813
+ class: 'text-cell-editor'
814
+ }
815
+ }]
816
+ }], ctorParameters: () => [] });
817
+
818
+ class AITableFieldPropertyEditor {
819
+ constructor() {
820
+ this.aiField = model.required();
821
+ this.aiExternalTemplate = null;
822
+ this.fieldType = computed(() => {
823
+ return FieldsMap[this.aiField().type];
824
+ });
825
+ this.fieldMaxLength = 32;
826
+ this.validatorConfig = {
827
+ validationMessages: {
828
+ fieldName: {
829
+ required: '列名不能为空',
830
+ thyUniqueCheck: '列名已存在'
831
+ }
832
+ }
833
+ };
834
+ this.selectableFields = Fields;
835
+ this.thyPopoverRef = inject((ThyPopoverRef));
836
+ this.checkUniqueName = (fieldName) => {
837
+ fieldName = fieldName?.trim();
838
+ return of(!!this.aiTable.fields()?.find((field) => field.name === fieldName && this.aiField()?._id !== field._id));
839
+ };
840
+ }
841
+ selectFieldType(fieldType) {
842
+ this.aiField.update((item) => ({ ...item, type: fieldType, name: createDefaultFieldName(this.aiTable, fieldType) }));
843
+ }
844
+ editFieldProperty() {
845
+ if (this.isUpdate) {
846
+ const path = this.aiTable.fields().findIndex((item) => item._id === this.aiField()._id);
847
+ Actions.setField(this.aiTable, this.aiField(), [path]);
848
+ }
849
+ else {
850
+ Actions.addField(this.aiTable, this.aiField(), [this.aiTable.fields().length]);
851
+ }
852
+ this.thyPopoverRef.close();
853
+ }
854
+ cancel() {
855
+ this.thyPopoverRef.close();
856
+ }
857
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
858
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableFieldPropertyEditor, isStandalone: true, selector: "ai-table-field-property-editor", inputs: { aiField: { classPropertyName: "aiField", publicName: "aiField", isSignal: true, isRequired: true, transformFunction: null }, aiTable: { classPropertyName: "aiTable", publicName: "aiTable", isSignal: false, isRequired: true, transformFunction: null }, aiExternalTemplate: { classPropertyName: "aiExternalTemplate", publicName: "aiExternalTemplate", isSignal: false, isRequired: false, transformFunction: null }, isUpdate: { classPropertyName: "isUpdate", publicName: "isUpdate", isSignal: false, isRequired: false, transformFunction: booleanAttribute } }, outputs: { aiField: "aiFieldChange" }, host: { classAttribute: "field-property-editor d-block pl-5 pr-5 pb-5 pt-4" }, ngImport: i0, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track $index) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyInputGroup, selector: "thy-input-group", inputs: ["thyAppendText", "thyAppendTextTranslateKey", "thyPrependText", "thyPrependTextTranslateKey", "thySize"] }, { kind: "component", type: ThyInputCount, selector: "thy-input-count", inputs: ["thyInput"] }, { kind: "directive", type: ThyInputDirective, selector: "input[thyInput], select[thyInput], textarea[thyInput]", inputs: ["thySize"], exportAs: ["thyInput"] }, { kind: "directive", type: ThyUniqueCheckValidator, selector: "[thyUniqueCheck]", inputs: ["thyUniqueCheck"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }, { kind: "directive", type: ThyDropdownMenuItemNameDirective, selector: "[thyDropdownMenuItemName]" }, { kind: "component", type: ThyButton, selector: "thy-button,[thy-button],[thyButton]", inputs: ["thyButton", "thyType", "thyLoading", "thyLoadingText", "thySize", "thyIcon", "thyBlock"] }, { kind: "ngmodule", type: ThyFormModule }, { kind: "directive", type: i2.ThyFormDirective, selector: "[thyForm],[thy-form]", inputs: ["thyLayout", "thyEnterKeyMode", "thyFormValidatorConfig"], exportAs: ["thyForm"] }, { kind: "component", type: i2.ThyFormGroup, selector: "thy-form-group", inputs: ["thyLabelText", "thyLabelTextTranslateKey", "thyLabelRequired", "thyLabelPaddingTopClear", "thyFeedbackIcon", "thyTipsMode", "thyTips", "thyTipsTranslateKey", "thyRowFill"] }, { kind: "directive", type: i2.ThyFormSubmitDirective, selector: "[thyFormSubmit],[thy-form-submit]", outputs: ["thyFormSubmit"] }, { kind: "component", type: i2.ThyFormGroupFooter, selector: "thy-form-group-footer", inputs: ["thyAlign"] }, { kind: "component", type: ThyListItem, selector: "thy-list-item,[thy-list-item]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: ThyAutofocusDirective, selector: "input[thyAutofocus],textarea[thyAutofocus]", inputs: ["thyAutofocus", "thyAutoSelect"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
859
+ }
860
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, decorators: [{
861
+ type: Component,
862
+ args: [{ selector: 'ai-table-field-property-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
863
+ NgIf,
864
+ NgForOf,
865
+ FormsModule,
866
+ ThyIcon,
867
+ ThyInput,
868
+ ThyInputGroup,
869
+ ThyInputCount,
870
+ ThyInputDirective,
871
+ ThyConfirmValidatorDirective,
872
+ ThyUniqueCheckValidator,
873
+ ThyDropdownDirective,
874
+ ThyDropdownMenuComponent,
875
+ ThyDropdownMenuItemDirective,
876
+ ThyDropdownMenuItemNameDirective,
877
+ ThyDropdownMenuItemIconDirective,
878
+ ThyButton,
879
+ ThyFormModule,
880
+ ThyListItem,
881
+ NgTemplateOutlet,
882
+ ThyAutofocusDirective
883
+ ], host: {
884
+ class: 'field-property-editor d-block pl-5 pr-5 pb-5 pt-4'
885
+ }, template: "<form thyForm name=\"createPropertyForm\" [thyFormValidatorConfig]=\"validatorConfig\" thyLayout=\"vertical\">\n <thy-form-group thyLabelRequired thyLabelText=\"\u8868\u683C\u5217\u540D\">\n <thy-input-group>\n <input\n thyInput\n [thyAutofocus]=\"true\"\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"aiField().name\"\n required\n placeholder=\"\u8F93\u5165\u5217\u540D\u79F0\"\n [thyUniqueCheck]=\"checkUniqueName\"\n />\n <ng-template #suffix>\n <thy-input-count></thy-input-count>\n </ng-template>\n </thy-input-group>\n </thy-form-group>\n <thy-form-group thyLabelText=\"\u5217\u7C7B\u578B\">\n <div class=\"ml-n5 mr-n5\">\n <thy-list-item [thyDropdown]=\"menu\" thyTrigger=\"hover\" thyPlacement=\"right\" class=\"justify-content-between\">\n <span>\n <thy-icon [thyIconName]=\"fieldType().icon\" class=\"text-desc mr-2\"></thy-icon>\n <span>{{ fieldType().name }}</span>\n </span>\n <thy-icon thyIconName=\"angle-right\" class=\"text-desc\"></thy-icon>\n </thy-list-item>\n </div>\n </thy-form-group>\n <ng-container *ngIf=\"aiExternalTemplate; else defaultTemplate\">\n <ng-container *ngTemplateOutlet=\"aiExternalTemplate\"></ng-container>\n </ng-container>\n <ng-template #defaultTemplate>\n <!-- TODO: \u5185\u90E8\u5C5E\u6027\u6E32\u67D3 -->\n </ng-template>\n <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"editFieldProperty()\" thySize=\"sm\">\u786E\u5B9A</button>\n </thy-form-group-footer>\n</form>\n\n<thy-dropdown-menu #menu>\n @for (item of selectableFields; track $index) {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"selectFieldType(item.type)\">\n <thy-icon [thyIconName]=\"item.icon\"></thy-icon>\n <span thyDropdownMenuItemName>{{ item.name }}</span>\n </a>\n }\n</thy-dropdown-menu>\n", styles: [":host{width:350px}\n"] }]
886
+ }], ctorParameters: () => [], propDecorators: { aiTable: [{
887
+ type: Input,
888
+ args: [{ required: true }]
889
+ }], aiExternalTemplate: [{
890
+ type: Input
891
+ }], isUpdate: [{
892
+ type: Input,
893
+ args: [{ transform: booleanAttribute }]
894
+ }] } });
895
+
896
+ const buildGridData = (recordValue, fieldsValue, references) => {
897
+ const fields = fieldsValue.map((item) => {
898
+ return {
899
+ ...item,
900
+ icon: item.icon || FieldsMap[item.type].icon,
901
+ width: item.width || FieldsMap[item.type].width
902
+ };
903
+ });
904
+ let records = buildRecordsByReferences(recordValue, fieldsValue, references);
905
+ return {
906
+ type: 'grid',
907
+ fields,
908
+ records
909
+ };
910
+ };
911
+ function buildRecordsByReferences(records, fields, references) {
912
+ if (!references) {
913
+ return records;
914
+ }
915
+ const memberFields = fields.filter((field) => [AITableFieldType.createdBy, AITableFieldType.updatedBy, AITableFieldType.member].includes(field.type));
916
+ if (memberFields.length) {
917
+ const uidToMember = references.members.reduce((map, member) => {
918
+ map[member.uid] = member;
919
+ return map;
920
+ }, {});
921
+ const draftRecords = createDraft(records);
922
+ draftRecords.forEach((record) => {
923
+ memberFields.forEach((field) => {
924
+ const value = record.values[field._id];
925
+ record.values[field._id] = value.map((uid) => uidToMember[uid]).filter(Boolean);
926
+ });
927
+ });
928
+ records = finishDraft(draftRecords);
929
+ }
930
+ return records;
931
+ }
932
+
933
+ function getRecordOrField(value, _id) {
934
+ return computed(() => {
935
+ return value().find((item) => item._id === _id);
936
+ });
937
+ }
938
+
939
+ class FieldMenu {
940
+ execute(menu) {
941
+ const field = getRecordOrField(this.aiTable.fields, this.fieldId);
942
+ menu.exec && menu.exec(this.aiTable, field, this.origin);
943
+ }
944
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
945
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: FieldMenu, isStandalone: true, selector: "field-menu", inputs: { fieldId: "fieldId", aiTable: "aiTable", fieldMenus: "fieldMenus", origin: "origin" }, ngImport: i0, template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.type === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n", dependencies: [{ kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyDivider, selector: "thy-divider", inputs: ["thyVertical", "thyStyle", "thyColor", "thyText", "thyTextDirection", "thyDeeper"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
946
+ }
947
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, decorators: [{
948
+ type: Component,
949
+ args: [{ selector: 'field-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
950
+ ThyIcon,
951
+ ThyDivider,
952
+ ThyDropdownMenuComponent,
953
+ ThyDropdownMenuItemDirective,
954
+ ThyDropdownMenuItemNameDirective,
955
+ ThyDropdownMenuItemIconDirective
956
+ ], template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.type === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n" }]
957
+ }], propDecorators: { fieldId: [{
958
+ type: Input,
959
+ args: [{ required: true }]
960
+ }], aiTable: [{
961
+ type: Input,
962
+ args: [{ required: true }]
963
+ }], fieldMenus: [{
964
+ type: Input,
965
+ args: [{ required: true }]
966
+ }], origin: [{
967
+ type: Input
968
+ }] } });
969
+
970
+ const DEFAULT_COLUMN_WIDTH = 200;
971
+ const MIN_COLUMN_WIDTH = 80;
972
+ const DBL_CLICK_EDIT_TYPE = [
973
+ AITableFieldType.text,
974
+ AITableFieldType.number,
975
+ AITableFieldType.select,
976
+ AITableFieldType.date,
977
+ AITableFieldType.member
978
+ ];
979
+ const MOUSEOVER_EDIT_TYPE = [AITableFieldType.progress];
980
+ const RowHeight = {
981
+ Short: 32,
982
+ Medium: 57,
983
+ Tall: 104,
984
+ ExtraTall: 152
985
+ };
986
+
987
+ const AI_TABLE_GRID_FIELD_SERVICE_MAP = new WeakMap();
988
+ class AITableGridFieldService {
989
+ constructor(thyPopover) {
990
+ this.thyPopover = thyPopover;
991
+ }
992
+ initAIFieldConfig(aiFieldConfig) {
993
+ this.aiFieldConfig = aiFieldConfig;
994
+ }
995
+ editFieldProperty(origin, aiTable, aiField, isUpdate) {
996
+ const component = this.aiFieldConfig?.fieldPropertyEditor ?? AITableFieldPropertyEditor;
997
+ this.thyPopover.open(component, {
998
+ origin: origin,
999
+ manualClosure: true,
1000
+ placement: 'bottomLeft',
1001
+ initialState: {
1002
+ aiTable,
1003
+ aiField,
1004
+ isUpdate
1005
+ }
1006
+ });
1007
+ }
1008
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, deps: [{ token: i1$1.ThyPopover }], target: i0.ɵɵFactoryTarget.Injectable }); }
1009
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService }); }
1010
+ }
1011
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, decorators: [{
1012
+ type: Injectable
1013
+ }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
1014
+
1015
+ const DividerMenuItem = {
1016
+ type: 'divider'
1017
+ };
1018
+ const EditFieldPropertyItem = {
1019
+ type: 'editFieldProperty',
1020
+ name: '编辑列',
1021
+ icon: 'edit',
1022
+ exec: (aiTable, field, origin) => {
1023
+ const fieldService = AI_TABLE_GRID_FIELD_SERVICE_MAP.get(aiTable);
1024
+ const copyField = signal(JSON.parse(JSON.stringify(field())));
1025
+ origin && fieldService?.editFieldProperty(origin, aiTable, copyField, true);
1026
+ }
1027
+ };
1028
+ const RemoveFieldItem = {
1029
+ type: 'removeField',
1030
+ name: '删除列',
1031
+ icon: 'trash',
1032
+ exec: (aiTable, field) => {
1033
+ const path = AITableQueries.findPath(aiTable, field());
1034
+ Actions.removeField(aiTable, path);
1035
+ }
1036
+ };
1037
+ const DefaultFieldMenus = [EditFieldPropertyItem, RemoveFieldItem];
1038
+
1039
+ class SelectOptionPipe {
1040
+ transform(_id, options) {
1041
+ return options.find((item) => item._id === _id);
1042
+ }
1043
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
1044
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, isStandalone: true, name: "selectOption" }); }
1045
+ }
1046
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectOptionPipe, decorators: [{
1047
+ type: Pipe,
1048
+ args: [{
1049
+ name: 'selectOption',
1050
+ standalone: true
1051
+ }]
1052
+ }] });
1053
+ class IsSelectRecordPipe {
1054
+ transform(recordId, selection) {
1055
+ return selection.selectedRecords.has(recordId);
1056
+ }
1057
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: IsSelectRecordPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
1058
+ static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "18.0.2", ngImport: i0, type: IsSelectRecordPipe, isStandalone: true, name: "isSelectRecord" }); }
1059
+ }
1060
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: IsSelectRecordPipe, decorators: [{
1061
+ type: Pipe,
1062
+ args: [{
1063
+ name: 'isSelectRecord',
1064
+ standalone: true
841
1065
  }]
842
1066
  }] });
843
1067
 
@@ -856,7 +1080,7 @@ class SelectCellEditorComponent extends AbstractEditCellEditor {
856
1080
  }
857
1081
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectCellEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
858
1082
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.0.2", type: SelectCellEditorComponent, isStandalone: true, selector: "single-select-cell-editor", inputs: { isMultiple: "isMultiple" }, host: { classAttribute: "d-block h-100" }, usesInheritance: true, ngImport: i0, template: `<thy-select [(ngModel)]="modelValue" [thyAutoExpand]="true" (thyOnExpandStatusChange)="updateValue($event)">
859
- <thy-option *ngFor="let option of selectOptions()" [thyValue]="option.id" [thyLabelText]="option.name"> </thy-option>
1083
+ <thy-option *ngFor="let option of selectOptions()" [thyValue]="option._id" [thyLabelText]="option.text"> </thy-option>
860
1084
  </thy-select> `, isInline: true, dependencies: [{ kind: "directive", type: NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ThySelect, selector: "thy-select,thy-custom-select", inputs: ["thyDropdownWidthMode", "thyShowSearch", "thyPlaceHolder", "thyServerSearch", "thyLoadState", "thyAutoActiveFirstItem", "thyMode", "thySize", "thyEmptyStateText", "thyEmptySearchMessageText", "thyEnableScrollLoad", "thyAllowClear", "thyDisabled", "thySortComparator", "thyFooterTemplate", "thyPlacement", "thyOrigin", "thyFooterClass", "thyAutoExpand", "thyHasBackdrop", "thyMaxTagCount", "thyBorderless", "thyOptions", "thyPreset"], outputs: ["thyOnSearch", "thyOnScrollToBottom", "thyOnExpandStatusChange"], exportAs: ["thySelect"] }, { kind: "component", type: ThyOption, selector: "thy-option", inputs: ["thyValue", "thyRawValue", "thyLabelText", "thyShowOptionCustom", "thySearchKey", "thyDisabled"], outputs: ["selectionChange", "visibleChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
861
1085
  }
862
1086
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: SelectCellEditorComponent, decorators: [{
@@ -864,7 +1088,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
864
1088
  args: [{
865
1089
  selector: 'single-select-cell-editor',
866
1090
  template: `<thy-select [(ngModel)]="modelValue" [thyAutoExpand]="true" (thyOnExpandStatusChange)="updateValue($event)">
867
- <thy-option *ngFor="let option of selectOptions()" [thyValue]="option.id" [thyLabelText]="option.name"> </thy-option>
1091
+ <thy-option *ngFor="let option of selectOptions()" [thyValue]="option._id" [thyLabelText]="option.text"> </thy-option>
868
1092
  </thy-select> `,
869
1093
  standalone: true,
870
1094
  changeDetection: ChangeDetectionStrategy.OnPush,
@@ -879,18 +1103,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
879
1103
 
880
1104
  const GRID_CELL_EDITOR_MAP = {
881
1105
  [AITableFieldType.text]: TextCellEditorComponent,
1106
+ [AITableFieldType.richText]: TextCellEditorComponent,
882
1107
  [AITableFieldType.select]: SelectCellEditorComponent,
883
1108
  [AITableFieldType.number]: NumberCellEditorComponent,
884
1109
  [AITableFieldType.date]: DateTimeCellEditorComponent,
885
1110
  [AITableFieldType.rate]: RatingCellEditorComponent,
886
- [AITableFieldType.link]: LinkCellEditorComponent
1111
+ [AITableFieldType.link]: LinkCellEditorComponent,
1112
+ [AITableFieldType.progress]: ProgressEditorComponent
887
1113
  };
888
1114
 
889
1115
  class AITableGridEventService {
890
- constructor(thyPopover) {
891
- this.thyPopover = thyPopover;
892
- this.takeUntilDestroyed = takeUntilDestroyed();
1116
+ constructor() {
1117
+ this.dblClickEvent$ = new Subject();
893
1118
  this.mousedownEvent$ = new Subject();
1119
+ this.mouseoverEvent$ = new Subject();
1120
+ this.globalMouseoverEvent$ = new Subject();
1121
+ this.globalMousedownEvent$ = new Subject();
1122
+ this.destroyRef = inject(DestroyRef);
1123
+ this.thyPopover = inject(ThyPopover);
894
1124
  }
895
1125
  initialize(aiTable, aiFieldRenderers) {
896
1126
  this.aiTable = aiTable;
@@ -898,22 +1128,30 @@ class AITableGridEventService {
898
1128
  }
899
1129
  registerEvents(element) {
900
1130
  fromEvent(element, 'dblclick')
901
- .pipe(this.takeUntilDestroyed)
1131
+ .pipe(takeUntilDestroyed(this.destroyRef))
902
1132
  .subscribe((event) => {
903
- this.dblClick(event);
1133
+ this.dblClickEvent$.next(event);
1134
+ });
1135
+ fromEvent(element, 'mouseover')
1136
+ .pipe(debounceTime(80), takeUntilDestroyed(this.destroyRef))
1137
+ .subscribe((event) => {
1138
+ this.mouseoverEvent$.next(event);
1139
+ });
1140
+ fromEvent(document, 'mouseover')
1141
+ .pipe(takeUntilDestroyed(this.destroyRef))
1142
+ .subscribe((event) => {
1143
+ this.globalMouseoverEvent$.next(event);
904
1144
  });
905
1145
  fromEvent(element, 'mousedown')
906
- .pipe(this.takeUntilDestroyed)
1146
+ .pipe(takeUntilDestroyed(this.destroyRef))
907
1147
  .subscribe((event) => {
908
1148
  this.mousedownEvent$.next(event);
909
1149
  });
910
- }
911
- dblClick(event) {
912
- const cellDom = event.target.closest('.grid-cell');
913
- const type = cellDom && cellDom.getAttribute('type');
914
- if (type && DBL_CLICK_EDIT_TYPE.includes(type)) {
915
- this.openEdit(cellDom);
916
- }
1150
+ fromEvent(document, 'mousedown')
1151
+ .pipe(takeUntilDestroyed(this.destroyRef))
1152
+ .subscribe((event) => {
1153
+ this.globalMousedownEvent$.next(event);
1154
+ });
917
1155
  }
918
1156
  getEditorComponent(type) {
919
1157
  if (this.aiFieldRenderers && this.aiFieldRenderers[type]) {
@@ -928,7 +1166,7 @@ class AITableGridEventService {
928
1166
  const field = getRecordOrField(this.aiTable.fields, fieldId);
929
1167
  const record = getRecordOrField(this.aiTable.records, recordId);
930
1168
  const component = this.getEditorComponent(field().type);
931
- this.thyPopover.open(component, {
1169
+ const ref = this.thyPopover.open(component, {
932
1170
  origin: cellDom,
933
1171
  originPosition: {
934
1172
  x: x - 1,
@@ -936,7 +1174,7 @@ class AITableGridEventService {
936
1174
  width: width + 2,
937
1175
  height: height + 2
938
1176
  },
939
- width: width + 2 + 'px',
1177
+ width: width + 1 + 'px',
940
1178
  height: height + 2 + 'px',
941
1179
  placement: 'top',
942
1180
  offset: -(height + 4),
@@ -950,46 +1188,17 @@ class AITableGridEventService {
950
1188
  outsideClosable: false,
951
1189
  hasBackdrop: false,
952
1190
  manualClosure: true,
953
- animationDisabled: true
1191
+ animationDisabled: true,
1192
+ autoAdaptive: true
954
1193
  });
1194
+ return ref;
955
1195
  }
956
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService, deps: [{ token: i1$1.ThyPopover }], target: i0.ɵɵFactoryTarget.Injectable }); }
1196
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
957
1197
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService }); }
958
1198
  }
959
1199
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridEventService, decorators: [{
960
1200
  type: Injectable
961
- }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
962
-
963
- class FieldMenu {
964
- execute(menu) {
965
- const field = getRecordOrField(this.aiTable.fields, this.fieldId);
966
- menu.exec && menu.exec(this.aiTable, field, this.origin);
967
- }
968
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
969
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: FieldMenu, isStandalone: true, selector: "field-menu", inputs: { fieldId: "fieldId", aiTable: "aiTable", fieldMenus: "fieldMenus", origin: "origin" }, ngImport: i0, template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.id === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n", dependencies: [{ kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyDivider, selector: "thy-divider", inputs: ["thyVertical", "thyStyle", "thyColor", "thyText", "thyTextDirection", "thyDeeper"] }, { kind: "directive", type: ThyDropdownMenuItemDirective, selector: "[thyDropdownMenuItem]", inputs: ["thyType", "thyDisabled"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
970
- }
971
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, decorators: [{
972
- type: Component,
973
- args: [{ selector: 'field-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
974
- ThyIcon,
975
- ThyDivider,
976
- ThyDropdownMenuComponent,
977
- ThyDropdownMenuItemDirective,
978
- ThyDropdownMenuItemNameDirective,
979
- ThyDropdownMenuItemIconDirective
980
- ], template: "@for (menu of fieldMenus; track index; let index = $index) {\n @if (menu.id === 'divider') {\n <thy-divider [thyStyle]=\"'solid'\"></thy-divider>\n } @else {\n <a thyDropdownMenuItem href=\"javascript:;\" (click)=\"execute(menu)\">\n <thy-icon [thyIconName]=\"menu.icon!\"></thy-icon>\n <span>{{ menu.name! }}</span>\n </a>\n }\n}\n" }]
981
- }], propDecorators: { fieldId: [{
982
- type: Input,
983
- args: [{ required: true }]
984
- }], aiTable: [{
985
- type: Input,
986
- args: [{ required: true }]
987
- }], fieldMenus: [{
988
- type: Input,
989
- args: [{ required: true }]
990
- }], origin: [{
991
- type: Input
992
- }] } });
1201
+ }] });
993
1202
 
994
1203
  class AITableGridSelectionService {
995
1204
  constructor() { }
@@ -1028,23 +1237,31 @@ class AITableGridSelectionService {
1028
1237
  this.clearSelection();
1029
1238
  if (checked) {
1030
1239
  this.aiTable.records().forEach((item) => {
1031
- this.selectRecord(item.id);
1240
+ this.selectRecord(item._id);
1032
1241
  });
1033
1242
  }
1034
1243
  }
1035
1244
  updateSelect(event) {
1036
- const target = event.target;
1245
+ const target = event?.target;
1246
+ if (!target) {
1247
+ return;
1248
+ }
1037
1249
  const cellDom = target.closest('.grid-cell');
1038
1250
  const colDom = target.closest('.grid-field');
1251
+ const checkbox = target.tagName === 'INPUT' && target.type === 'checkbox' && target.closest('.grid-checkbox');
1252
+ const fieldAction = target.closest('.grid-field-action');
1039
1253
  if (cellDom) {
1040
1254
  const fieldId = cellDom.getAttribute('fieldId');
1041
1255
  const recordId = cellDom.getAttribute('recordId');
1042
1256
  fieldId && recordId && this.selectCell(recordId, fieldId);
1043
1257
  }
1044
- if (colDom) {
1258
+ if (colDom && !fieldAction) {
1045
1259
  const fieldId = colDom.getAttribute('fieldId');
1046
1260
  fieldId && this.selectField(fieldId);
1047
1261
  }
1262
+ if (!cellDom && !colDom && !checkbox) {
1263
+ this.clearSelection();
1264
+ }
1048
1265
  }
1049
1266
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridSelectionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1050
1267
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridSelectionService }); }
@@ -1054,40 +1271,34 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
1054
1271
  }], ctorParameters: () => [] });
1055
1272
 
1056
1273
  class AITableGrid {
1057
- get isSelectedAll() {
1058
- return this.aiTable.selection().selectedRecords.size === this.aiRecords().length;
1059
- }
1060
- constructor(elementRef, aiTableGridEventService, aiTableGridSelectionService, aiTableGridFieldService, ngZone) {
1061
- this.elementRef = elementRef;
1062
- this.aiTableGridEventService = aiTableGridEventService;
1063
- this.aiTableGridSelectionService = aiTableGridSelectionService;
1064
- this.aiTableGridFieldService = aiTableGridFieldService;
1065
- this.ngZone = ngZone;
1274
+ constructor() {
1066
1275
  this.aiRecords = model.required();
1067
1276
  this.aiFields = model.required();
1068
- this.aiRowHeight = input();
1069
1277
  this.aiFieldConfig = input();
1070
1278
  this.aiReadonly = input();
1071
1279
  this.aiPlugins = input();
1280
+ this.aiReferences = input();
1072
1281
  this.AITableFieldType = AITableFieldType;
1073
- this.takeUntilDestroyed = takeUntilDestroyed();
1282
+ this.isSelectedAll = computed(() => {
1283
+ return this.aiTable.selection().selectedRecords.size === this.aiRecords().length;
1284
+ });
1074
1285
  this.onChange = output();
1075
1286
  this.aiTableInitialized = output();
1076
1287
  this.gridData = computed(() => {
1077
- return buildGridData(this.aiRecords(), this.aiFields(), this.aiTable.selection());
1288
+ return buildGridData(this.aiRecords(), this.aiFields(), this.aiReferences());
1078
1289
  });
1290
+ this.ngZone = inject(NgZone);
1291
+ this.elementRef = inject(ElementRef);
1292
+ this.destroyRef = inject(DestroyRef);
1293
+ this.aiTableGridFieldService = inject(AITableGridFieldService);
1294
+ this.aiTableGridEventService = inject(AITableGridEventService);
1295
+ this.aiTableGridSelectionService = inject(AITableGridSelectionService);
1079
1296
  }
1080
1297
  ngOnInit() {
1081
1298
  this.initAITable();
1082
1299
  this.initService();
1083
1300
  this.buildFieldMenus();
1084
- this.ngZone.runOutsideAngular(() => {
1085
- this.aiTableGridEventService.mousedownEvent$.pipe(this.takeUntilDestroyed).subscribe((event) => {
1086
- if (event?.target) {
1087
- this.aiTableGridSelectionService.updateSelect(event);
1088
- }
1089
- });
1090
- });
1301
+ this.subscribeEvents();
1091
1302
  }
1092
1303
  initAITable() {
1093
1304
  this.aiTable = createAITable(this.aiRecords, this.aiFields);
@@ -1126,8 +1337,53 @@ class AITableGrid {
1126
1337
  const field = signal(createDefaultField(this.aiTable, AITableFieldType.text));
1127
1338
  this.aiTableGridFieldService.editFieldProperty(gridColumnBlank, this.aiTable, field, false);
1128
1339
  }
1129
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, deps: [{ token: i0.ElementRef }, { token: AITableGridEventService }, { token: AITableGridSelectionService }, { token: AITableGridFieldService }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Component }); }
1130
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableGrid, isStandalone: true, selector: "ai-table-grid", inputs: { aiRecords: { classPropertyName: "aiRecords", publicName: "aiRecords", isSignal: true, isRequired: true, transformFunction: null }, aiFields: { classPropertyName: "aiFields", publicName: "aiFields", isSignal: true, isRequired: true, transformFunction: null }, aiRowHeight: { classPropertyName: "aiRowHeight", publicName: "aiRowHeight", isSignal: true, isRequired: false, transformFunction: null }, aiFieldConfig: { classPropertyName: "aiFieldConfig", publicName: "aiFieldConfig", isSignal: true, isRequired: false, transformFunction: null }, aiReadonly: { classPropertyName: "aiReadonly", publicName: "aiReadonly", isSignal: true, isRequired: false, transformFunction: null }, aiPlugins: { classPropertyName: "aiPlugins", publicName: "aiPlugins", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { aiRecords: "aiRecordsChange", aiFields: "aiFieldsChange", onChange: "onChange", aiTableInitialized: "aiTableInitialized" }, host: { classAttribute: "ai-table-grid" }, providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], ngImport: i0, template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field.id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field.id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field.id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field.id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record.id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: aiTable.selection().selectedRecords.has(record.id) }\">\n <div class=\"grid-row-index\">\n <label\n [ngClass]=\"record.checked ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record.checked\"\n (ngModelChange)=\"selectRecord(record.id)\"\n ></label>\n <span [ngClass]=\"record.checked ? 'grid-row-no-number' : 'grid-row-number'\"> {{ index + 1 }} </span>\n </div>\n @for (field of gridData().fields; track $index) {\n <div\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record.id) || aiTable.selection().selectedFields.has(field.id),\n selected: aiTable.selection().selectedCells.get(record.id)?.hasOwnProperty(field.id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field.id]\"\n [attr.recordId]=\"[record.id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n #cell\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.rate) {\n <thy-rate [(ngModel)]=\"record.values[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field.id]?.text\"\n [href]=\"record.values[field.id]?.url\"\n target=\"_blank\"\n >{{ record.values[field.id]?.text }}</a\n >\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field.id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i4.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SelectOptionPipe, name: "selectOption" }, { kind: "component", type: ThyTag, selector: "thy-tag,[thyTag]", inputs: ["thyTag", "thyShape", "thyColor", "thyTheme", "thySize", "thyHoverable"] }, { kind: "ngmodule", type: ThyPopoverModule }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }, { kind: "pipe", type: ThyDatePickerFormatPipe, name: "thyDatePickerFormat" }, { kind: "ngmodule", type: ThyTooltipModule }, { kind: "component", type: ThyFlexibleText, selector: "thy-flexible-text,[thyFlexibleText]", inputs: ["thyTooltipTrigger", "thyContainerClass", "thyTooltipContent", "thyTooltipPlacement", "thyTooltipOffset"], exportAs: ["thyFlexibleText"] }, { kind: "directive", type: ThyStopPropagationDirective, selector: "[thyStopPropagation]", inputs: ["thyStopPropagation"] }, { kind: "component", type: FieldMenu, selector: "field-menu", inputs: ["fieldId", "aiTable", "fieldMenus", "origin"] }, { kind: "component", type: ThyAction, selector: "thy-action, [thyAction]", inputs: ["thyType", "thyIcon", "thyActionIcon", "thyActive", "thyActionActive", "thyTheme", "thyHoverIcon", "thyDisabled"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "ngmodule", type: ThyCheckboxModule }, { kind: "component", type: i6.ThyCheckbox, selector: "thy-checkbox,[thy-checkbox],[thyCheckbox]", inputs: ["thyIndeterminate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1340
+ subscribeEvents() {
1341
+ this.ngZone.runOutsideAngular(() => {
1342
+ this.aiTableGridEventService.dblClickEvent$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
1343
+ this.dblClick(event);
1344
+ });
1345
+ this.aiTableGridEventService.mousedownEvent$
1346
+ .pipe(mergeWith(this.aiTableGridEventService.globalMousedownEvent$), takeUntilDestroyed(this.destroyRef))
1347
+ .subscribe((event) => {
1348
+ this.aiTableGridSelectionService.updateSelect(event);
1349
+ });
1350
+ this.aiTableGridEventService.mouseoverEvent$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
1351
+ this.mouseoverHandle(event);
1352
+ });
1353
+ this.aiTableGridEventService.globalMouseoverEvent$.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((event) => {
1354
+ this.closeHoverCellEditor(event);
1355
+ });
1356
+ });
1357
+ }
1358
+ dblClick(event) {
1359
+ const cellDom = event.target.closest('.grid-cell');
1360
+ const type = cellDom && cellDom.getAttribute('type');
1361
+ const readonly = cellDom && cellDom.getAttribute('readonly');
1362
+ if (type && !readonly && DBL_CLICK_EDIT_TYPE.includes(type)) {
1363
+ this.aiTableGridEventService.openEdit(cellDom);
1364
+ }
1365
+ }
1366
+ mouseoverHandle(event) {
1367
+ if (this.mouseoverRef) {
1368
+ this.mouseoverRef?.close();
1369
+ }
1370
+ const cellDom = event.target.closest('.grid-cell');
1371
+ const type = cellDom && cellDom.getAttribute('type');
1372
+ if (type && MOUSEOVER_EDIT_TYPE.includes(type)) {
1373
+ this.mouseoverRef = this.aiTableGridEventService.openEdit(cellDom);
1374
+ }
1375
+ }
1376
+ closeHoverCellEditor(e) {
1377
+ if (this.mouseoverRef) {
1378
+ const hasGrid = e.target && e.target.closest('.ai-table-grid');
1379
+ const hasCellEditor = e.target && e.target.closest('.grid-cell-editor');
1380
+ if (!hasGrid && !hasCellEditor) {
1381
+ this.mouseoverRef.close();
1382
+ }
1383
+ }
1384
+ }
1385
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
1386
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableGrid, isStandalone: true, selector: "ai-table-grid", inputs: { aiRecords: { classPropertyName: "aiRecords", publicName: "aiRecords", isSignal: true, isRequired: true, transformFunction: null }, aiFields: { classPropertyName: "aiFields", publicName: "aiFields", isSignal: true, isRequired: true, transformFunction: null }, aiFieldConfig: { classPropertyName: "aiFieldConfig", publicName: "aiFieldConfig", isSignal: true, isRequired: false, transformFunction: null }, aiReadonly: { classPropertyName: "aiReadonly", publicName: "aiReadonly", isSignal: true, isRequired: false, transformFunction: null }, aiPlugins: { classPropertyName: "aiPlugins", publicName: "aiPlugins", isSignal: true, isRequired: false, transformFunction: null }, aiReferences: { classPropertyName: "aiReferences", publicName: "aiReferences", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { aiRecords: "aiRecordsChange", aiFields: "aiFieldsChange", onChange: "onChange", aiTableInitialized: "aiTableInitialized" }, host: { classAttribute: "ai-table-grid" }, providers: [AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], ngImport: i0, template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell grid-checkbox\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll()\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field._id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field._id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field._id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record._id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: (record._id | isSelectRecord: aiTable.selection()) }\">\n <div class=\"grid-row-index grid-checkbox\">\n <label\n [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record._id | isSelectRecord: aiTable.selection()\"\n (ngModelChange)=\"selectRecord(record._id)\"\n ></label>\n <span [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'grid-row-no-number' : 'grid-row-number'\">\n {{ index + 1 }}\n </span>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n #cell\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record._id) || aiTable.selection().selectedFields.has(field._id),\n selected: aiTable.selection().selectedCells.get(record._id)?.hasOwnProperty(field._id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field._id]\"\n [attr.readonly]=\"[field?.readonly]\"\n [attr.recordId]=\"[record._id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field._id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color! || selectedOption!.bg_color! || 'default'\">{{\n selectedOption.text\n }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field._id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.updatedAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.createdAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.rate) {\n <thy-rate [ngModel]=\"record.values[field._id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n target=\"_blank\"\n [href]=\"record.values[field._id]?.url\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field._id]?.text\"\n >\n {{ record.values[field._id]?.text }}\n </a>\n }\n @case (AITableFieldType.progress) {\n <thy-progress\n class=\"w-100\"\n [thyValue]=\"record.values[field._id]\"\n [thySize]=\"record.values[field._id]?.config?.size || 'md'\"\n [thyMax]=\"record.values[field._id]?.config?.max || 100\"\n [thyType]=\"record.values[field._id]?.config?.progressType || 'success'\"\n >\n <span> {{ record.values[field._id] }}{{ record.values[field._id]?.config?.suffix || '%' }} </span>\n </thy-progress>\n }\n @case (AITableFieldType.member) {\n @if (!field.isMultiple) {\n @if (record.values[field._id][0]; as recordValue) {\n <thy-avatar\n [thyName]=\"recordValue.display_name\"\n [thySrc]=\"recordValue.avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n } @else {\n <thy-avatar-list thyAvatarSize=\"xs\">\n @for (item of record.values[field._id]; track $index) {\n <thy-avatar [thyName]=\"item.display_name\" [thySrc]=\"item.avatar\"></thy-avatar>\n }\n </thy-avatar-list>\n }\n }\n @case (AITableFieldType.createdBy) {\n @if (record.values[field._id][0]; as recordValue) {\n <thy-avatar\n [thyName]=\"recordValue.display_name\"\n [thySrc]=\"recordValue.avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n }\n @case (AITableFieldType.updatedBy) {\n @if (record.values[field._id][0]; as recordValue) {\n <thy-avatar\n [thyName]=\"recordValue.display_name\"\n [thySrc]=\"recordValue.avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field._id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>\n", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1$2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "pipe", type: SelectOptionPipe, name: "selectOption" }, { kind: "component", type: ThyTag, selector: "thy-tag,[thyTag]", inputs: ["thyTag", "thyShape", "thyColor", "thyTheme", "thySize", "thyHoverable"] }, { kind: "ngmodule", type: ThyPopoverModule }, { kind: "component", type: ThyIcon, selector: "thy-icon, [thy-icon]", inputs: ["thyIconType", "thyTwotoneColor", "thyIconName", "thyIconRotate", "thyIconSet", "thyIconLegging", "thyIconLinearGradient"] }, { kind: "component", type: ThyRate, selector: "thy-rate", inputs: ["thyCount", "thyDisabled", "thyAllowHalf", "thyAllowClear", "thyTooltips", "thyIconTemplate"], outputs: ["thyItemHoverChange"] }, { kind: "component", type: ThyProgress, selector: "thy-progress", inputs: ["thyType", "thySize", "thyValue", "thyMax", "thyTips", "thyShape", "thyGapDegree", "thyGapPosition", "thyStrokeWidth"] }, { kind: "pipe", type: ThyDatePickerFormatPipe, name: "thyDatePickerFormat" }, { kind: "component", type: ThyFlexibleText, selector: "thy-flexible-text,[thyFlexibleText]", inputs: ["thyTooltipTrigger", "thyContainerClass", "thyTooltipContent", "thyTooltipPlacement", "thyTooltipOffset"], exportAs: ["thyFlexibleText"] }, { kind: "directive", type: ThyStopPropagationDirective, selector: "[thyStopPropagation]", inputs: ["thyStopPropagation"] }, { kind: "component", type: FieldMenu, selector: "field-menu", inputs: ["fieldId", "aiTable", "fieldMenus", "origin"] }, { kind: "component", type: ThyAction, selector: "thy-action, [thyAction]", inputs: ["thyType", "thyIcon", "thyActionIcon", "thyActive", "thyActionActive", "thyTheme", "thyHoverIcon", "thyDisabled"] }, { kind: "directive", type: ThyDropdownDirective, selector: "[thyDropdown]", inputs: ["thyDropdownMenu", "thyDropdown", "thyTrigger", "thyShowDelay", "thyHideDelay", "thyActiveClass", "thyPopoverOptions", "thyPlacement", "thyMenuInsideClosable", "thyPanelClass"], outputs: ["thyActiveChange"] }, { kind: "component", type: ThyDropdownMenuComponent, selector: "thy-dropdown-menu", inputs: ["thyWidth", "thyImmediateRender"] }, { kind: "ngmodule", type: ThyCheckboxModule }, { kind: "component", type: i3.ThyCheckbox, selector: "thy-checkbox,[thy-checkbox],[thyCheckbox]", inputs: ["thyIndeterminate"] }, { kind: "ngmodule", type: ThyAvatarModule }, { kind: "component", type: i4.ThyAvatar, selector: "thy-avatar", inputs: ["thyShowName", "thySrc", "thyName", "thySize", "thyShowRemove", "thyRemovable", "thyImgClass", "thyDisabled", "thyLoading", "thyFetchPriority"], outputs: ["thyOnRemove", "thyRemove", "thyError"] }, { kind: "component", type: i4.ThyAvatarList, selector: "thy-avatar-list", inputs: ["thyMode", "thyAvatarSize"] }, { kind: "pipe", type: IsSelectRecordPipe, name: "isSelectRecord" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
1131
1387
  }
1132
1388
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, decorators: [{
1133
1389
  type: Component,
@@ -1144,30 +1400,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
1144
1400
  ThyPopoverModule,
1145
1401
  ThyIcon,
1146
1402
  ThyRate,
1403
+ ThyProgress,
1147
1404
  AITableFieldPropertyEditor,
1148
1405
  ThyDatePickerFormatPipe,
1149
- ThyTooltipModule,
1150
1406
  ThyFlexibleText,
1151
1407
  ThyStopPropagationDirective,
1152
1408
  FieldMenu,
1153
1409
  ThyAction,
1154
1410
  ThyDropdownDirective,
1155
1411
  ThyDropdownMenuComponent,
1156
- ThyCheckboxModule
1157
- ], providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field.id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field.id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field.id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field.id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record.id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: aiTable.selection().selectedRecords.has(record.id) }\">\n <div class=\"grid-row-index\">\n <label\n [ngClass]=\"record.checked ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record.checked\"\n (ngModelChange)=\"selectRecord(record.id)\"\n ></label>\n <span [ngClass]=\"record.checked ? 'grid-row-no-number' : 'grid-row-number'\"> {{ index + 1 }} </span>\n </div>\n @for (field of gridData().fields; track $index) {\n <div\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record.id) || aiTable.selection().selectedFields.has(field.id),\n selected: aiTable.selection().selectedCells.get(record.id)?.hasOwnProperty(field.id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field.id]\"\n [attr.recordId]=\"[record.id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n #cell\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.rate) {\n <thy-rate [(ngModel)]=\"record.values[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field.id]?.text\"\n [href]=\"record.values[field.id]?.url\"\n target=\"_blank\"\n >{{ record.values[field.id]?.text }}</a\n >\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field.id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>\n" }]
1158
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: AITableGridEventService }, { type: AITableGridSelectionService }, { type: AITableGridFieldService }, { type: i0.NgZone }] });
1159
-
1160
- var AITableRowHeight;
1161
- (function (AITableRowHeight) {
1162
- AITableRowHeight[AITableRowHeight["Short"] = 1] = "Short";
1163
- AITableRowHeight[AITableRowHeight["Medium"] = 2] = "Medium";
1164
- AITableRowHeight[AITableRowHeight["Tall"] = 3] = "Tall";
1165
- AITableRowHeight[AITableRowHeight["ExtraTall"] = 4] = "ExtraTall";
1166
- })(AITableRowHeight || (AITableRowHeight = {}));
1412
+ ThyCheckboxModule,
1413
+ ProgressEditorComponent,
1414
+ ThyAvatarModule,
1415
+ NgTemplateOutlet,
1416
+ IsSelectRecordPipe
1417
+ ], providers: [AITableGridEventService, AITableGridFieldService, AITableGridSelectionService], template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell grid-checkbox\">\n <label thyCheckbox thyLabelText=\"\" [ngModel]=\"isSelectedAll()\" (ngModelChange)=\"toggleSelectAll($event)\"></label>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n class=\"grid-cell grid-field\"\n #fieldAction\n [attr.fieldId]=\"field._id\"\n [ngClass]=\"{ highlight: aiTable.selection().selectedFields.has(field._id) }\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n <span class=\"text-truncate\">\n <thy-icon [thyIconName]=\"field.icon!\" class=\"mr-2 text-muted\"></thy-icon>\n <span>{{ field.name }}</span>\n </span>\n <a\n class=\"grid-field-action\"\n thyAction\n thyActiveClass=\"active\"\n thyIcon=\"more-vertical\"\n [thyDropdown]=\"fieldMenu\"\n href=\"javascript:;\"\n >\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [fieldId]=\"field._id\" [aiTable]=\"aiTable\" [fieldMenus]=\"fieldMenus\"></field-menu>\n </thy-dropdown-menu>\n </a>\n </div>\n }\n <div class=\"grid-column-blank cursor-pointer\" #gridColumnBlank (click)=\"addField(gridColumnBlank)\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n<div class=\"grid-body d-flex\">\n @for (record of gridData().records; track record._id; let index = $index) {\n <div class=\"grid-row d-flex\" [ngClass]=\"{ highlight: (record._id | isSelectRecord: aiTable.selection()) }\">\n <div class=\"grid-row-index grid-checkbox\">\n <label\n [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'checked-box' : 'unchecked-box'\"\n thyCheckbox\n thyLabelText=\"\"\n [ngModel]=\"record._id | isSelectRecord: aiTable.selection()\"\n (ngModelChange)=\"selectRecord(record._id)\"\n ></label>\n <span [ngClass]=\"(record._id | isSelectRecord: aiTable.selection()) ? 'grid-row-no-number' : 'grid-row-number'\">\n {{ index + 1 }}\n </span>\n </div>\n @for (field of gridData().fields; track field._id) {\n <div\n #cell\n class=\"grid-cell\"\n [ngClass]=\"{\n highlight: aiTable.selection().selectedCells.has(record._id) || aiTable.selection().selectedFields.has(field._id),\n selected: aiTable.selection().selectedCells.get(record._id)?.hasOwnProperty(field._id)\n }\"\n [attr.type]=\"[field.type]\"\n [attr.fieldId]=\"[field._id]\"\n [attr.readonly]=\"[field?.readonly]\"\n [attr.recordId]=\"[record._id]\"\n [ngStyle]=\"{ width: field.width + 'px' }\"\n >\n @switch (field.type) {\n @case (AITableFieldType.select) {\n @if (!field.isMultiple && record.values[field._id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color! || selectedOption!.bg_color! || 'default'\">{{\n selectedOption.text\n }}</thy-tag>\n }\n }\n @case (AITableFieldType.date) {\n {{ record.values[field._id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.updatedAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.createdAt) {\n <div class=\"d-block user-select-none\">\n <span class=\"text-truncate\">\n {{ record.values[field._id] | thyDatePickerFormat: 'yyyy-MM-dd HH:mm' }}\n </span>\n </div>\n }\n @case (AITableFieldType.rate) {\n <thy-rate [ngModel]=\"record.values[field._id]\"></thy-rate>\n }\n @case (AITableFieldType.link) {\n <a\n class=\"d-block\"\n target=\"_blank\"\n [href]=\"record.values[field._id]?.url\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.values[field._id]?.text\"\n >\n {{ record.values[field._id]?.text }}\n </a>\n }\n @case (AITableFieldType.progress) {\n <thy-progress\n class=\"w-100\"\n [thyValue]=\"record.values[field._id]\"\n [thySize]=\"record.values[field._id]?.config?.size || 'md'\"\n [thyMax]=\"record.values[field._id]?.config?.max || 100\"\n [thyType]=\"record.values[field._id]?.config?.progressType || 'success'\"\n >\n <span> {{ record.values[field._id] }}{{ record.values[field._id]?.config?.suffix || '%' }} </span>\n </thy-progress>\n }\n @case (AITableFieldType.member) {\n @if (!field.isMultiple) {\n @if (record.values[field._id][0]; as recordValue) {\n <thy-avatar\n [thyName]=\"recordValue.display_name\"\n [thySrc]=\"recordValue.avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n } @else {\n <thy-avatar-list thyAvatarSize=\"xs\">\n @for (item of record.values[field._id]; track $index) {\n <thy-avatar [thyName]=\"item.display_name\" [thySrc]=\"item.avatar\"></thy-avatar>\n }\n </thy-avatar-list>\n }\n }\n @case (AITableFieldType.createdBy) {\n @if (record.values[field._id][0]; as recordValue) {\n <thy-avatar\n [thyName]=\"recordValue.display_name\"\n [thySrc]=\"recordValue.avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n }\n @case (AITableFieldType.updatedBy) {\n @if (record.values[field._id][0]; as recordValue) {\n <thy-avatar\n [thyName]=\"recordValue.display_name\"\n [thySrc]=\"recordValue.avatar\"\n thySize=\"xs\"\n thyShowName=\"true\"\n ></thy-avatar>\n }\n }\n @default {\n <span class=\"text-truncate\"> {{ record.values[field._id] }}</span>\n }\n }\n <div class=\"autofill-container\"></div>\n </div>\n }\n <div class=\"grid-column-blank\"></div>\n </div>\n }\n <div class=\"grid-row-insert grid-row cursor-pointer\" (click)=\"addRecord()\">\n <thy-icon thyIconName=\"plus\"></thy-icon>\n </div>\n</div>\n\n<div #activeBorder class=\"active-border\"></div>\n" }]
1418
+ }] });
1167
1419
 
1168
1420
  /**
1169
1421
  * Generated bundle index. Do not edit.
1170
1422
  */
1171
1423
 
1172
- export { AITableFieldPropertyEditor, AITableFieldType, AITableGrid, AITableQueries, AITableRowHeight, AITableStatType, ActionName, Actions, BasicFields, DBL_CLICK_EDIT_TYPE, DEFAULT_COLUMN_WIDTH, DefaultFieldMenus, DividerMenuItem, EditFieldPropertyItem, ExecuteType, FLUSHING, Fields, FieldsMap, MIN_COLUMN_WIDTH, RemoveFieldItem, RowHeight, SelectOptionPipe, buildGridData, createAITable, createDefaultField, createDefaultFieldName, getDefaultFieldValue, getDefaultRecord, getRecordOrField, idCreator, isPathEqual };
1424
+ export { AITableFieldPropertyEditor, AITableFieldType, AITableGrid, AITableQueries, AITableStatType, ActionName, Actions, BasicFields, DBL_CLICK_EDIT_TYPE, DEFAULT_COLUMN_WIDTH, DateTimeCellEditorComponent, DefaultFieldMenus, DividerMenuItem, EditFieldPropertyItem, ExecuteType, FLUSHING, Fields, FieldsMap, IsSelectRecordPipe, LinkCellEditorComponent, MIN_COLUMN_WIDTH, MOUSEOVER_EDIT_TYPE, NumberCellEditorComponent, ProgressEditorComponent, RatingCellEditorComponent, RemoveFieldItem, RowHeight, SelectOptionPipe, TextCellEditorComponent, buildGridData, buildRecordsByReferences, createAITable, createDefaultField, createDefaultFieldName, getDefaultFieldValue, getDefaultRecord, getRecordOrField, idCreator, isPathEqual };
1173
1425
  //# sourceMappingURL=ai-table-grid.mjs.map