@ai-table/grid 0.0.1 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) 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/cell-editors/number/number-editor.component.mjs +1 -1
  32. package/esm2022/components/field-menu/field-menu.component.mjs +36 -0
  33. package/esm2022/components/field-property-editor/field-property-editor.component.mjs +32 -24
  34. package/esm2022/components/index.mjs +2 -0
  35. package/esm2022/constants/field.mjs +15 -0
  36. package/esm2022/constants/grid.mjs +1 -1
  37. package/esm2022/constants/index.mjs +2 -1
  38. package/esm2022/core/action/field.mjs +1 -1
  39. package/esm2022/core/action/record.mjs +1 -1
  40. package/esm2022/core/constants/field.mjs +4 -4
  41. package/esm2022/core/index.mjs +2 -1
  42. package/esm2022/core/types/action.mjs +1 -1
  43. package/esm2022/core/types/core.mjs +1 -1
  44. package/esm2022/core/utils/field.mjs +12 -1
  45. package/esm2022/core/utils/queries.mjs +1 -1
  46. package/esm2022/grid.component.mjs +41 -30
  47. package/esm2022/public-api.mjs +2 -1
  48. package/esm2022/services/event.service.mjs +4 -4
  49. package/esm2022/services/field.service.mjs +32 -0
  50. package/esm2022/types/field.mjs +2 -0
  51. package/esm2022/types/grid.mjs +1 -1
  52. package/esm2022/types/index.mjs +2 -1
  53. package/fesm2022/ai-table-grid.mjs +237 -137
  54. package/fesm2022/ai-table-grid.mjs.map +1 -1
  55. package/grid.component.d.ts +13 -9
  56. package/grid.component.d.ts.map +1 -1
  57. package/package.json +1 -1
  58. package/public-api.d.ts +1 -0
  59. package/public-api.d.ts.map +1 -1
  60. package/services/field.service.d.ts +16 -0
  61. package/services/field.service.d.ts.map +1 -0
  62. package/{styles.scss → styles/styles.scss} +1 -1
  63. package/types/field.d.ts +11 -0
  64. package/types/field.d.ts.map +1 -0
  65. package/types/grid.d.ts +8 -3
  66. package/types/grid.d.ts.map +1 -1
  67. package/types/index.d.ts +1 -0
  68. 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() {
@@ -400,7 +565,7 @@ class NumberCellEditorComponent extends AbstractEditCellEditor {
400
565
  (thyEnter)="updateValue()"
401
566
  (thyBlur)="updateValue()"
402
567
  placeholder=""
403
- /> `, 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 }); }
568
+ /> `, 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 }); }
404
569
  }
405
570
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.0.2", ngImport: i0, type: NumberCellEditorComponent, decorators: [{
406
571
  type: Component,
@@ -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