@lucca-front/ng 22.0.3 → 22.1.0-rc.1

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 (70) hide show
  1. package/README.md +0 -1
  2. package/fesm2022/lucca-front-ng-activity-feed.mjs +2 -2
  3. package/fesm2022/lucca-front-ng-activity-feed.mjs.map +1 -1
  4. package/fesm2022/lucca-front-ng-approbation-inbox.mjs +1 -1
  5. package/fesm2022/lucca-front-ng-approbation-inbox.mjs.map +1 -1
  6. package/fesm2022/lucca-front-ng-bubble-icon.mjs +2 -2
  7. package/fesm2022/lucca-front-ng-bubble-icon.mjs.map +1 -1
  8. package/fesm2022/lucca-front-ng-callout.mjs +2 -2
  9. package/fesm2022/lucca-front-ng-callout.mjs.map +1 -1
  10. package/fesm2022/lucca-front-ng-core-select-api.mjs +0 -9
  11. package/fesm2022/lucca-front-ng-core-select-api.mjs.map +1 -1
  12. package/fesm2022/lucca-front-ng-core-select-establishment.mjs +9 -32
  13. package/fesm2022/lucca-front-ng-core-select-establishment.mjs.map +1 -1
  14. package/fesm2022/lucca-front-ng-core-select-job-qualification.mjs +0 -11
  15. package/fesm2022/lucca-front-ng-core-select-job-qualification.mjs.map +1 -1
  16. package/fesm2022/lucca-front-ng-core-select-user.mjs +5 -10
  17. package/fesm2022/lucca-front-ng-core-select-user.mjs.map +1 -1
  18. package/fesm2022/lucca-front-ng-core-select.mjs +29 -65
  19. package/fesm2022/lucca-front-ng-core-select.mjs.map +1 -1
  20. package/fesm2022/lucca-front-ng-core.mjs +5 -1
  21. package/fesm2022/lucca-front-ng-core.mjs.map +1 -1
  22. package/fesm2022/lucca-front-ng-data-table.mjs +5 -8
  23. package/fesm2022/lucca-front-ng-data-table.mjs.map +1 -1
  24. package/fesm2022/lucca-front-ng-date2.mjs +41 -9
  25. package/fesm2022/lucca-front-ng-date2.mjs.map +1 -1
  26. package/fesm2022/lucca-front-ng-dialog.mjs +4 -9
  27. package/fesm2022/lucca-front-ng-dialog.mjs.map +1 -1
  28. package/fesm2022/lucca-front-ng-dropdown.mjs +0 -3
  29. package/fesm2022/lucca-front-ng-dropdown.mjs.map +1 -1
  30. package/fesm2022/lucca-front-ng-filter-pills.mjs +0 -27
  31. package/fesm2022/lucca-front-ng-filter-pills.mjs.map +1 -1
  32. package/fesm2022/lucca-front-ng-form-label.mjs +1 -1
  33. package/fesm2022/lucca-front-ng-form-label.mjs.map +1 -1
  34. package/fesm2022/lucca-front-ng-forms-rich-text-input-formatters-plain-text.mjs +2 -5
  35. package/fesm2022/lucca-front-ng-forms-rich-text-input-formatters-plain-text.mjs.map +1 -1
  36. package/fesm2022/lucca-front-ng-forms-rich-text-input.mjs +24 -56
  37. package/fesm2022/lucca-front-ng-forms-rich-text-input.mjs.map +1 -1
  38. package/fesm2022/lucca-front-ng-index-table.mjs +2 -2
  39. package/fesm2022/lucca-front-ng-index-table.mjs.map +1 -1
  40. package/fesm2022/lucca-front-ng-modal.mjs +2 -7
  41. package/fesm2022/lucca-front-ng-modal.mjs.map +1 -1
  42. package/fesm2022/lucca-front-ng-multi-select.mjs +3 -3
  43. package/fesm2022/lucca-front-ng-multi-select.mjs.map +1 -1
  44. package/fesm2022/lucca-front-ng-popover2.mjs +2 -2
  45. package/fesm2022/lucca-front-ng-popover2.mjs.map +1 -1
  46. package/fesm2022/lucca-front-ng-resource-card.mjs +2 -2
  47. package/fesm2022/lucca-front-ng-resource-card.mjs.map +1 -1
  48. package/fesm2022/lucca-front-ng-safe-content.mjs +3 -40
  49. package/fesm2022/lucca-front-ng-safe-content.mjs.map +1 -1
  50. package/package.json +4 -4
  51. package/schematics/collection.json +0 -5
  52. package/schematics/deprecated-resolver/index.js +4 -1
  53. package/schematics/lib/angular-component-ast.js +1 -3
  54. package/schematics/lib/deprecated-mapper.js +10 -2
  55. package/schematics/lib/html-ast.js +0 -26
  56. package/src/components/_listbox.scss +6 -12
  57. package/types/lucca-front-ng-core-select-api.d.ts +0 -11
  58. package/types/lucca-front-ng-core-select-establishment.d.ts +0 -7
  59. package/types/lucca-front-ng-core-select-job-qualification.d.ts +0 -8
  60. package/types/lucca-front-ng-core-select-user.d.ts +0 -6
  61. package/types/lucca-front-ng-core-select.d.ts +0 -13
  62. package/types/lucca-front-ng-core.d.ts +3 -1
  63. package/types/lucca-front-ng-data-table.d.ts +1 -3
  64. package/types/lucca-front-ng-date2.d.ts +6 -2
  65. package/types/lucca-front-ng-forms-rich-text-input.d.ts +2 -3
  66. package/types/lucca-front-ng-safe-content.d.ts +2 -8
  67. package/schematics/file-upload/index.js +0 -22
  68. package/schematics/file-upload/migration.js +0 -230
  69. package/schematics/file-upload/migration.spec.js +0 -56
  70. package/schematics/file-upload/schema.json +0 -23
@@ -262,6 +262,8 @@ declare function ɵeffectWithDeps<const T extends EffectWithDepsInput>(dependenc
262
262
  */
263
263
  declare function syncInputSignal<T>(signal: ReturnType<typeof input<T>>, setter: (value: T) => void): void;
264
264
 
265
+ declare function capitalize<T extends string>(str: T): Capitalize<T>;
266
+
265
267
  /**
266
268
  * Transforms a boolean or a string representation of a boolean into a boolean.
267
269
  * @template T The specific boolean literal type to narrow to.
@@ -389,5 +391,5 @@ interface ILuTree<T> {
389
391
  disabled?: boolean;
390
392
  }
391
393
 
392
- export { ALuDateAdapter, ALuOnCloseSubscriber, ALuOnOpenSubscriber, ALuOnScrollBottomSubscriber, ELuDateGranularity, IntlParamsPipe, IntlPluralLabelPipe, LOCALE_PLURAL_RULES, LU_NATIVE_DATE_ADAPTER_OPTIONS, LuNativeDateAdapter, LuStringDateAdapter, LuTypeGuardPipe, PORTAL_CONTEXT, PortalDirective, assertNotNil, defaultBreakpoints, generateId, getIntl, getIntlPluralLabel, getPushPanelInlineSize, getPushPanelViewportMargin, injectMediaMinBreakpoint, intlInputOptions, isNil, isNilOrEmptyString, isNotNil, isNotNilOrEmptyString, isRouterLinkParam, luBooleanAttribute, luDefaultNativeDateAdapterOptions, luNullableBooleanAttribute, luNullableNumberAttribute, luNumberAttribute, luOptionalBooleanAttribute, luOptionalNullableBooleanAttribute, luOptionalNullableNumberAttribute, luOptionalNumberAttribute, syncInputSignal, ɵeffectWithDeps };
394
+ export { ALuDateAdapter, ALuOnCloseSubscriber, ALuOnOpenSubscriber, ALuOnScrollBottomSubscriber, ELuDateGranularity, IntlParamsPipe, IntlPluralLabelPipe, LOCALE_PLURAL_RULES, LU_NATIVE_DATE_ADAPTER_OPTIONS, LuNativeDateAdapter, LuStringDateAdapter, LuTypeGuardPipe, PORTAL_CONTEXT, PortalDirective, assertNotNil, capitalize, defaultBreakpoints, generateId, getIntl, getIntlPluralLabel, getPushPanelInlineSize, getPushPanelViewportMargin, injectMediaMinBreakpoint, intlInputOptions, isNil, isNilOrEmptyString, isNotNil, isNotNilOrEmptyString, isRouterLinkParam, luBooleanAttribute, luDefaultNativeDateAdapterOptions, luNullableBooleanAttribute, luNullableNumberAttribute, luNumberAttribute, luOptionalBooleanAttribute, luOptionalNullableBooleanAttribute, luOptionalNullableNumberAttribute, luOptionalNumberAttribute, syncInputSignal, ɵeffectWithDeps };
393
395
  export type { At, Breakpoint, EffectWithDepsInput, EnumValue, ILuDateAdapter, ILuGroup, ILuNativeDateAdapterOptions, ILuOnCloseSubscriber, ILuOnOpenSubscriber, ILuOnScrollBottomSubscriber, ILuTranslation, ILuTree, LuDateGranularity, LuPluralForms, LuTranslation, PortalContent, ResponsiveConfig, ResponsiveProperty, RouterLinkParam };
@@ -63,7 +63,6 @@ declare class DataTableHeadComponent {
63
63
  readonly sticky: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
64
64
  readonly isFirstVisible: _angular_core.WritableSignal<boolean>;
65
65
  readonly cols: _angular_core.Signal<readonly DataTableRowCellHeaderComponent[]>;
66
- tableRef: _lucca_front_ng_data_table.DataTableComponent;
67
66
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataTableHeadComponent, never>;
68
67
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTableHeadComponent, "thead[luDataTableHead]", never, { "sticky": { "alias": "sticky"; "required": false; "isSignal": true; }; }, {}, ["cols"], ["*"], true, never>;
69
68
  }
@@ -98,7 +97,6 @@ declare class DataTableComponent implements OnInit {
98
97
  readonly nested: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
99
98
  readonly drag: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
100
99
  readonly noOverflow: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
101
- readonly empty: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
102
100
  readonly responsive: _angular_core.InputSignal<Partial<Record<"layoutFixedAtMediaMinXXXS" | "layoutFixedAtMediaMinXXS" | "layoutFixedAtMediaMinXS" | "layoutFixedAtMediaMinS" | "layoutFixedAtMediaMinM" | "layoutFixedAtMediaMinL" | "layoutFixedAtMediaMinXL" | "layoutFixedAtMediaMinXXL" | "layoutFixedAtMediaMinXXXL" | "layoutFixedAtContainerMinXXXS" | "layoutFixedAtContainerMinXXS" | "layoutFixedAtContainerMinXS" | "layoutFixedAtContainerMinS" | "layoutFixedAtContainerMinM" | "layoutFixedAtContainerMinL" | "layoutFixedAtContainerMinXL" | "layoutFixedAtContainerMinXXL" | "layoutFixedAtContainerMinXXXL", true>>>;
103
101
  readonly verticalAlign: _angular_core.InputSignal<"top" | "middle" | "bottom">;
104
102
  readonly rows: _angular_core.Signal<readonly DataTableRowComponent[]>;
@@ -134,7 +132,7 @@ declare class DataTableComponent implements OnInit {
134
132
  constructor();
135
133
  ngOnInit(): void;
136
134
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DataTableComponent, never>;
137
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTableComponent, "lu-data-table", never, { "hover": { "alias": "hover"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "layoutFixed": { "alias": "layoutFixed"; "required": false; "isSignal": true; }; "cellBorder": { "alias": "cellBorder"; "required": false; "isSignal": true; }; "nested": { "alias": "nested"; "required": false; "isSignal": true; }; "drag": { "alias": "drag"; "required": false; "isSignal": true; }; "noOverflow": { "alias": "noOverflow"; "required": false; "isSignal": true; }; "empty": { "alias": "empty"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "verticalAlign": { "alias": "verticalAlign"; "required": false; "isSignal": true; }; "stickyColsStart": { "alias": "stickyColsStart"; "required": false; "isSignal": true; }; "stickyColsEnd": { "alias": "stickyColsEnd"; "required": false; "isSignal": true; }; }, {}, ["rows", "header"], ["*", "[dataTablePagination]"], true, never>;
135
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DataTableComponent, "lu-data-table", never, { "hover": { "alias": "hover"; "required": false; "isSignal": true; }; "selectable": { "alias": "selectable"; "required": false; "isSignal": true; }; "layoutFixed": { "alias": "layoutFixed"; "required": false; "isSignal": true; }; "cellBorder": { "alias": "cellBorder"; "required": false; "isSignal": true; }; "nested": { "alias": "nested"; "required": false; "isSignal": true; }; "drag": { "alias": "drag"; "required": false; "isSignal": true; }; "noOverflow": { "alias": "noOverflow"; "required": false; "isSignal": true; }; "responsive": { "alias": "responsive"; "required": false; "isSignal": true; }; "verticalAlign": { "alias": "verticalAlign"; "required": false; "isSignal": true; }; "stickyColsStart": { "alias": "stickyColsStart"; "required": false; "isSignal": true; }; "stickyColsEnd": { "alias": "stickyColsEnd"; "required": false; "isSignal": true; }; }, {}, ["rows", "header"], ["*", "[dataTablePagination]"], true, never>;
138
136
  }
139
137
 
140
138
  declare const LU_DATA_TABLE_INSTANCE: InjectionToken<DataTableComponent>;
@@ -159,6 +159,7 @@ declare class Calendar2Component implements OnInit {
159
159
  declare function getDateFormat(locale: string, mode?: CalendarMode): string;
160
160
  declare function getSeparator(locale: string): string;
161
161
  declare function getLocalizedDateFormat(locale: string, period?: CalendarMode, weekPrefix?: string): string;
162
+ declare function humanizeDate(locale: string, date: Date, mode?: CalendarMode, reference?: Date): string | null;
162
163
 
163
164
  /**
164
165
  * Available DateComponent Types
@@ -234,14 +235,17 @@ declare class DateInputComponent extends AbstractDateComponent implements OnInit
234
235
  readonly disableOverflow: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
235
236
  readonly hideOverflow: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
236
237
  readonly widthAuto: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
238
+ readonly humanized: _angular_core.InputSignalWithTransform<boolean, boolean | "" | "false" | "true">;
237
239
  readonly filterPillDisabled: _angular_core.WritableSignal<boolean>;
238
240
  popoverPositions: ConnectionPositionPair[];
239
241
  readonly inputFocused: _angular_core.WritableSignal<boolean>;
242
+ readonly panelOpen: _angular_core.WritableSignal<boolean>;
240
243
  readonly selectedDate: _angular_core.WritableSignal<Date>;
241
244
  readonly initialValue: _angular_core.WritableSignal<Date>;
242
245
  readonly dateFromWriteValue: _angular_core.WritableSignal<Date>;
243
246
  readonly calendar: _angular_core.Signal<Calendar2Component>;
244
247
  readonly inputRef: _angular_core.Signal<ElementRef<HTMLInputElement>>;
248
+ readonly formattedValue: _angular_core.Signal<string>;
245
249
  readonly displayValue: _angular_core.Signal<string>;
246
250
  readonly userTextInput: _angular_core.WritableSignal<string>;
247
251
  combinedGetCellInfo: (date: Date, mode: CalendarMode) => CellStatus;
@@ -273,7 +277,7 @@ declare class DateInputComponent extends AbstractDateComponent implements OnInit
273
277
  dateClicked(date: Date, popoverRef: PopoverDirective): void;
274
278
  inputBlurred(): void;
275
279
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DateInputComponent, never>;
276
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DateInputComponent, "lu-date-input", never, { "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disableOverflow": { "alias": "disableOverflow"; "required": false; "isSignal": true; }; "hideOverflow": { "alias": "hideOverflow"; "required": false; "isSignal": true; }; "widthAuto": { "alias": "widthAuto"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
280
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DateInputComponent, "lu-date-input", never, { "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "disableOverflow": { "alias": "disableOverflow"; "required": false; "isSignal": true; }; "hideOverflow": { "alias": "hideOverflow"; "required": false; "isSignal": true; }; "widthAuto": { "alias": "widthAuto"; "required": false; "isSignal": true; }; "humanized": { "alias": "humanized"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
277
281
  }
278
282
 
279
283
  interface CalendarShortcut {
@@ -349,5 +353,5 @@ declare class DateRangeInputComponent extends AbstractDateComponent implements O
349
353
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<DateRangeInputComponent, "lu-date-range-input", never, { "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "widthAuto": { "alias": "widthAuto"; "required": false; "isSignal": true; }; "shortcuts": { "alias": "shortcuts"; "required": false; "isSignal": true; }; "autocomplete": { "alias": "autocomplete"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
350
354
  }
351
355
 
352
- export { CALENDAR_MODE, Calendar2Component, DATE2_CLEAR_BEHAVIOR, DATE_FORMAT, DATE_FORMAT_CONST, DATE_ISO_FORMAT, DateInputComponent, DateRangeInputComponent, PremadeShortcuts, getDateFormat, getLocalizedDateFormat, getSeparator };
356
+ export { CALENDAR_MODE, Calendar2Component, DATE2_CLEAR_BEHAVIOR, DATE_FORMAT, DATE_FORMAT_CONST, DATE_ISO_FORMAT, DateInputComponent, DateRangeInputComponent, PremadeShortcuts, getDateFormat, getLocalizedDateFormat, getSeparator, humanizeDate };
353
357
  export type { CalendarMode, CalendarShortcut, CellStatus, Date2ClearBehavior, DateFormat, DateInputValidatorErrorType, DateRange, DateRangeInput };
@@ -246,8 +246,6 @@ type SerializedTagNode = Spread<{
246
246
  tagDescription?: string;
247
247
  disabled?: boolean;
248
248
  }, SerializedLexicalNode>;
249
- /** Destroy stale chip components once Lexical has reconciled the DOM. */
250
- declare function registerTagChipsCleanup(editor: LexicalEditor): () => void;
251
249
  declare class TagNode extends DecoratorNode<string> {
252
250
  #private;
253
251
  setViewContainerRef(vcr: ViewContainerRef): this;
@@ -267,6 +265,7 @@ declare class TagNode extends DecoratorNode<string> {
267
265
  decorate(): string;
268
266
  createDOM(_config: EditorConfig, editor: LexicalEditor): HTMLElement;
269
267
  updateDOM(prevNode: TagNode, _dom: HTMLElement, _config: EditorConfig): boolean;
268
+ remove(preserveEmptyParent?: boolean): void;
270
269
  exportDOM(): DOMExportOutput;
271
270
  static importDOM(): DOMConversionMap;
272
271
  static importJSON(serializedNode: SerializedTagNode): TagNode;
@@ -313,5 +312,5 @@ declare class RichTextInputToolbarComponent implements RichTextPluginComponent {
313
312
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<RichTextInputToolbarComponent, "lu-rich-text-input-toolbar", never, {}, {}, never, never, true, never>;
314
313
  }
315
314
 
316
- export { $createTagNode, $isTagNode, ClearFormatComponent, HeadingsComponent, INITIAL_UPDATE_TAG, LinkComponent, ListStyleToolbarComponent, RICH_TEXT_FORMATTER, RICH_TEXT_PLUGIN_COMPONENT, RichTextFormatter, RichTextInputComponent, RichTextInputToolbarComponent, RichTextPluginTagComponent, TagNode, TextStyleComponent, TextStyleToolbarComponent, registerTagChipsCleanup };
315
+ export { $createTagNode, $isTagNode, ClearFormatComponent, HeadingsComponent, INITIAL_UPDATE_TAG, LinkComponent, ListStyleToolbarComponent, RICH_TEXT_FORMATTER, RICH_TEXT_PLUGIN_COMPONENT, RichTextFormatter, RichTextInputComponent, RichTextInputToolbarComponent, RichTextPluginTagComponent, TagNode, TextStyleComponent, TextStyleToolbarComponent };
317
316
  export type { RichTextPluginComponent, SerializedTagNode, Tag };
@@ -2,6 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { PipeTransform } from '@angular/core';
3
3
  import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
4
4
  import { Config } from 'isomorphic-dompurify';
5
+ export * from '@lucca/prisme/safe-content';
5
6
 
6
7
  type SanitizerConfig = Config & {
7
8
  RETURN_DOM_FRAGMENT?: false | undefined;
@@ -24,11 +25,4 @@ declare class LuSafeContentModule {
24
25
  static ɵinj: i0.ɵɵInjectorDeclaration<LuSafeContentModule>;
25
26
  }
26
27
 
27
- declare class LuSafeExternalSvgPipe implements PipeTransform {
28
- #private;
29
- transform(url: string): SafeHtml;
30
- static ɵfac: i0.ɵɵFactoryDeclaration<LuSafeExternalSvgPipe, never>;
31
- static ɵpipe: i0.ɵɵPipeDeclaration<LuSafeExternalSvgPipe, "luSafeExternalSvg", true>;
32
- }
33
-
34
- export { LuSafeContentModule, LuSafeExternalSvgPipe, LuSafeHtmlPipe };
28
+ export { LuSafeContentModule, LuSafeHtmlPipe };
@@ -1,22 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const lib_1 = require("../lib");
4
- const migration_1 = require("./migration");
5
- // Nx need to see "@angular-devkit/schematics" in order to run this migration correctly (see https://github.com/nrwl/nx/blob/d9fed4b832bf01d1b9a44ae9e486a5e5cd2d2253/packages/nx/src/command-line/migrate/migrate.ts#L1729-L1738)
6
- // eslint-disable-next-line @typescript-eslint/no-require-imports
7
- require('@angular-devkit/schematics');
8
- exports.default = (options) => {
9
- return async (tree, context) => {
10
- await lib_1.currentSchematicContext.init(context, options);
11
- // Templates are reached through their component: rendering a FileEntry or a wrapper needs the
12
- // matching symbol in the `imports` of the component that owns the template.
13
- tree.visit((path, entry) => {
14
- if (path.includes('node_modules') || !entry) {
15
- return;
16
- }
17
- if (path.endsWith('.ts') && !path.endsWith('.d.ts')) {
18
- (0, lib_1.migrateFile)(path, entry, tree, (content) => (0, migration_1.migrateComponent)(path, content, tree));
19
- }
20
- });
21
- };
22
- };
@@ -1,230 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.migrateComponent = migrateComponent;
4
- const change_1 = require("@schematics/angular/utility/change");
5
- const typescript_1 = require("typescript");
6
- const lib_1 = require("../lib");
7
- const fileUploadEntrypoint = '@lucca-front/ng/file-upload';
8
- const wrapperClass = 'fileEntryDisplayWrapper';
9
- /** Alias given to the migrated entry in the generated `@if` block. */
10
- const entryAlias = 'fileEntry';
11
- /** Components whose `size` input has been flipped: `S` became the default, `L` restores the previous rendering. */
12
- const sizedComponents = ['lu-single-file-upload', 'lu-multi-file-upload', 'lu-file-entry'];
13
- /** Inputs `lu-single-file-upload` used to forward to the `lu-file-entry` it rendered itself. */
14
- const fileEntryInputs = ['entry', 'state', 'previewUrl', 'inlineMessageError', 'displayFileName'];
15
- /** Outputs `lu-single-file-upload` used to forward to the `lu-file-entry` it rendered itself. */
16
- const fileEntryOutputs = ['deleteFile'];
17
- function migrateComponent(path, content, tree) {
18
- const sourceFile = (0, typescript_1.createSourceFile)(path, content, typescript_1.ScriptTarget.ESNext);
19
- const symbolsToImport = new Set();
20
- // External templates are rewritten in place, they are not part of the component file.
21
- (0, lib_1.extractNgTemplatesIncludingHtml)(sourceFile, tree, path)
22
- .filter((template) => template.filePath !== path)
23
- .forEach((template) => {
24
- const migrated = migrateTemplate(template.filePath, template.content, symbolsToImport);
25
- if (migrated !== template.content) {
26
- tree.overwrite(template.filePath, migrated);
27
- }
28
- });
29
- const result = (0, lib_1.updateAngularTemplate)(path, content, (template) => migrateTemplate(path, template, symbolsToImport));
30
- if (symbolsToImport.size === 0) {
31
- return result;
32
- }
33
- // Imports are inserted one symbol at a time: every insertion shifts the offsets the next one relies on.
34
- tree.overwrite(path, result);
35
- symbolsToImport.forEach((symbol) => {
36
- const updatedSourceFile = (0, typescript_1.createSourceFile)(path, tree.readText(path), typescript_1.ScriptTarget.ESNext);
37
- const recorder = tree.beginUpdate(path);
38
- (0, change_1.applyToUpdateRecorder)(recorder, [(0, lib_1.insertTSImportIfNeeded)(updatedSourceFile, path, symbol, fileUploadEntrypoint), (0, lib_1.insertAngularImportIfNeeded)(updatedSourceFile, path, symbol)]);
39
- tree.commitUpdate(recorder);
40
- });
41
- return tree.readText(path);
42
- }
43
- /**
44
- * Rules are applied in this order on purpose:
45
- * 1. sizes are normalized first, so that splitting a `lu-single-file-upload` reads an already migrated size;
46
- * 2. the split then emits its own `lu-file-entry-wrapper`, which the class rule must not visit again.
47
- */
48
- function migrateTemplate(path, template, symbolsToImport) {
49
- let result = migrateSize(path, template);
50
- result = migrateFileEntryRendering(path, result, symbolsToImport);
51
- return migrateWrapperClass(path, result, symbolsToImport);
52
- }
53
- function migrateSize(path, template) {
54
- return (0, lib_1.updateContent)(template, (updates) => {
55
- const htmlAst = new lib_1.HtmlAst(template);
56
- sizedComponents.forEach((component) => {
57
- htmlAst.visitElements(component, (element) => {
58
- const boundSize = element.inputs.find((input) => input.name === 'size');
59
- if (boundSize) {
60
- const source = boundSize.value instanceof lib_1.currentSchematicContext.angularCompiler.ASTWithSource ? boundSize.value.source ?? '' : '';
61
- switch (source.trim()) {
62
- case `'S'`:
63
- case `"S"`:
64
- updates.push((0, lib_1.removeAttributeUpdate)(template, boundSize));
65
- lib_1.currentSchematicContext.logSuccess(`Removing redundant [size] on <${component}> in ${path}`);
66
- break;
67
- case 'null':
68
- updates.push({
69
- position: boundSize.value.sourceSpan.start,
70
- oldContent: source,
71
- newContent: source.replace('null', `'L'`),
72
- });
73
- lib_1.currentSchematicContext.logSuccess(`Setting [size] to 'L' on <${component}> in ${path}`);
74
- break;
75
- default:
76
- lib_1.currentSchematicContext.warn(`${path}: [size] of <${component}> is bound to an expression, migrate it manually ('S' is now the default value, 'L' is the previous one).`);
77
- }
78
- return;
79
- }
80
- const size = element.attributes.find((attribute) => attribute.name === 'size');
81
- if (!size) {
82
- updates.push((0, lib_1.addAttributeUpdate)(element, 'size', 'L'));
83
- lib_1.currentSchematicContext.logSuccess(`Adding size="L" on <${component}> in ${path}`);
84
- return;
85
- }
86
- if (size.value === 'S') {
87
- updates.push((0, lib_1.removeAttributeUpdate)(template, size));
88
- lib_1.currentSchematicContext.logSuccess(`Removing redundant size="S" on <${component}> in ${path}`);
89
- return;
90
- }
91
- lib_1.currentSchematicContext.warn(`${path}: size="${size.value}" of <${component}> is not a known value, migrate it manually ('S' is now the default value, 'L' is the previous one).`);
92
- });
93
- });
94
- });
95
- }
96
- /**
97
- * `lu-single-file-upload` no longer renders the `FileEntry` it receives: the parent now displays it itself,
98
- * through a `lu-file-entry` wrapped in a `lu-file-entry-wrapper`.
99
- */
100
- function migrateFileEntryRendering(path, template, symbolsToImport) {
101
- return (0, lib_1.updateContent)(template, (updates) => {
102
- const htmlAst = new lib_1.HtmlAst(template);
103
- htmlAst.visitElements('lu-single-file-upload', (element) => {
104
- const entry = element.inputs.find((input) => input.name === 'entry');
105
- if (!entry) {
106
- if (element.attributes.some((attribute) => attribute.name === 'entry')) {
107
- lib_1.currentSchematicContext.warn(`${path}: <lu-single-file-upload> has a static entry attribute, migrate it manually.`);
108
- }
109
- return;
110
- }
111
- // A size left bound to an expression by the size rule cannot be turned into the `media` of the file
112
- // entry, which is what the file upload used to derive from it.
113
- if (element.inputs.some((input) => input.name === 'size') && !hasSizeL(element)) {
114
- lib_1.currentSchematicContext.warn(`${path}: <lu-single-file-upload [entry]> has a [size] bound to an expression, migrate it manually.`);
115
- return;
116
- }
117
- const openingTag = template.slice(element.startSourceSpan.start.offset, element.startSourceSpan.end.offset);
118
- if (/\s\*[\w-]+/.test(openingTag)) {
119
- lib_1.currentSchematicContext.warn(`${path}: <lu-single-file-upload [entry]> carries a structural directive, migrate it manually.`);
120
- return;
121
- }
122
- const entryExpression = entry.value instanceof lib_1.currentSchematicContext.angularCompiler.ASTWithSource ? (entry.value.source ?? '').trim() : '';
123
- if (!entryExpression) {
124
- lib_1.currentSchematicContext.warn(`${path}: could not read the [entry] expression of <lu-single-file-upload>, migrate it manually.`);
125
- return;
126
- }
127
- updates.push(buildFileEntryRendering(template, element, entryExpression));
128
- symbolsToImport.add('FileEntryComponent');
129
- symbolsToImport.add('FileEntryWrapperComponent');
130
- lib_1.currentSchematicContext.logSuccess(`Extracting the FileEntry of <lu-single-file-upload> in ${path}`);
131
- });
132
- });
133
- }
134
- function buildFileEntryRendering(template, element, entryExpression) {
135
- const start = element.sourceSpan.start.offset;
136
- const end = (element.endSourceSpan ?? element.sourceSpan).end.offset;
137
- const movedAttributes = [
138
- ...element.inputs.filter((input) => fileEntryInputs.includes(input.name)),
139
- ...element.attributes.filter((attribute) => fileEntryInputs.includes(attribute.name)),
140
- ...element.outputs.filter((output) => fileEntryOutputs.includes(output.name)),
141
- ];
142
- // `lu-single-file-upload` used to render its entry as a media only in its large variant, always at size L.
143
- const isLarge = hasSizeL(element);
144
- const hasStructure = [...element.attributes, ...element.inputs].some((attribute) => attribute.name === 'structure');
145
- const fileEntryAttributes = [
146
- `[entry]="${entryAlias}"`,
147
- 'size="L"',
148
- isLarge ? 'media' : '',
149
- hasStructure ? 'structure' : '',
150
- ...movedAttributes.filter((attribute) => attribute.name !== 'entry').map((attribute) => template.slice(attribute.sourceSpan.start.offset, attribute.sourceSpan.end.offset)),
151
- ].filter(Boolean);
152
- // The remaining file upload keeps everything the file entry did not take, formatting included.
153
- const fileUpload = (0, lib_1.applyUpdates)(template.slice(start, end), movedAttributes.map((attribute) => {
154
- const update = (0, lib_1.removeAttributeUpdate)(template, attribute);
155
- return { ...update, position: update.position - start };
156
- }));
157
- const indent = getIndent(template, start);
158
- const unit = indent.includes(' ') && !indent.includes('\t') ? ' ' : '\t';
159
- return {
160
- position: start,
161
- oldContent: template.slice(start, end),
162
- newContent: [
163
- `@if (${entryExpression}; as ${entryAlias}) {`,
164
- `${indent}${unit}<lu-file-entry-wrapper>`,
165
- `${indent}${unit}${unit}<lu-file-entry ${fileEntryAttributes.join(' ')} />`,
166
- `${indent}${unit}</lu-file-entry-wrapper>`,
167
- `${indent}} @else {`,
168
- `${indent}${unit}${fileUpload}`,
169
- `${indent}}`,
170
- ].join('\n'),
171
- };
172
- }
173
- /** The `fileEntryDisplayWrapper` CSS class is now carried by the `lu-file-entry-wrapper` component. */
174
- function migrateWrapperClass(path, template, symbolsToImport) {
175
- return (0, lib_1.updateContent)(template, (updates) => {
176
- const htmlAst = new lib_1.HtmlAst(template);
177
- htmlAst.visitElements(/.*/, (element) => {
178
- const boundClass = element.inputs.find((input) => input.name === 'class' || input.name === `class.${wrapperClass}` || input.name === 'ngClass');
179
- if (boundClass && template.slice(boundClass.sourceSpan.start.offset, boundClass.sourceSpan.end.offset).includes(wrapperClass)) {
180
- lib_1.currentSchematicContext.warn(`${path}: .${wrapperClass} is applied through a binding on <${element.name}>, migrate it manually.`);
181
- return;
182
- }
183
- const classAttribute = element.attributes.find((attribute) => attribute.name === 'class');
184
- const classes = classAttribute?.value.split(/\s+/).filter(Boolean) ?? [];
185
- if (!classes.includes(wrapperClass) || !classAttribute) {
186
- return;
187
- }
188
- updates.push({
189
- position: element.startSourceSpan.start.offset + '<'.length,
190
- oldContent: element.name,
191
- newContent: 'lu-file-entry-wrapper',
192
- });
193
- if (element.endSourceSpan && !element.isSelfClosing) {
194
- updates.push({
195
- position: element.endSourceSpan.start.offset + '</'.length,
196
- oldContent: element.name,
197
- newContent: 'lu-file-entry-wrapper',
198
- });
199
- }
200
- const remainingClasses = classes.filter((className) => className !== wrapperClass);
201
- if (remainingClasses.length === 0) {
202
- updates.push((0, lib_1.removeAttributeUpdate)(template, classAttribute));
203
- }
204
- else if (classAttribute.valueSpan) {
205
- updates.push({
206
- position: classAttribute.valueSpan.start.offset,
207
- oldContent: classAttribute.value,
208
- newContent: remainingClasses.join(' '),
209
- });
210
- }
211
- symbolsToImport.add('FileEntryWrapperComponent');
212
- lib_1.currentSchematicContext.logSuccess(`Replacing .${wrapperClass} with <lu-file-entry-wrapper> in ${path}`);
213
- });
214
- });
215
- }
216
- function hasSizeL(element) {
217
- if (element.attributes.some((attribute) => attribute.name === 'size' && attribute.value === 'L')) {
218
- return true;
219
- }
220
- return element.inputs.some((input) => {
221
- const source = input.value instanceof lib_1.currentSchematicContext.angularCompiler.ASTWithSource ? input.value.source ?? '' : '';
222
- return input.name === 'size' && /^['"]L['"]$/.test(source.trim());
223
- });
224
- }
225
- /** Whitespace preceding the element on its own line, used to indent the generated block. */
226
- function getIndent(template, position) {
227
- const lineStart = template.lastIndexOf('\n', position - 1) + 1;
228
- const prefix = template.slice(lineStart, position);
229
- return /^\s*$/.test(prefix) ? prefix : '';
230
- }
@@ -1,56 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- const path = __importStar(require("path"));
37
- const lib_1 = require("../lib");
38
- const collectionPath = path.normalize(path.join(__dirname, '..', 'collection.json'));
39
- const testsRoot = path.join(__dirname, 'tests');
40
- describe('file-upload Migration', () => {
41
- it('should handle basic case files', async () => {
42
- // Arrange
43
- const tree = (0, lib_1.createTreeFromFolder)(path.join(testsRoot, 'input'));
44
- const expectedTree = (0, lib_1.createTreeFromFolder)(path.join(testsRoot, 'output'));
45
- // Act
46
- try {
47
- await (0, lib_1.runSchematic)('collection', collectionPath, 'file-upload', { skipInstall: true }, tree);
48
- }
49
- catch (error) {
50
- // eslint-disable-next-line no-console
51
- console.log(error);
52
- }
53
- // Assert
54
- (0, lib_1.expectTree)(tree).toMatchTree(expectedTree);
55
- });
56
- });
@@ -1,23 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema",
3
- "$id": "LuccaFrontFileUpload",
4
- "title": "Lucca Front File Upload Schema",
5
- "type": "object",
6
- "properties": {
7
- "dryRun": {
8
- "type": "boolean",
9
- "description": "Run through the migration without making any changes.",
10
- "default": false
11
- },
12
- "skipInstall": {
13
- "type": "boolean",
14
- "description": "Skip installing dependencies.",
15
- "default": false
16
- },
17
- "verbose": {
18
- "type": "boolean",
19
- "description": "Enable verbose logging.",
20
- "default": false
21
- }
22
- }
23
- }