@ai-table/grid 0.0.2 → 0.0.3

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 (66) hide show
  1. package/components/cell-editors/abstract-cell-editor.component.d.ts +2 -2
  2. package/components/cell-editors/abstract-cell-editor.component.d.ts.map +1 -1
  3. package/components/field-menu/field-menu.component.d.ts +14 -0
  4. package/components/field-menu/field-menu.component.d.ts.map +1 -0
  5. package/components/field-property-editor/field-property-editor.component.d.ts +12 -15
  6. package/components/field-property-editor/field-property-editor.component.d.ts.map +1 -1
  7. package/components/index.d.ts +2 -0
  8. package/components/index.d.ts.map +1 -0
  9. package/constants/field.d.ts +14 -0
  10. package/constants/field.d.ts.map +1 -0
  11. package/constants/grid.d.ts.map +1 -1
  12. package/constants/index.d.ts +1 -0
  13. package/constants/index.d.ts.map +1 -1
  14. package/core/action/field.d.ts +2 -2
  15. package/core/action/field.d.ts.map +1 -1
  16. package/core/action/record.d.ts +3 -3
  17. package/core/action/record.d.ts.map +1 -1
  18. package/core/constants/field.d.ts +4 -8
  19. package/core/constants/field.d.ts.map +1 -1
  20. package/core/index.d.ts +1 -0
  21. package/core/index.d.ts.map +1 -1
  22. package/core/types/action.d.ts +7 -6
  23. package/core/types/action.d.ts.map +1 -1
  24. package/core/types/core.d.ts +5 -0
  25. package/core/types/core.d.ts.map +1 -1
  26. package/core/utils/field.d.ts +7 -1
  27. package/core/utils/field.d.ts.map +1 -1
  28. package/core/utils/queries.d.ts +2 -2
  29. package/core/utils/queries.d.ts.map +1 -1
  30. package/esm2022/components/cell-editors/abstract-cell-editor.component.mjs +11 -9
  31. package/esm2022/components/field-menu/field-menu.component.mjs +36 -0
  32. package/esm2022/components/field-property-editor/field-property-editor.component.mjs +32 -24
  33. package/esm2022/components/index.mjs +2 -0
  34. package/esm2022/constants/field.mjs +15 -0
  35. package/esm2022/constants/grid.mjs +1 -1
  36. package/esm2022/constants/index.mjs +2 -1
  37. package/esm2022/core/action/field.mjs +1 -1
  38. package/esm2022/core/action/record.mjs +1 -1
  39. package/esm2022/core/constants/field.mjs +4 -4
  40. package/esm2022/core/index.mjs +2 -1
  41. package/esm2022/core/types/action.mjs +1 -1
  42. package/esm2022/core/types/core.mjs +1 -1
  43. package/esm2022/core/utils/field.mjs +12 -1
  44. package/esm2022/core/utils/queries.mjs +1 -1
  45. package/esm2022/grid.component.mjs +41 -30
  46. package/esm2022/public-api.mjs +2 -1
  47. package/esm2022/services/event.service.mjs +4 -4
  48. package/esm2022/services/field.service.mjs +32 -0
  49. package/esm2022/types/field.mjs +2 -0
  50. package/esm2022/types/grid.mjs +1 -1
  51. package/esm2022/types/index.mjs +2 -1
  52. package/fesm2022/ai-table-grid.mjs +236 -136
  53. package/fesm2022/ai-table-grid.mjs.map +1 -1
  54. package/grid.component.d.ts +13 -9
  55. package/grid.component.d.ts.map +1 -1
  56. package/package.json +1 -1
  57. package/public-api.d.ts +1 -0
  58. package/public-api.d.ts.map +1 -1
  59. package/services/field.service.d.ts +16 -0
  60. package/services/field.service.d.ts.map +1 -0
  61. package/types/field.d.ts +11 -0
  62. package/types/field.d.ts.map +1 -0
  63. package/types/grid.d.ts +8 -3
  64. package/types/grid.d.ts.map +1 -1
  65. package/types/index.d.ts +1 -0
  66. package/types/index.d.ts.map +1 -1
@@ -1,30 +1,32 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Pipe, computed, input, inject, Component, ChangeDetectionStrategy, signal, Injectable, Input, model, output } from '@angular/core';
3
- import { NgForOf, NgIf, CommonModule, NgClass, NgComponentOutlet } from '@angular/common';
2
+ import { Pipe, computed, model, inject, booleanAttribute, Component, ChangeDetectionStrategy, Input, Injectable, input, signal, output } from '@angular/core';
3
+ import { NgIf, NgTemplateOutlet, NgForOf, CommonModule, NgClass, NgComponentOutlet } from '@angular/common';
4
4
  import { ThyTag } from 'ngx-tethys/tag';
5
5
  import * as i1$1 from 'ngx-tethys/popover';
6
6
  import { ThyPopoverRef, ThyPopoverModule } from 'ngx-tethys/popover';
7
7
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
8
8
  import { createDraft, finishDraft } from 'immer';
9
- import { isUndefinedOrNull, helpers } from 'ngx-tethys/util';
9
+ import { helpers, isUndefinedOrNull } from 'ngx-tethys/util';
10
10
  import { ThyIcon } from 'ngx-tethys/icon';
11
- import { fromEvent, of } from 'rxjs';
11
+ import { of, fromEvent } from 'rxjs';
12
12
  import * as i1 from '@angular/forms';
13
13
  import { FormsModule } from '@angular/forms';
14
+ import { ThyInputGroup, ThyInputCount, ThyInputDirective, ThyInput } from 'ngx-tethys/input';
15
+ import * as i2 from 'ngx-tethys/form';
16
+ import { ThyUniqueCheckValidator, ThyFormModule, ThyConfirmValidatorDirective } from 'ngx-tethys/form';
17
+ import { ThyDropdownDirective, ThyDropdownMenuComponent, ThyDropdownMenuItemDirective, ThyDropdownMenuItemNameDirective, ThyDropdownMenuItemIconDirective } from 'ngx-tethys/dropdown';
18
+ import { ThyButton } from 'ngx-tethys/button';
19
+ import { ThyListItem } from 'ngx-tethys/list';
14
20
  import { ThySelect } from 'ngx-tethys/select';
15
21
  import { ThyOption, ThyAutofocusDirective, ThyEnterDirective, ThyStopPropagationDirective } from 'ngx-tethys/shared';
16
- import { ThyInputDirective, ThyInputGroup, ThyInputCount, ThyInput } from 'ngx-tethys/input';
17
22
  import { ThyInputNumber } from 'ngx-tethys/input-number';
18
23
  import { ThyDatePicker, ThyDatePickerFormatPipe } from 'ngx-tethys/date-picker';
19
24
  import { ThyTimePickerModule } from 'ngx-tethys/time-picker';
20
25
  import { ThyRate } from 'ngx-tethys/rate';
21
26
  import { ThyTooltipModule, ThyTooltipService } from 'ngx-tethys/tooltip';
22
- import * as i2 from 'ngx-tethys/form';
23
- import { ThyUniqueCheckValidator, ThyFormModule, ThyConfirmValidatorDirective } from 'ngx-tethys/form';
24
- import { ThyDropdownDirective, ThyDropdownMenuComponent, ThyDropdownMenuItemDirective, ThyDropdownMenuItemNameDirective, ThyDropdownMenuItemIconDirective } from 'ngx-tethys/dropdown';
25
- import { ThyButton } from 'ngx-tethys/button';
26
- import { ThyListItem } from 'ngx-tethys/list';
27
27
  import { ThyFlexibleText } from 'ngx-tethys/flexible-text';
28
+ import { ThyDivider } from 'ngx-tethys/divider';
29
+ import { ThyAction } from 'ngx-tethys/action';
28
30
 
29
31
  ;
30
32
  class SelectOptionPipe {
@@ -178,9 +180,52 @@ function idCreator(length = 5) {
178
180
  return key;
179
181
  }
180
182
 
183
+ const BasicFields = [
184
+ {
185
+ type: AITableFieldType.Text,
186
+ name: '文本',
187
+ icon: 'font'
188
+ },
189
+ {
190
+ type: AITableFieldType.SingleSelect,
191
+ name: '单选',
192
+ icon: 'check-circle'
193
+ },
194
+ {
195
+ type: AITableFieldType.Number,
196
+ name: '数字',
197
+ icon: 'hashtag'
198
+ },
199
+ {
200
+ type: AITableFieldType.DateTime,
201
+ name: '日期',
202
+ icon: 'calendar'
203
+ },
204
+ {
205
+ type: AITableFieldType.Rating,
206
+ name: '评分',
207
+ icon: 'star-circle'
208
+ },
209
+ {
210
+ type: AITableFieldType.Link,
211
+ name: '链接',
212
+ icon: 'link-insert'
213
+ }
214
+ ];
215
+ const Fields = [...BasicFields];
216
+ const FieldsMap = helpers.keyBy([...BasicFields], 'type');
217
+
181
218
  function getDefaultFieldValue(type) {
182
219
  return '';
183
220
  }
221
+ function createDefaultFieldName(aiTable, type = AITableFieldType.Text) {
222
+ const fields = aiTable.fields();
223
+ const count = fields.filter((item) => item.type === type).length;
224
+ return count === 0 ? FieldsMap[type].name : FieldsMap[type].name + count;
225
+ }
226
+ function createDefaultField(aiTable, type = AITableFieldType.Text) {
227
+ return { id: idCreator(), type, name: createDefaultFieldName(aiTable, type) };
228
+ }
184
229
 
185
230
  const FLUSHING = new WeakMap();
186
231
 
@@ -287,28 +332,145 @@ const RowHeight = {
287
332
  ExtraTall: 152
288
333
  };
289
334
 
335
+ class AITableFieldPropertyEditor {
336
+ constructor() {
337
+ this.aiField = model.required();
338
+ this.aiExternalTemplate = null;
339
+ this.fieldType = computed(() => {
340
+ return FieldsMap[this.aiField().type];
341
+ });
342
+ this.fieldMaxLength = 32;
343
+ this.validatorConfig = {
344
+ validationMessages: {
345
+ fieldName: {
346
+ required: '列名不能为空',
347
+ thyUniqueCheck: '列名已存在'
348
+ }
349
+ }
350
+ };
351
+ this.selectableFields = Fields;
352
+ this.thyPopoverRef = inject((ThyPopoverRef));
353
+ this.checkUniqueName = (fieldName) => {
354
+ fieldName = fieldName?.trim();
355
+ return of(!!this.aiTable.fields()?.find((field) => field.name === fieldName && this.aiField()?.id !== field.id));
356
+ };
357
+ }
358
+ selectFieldType(fieldType) {
359
+ this.aiField.update((item) => ({ ...item, type: fieldType, name: createDefaultFieldName(this.aiTable, fieldType) }));
360
+ }
361
+ editFieldProperty() {
362
+ if (this.isUpdate) {
363
+ //TODO: updateField
364
+ }
365
+ else {
366
+ Actions.addField(this.aiTable, this.aiField(), [this.aiTable.fields().length]);
367
+ }
368
+ this.thyPopoverRef.close();
369
+ }
370
+ cancel() {
371
+ this.thyPopoverRef.close();
372
+ }
373
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
374
+ 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\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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
375
+ }
376
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableFieldPropertyEditor, decorators: [{
377
+ type: Component,
378
+ args: [{ selector: 'ai-table-field-property-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
379
+ NgIf,
380
+ NgForOf,
381
+ FormsModule,
382
+ ThyIcon,
383
+ ThyInput,
384
+ ThyInputGroup,
385
+ ThyInputCount,
386
+ ThyInputDirective,
387
+ ThyConfirmValidatorDirective,
388
+ ThyUniqueCheckValidator,
389
+ ThyDropdownDirective,
390
+ ThyDropdownMenuComponent,
391
+ ThyDropdownMenuItemDirective,
392
+ ThyDropdownMenuItemNameDirective,
393
+ ThyDropdownMenuItemIconDirective,
394
+ ThyButton,
395
+ ThyFormModule,
396
+ ThyListItem,
397
+ NgTemplateOutlet
398
+ ], host: {
399
+ class: 'field-property-editor d-block pl-5 pr-5 pb-5 pt-4'
400
+ }, 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\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"] }]
401
+ }], ctorParameters: () => [], propDecorators: { aiTable: [{
402
+ type: Input,
403
+ args: [{ required: true }]
404
+ }], aiExternalTemplate: [{
405
+ type: Input
406
+ }], isUpdate: [{
407
+ type: Input,
408
+ args: [{ transform: booleanAttribute }]
409
+ }] } });
410
+
411
+ const AI_TABLE_GRID_FIELD_SERVICE_MAP = new WeakMap();
412
+ class AITableGridFieldService {
413
+ constructor(thyPopover) {
414
+ this.thyPopover = thyPopover;
415
+ }
416
+ initAIFieldConfig(aiFieldConfig) {
417
+ this.aiFieldConfig = aiFieldConfig;
418
+ }
419
+ editFieldProperty(origin, aiTable, aiField, isUpdate) {
420
+ const component = this.aiFieldConfig?.fieldPropertyEditor ?? AITableFieldPropertyEditor;
421
+ this.thyPopover.open(component, {
422
+ origin: origin,
423
+ manualClosure: true,
424
+ placement: 'bottomLeft',
425
+ initialState: {
426
+ aiTable,
427
+ aiField,
428
+ isUpdate
429
+ }
430
+ });
431
+ }
432
+ 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 }); }
433
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService }); }
434
+ }
435
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridFieldService, decorators: [{
436
+ type: Injectable
437
+ }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
438
+
439
+ const DividerMenuItem = {
440
+ id: 'divider'
441
+ };
442
+ const EditFieldPropertyItem = {
443
+ id: 'editFieldProperty',
444
+ name: '编辑列',
445
+ icon: 'edit',
446
+ exec: (aiTable, field, origin) => {
447
+ const fieldService = AI_TABLE_GRID_FIELD_SERVICE_MAP.get(aiTable);
448
+ origin && fieldService?.editFieldProperty(origin, aiTable, field, true);
449
+ }
450
+ };
451
+ const DefaultFieldMenus = [EditFieldPropertyItem];
452
+
290
453
  class AbstractEditCellEditor {
291
454
  constructor() {
292
455
  this.field = input.required();
293
456
  this.record = input.required();
294
- this.aiTable = input.required();
295
457
  this.thyPopoverRef = inject((ThyPopoverRef));
296
458
  }
297
459
  ngOnInit() {
298
460
  this.modelValue = computed(() => {
299
- const path = AITableQueries.findPath(this.aiTable(), this.field(), this.record());
300
- return AITableQueries.getFieldValue(this.aiTable(), path);
461
+ const path = AITableQueries.findPath(this.aiTable, this.field(), this.record());
462
+ return AITableQueries.getFieldValue(this.aiTable, path);
301
463
  })();
302
464
  }
303
465
  updateFieldValue() {
304
- const path = AITableQueries.findPath(this.aiTable(), this.field(), this.record());
305
- Actions.updateFieldValue(this.aiTable(), this.modelValue, path);
466
+ const path = AITableQueries.findPath(this.aiTable, this.field(), this.record());
467
+ Actions.updateFieldValue(this.aiTable, this.modelValue, path);
306
468
  }
307
469
  closePopover() {
308
470
  this.thyPopoverRef.close();
309
471
  }
310
472
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AbstractEditCellEditor, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
311
- 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: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: ``, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
473
+ 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 }); }
312
474
  }
313
475
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AbstractEditCellEditor, decorators: [{
314
476
  type: Component,
@@ -318,7 +480,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
318
480
  standalone: true,
319
481
  changeDetection: ChangeDetectionStrategy.OnPush
320
482
  }]
321
- }] });
483
+ }], propDecorators: { aiTable: [{
484
+ type: Input,
485
+ args: [{ required: true }]
486
+ }] } });
322
487
 
323
488
  class SingleSelectCellEditorComponent extends AbstractEditCellEditor {
324
489
  constructor() {
@@ -567,7 +732,7 @@ class AITableGridEventService {
567
732
  }
568
733
  getEditorComponent(type) {
569
734
  if (this.aiFieldRenderers && this.aiFieldRenderers[type]) {
570
- return this.aiFieldRenderers[type].edit;
735
+ return this.aiFieldRenderers[type].editor;
571
736
  }
572
737
  return GRID_CELL_EDITOR_MAP[type];
573
738
  }
@@ -593,7 +758,7 @@ class AITableGridEventService {
593
758
  initialState: {
594
759
  field: field,
595
760
  record: record,
596
- aiTable: signal(this.aiTable)
761
+ aiTable: this.aiTable
597
762
  },
598
763
  panelClass: 'grid-cell-editor',
599
764
  outsideClosable: false,
@@ -609,132 +774,63 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
609
774
  type: Injectable
610
775
  }], ctorParameters: () => [{ type: i1$1.ThyPopover }] });
611
776
 
612
- const BasicFieldTypes = [
613
- {
614
- type: AITableFieldType.Text,
615
- name: '文本',
616
- icon: 'font'
617
- },
618
- {
619
- type: AITableFieldType.SingleSelect,
620
- name: '单选',
621
- icon: 'check-circle'
622
- },
623
- {
624
- type: AITableFieldType.Number,
625
- name: '数字',
626
- icon: 'hashtag'
627
- },
628
- {
629
- type: AITableFieldType.DateTime,
630
- name: '日期',
631
- icon: 'calendar'
632
- },
633
- {
634
- type: AITableFieldType.Rating,
635
- name: '评分',
636
- icon: 'star-circle'
637
- },
638
- {
639
- type: AITableFieldType.Link,
640
- name: '链接',
641
- icon: 'link-insert'
642
- }
643
- ];
644
- const FieldTypes = [...BasicFieldTypes];
645
- const FieldTypesMap = helpers.keyBy([...FieldTypes], 'type');
646
-
647
- class FieldPropertyEditorComponent {
648
- constructor() {
649
- this.fields = input.required();
650
- this.confirmAction = null;
651
- this.field = signal({ id: idCreator(), type: AITableFieldType.Text, name: '' });
652
- this.fieldType = computed(() => {
653
- return FieldTypesMap[this.field().type];
654
- });
655
- this.fieldMaxLength = 32;
656
- this.validatorConfig = {
657
- validationMessages: {
658
- fieldName: {
659
- required: '列名不能为空',
660
- thyUniqueCheck: '列名已存在'
661
- }
662
- }
663
- };
664
- this.selectableFields = FieldTypes;
665
- this.thyPopoverRef = inject((ThyPopoverRef));
666
- this.checkUniqueName = (fieldName) => {
667
- fieldName = fieldName?.trim();
668
- return of(!!this.fields()?.find((field) => field.name === fieldName));
669
- };
777
+ class FieldMenu {
778
+ execute(menu) {
779
+ const field = signal({ ...this.field });
780
+ menu.exec && menu.exec(this.aiTable, field, this.origin);
670
781
  }
671
- ngOnInit() { }
672
- selectFieldType(fieldType) {
673
- this.field.update((item) => ({ ...item, type: fieldType }));
674
- }
675
- addField() {
676
- this.confirmAction(this.field());
677
- this.thyPopoverRef.close();
678
- }
679
- cancel() {
680
- this.thyPopoverRef.close();
681
- }
682
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldPropertyEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
683
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: FieldPropertyEditorComponent, isStandalone: true, selector: "field-property-editor", inputs: { fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: true, transformFunction: null }, confirmAction: { classPropertyName: "confirmAction", publicName: "confirmAction", isSignal: false, isRequired: true, transformFunction: null } }, 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\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"field().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 <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"addField()\" 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: "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]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
782
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
783
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: FieldMenu, isStandalone: true, selector: "field-menu", inputs: { field: "field", 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 }); }
684
784
  }
685
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldPropertyEditorComponent, decorators: [{
785
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: FieldMenu, decorators: [{
686
786
  type: Component,
687
- args: [{ selector: 'field-property-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
688
- NgIf,
689
- NgForOf,
690
- FormsModule,
787
+ args: [{ selector: 'field-menu', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
691
788
  ThyIcon,
692
- ThyInput,
693
- ThyInputGroup,
694
- ThyInputCount,
695
- ThyInputDirective,
696
- ThyConfirmValidatorDirective,
697
- ThyUniqueCheckValidator,
698
- ThyDropdownDirective,
789
+ ThyDivider,
699
790
  ThyDropdownMenuComponent,
700
791
  ThyDropdownMenuItemDirective,
701
792
  ThyDropdownMenuItemNameDirective,
702
- ThyDropdownMenuItemIconDirective,
703
- ThyButton,
704
- ThyFormModule,
705
- ThyListItem
706
- ], host: {
707
- class: 'field-property-editor d-block pl-5 pr-5 pb-5 pt-4'
708
- }, 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\n name=\"fieldName\"\n [maxlength]=\"fieldMaxLength\"\n [(ngModel)]=\"field().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 <thy-form-group-footer thyAlign=\"right\">\n <button thyButton=\"link-secondary\" (click)=\"cancel()\" thySize=\"sm\">\u53D6\u6D88</button>\n <button thyButton=\"primary\" (thyFormSubmit)=\"addField()\" 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"] }]
709
- }], ctorParameters: () => [], propDecorators: { confirmAction: [{
793
+ ThyDropdownMenuItemIconDirective
794
+ ], 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" }]
795
+ }], propDecorators: { field: [{
796
+ type: Input,
797
+ args: [{ required: true }]
798
+ }], aiTable: [{
799
+ type: Input,
800
+ args: [{ required: true }]
801
+ }], fieldMenus: [{
710
802
  type: Input,
711
803
  args: [{ required: true }]
804
+ }], origin: [{
805
+ type: Input
712
806
  }] } });
713
807
 
714
- class AITableGridComponent {
715
- constructor(elementRef, aiTableGridEventService, thyPopover) {
808
+ class AITableGrid {
809
+ constructor(elementRef, aiTableGridEventService, aiTableGridFieldService) {
716
810
  this.elementRef = elementRef;
717
811
  this.aiTableGridEventService = aiTableGridEventService;
718
- this.thyPopover = thyPopover;
812
+ this.aiTableGridFieldService = aiTableGridFieldService;
719
813
  this.aiRecords = model.required();
720
814
  this.aiFields = model.required();
721
815
  this.aiRowHeight = input();
722
- this.aiFieldRenderers = input();
816
+ this.aiFieldConfig = input();
723
817
  this.aiReadonly = input();
724
818
  this.AITableFieldType = AITableFieldType;
725
819
  this.takeUntilDestroyed = takeUntilDestroyed();
726
820
  this.onChange = output();
821
+ this.aiTableInitialized = output();
727
822
  this.gridData = computed(() => {
728
823
  return buildGridData(this.aiRecords(), this.aiFields());
729
824
  });
730
825
  }
731
826
  ngOnInit() {
732
827
  this.initAITable();
733
- this.aiTableGridEventService.initialize(this.aiTable, this.aiFieldRenderers());
734
- this.aiTableGridEventService.registerEvents(this.elementRef.nativeElement);
828
+ this.initService();
829
+ this.buildFieldMenus();
735
830
  }
736
831
  initAITable() {
737
832
  this.aiTable = createAITable(this.aiRecords, this.aiFields);
833
+ this.aiTableInitialized.emit(this.aiTable);
738
834
  this.aiTable.onChange = () => {
739
835
  this.onChange.emit({
740
836
  records: this.aiRecords(),
@@ -743,26 +839,26 @@ class AITableGridComponent {
743
839
  });
744
840
  };
745
841
  }
842
+ initService() {
843
+ this.aiTableGridEventService.initialize(this.aiTable, this.aiFieldConfig()?.fieldPropertyEditor);
844
+ this.aiTableGridEventService.registerEvents(this.elementRef.nativeElement);
845
+ this.aiTableGridFieldService.initAIFieldConfig(this.aiFieldConfig());
846
+ AI_TABLE_GRID_FIELD_SERVICE_MAP.set(this.aiTable, this.aiTableGridFieldService);
847
+ }
848
+ buildFieldMenus() {
849
+ this.fieldMenus = this.aiFieldConfig()?.fieldMenus ?? DefaultFieldMenus;
850
+ }
746
851
  addRecord() {
747
852
  Actions.addRecord(this.aiTable, getDefaultRecord(this.aiFields()), [this.aiRecords().length]);
748
853
  }
749
- addField(event) {
750
- this.thyPopover.open(FieldPropertyEditorComponent, {
751
- origin: event.currentTarget,
752
- manualClosure: true,
753
- placement: 'bottomLeft',
754
- initialState: {
755
- fields: this.aiFields,
756
- confirmAction: (field) => {
757
- Actions.addField(this.aiTable, field, [this.aiFields().length]);
758
- }
759
- }
760
- });
854
+ addField(gridColumnBlank) {
855
+ const field = signal(createDefaultField(this.aiTable, AITableFieldType.Text));
856
+ this.aiTableGridFieldService.editFieldProperty(gridColumnBlank, this.aiTable, field, false);
761
857
  }
762
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridComponent, deps: [{ token: i0.ElementRef }, { token: AITableGridEventService }, { token: i1$1.ThyPopover }], target: i0.ɵɵFactoryTarget.Component }); }
763
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.0.2", type: AITableGridComponent, 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 }, aiFieldRenderers: { classPropertyName: "aiFieldRenderers", publicName: "aiFieldRenderers", isSignal: true, isRequired: false, transformFunction: null }, aiReadonly: { classPropertyName: "aiReadonly", publicName: "aiReadonly", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { aiRecords: "aiRecordsChange", aiFields: "aiFieldsChange", onChange: "onChange" }, host: { classAttribute: "ai-table-grid" }, providers: [ThyTooltipService, AITableGridEventService], ngImport: i0, template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <input type=\"checkbox\" />\n </div>\n @for (field of gridData().fields; track field.id) {\n <div class=\"grid-cell\">{{ field.name }}</div>\n }\n <div class=\"grid-column-blank cursor-pointer\" (click)=\"addField($event)\"><thy-icon thyIconName=\"plus\"></thy-icon></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\">\n <div class=\"grid-row-index\">\n {{ index + 1 }}\n </div>\n @for (field of gridData().fields; track $index) {\n <div class=\"grid-cell\" [attr.type]=\"[field.type]\" [attr.fieldId]=\"[field.id]\" [attr.recordId]=\"[record.id]\" #cell>\n @switch (field.type) {\n @case (AITableFieldType.SingleSelect) {\n @if (record.value[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.DateTime) {\n {{ record.value[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.Rating) {\n <thy-rate [(ngModel)]=\"record.value[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.Link) {\n <a\n class=\"d-block pl-4 pr-4\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.value[field.id]?.text\"\n [href]=\"record.value[field.id]?.url\"\n target=\"_blank\"\n >{{ record.value[field.id]?.text }}</a\n >\n }\n @default {\n {{ record.value[field.id] }}\n }\n }\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: "ngmodule", type: CommonModule }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
858
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, deps: [{ token: i0.ElementRef }, { token: AITableGridEventService }, { token: AITableGridFieldService }], target: i0.ɵɵFactoryTarget.Component }); }
859
+ 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 } }, outputs: { aiRecords: "aiRecordsChange", aiFields: "aiFieldsChange", onChange: "onChange", aiTableInitialized: "aiTableInitialized" }, host: { classAttribute: "ai-table-grid" }, providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService], ngImport: i0, template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <input type=\"checkbox\" />\n </div>\n @for (field of gridData().fields; track field.id) {\n <div class=\"grid-cell grid-field\" #fieldAction>\n {{ field.name }}\n <a thyAction thyActiveClass=\"active\" thyIcon=\"more-vertical\" [thyDropdown]=\"fieldMenu\" href=\"javascript:;\">\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [field]=\"field\" [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\">\n <div class=\"grid-row-index\">\n {{ index + 1 }}\n </div>\n @for (field of gridData().fields; track $index) {\n <div class=\"grid-cell\" [attr.type]=\"[field.type]\" [attr.fieldId]=\"[field.id]\" [attr.recordId]=\"[record.id]\" #cell>\n @switch (field.type) {\n @case (AITableFieldType.SingleSelect) {\n @if (record.value[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.DateTime) {\n {{ record.value[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.Rating) {\n <thy-rate [(ngModel)]=\"record.value[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.Link) {\n <a\n class=\"d-block pl-4 pr-4\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.value[field.id]?.text\"\n [href]=\"record.value[field.id]?.url\"\n target=\"_blank\"\n >{{ record.value[field.id]?.text }}</a\n >\n }\n @default {\n {{ record.value[field.id] }}\n }\n }\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: "ngmodule", type: CommonModule }, { 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: ["field", "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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
764
860
  }
765
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGridComponent, decorators: [{
861
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: AITableGrid, decorators: [{
766
862
  type: Component,
767
863
  args: [{ selector: 'ai-table-grid', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, host: {
768
864
  class: 'ai-table-grid'
@@ -777,13 +873,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImpor
777
873
  ThyPopoverModule,
778
874
  ThyIcon,
779
875
  ThyRate,
780
- FieldPropertyEditorComponent,
876
+ AITableFieldPropertyEditor,
781
877
  ThyDatePickerFormatPipe,
782
878
  ThyTooltipModule,
783
879
  ThyFlexibleText,
784
- ThyStopPropagationDirective
785
- ], providers: [ThyTooltipService, AITableGridEventService], template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <input type=\"checkbox\" />\n </div>\n @for (field of gridData().fields; track field.id) {\n <div class=\"grid-cell\">{{ field.name }}</div>\n }\n <div class=\"grid-column-blank cursor-pointer\" (click)=\"addField($event)\"><thy-icon thyIconName=\"plus\"></thy-icon></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\">\n <div class=\"grid-row-index\">\n {{ index + 1 }}\n </div>\n @for (field of gridData().fields; track $index) {\n <div class=\"grid-cell\" [attr.type]=\"[field.type]\" [attr.fieldId]=\"[field.id]\" [attr.recordId]=\"[record.id]\" #cell>\n @switch (field.type) {\n @case (AITableFieldType.SingleSelect) {\n @if (record.value[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.DateTime) {\n {{ record.value[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.Rating) {\n <thy-rate [(ngModel)]=\"record.value[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.Link) {\n <a\n class=\"d-block pl-4 pr-4\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.value[field.id]?.text\"\n [href]=\"record.value[field.id]?.url\"\n target=\"_blank\"\n >{{ record.value[field.id]?.text }}</a\n >\n }\n @default {\n {{ record.value[field.id] }}\n }\n }\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" }]
786
- }], ctorParameters: () => [{ type: i0.ElementRef }, { type: AITableGridEventService }, { type: i1$1.ThyPopover }] });
880
+ ThyStopPropagationDirective,
881
+ FieldMenu,
882
+ ThyAction,
883
+ ThyDropdownDirective,
884
+ ThyDropdownMenuComponent
885
+ ], providers: [ThyTooltipService, AITableGridEventService, AITableGridFieldService], template: "<div class=\"grid-header d-flex\">\n <div class=\"grid-column-checkbox grid-cell\">\n <input type=\"checkbox\" />\n </div>\n @for (field of gridData().fields; track field.id) {\n <div class=\"grid-cell grid-field\" #fieldAction>\n {{ field.name }}\n <a thyAction thyActiveClass=\"active\" thyIcon=\"more-vertical\" [thyDropdown]=\"fieldMenu\" href=\"javascript:;\">\n <thy-dropdown-menu #fieldMenu>\n <field-menu [origin]=\"fieldAction\" [field]=\"field\" [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\">\n <div class=\"grid-row-index\">\n {{ index + 1 }}\n </div>\n @for (field of gridData().fields; track $index) {\n <div class=\"grid-cell\" [attr.type]=\"[field.type]\" [attr.fieldId]=\"[field.id]\" [attr.recordId]=\"[record.id]\" #cell>\n @switch (field.type) {\n @case (AITableFieldType.SingleSelect) {\n @if (record.value[field.id] | selectOption: field['options']; as selectedOption) {\n <thy-tag [thyColor]=\"selectedOption!.color!\">{{ selectedOption.name }}</thy-tag>\n }\n }\n @case (AITableFieldType.DateTime) {\n {{ record.value[field.id] | thyDatePickerFormat }}\n }\n @case (AITableFieldType.Rating) {\n <thy-rate [(ngModel)]=\"record.value[field.id]\"></thy-rate>\n }\n @case (AITableFieldType.Link) {\n <a\n class=\"d-block pl-4 pr-4\"\n thyStopPropagation\n thyFlexibleText\n [thyTooltipContent]=\"record.value[field.id]?.text\"\n [href]=\"record.value[field.id]?.url\"\n target=\"_blank\"\n >{{ record.value[field.id]?.text }}</a\n >\n }\n @default {\n {{ record.value[field.id] }}\n }\n }\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" }]
886
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: AITableGridEventService }, { type: AITableGridFieldService }] });
787
887
 
788
888
  var AITableRowHeight;
789
889
  (function (AITableRowHeight) {
@@ -797,5 +897,5 @@ var AITableRowHeight;
797
897
  * Generated bundle index. Do not edit.
798
898
  */
799
899
 
800
- export { AITableFieldType, AITableGridComponent, AITableQueries, AITableRowHeight, AITableStatType, ActionName, Actions, DBL_CLICK_EDIT_TYPE, DEFAULT_COLUMN_WIDTH, ExecuteType, FLUSHING, MIN_COLUMN_WIDTH, RowHeight, SelectOptionPipe, buildGridData, createAITable, getDefaultFieldValue, getDefaultRecord, getRecordOrField, idCreator };
900
+ 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, RowHeight, SelectOptionPipe, buildGridData, createAITable, createDefaultField, createDefaultFieldName, getDefaultFieldValue, getDefaultRecord, getRecordOrField, idCreator };
801
901
  //# sourceMappingURL=ai-table-grid.mjs.map