@taiga-ui/cdk 2.49.1 → 2.49.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ui/cdk",
3
- "version": "2.49.1",
3
+ "version": "2.49.2",
4
4
  "description": "Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance",
5
5
  "keywords": [
6
6
  "angular",
@@ -21,6 +21,8 @@
21
21
  "@tinkoff/ng-event-plugins": "^2.5.1",
22
22
  "@tinkoff/ng-polymorpheus": "^3.1.12",
23
23
  "@types/resize-observer-browser": "^0.1.7",
24
+ "ng-morph": "^2.0.0",
25
+ "parse5": "^6.0.1",
24
26
  "tslib": "^1.10.0"
25
27
  },
26
28
  "peerDependencies": {
@@ -71,4 +71,22 @@ exports.ATTR_TO_DIRECTIVE = [
71
71
  moduleSpecifier: '@taiga-ui/cdk',
72
72
  },
73
73
  },
74
+ {
75
+ componentSelector: 'tui-input-slider',
76
+ inputProperty: 'size',
77
+ directive: 'tuiTextfieldSize',
78
+ directiveModule: {
79
+ name: 'TuiTextfieldControllerModule',
80
+ moduleSpecifier: '@taiga-ui/core',
81
+ },
82
+ },
83
+ {
84
+ componentSelector: 'tui-input-slider',
85
+ inputProperty: 'secondary',
86
+ directive: 'tuiTextfieldCustomContent',
87
+ directiveModule: {
88
+ name: 'TuiTextfieldControllerModule',
89
+ moduleSpecifier: '@taiga-ui/core',
90
+ },
91
+ },
74
92
  ];
@@ -1,24 +1,69 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const get_component_templates_1 = require("../../../utils/templates/get-component-templates");
3
+ const ng_morph_1 = require("ng-morph");
4
4
  const devkit_file_system_1 = require("ng-morph/project/classes/devkit-file-system");
5
5
  const ng_component_input_manipulations_1 = require("../../../utils/templates/ng-component-input-manipulations");
6
+ const ng_component_1 = require("../../../utils/angular/ng-component");
7
+ const add_unique_import_1 = require("../../../utils/add-unique-import");
8
+ const get_component_templates_1 = require("../../../utils/templates/get-component-templates");
9
+ const elements_1 = require("../../../utils/templates/elements");
6
10
  function migrateInputSlider(tree) {
7
11
  const fileSystem = new devkit_file_system_1.DevkitFileSystem(tree);
8
12
  const templateResources = get_component_templates_1.getComponentTemplates('**/**');
9
13
  for (const templateResource of templateResources) {
10
- ng_component_input_manipulations_1.replaceInputPropertyByDirective({
11
- templateResource,
12
- fileSystem,
13
- componentSelector: 'tui-input-slider',
14
- inputProperty: 'secondary',
15
- directive: 'tuiTextfieldCustomContent',
16
- directiveModule: {
17
- name: 'TuiTextfieldControllerModule',
18
- moduleSpecifier: '@taiga-ui/core',
19
- },
20
- });
14
+ replaceMinMaxLabels(templateResource, fileSystem);
21
15
  }
22
- fileSystem.commitEdits();
23
16
  }
24
17
  exports.migrateInputSlider = migrateInputSlider;
18
+ function replaceMinMaxLabels(templateResource, fileSystem) {
19
+ const wasMaxLabelModified = ng_component_input_manipulations_1.replaceInputProperty({
20
+ templateResource,
21
+ fileSystem,
22
+ componentSelector: 'tui-input-slider',
23
+ from: 'maxLabel',
24
+ to: '[valueContent]',
25
+ newValue: 'tuiMigrationMinMaxLabel',
26
+ });
27
+ const wasMinLabelModified = ng_component_input_manipulations_1.replaceInputProperty({
28
+ templateResource,
29
+ fileSystem,
30
+ componentSelector: 'tui-input-slider',
31
+ from: 'minLabel',
32
+ to: '[valueContent]',
33
+ newValue: 'tuiMigrationMinMaxLabel',
34
+ filterFn: element => !elements_1.hasElementAttribute(element, 'maxLabel'),
35
+ });
36
+ ng_component_input_manipulations_1.removeInputProperty({
37
+ templateResource,
38
+ fileSystem,
39
+ componentSelector: 'tui-input-slider',
40
+ inputProperty: 'minLabel',
41
+ filterFn: element => elements_1.hasElementAttribute(element, 'maxLabel'),
42
+ });
43
+ /**
44
+ * We should update virtual file tree
45
+ * otherwise all following ng-morph commands will overwrite all previous template manipulations
46
+ * */
47
+ fileSystem.commitEdits();
48
+ ng_morph_1.saveActiveProject();
49
+ ng_morph_1.setActiveProject(ng_morph_1.createProject(fileSystem.tree, '/', '**/**'));
50
+ const [ngComponent] = ng_component_1.getNgComponents(templateResource.componentPath);
51
+ if ((wasMaxLabelModified || wasMinLabelModified) && ngComponent) {
52
+ add_unique_import_1.addUniqueImport(templateResource.componentPath, 'TuiContextWithImplicit', '@taiga-ui/cdk');
53
+ ng_morph_1.addMethods(ngComponent, {
54
+ name: 'tuiMigrationMinMaxLabel',
55
+ returnType: 'string',
56
+ parameters: [{ name: 'context', type: 'TuiContextWithImplicit<number>' }],
57
+ statements: [
58
+ 'const currentValue = context.$implicit;',
59
+ 'const maxValue = 100; // TODO replace with the MAX value of the input',
60
+ 'const maxLabelText = "Max"; // TODO replace with the required label',
61
+ 'const minValue = 0; // TODO replace with the MIN value of the input',
62
+ 'const minLabelText = "Min"; // TODO replace with the required label',
63
+ 'if (currentValue === maxValue) return maxLabelText;',
64
+ 'if (currentValue === minValue) return minLabelText;',
65
+ 'return String(currentValue);',
66
+ ],
67
+ });
68
+ }
69
+ }
@@ -6,6 +6,7 @@ const elements_1 = require("../../utils/templates/elements");
6
6
  const devkit_file_system_1 = require("ng-morph/project/classes/devkit-file-system");
7
7
  const ng_component_input_manipulations_1 = require("../../utils/templates/ng-component-input-manipulations");
8
8
  const template_resource_1 = require("../../utils/templates/template-resource");
9
+ const ng_morph_1 = require("ng-morph");
9
10
  const START_TAG_OFFSET = 1;
10
11
  const END_TAG_OFFSET = 2;
11
12
  function migrateTemplates(tree) {
@@ -19,7 +20,13 @@ function migrateTemplates(tree) {
19
20
  replaceTags(template, recorder, offset);
20
21
  replaceAttrs(template, recorder, offset);
21
22
  replaceAttrsByDirective(fileSystem, resource);
23
+ /**
24
+ * We should update virtual file tree
25
+ * otherwise all following ng-morph commands will overwrite all previous template manipulations
26
+ * */
22
27
  fileSystem.commitEdits();
28
+ ng_morph_1.saveActiveProject();
29
+ ng_morph_1.setActiveProject(ng_morph_1.createProject(fileSystem.tree, '/', '**/**'));
23
30
  });
24
31
  }
25
32
  exports.migrateTemplates = migrateTemplates;
@@ -9,11 +9,13 @@ export declare function findElementsWithAttribute(html: string, attributeName: s
9
9
  * Finds elements with explicit tag names that also contain the specified attribute. Returns the
10
10
  * attribute start offset based on the specified HTML.
11
11
  */
12
- export declare function findAttributeOnElementWithTag(html: string, name: string, tagNames: string[]): number[];
12
+ export declare function findAttributeOnElementWithTag(html: string, name: string, tagNames: string[], filterFn?: (element: Element) => boolean): number[];
13
13
  /**
14
14
  * Finds elements that contain the given attribute and contain at least one of the other
15
15
  * specified attributes. Returns the primary attribute's start offset based on the specified HTML.
16
16
  */
17
- export declare function findAttributeOnElementWithAttrs(html: string, name: string, attrs: string[]): number[];
17
+ export declare function findAttributeOnElementWithAttrs(html: string, name: string, attrs: string[], filterFn?: (element: Element) => boolean): number[];
18
+ /** Shorthand function that checks if the specified element contains the given attribute. */
19
+ export declare function hasElementAttribute(element: Element, attributeName: string): boolean;
18
20
  /** Gets the start offset of the given attribute from a Parse5 element. */
19
21
  export declare function getStartOffsetOfAttribute(element: Element, attributeName: string): number;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const parse5_1 = require("parse5");
4
+ const ALWAYS_TRUE_HANDLER = () => true;
4
5
  function findElementsByTagName(html, tagName) {
5
6
  const document = parse5_1.parseFragment(html, { sourceCodeLocationInfo: true });
6
7
  const elements = [];
@@ -46,9 +47,9 @@ exports.findElementsWithAttribute = findElementsWithAttribute;
46
47
  * Finds elements with explicit tag names that also contain the specified attribute. Returns the
47
48
  * attribute start offset based on the specified HTML.
48
49
  */
49
- function findAttributeOnElementWithTag(html, name, tagNames) {
50
+ function findAttributeOnElementWithTag(html, name, tagNames, filterFn = ALWAYS_TRUE_HANDLER) {
50
51
  return findElementsWithAttribute(html, name)
51
- .filter(element => tagNames.includes(element.tagName))
52
+ .filter(element => tagNames.includes(element.tagName) && filterFn(element))
52
53
  .map(element => getStartOffsetOfAttribute(element, name));
53
54
  }
54
55
  exports.findAttributeOnElementWithTag = findAttributeOnElementWithTag;
@@ -56,9 +57,10 @@ exports.findAttributeOnElementWithTag = findAttributeOnElementWithTag;
56
57
  * Finds elements that contain the given attribute and contain at least one of the other
57
58
  * specified attributes. Returns the primary attribute's start offset based on the specified HTML.
58
59
  */
59
- function findAttributeOnElementWithAttrs(html, name, attrs) {
60
+ function findAttributeOnElementWithAttrs(html, name, attrs, filterFn = ALWAYS_TRUE_HANDLER) {
60
61
  return findElementsWithAttribute(html, name)
61
- .filter(element => attrs.some(attr => hasElementAttribute(element, attr)))
62
+ .filter(element => attrs.some(attr => hasElementAttribute(element, attr)) &&
63
+ filterFn(element))
62
64
  .map(element => getStartOffsetOfAttribute(element, name));
63
65
  }
64
66
  exports.findAttributeOnElementWithAttrs = findAttributeOnElementWithAttrs;
@@ -67,6 +69,7 @@ function hasElementAttribute(element, attributeName) {
67
69
  return (element.attrs &&
68
70
  element.attrs.some(attr => attr.name === attributeName.toLowerCase()));
69
71
  }
72
+ exports.hasElementAttribute = hasElementAttribute;
70
73
  /** Gets the start offset of the given attribute from a Parse5 element. */
71
74
  function getStartOffsetOfAttribute(element, attributeName) {
72
75
  var _a, _b;
@@ -1,4 +1,5 @@
1
1
  import { DevkitFileSystem } from 'ng-morph/project/classes/devkit-file-system';
2
+ import { Element } from 'parse5';
2
3
  import { TemplateResource } from '../../ng-update/interfaces/template-resourse';
3
4
  /**
4
5
  * Replace component input property by new value
@@ -25,13 +26,31 @@ import { TemplateResource } from '../../ng-update/interfaces/template-resourse';
25
26
  * ___
26
27
  * @return true if something was changed
27
28
  */
28
- export declare function replaceInputProperty({ templateResource, fileSystem, componentSelector, from, to, }: {
29
+ export declare function replaceInputProperty({ templateResource, fileSystem, componentSelector, from, to, newValue, filterFn, }: {
29
30
  templateResource: TemplateResource;
30
31
  fileSystem: DevkitFileSystem;
31
32
  componentSelector: string | string[];
32
33
  from: string;
33
34
  to: string;
35
+ newValue?: string;
36
+ filterFn?: (element: Element) => boolean;
34
37
  }): boolean;
38
+ /**
39
+ * @example
40
+ * // 10 symbols before property `size` and string `size="s"` has 8-symbols length
41
+ * const template = '<tui-card size="s"></tui-card>';
42
+ *
43
+ * getInputPropertyOffsets(template, 'size', ['tui-card']) // [[10, 18]]
44
+ */
45
+ export declare function getInputPropertyOffsets(html: string, attrName: string, tags: string[], filterFn?: (element: Element) => boolean): [number, number][];
46
+ /**
47
+ * @example
48
+ * // `<tui-card size="` has 16-symbols length
49
+ * const template = '<tui-card size="xl"></tui-card>';
50
+ *
51
+ * getInputPropertyValueOffsets(template, 'size', ['tui-card']) // [ [16, 18] ]
52
+ */
53
+ export declare function getInputPropertyValueOffsets(template: string, attrName: string, tags: string[]): [number, number][];
35
54
  export declare function replaceInputPropertyByDirective({ templateResource, fileSystem, componentSelector, inputProperty, directive, directiveModule, }: {
36
55
  templateResource: TemplateResource;
37
56
  fileSystem: DevkitFileSystem;
@@ -43,3 +62,15 @@ export declare function replaceInputPropertyByDirective({ templateResource, file
43
62
  moduleSpecifier: string;
44
63
  };
45
64
  }): void;
65
+ /**
66
+ * After removing property from the tag (which uses multi lines inside template) it can leave redundant space.
67
+ * It is not critical because html is valid even with this extra space.
68
+ * TODO: Find a way to fix it
69
+ */
70
+ export declare function removeInputProperty({ templateResource, fileSystem, componentSelector, inputProperty, filterFn, }: {
71
+ templateResource: TemplateResource;
72
+ fileSystem: DevkitFileSystem;
73
+ componentSelector: string;
74
+ inputProperty: string;
75
+ filterFn?: (element: Element) => boolean;
76
+ }): void;
@@ -31,7 +31,7 @@ const elements_1 = require("./elements");
31
31
  * ___
32
32
  * @return true if something was changed
33
33
  */
34
- function replaceInputProperty({ templateResource, fileSystem, componentSelector, from, to, }) {
34
+ function replaceInputProperty({ templateResource, fileSystem, componentSelector, from, to, newValue = '', filterFn, }) {
35
35
  const template = template_resource_1.getTemplateFromTemplateResource(templateResource, fileSystem);
36
36
  const path = fileSystem.resolve(template_resource_1.getPathFromTemplateResource(templateResource));
37
37
  const recorder = fileSystem.edit(path);
@@ -40,27 +40,67 @@ function replaceInputProperty({ templateResource, fileSystem, componentSelector,
40
40
  ? componentSelector
41
41
  : [componentSelector];
42
42
  const stringProperties = [
43
- ...elements_1.findAttributeOnElementWithTag(template, from, selector),
44
- ...elements_1.findAttributeOnElementWithAttrs(template, from, selector),
45
- ];
43
+ ...elements_1.findAttributeOnElementWithTag(template, from, selector, filterFn),
44
+ ...elements_1.findAttributeOnElementWithAttrs(template, from, selector, filterFn),
45
+ ].map(offset => templateOffset + offset);
46
46
  const propertyBindings = [
47
- ...elements_1.findAttributeOnElementWithTag(template, `[${from}]`, selector),
48
- ...elements_1.findAttributeOnElementWithAttrs(template, `[${from}]`, selector),
49
- ];
47
+ ...elements_1.findAttributeOnElementWithTag(template, `[${from}]`, selector, filterFn),
48
+ ...elements_1.findAttributeOnElementWithAttrs(template, `[${from}]`, selector, filterFn),
49
+ ].map(offset => templateOffset + offset);
50
+ const propertyValues = newValue
51
+ ? getInputPropertyValueOffsets(template, from, selector).map(([start, end]) => [
52
+ templateOffset + start,
53
+ templateOffset + end,
54
+ ])
55
+ : [];
50
56
  if (!stringProperties.length && !propertyBindings.length) {
51
57
  return false;
52
58
  }
53
59
  stringProperties.forEach(offset => {
54
- recorder.remove(offset + templateOffset, from.length);
55
- recorder.insertRight(offset + templateOffset, to);
60
+ recorder.remove(offset, from.length);
61
+ recorder.insertRight(offset, to);
56
62
  });
57
63
  propertyBindings.forEach(offset => {
58
- recorder.remove(offset + templateOffset, `[${from}]`.length);
59
- recorder.insertRight(offset + templateOffset, `[${to}]`);
64
+ recorder.remove(offset, `[${from}]`.length);
65
+ recorder.insertRight(offset, to.startsWith('[') ? to : `[${to}]`);
66
+ });
67
+ propertyValues.forEach(([startOffset, endOffset]) => {
68
+ recorder.remove(startOffset, endOffset - startOffset);
69
+ recorder.insertRight(startOffset, newValue);
60
70
  });
61
71
  return true;
62
72
  }
63
73
  exports.replaceInputProperty = replaceInputProperty;
74
+ /**
75
+ * @example
76
+ * // 10 symbols before property `size` and string `size="s"` has 8-symbols length
77
+ * const template = '<tui-card size="s"></tui-card>';
78
+ *
79
+ * getInputPropertyOffsets(template, 'size', ['tui-card']) // [[10, 18]]
80
+ */
81
+ function getInputPropertyOffsets(html, attrName, tags, filterFn = () => true) {
82
+ return elements_1.findElementsWithAttribute(html, attrName)
83
+ .filter(element => tags.includes(element.tagName) && filterFn(element))
84
+ .map((element) => {
85
+ var _a, _b;
86
+ const { startOffset = 0, endOffset = 0 } = ((_b = (_a = element.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b[attrName.toLowerCase()]) || {};
87
+ return [startOffset, endOffset];
88
+ });
89
+ }
90
+ exports.getInputPropertyOffsets = getInputPropertyOffsets;
91
+ /**
92
+ * @example
93
+ * // `<tui-card size="` has 16-symbols length
94
+ * const template = '<tui-card size="xl"></tui-card>';
95
+ *
96
+ * getInputPropertyValueOffsets(template, 'size', ['tui-card']) // [ [16, 18] ]
97
+ */
98
+ function getInputPropertyValueOffsets(template, attrName, tags) {
99
+ const stringProperties = getInputPropertyOffsets(template, attrName, tags).map(([start, end]) => [start + attrName.length + '="'.length, end - 1]);
100
+ const propertyBindings = getInputPropertyOffsets(template, `[${attrName}]`, tags).map(([start, end]) => [start + `[${attrName}]`.length + '="'.length, end - 1]);
101
+ return [...stringProperties, ...propertyBindings];
102
+ }
103
+ exports.getInputPropertyValueOffsets = getInputPropertyValueOffsets;
64
104
  function replaceInputPropertyByDirective({ templateResource, fileSystem, componentSelector, inputProperty, directive, directiveModule, }) {
65
105
  const wasModified = replaceInputProperty({
66
106
  templateResource,
@@ -81,3 +121,22 @@ function replaceInputPropertyByDirective({ templateResource, fileSystem, compone
81
121
  }
82
122
  }
83
123
  exports.replaceInputPropertyByDirective = replaceInputPropertyByDirective;
124
+ /**
125
+ * After removing property from the tag (which uses multi lines inside template) it can leave redundant space.
126
+ * It is not critical because html is valid even with this extra space.
127
+ * TODO: Find a way to fix it
128
+ */
129
+ function removeInputProperty({ templateResource, fileSystem, componentSelector, inputProperty, filterFn, }) {
130
+ const template = template_resource_1.getTemplateFromTemplateResource(templateResource, fileSystem);
131
+ const templateOffset = template_resource_1.getTemplateOffset(templateResource);
132
+ const path = fileSystem.resolve(template_resource_1.getPathFromTemplateResource(templateResource));
133
+ const recorder = fileSystem.edit(path);
134
+ const propertyOffsets = [
135
+ ...getInputPropertyOffsets(template, inputProperty, [componentSelector], filterFn),
136
+ ...getInputPropertyOffsets(template, `[${inputProperty}]`, [componentSelector], filterFn),
137
+ ].map(([start, end]) => [templateOffset + start, templateOffset + end]);
138
+ propertyOffsets.forEach(([start, end]) => {
139
+ recorder.remove(start, end - start);
140
+ });
141
+ }
142
+ exports.removeInputProperty = removeInputProperty;