igniteui-angular 22.2.0-rc.0 → 22.2.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.
- package/fesm2022/igniteui-angular-combo.mjs +5 -9
- package/fesm2022/igniteui-angular-combo.mjs.map +1 -1
- package/fesm2022/igniteui-angular-core.mjs +32 -13
- package/fesm2022/igniteui-angular-core.mjs.map +1 -1
- package/fesm2022/igniteui-angular-date-picker.mjs +15 -32
- package/fesm2022/igniteui-angular-date-picker.mjs.map +1 -1
- package/fesm2022/igniteui-angular-input-group.mjs +34 -30
- package/fesm2022/igniteui-angular-input-group.mjs.map +1 -1
- package/fesm2022/igniteui-angular-select.mjs +4 -8
- package/fesm2022/igniteui-angular-select.mjs.map +1 -1
- package/fesm2022/igniteui-angular-time-picker.mjs +7 -17
- package/fesm2022/igniteui-angular-time-picker.mjs.map +1 -1
- package/migrations/common/UpdateChanges.d.ts +36 -0
- package/migrations/common/UpdateChanges.js +175 -31
- package/migrations/common/UpdateChanges.spec.js +66 -0
- package/migrations/update-22_2_0/index.spec.js +73 -0
- package/package.json +1 -1
- package/types/igniteui-angular-core.d.ts +15 -6
- package/types/igniteui-angular-input-group.d.ts +17 -3
- package/types/igniteui-angular-time-picker.d.ts +0 -1
|
@@ -65,6 +65,39 @@ export declare class UpdateChanges {
|
|
|
65
65
|
protected updateClasses(entryPath: string): void;
|
|
66
66
|
protected updateBindings(entryPath: string, bindChanges: BindingChanges, type?: BindingType): void;
|
|
67
67
|
protected updateThemeProps(entryPath: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* Returns the argument list boundaries of every top-level `owner(...)` call in the content.
|
|
70
|
+
* Strings, comments and `url()` tokens are scanned over, so an `owner(` that is only mentioned
|
|
71
|
+
* in one of those is not taken for a call, and a `@mixin` or `@function` that declares the same
|
|
72
|
+
* name is left alone. The brackets are tracked too, so a call nested in another one -
|
|
73
|
+
* `@include scrollbar(scrollbar-theme($sb-size: 6px))` - reports its own closing bracket
|
|
74
|
+
* rather than the one of the call surrounding it.
|
|
75
|
+
*/
|
|
76
|
+
private findFunctionCalls;
|
|
77
|
+
/**
|
|
78
|
+
* Returns the index of the bracket closing the one `start` is inside of, or -1 when the
|
|
79
|
+
* content is unbalanced. Brackets in strings, comments and `url()` tokens are ignored.
|
|
80
|
+
*/
|
|
81
|
+
private findClosingBracket;
|
|
82
|
+
/**
|
|
83
|
+
* Tells whether the name at `index` is the one a `@mixin` or a `@function` declares rather
|
|
84
|
+
* than a call to it. Rewriting a declaration would strip a parameter its body still reads.
|
|
85
|
+
*/
|
|
86
|
+
private isDeclaredName;
|
|
87
|
+
/**
|
|
88
|
+
* When a string, a comment or a `url()` token starts at `index`, returns the index of its last
|
|
89
|
+
* character so that a scan can carry on past it. Returns -1 when `index` is on code.
|
|
90
|
+
*/
|
|
91
|
+
private skipNonCode;
|
|
92
|
+
/**
|
|
93
|
+
* Sass parses an unquoted `url()` as a single token, so a `//` inside one is part of the
|
|
94
|
+
* address - `url(//cdn.example.com/bg.png)` - and not the start of a comment.
|
|
95
|
+
*/
|
|
96
|
+
private isUrlToken;
|
|
97
|
+
/** Returns the index of the bracket closing a `url(` whose contents start at `start`. */
|
|
98
|
+
private skipUrl;
|
|
99
|
+
/** Returns the index of the quote closing the string opened at `start`. */
|
|
100
|
+
private skipString;
|
|
68
101
|
protected isNamedArgument(fileContent: string, i: number, occurrences: number[], change: ThemeChange): boolean;
|
|
69
102
|
protected updateSassVariables(entryPath: string): void;
|
|
70
103
|
protected updateSassFunctionsAndMixins(entryPath: string): void;
|
|
@@ -94,6 +127,9 @@ export declare class UpdateChanges {
|
|
|
94
127
|
* prop: inner-func(),
|
|
95
128
|
* prop2: inner2(inner-param: 3, inner-param: inner-func(..))
|
|
96
129
|
* ```
|
|
130
|
+
*
|
|
131
|
+
* Strings, comments and `url()` tokens are scanned over the same way the rest of the scanner
|
|
132
|
+
* does it, so a `','` inside one of them is not taken for an argument separator.
|
|
97
133
|
*/
|
|
98
134
|
private splitFunctionProps;
|
|
99
135
|
private updateTemplateFiles;
|
|
@@ -47,6 +47,7 @@ const tsUtils_1 = require("./tsUtils");
|
|
|
47
47
|
const util_1 = require("./util");
|
|
48
48
|
const project_service_container_1 = require("./project-service-container");
|
|
49
49
|
const TSCONFIG_PATH = 'tsconfig.json';
|
|
50
|
+
const URL_TOKEN = 'url(';
|
|
50
51
|
var InputPropertyType;
|
|
51
52
|
(function (InputPropertyType) {
|
|
52
53
|
InputPropertyType["EVAL"] = "eval";
|
|
@@ -361,52 +362,187 @@ class UpdateChanges {
|
|
|
361
362
|
}
|
|
362
363
|
}
|
|
363
364
|
updateThemeProps(entryPath) {
|
|
364
|
-
var _a;
|
|
365
365
|
let fileContent = this.host.read(entryPath).toString();
|
|
366
366
|
let overwrite = false;
|
|
367
367
|
for (const change of this.themeChanges.changes) {
|
|
368
368
|
if (change.type !== schema_1.ThemeType.Property) {
|
|
369
369
|
continue;
|
|
370
370
|
}
|
|
371
|
-
if (fileContent.indexOf(change.owner)
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
371
|
+
if (fileContent.indexOf(change.owner) === -1) {
|
|
372
|
+
continue;
|
|
373
|
+
}
|
|
374
|
+
/** owner-func:( * ) */
|
|
375
|
+
const calls = this.findFunctionCalls(fileContent, change.owner);
|
|
376
|
+
// rewrite back to front so the collected indices stay valid
|
|
377
|
+
for (const call of calls.reverse()) {
|
|
378
|
+
const rawBody = fileContent.substring(call.bodyStart, call.bodyEnd);
|
|
379
|
+
if (rawBody.indexOf(change.name) === -1) {
|
|
376
380
|
continue;
|
|
377
381
|
}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
arr.push(param.replace(change.name, change.replaceWith));
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
else {
|
|
396
|
-
arr.push(param);
|
|
397
|
-
}
|
|
398
|
-
return arr;
|
|
399
|
-
}, []);
|
|
400
|
-
fileContent = fileContent.replace(match, opening + params.join(',') + closing);
|
|
401
|
-
overwrite = true;
|
|
382
|
+
const name = (0, util_1.escapeRegExp)(change.name);
|
|
383
|
+
const replaceWith = change.replaceWith ? (0, util_1.escapeRegExp)(change.replaceWith) : undefined;
|
|
384
|
+
const reg = new RegExp(String.raw `^\s*${name}:`);
|
|
385
|
+
const existing = new RegExp(String.raw `${replaceWith}:`);
|
|
386
|
+
// keep whatever sits in front of the closing bracket so the formatting is preserved
|
|
387
|
+
const trailing = /\s*$/.exec(rawBody).pop();
|
|
388
|
+
const body = rawBody.substring(0, rawBody.length - trailing.length);
|
|
389
|
+
let params = this.splitFunctionProps(body);
|
|
390
|
+
params = params.reduce((arr, param) => {
|
|
391
|
+
if (reg.test(param)) {
|
|
392
|
+
const duplicate = !!replaceWith && arr.some(p => existing.test(p));
|
|
393
|
+
if (!change.remove && !duplicate) {
|
|
394
|
+
arr.push(param.replace(change.name, change.replaceWith));
|
|
395
|
+
}
|
|
402
396
|
}
|
|
403
|
-
|
|
397
|
+
else {
|
|
398
|
+
arr.push(param);
|
|
399
|
+
}
|
|
400
|
+
return arr;
|
|
401
|
+
}, []);
|
|
402
|
+
fileContent = fileContent.substring(0, call.bodyStart)
|
|
403
|
+
+ params.join(',')
|
|
404
|
+
+ trailing
|
|
405
|
+
+ fileContent.substring(call.bodyEnd);
|
|
406
|
+
overwrite = true;
|
|
404
407
|
}
|
|
405
408
|
}
|
|
406
409
|
if (overwrite) {
|
|
407
410
|
this.host.overwrite(entryPath, fileContent);
|
|
408
411
|
}
|
|
409
412
|
}
|
|
413
|
+
/**
|
|
414
|
+
* Returns the argument list boundaries of every top-level `owner(...)` call in the content.
|
|
415
|
+
* Strings, comments and `url()` tokens are scanned over, so an `owner(` that is only mentioned
|
|
416
|
+
* in one of those is not taken for a call, and a `@mixin` or `@function` that declares the same
|
|
417
|
+
* name is left alone. The brackets are tracked too, so a call nested in another one -
|
|
418
|
+
* `@include scrollbar(scrollbar-theme($sb-size: 6px))` - reports its own closing bracket
|
|
419
|
+
* rather than the one of the call surrounding it.
|
|
420
|
+
*/
|
|
421
|
+
findFunctionCalls(content, owner) {
|
|
422
|
+
const calls = [];
|
|
423
|
+
const opening = `${owner}(`;
|
|
424
|
+
for (let i = 0; i < content.length; i++) {
|
|
425
|
+
const nonCodeEnd = this.skipNonCode(content, i);
|
|
426
|
+
if (nonCodeEnd !== -1) {
|
|
427
|
+
i = nonCodeEnd;
|
|
428
|
+
continue;
|
|
429
|
+
}
|
|
430
|
+
if (!content.startsWith(opening, i) || this.isDeclaredName(content, i)) {
|
|
431
|
+
continue;
|
|
432
|
+
}
|
|
433
|
+
const bodyStart = i + opening.length;
|
|
434
|
+
const bodyEnd = this.findClosingBracket(content, bodyStart);
|
|
435
|
+
if (bodyEnd === -1) {
|
|
436
|
+
// unbalanced from here on, leave this call rather than the rest of the file
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
calls.push({ bodyStart, bodyEnd });
|
|
440
|
+
// a same-owner call nested in this one is already covered by it
|
|
441
|
+
i = bodyEnd;
|
|
442
|
+
}
|
|
443
|
+
return calls;
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Returns the index of the bracket closing the one `start` is inside of, or -1 when the
|
|
447
|
+
* content is unbalanced. Brackets in strings, comments and `url()` tokens are ignored.
|
|
448
|
+
*/
|
|
449
|
+
findClosingBracket(content, start) {
|
|
450
|
+
let level = 0;
|
|
451
|
+
for (let i = start; i < content.length; i++) {
|
|
452
|
+
const nonCodeEnd = this.skipNonCode(content, i);
|
|
453
|
+
if (nonCodeEnd !== -1) {
|
|
454
|
+
i = nonCodeEnd;
|
|
455
|
+
continue;
|
|
456
|
+
}
|
|
457
|
+
const char = content[i];
|
|
458
|
+
if (char === '(') {
|
|
459
|
+
level++;
|
|
460
|
+
}
|
|
461
|
+
else if (char === ')') {
|
|
462
|
+
if (!level) {
|
|
463
|
+
return i;
|
|
464
|
+
}
|
|
465
|
+
level--;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return -1;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* Tells whether the name at `index` is the one a `@mixin` or a `@function` declares rather
|
|
472
|
+
* than a call to it. Rewriting a declaration would strip a parameter its body still reads.
|
|
473
|
+
*/
|
|
474
|
+
isDeclaredName(content, index) {
|
|
475
|
+
let end = index;
|
|
476
|
+
while (end > 0 && /\s/.test(content[end - 1])) {
|
|
477
|
+
end--;
|
|
478
|
+
}
|
|
479
|
+
let start = end;
|
|
480
|
+
while (start > 0 && /[\w@-]/.test(content[start - 1])) {
|
|
481
|
+
start--;
|
|
482
|
+
}
|
|
483
|
+
const keyword = content.substring(start, end);
|
|
484
|
+
return keyword === '@mixin' || keyword === '@function';
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* When a string, a comment or a `url()` token starts at `index`, returns the index of its last
|
|
488
|
+
* character so that a scan can carry on past it. Returns -1 when `index` is on code.
|
|
489
|
+
*/
|
|
490
|
+
skipNonCode(content, index) {
|
|
491
|
+
const char = content[index];
|
|
492
|
+
const next = content[index + 1];
|
|
493
|
+
if (char === '\'' || char === '"') {
|
|
494
|
+
return this.skipString(content, index);
|
|
495
|
+
}
|
|
496
|
+
if (char === '/' && next === '*') {
|
|
497
|
+
const end = content.indexOf('*/', index + 2);
|
|
498
|
+
return end === -1 ? content.length : end + 1;
|
|
499
|
+
}
|
|
500
|
+
if (char === '/' && next === '/') {
|
|
501
|
+
const end = content.indexOf('\n', index + 2);
|
|
502
|
+
return end === -1 ? content.length : end;
|
|
503
|
+
}
|
|
504
|
+
if (this.isUrlToken(content, index)) {
|
|
505
|
+
return this.skipUrl(content, index + URL_TOKEN.length);
|
|
506
|
+
}
|
|
507
|
+
return -1;
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Sass parses an unquoted `url()` as a single token, so a `//` inside one is part of the
|
|
511
|
+
* address - `url(//cdn.example.com/bg.png)` - and not the start of a comment.
|
|
512
|
+
*/
|
|
513
|
+
isUrlToken(content, index) {
|
|
514
|
+
if (content.substr(index, URL_TOKEN.length).toLowerCase() !== URL_TOKEN) {
|
|
515
|
+
return false;
|
|
516
|
+
}
|
|
517
|
+
const previous = content[index - 1];
|
|
518
|
+
return previous === undefined || !/[\w-]/.test(previous);
|
|
519
|
+
}
|
|
520
|
+
/** Returns the index of the bracket closing a `url(` whose contents start at `start`. */
|
|
521
|
+
skipUrl(content, start) {
|
|
522
|
+
for (let i = start; i < content.length; i++) {
|
|
523
|
+
const char = content[i];
|
|
524
|
+
if (char === '\'' || char === '"') {
|
|
525
|
+
i = this.skipString(content, i);
|
|
526
|
+
}
|
|
527
|
+
else if (char === ')') {
|
|
528
|
+
return i;
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
return content.length;
|
|
532
|
+
}
|
|
533
|
+
/** Returns the index of the quote closing the string opened at `start`. */
|
|
534
|
+
skipString(content, start) {
|
|
535
|
+
const quote = content[start];
|
|
536
|
+
for (let i = start + 1; i < content.length; i++) {
|
|
537
|
+
if (content[i] === '\\') {
|
|
538
|
+
i++;
|
|
539
|
+
}
|
|
540
|
+
else if (content[i] === quote) {
|
|
541
|
+
return i;
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return content.length;
|
|
545
|
+
}
|
|
410
546
|
isNamedArgument(fileContent, i, occurrences, change) {
|
|
411
547
|
const openingBrackets = [];
|
|
412
548
|
const closingBrackets = [];
|
|
@@ -777,12 +913,20 @@ class UpdateChanges {
|
|
|
777
913
|
* prop: inner-func(),
|
|
778
914
|
* prop2: inner2(inner-param: 3, inner-param: inner-func(..))
|
|
779
915
|
* ```
|
|
916
|
+
*
|
|
917
|
+
* Strings, comments and `url()` tokens are scanned over the same way the rest of the scanner
|
|
918
|
+
* does it, so a `','` inside one of them is not taken for an argument separator.
|
|
780
919
|
*/
|
|
781
920
|
splitFunctionProps(body) {
|
|
782
921
|
const parts = [];
|
|
783
922
|
let lastIndex = 0;
|
|
784
923
|
let level = 0;
|
|
785
924
|
for (let i = 0; i < body.length; i++) {
|
|
925
|
+
const nonCodeEnd = this.skipNonCode(body, i);
|
|
926
|
+
if (nonCodeEnd !== -1) {
|
|
927
|
+
i = nonCodeEnd;
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
786
930
|
const char = body[i];
|
|
787
931
|
switch (char) {
|
|
788
932
|
case '(':
|
|
@@ -567,6 +567,72 @@ $var3: igx-comp-theme(
|
|
|
567
567
|
expect(appTree.readContent('test.component.scss')).toEqual(`igx-theme-func($replaced: 10px, $old-prop: 3, $prop3: 2);`);
|
|
568
568
|
done();
|
|
569
569
|
});
|
|
570
|
+
it('should keep the brackets balanced for nested theme functions', done => {
|
|
571
|
+
const themeChangesJson = {
|
|
572
|
+
changes: [
|
|
573
|
+
{
|
|
574
|
+
name: '$remove-me', remove: true,
|
|
575
|
+
owner: 'igx-theme-func',
|
|
576
|
+
type: schema_1.ThemeType.Property
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
name: '$replace-me', replaceWith: '$replaced',
|
|
580
|
+
owner: 'igx-theme-func',
|
|
581
|
+
type: schema_1.ThemeType.Property
|
|
582
|
+
}
|
|
583
|
+
]
|
|
584
|
+
};
|
|
585
|
+
const jsonPath = path.join(__dirname, 'changes', 'theme-changes.json');
|
|
586
|
+
spyOn(fs, 'existsSync').and.callFake((filePath) => filePath === jsonPath);
|
|
587
|
+
spyOn(fs, 'readFileSync').and.callFake(() => JSON.stringify(themeChangesJson));
|
|
588
|
+
appTree.create('styles.scss', `@include igx-mixin(igx-theme-func($remove-me: 6px));
|
|
589
|
+
@include igx-mixin(igx-theme-func($prop1: red, $remove-me: 6px));
|
|
590
|
+
@include igx-mixin(igx-theme-func($remove-me: 6px, $prop1: red));
|
|
591
|
+
@include igx-mixin(igx-theme-func($replace-me: 6px));
|
|
592
|
+
$var: igx-theme-func($content: "not a ( bracket", $remove-me: 6px);
|
|
593
|
+
$var2: igx-theme-func($image: url(https://example.com/a.png), $remove-me: 6px);
|
|
594
|
+
$var3: igx-theme-func(
|
|
595
|
+
$remove-me: 6px, // not a ) bracket
|
|
596
|
+
$prop1: red
|
|
597
|
+
);`);
|
|
598
|
+
const update = new UnitUpdateChanges(__dirname, appTree);
|
|
599
|
+
update.applyChanges();
|
|
600
|
+
expect(appTree.readContent('styles.scss')).toEqual(`@include igx-mixin(igx-theme-func());
|
|
601
|
+
@include igx-mixin(igx-theme-func($prop1: red));
|
|
602
|
+
@include igx-mixin(igx-theme-func( $prop1: red));
|
|
603
|
+
@include igx-mixin(igx-theme-func($replaced: 6px));
|
|
604
|
+
$var: igx-theme-func($content: "not a ( bracket");
|
|
605
|
+
$var2: igx-theme-func($image: url(https://example.com/a.png));
|
|
606
|
+
$var3: igx-theme-func( // not a ) bracket
|
|
607
|
+
$prop1: red
|
|
608
|
+
);`);
|
|
609
|
+
done();
|
|
610
|
+
});
|
|
611
|
+
it('should not treat a theme function mentioned in a comment or a string as a call', done => {
|
|
612
|
+
const themeChangesJson = {
|
|
613
|
+
changes: [
|
|
614
|
+
{
|
|
615
|
+
name: '$remove-me', remove: true,
|
|
616
|
+
owner: 'igx-theme-func',
|
|
617
|
+
type: schema_1.ThemeType.Property
|
|
618
|
+
}
|
|
619
|
+
]
|
|
620
|
+
};
|
|
621
|
+
const jsonPath = path.join(__dirname, 'changes', 'theme-changes.json');
|
|
622
|
+
spyOn(fs, 'existsSync').and.callFake((filePath) => filePath === jsonPath);
|
|
623
|
+
spyOn(fs, 'readFileSync').and.callFake(() => JSON.stringify(themeChangesJson));
|
|
624
|
+
appTree.create('styles.scss', `// igx-theme-func($remove-me: 1px) is gone, use the grid's own borders
|
|
625
|
+
/* igx-theme-func($remove-me: 2px */
|
|
626
|
+
$doc: "igx-theme-func($remove-me: 3px";
|
|
627
|
+
$var: igx-theme-func($remove-me: 4px, $prop1: red);`);
|
|
628
|
+
const update = new UnitUpdateChanges(__dirname, appTree);
|
|
629
|
+
update.applyChanges();
|
|
630
|
+
expect(appTree.readContent('styles.scss')).toEqual(`// igx-theme-func($remove-me: 1px) is gone, use the grid's own borders
|
|
631
|
+
/* igx-theme-func($remove-me: 2px */
|
|
632
|
+
$doc: "igx-theme-func($remove-me: 3px";
|
|
633
|
+
$var: igx-theme-func( $prop1: red);`);
|
|
634
|
+
done();
|
|
635
|
+
});
|
|
570
636
|
it('should replace imports', done => {
|
|
571
637
|
const importsJson = {
|
|
572
638
|
changes: [
|
|
@@ -77,6 +77,79 @@ describe(`Update to ${version}`, () => {
|
|
|
77
77
|
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
78
78
|
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(content);
|
|
79
79
|
}));
|
|
80
|
+
it('should keep the brackets balanced when the theme is nested in another call', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
|
+
appTree.create(`/testSrc/appPrefix/component/test.component.scss`, `.selection-area {
|
|
82
|
+
@include scrollbar(scrollbar-theme($sb-size: 6px));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
igx-grid {
|
|
86
|
+
@include scrollbar(scrollbar-theme($sb-thumb-bg-color: blue, $sb-size: 16px));
|
|
87
|
+
}`);
|
|
88
|
+
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
89
|
+
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(`.selection-area {
|
|
90
|
+
@include scrollbar(scrollbar-theme());
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
igx-grid {
|
|
94
|
+
@include scrollbar(scrollbar-theme($sb-thumb-bg-color: blue));
|
|
95
|
+
}`);
|
|
96
|
+
}));
|
|
97
|
+
it('should migrate a theme call that is not terminated by a semicolon', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
98
|
+
appTree.create(`/testSrc/appPrefix/component/test.component.scss`, `$my-scrollbar: scrollbar-theme(
|
|
99
|
+
$sb-size: 16px,
|
|
100
|
+
$sb-thumb-bg-color: blue
|
|
101
|
+
)`);
|
|
102
|
+
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
103
|
+
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(`$my-scrollbar: scrollbar-theme(
|
|
104
|
+
$sb-thumb-bg-color: blue
|
|
105
|
+
)`);
|
|
106
|
+
}));
|
|
107
|
+
it('should keep a retained property when a comment in the argument list holds an apostrophe', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
108
|
+
appTree.create(`/testSrc/appPrefix/component/test.component.scss`, `$my-scrollbar: scrollbar-theme($sb-size: 6px /* user's size */, $sb-thumb-bg-color: red);`);
|
|
109
|
+
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
110
|
+
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(`$my-scrollbar: scrollbar-theme( $sb-thumb-bg-color: red);`);
|
|
111
|
+
}));
|
|
112
|
+
it('should remove the properties that follow a comment holding an apostrophe', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
113
|
+
appTree.create(`/testSrc/appPrefix/component/test.component.scss`, `$my-scrollbar: scrollbar-theme(
|
|
114
|
+
$sb-size: 16px, // don't need this anymore
|
|
115
|
+
$sb-thumb-bg-color: blue,
|
|
116
|
+
$sb-corner-bg: gray
|
|
117
|
+
);`);
|
|
118
|
+
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
119
|
+
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(`$my-scrollbar: scrollbar-theme( // don't need this anymore
|
|
120
|
+
$sb-thumb-bg-color: blue
|
|
121
|
+
);`);
|
|
122
|
+
}));
|
|
123
|
+
it('should migrate a theme below a comment glued to a closing brace', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
124
|
+
appTree.create(`/testSrc/appPrefix/component/test.component.scss`, `.selection-area {
|
|
125
|
+
color: red;
|
|
126
|
+
}// don't set $sb-size here
|
|
127
|
+
|
|
128
|
+
$my-scrollbar: scrollbar-theme($sb-size: 16px, $sb-thumb-bg-color: blue);`);
|
|
129
|
+
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
130
|
+
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(`.selection-area {
|
|
131
|
+
color: red;
|
|
132
|
+
}// don't set $sb-size here
|
|
133
|
+
|
|
134
|
+
$my-scrollbar: scrollbar-theme( $sb-thumb-bg-color: blue);`);
|
|
135
|
+
}));
|
|
136
|
+
it('should migrate a theme preceded on the same line by a protocol-relative url()', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
137
|
+
appTree.create(`/testSrc/appPrefix/component/test.component.scss`, `.a { background: url(//cdn.example.com/bg.png); $my: scrollbar-theme($sb-size: 16px, $sb-thumb-bg-color: red); }`);
|
|
138
|
+
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
139
|
+
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(`.a { background: url(//cdn.example.com/bg.png); $my: scrollbar-theme( $sb-thumb-bg-color: red); }`);
|
|
140
|
+
}));
|
|
141
|
+
it('should not rewrite a mixin or a function declared with the theme name', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
142
|
+
const content = `@mixin scrollbar-theme($sb-size: 16px) {
|
|
143
|
+
width: $sb-size;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
@function scrollbar-theme($sb-size: 6px) {
|
|
147
|
+
@return ($size: $sb-size);
|
|
148
|
+
}`;
|
|
149
|
+
appTree.create(`/testSrc/appPrefix/component/test.component.scss`, content);
|
|
150
|
+
const tree = yield schematicRunner.runSchematic(migrationName, { shouldInvokeLS: false }, appTree);
|
|
151
|
+
expect(tree.readContent('/testSrc/appPrefix/component/test.component.scss')).toEqual(content);
|
|
152
|
+
}));
|
|
80
153
|
it('should not touch same-named properties on other themes', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
81
154
|
const content = `$my-grid: grid-theme(
|
|
82
155
|
$sb-size: 16px
|
package/package.json
CHANGED
|
@@ -831,6 +831,8 @@ declare class IgxTouchManager {
|
|
|
831
831
|
type NgControlBackend = 'observable' | 'signal';
|
|
832
832
|
/** Whether a control took a value written through `setValue`. */
|
|
833
833
|
type ValueWriteResult = 'accepted' | 'ignored';
|
|
834
|
+
/** Validation outcome of a control, mirroring `FormControlStatus`. */
|
|
835
|
+
type ControlStatus = 'valid' | 'invalid' | 'pending' | 'disabled';
|
|
834
836
|
/**
|
|
835
837
|
* Uniform access to the `NgControl` bound to a form control.
|
|
836
838
|
*
|
|
@@ -852,11 +854,14 @@ declare class NgControlAdapter {
|
|
|
852
854
|
get disabled(): boolean;
|
|
853
855
|
get valid(): boolean;
|
|
854
856
|
get invalid(): boolean;
|
|
857
|
+
get pending(): boolean;
|
|
858
|
+
/** Derived, not read from `status`: the Signal Forms interop throws on a status it does not know. */
|
|
859
|
+
get status(): ControlStatus;
|
|
855
860
|
get touchedOrDirty(): boolean;
|
|
856
861
|
/**
|
|
857
|
-
* Signal Forms expose no rule list. A field that is required, or was
|
|
858
|
-
*
|
|
859
|
-
*
|
|
862
|
+
* Signal Forms expose no rule list. A field that is required, or was invalid or
|
|
863
|
+
* pending since it was last pristine and untouched, is known to have rules;
|
|
864
|
+
* a rule satisfied from that point on stays undetected.
|
|
860
865
|
*/
|
|
861
866
|
get hasValidators(): boolean;
|
|
862
867
|
get required(): boolean;
|
|
@@ -875,8 +880,12 @@ declare class NgControlAdapter {
|
|
|
875
880
|
* (DOM or `ControlValueAccessor`), so the caller must update that instead.
|
|
876
881
|
*/
|
|
877
882
|
setValue(value: unknown): ValueWriteResult;
|
|
878
|
-
/**
|
|
879
|
-
|
|
883
|
+
/**
|
|
884
|
+
* Records that the field has rules. A `[formField]` switch reuses the same interop
|
|
885
|
+
* `NgControl`, so an untouched, pristine control drops earlier observations and keeps
|
|
886
|
+
* only its current state, e.g. an empty field failing a custom rule before the first edit.
|
|
887
|
+
*/
|
|
888
|
+
private observeErrors;
|
|
880
889
|
private watch;
|
|
881
890
|
}
|
|
882
891
|
|
|
@@ -4392,4 +4401,4 @@ declare global {
|
|
|
4392
4401
|
}
|
|
4393
4402
|
|
|
4394
4403
|
export { AbsolutePosition, AbsoluteScrollStrategy, ActionStripResourceStringsEN, AutoPositionStrategy, BannerResourceStringsEN, BaseFilteringStrategy, BaseFitPositionStrategy, BaseFormatter, BlockScrollStrategy, ByLevelTreeGridMergeStrategy, CachedDataCloneStrategy, CalendarDay, CalendarResourceStringsEN, CarouselResourceStringsEN, ChipResourceStringsEN, CloseScrollStrategy, ColumnPinningPosition, ComboResourceStringsEN, ConnectedPositioningStrategy, ContainerPositionStrategy, DEFAULT_LOCALE, DataUtil, DatePart, DatePickerResourceStringsEN, DateRangePickerResourceStringsEN, DateRangeType, DateTimeUtil, DefaultDataCloneStrategy, DefaultMergeStrategy, DefaultSortingStrategy, DefaultTreeGridMergeStrategy, EDITOR_PROVIDER, ELEMENTS_TOKEN, ElasticPositionStrategy, ExpressionsTreeUtil, FilterUtil, FilteringExpressionsTree, FilteringExpressionsTreeType, FilteringLogic, FilteringStrategy, FormattedValuesFilteringStrategy, FormattedValuesSortingStrategy, GlobalPositionStrategy, GridColumnDataType, GridResourceStringsEN, GridSummaryCalculationMode, GroupMemberCountSortingStrategy, GroupedRecords, HorizontalAlignment, I18N_FORMATTER, IgxActionStripActionsToken, IgxActionStripToken, IgxAngularAnimationPlayer, IgxAngularAnimationService, IgxBaseTransactionService, IgxBooleanFilteringOperand, IgxCurrencyFormatterPipe, IgxDataRecordSorting, IgxDateFilteringOperand, IgxDateFormatterPipe, IgxDateSummaryOperand, IgxDateTimeFilteringOperand, IgxFilteringOperand, IgxFlatTransactionFactory, IgxGridTransaction, IgxGrouping, IgxHierarchicalTransactionFactory, IgxHierarchicalTransactionService, IgxNavigationCloseDirective, IgxNavigationService, IgxNavigationToggleDirective, IgxNumberFilteringOperand, IgxNumberFormatterPipe, IgxNumberSummaryOperand, IgxOverlayOutletDirective, IgxOverlayService, IgxPercentFormatterPipe, IgxPickerActionsDirective, IgxPickerClearComponent, IgxPickerToggleComponent, IgxSelectionAPIService, IgxSorting, IgxStringFilteringOperand, IgxStylesRegistrar, IgxSummaryOperand, IgxTimeFilteringOperand, IgxTimeSummaryOperand, IgxTouchManager, IgxTransactionService, InputResourceStringsEN, IntlFormatter, ListResourceStringsEN, NAVIGATION_KEYS, NgControlAdapter, NoOpScrollStrategy, NoopFilteringStrategy, NoopSortingStrategy, OffsetMode, PaginatorResourceStringsEN, PagingError, PickerCalendarOrientation, PickerHeaderOrientation, PickerInteractionMode, PlatformUtil, Point, QueryBuilderResourceStringsEN, RelativePosition, RelativePositionStrategy, ScrollStrategy, SortingDirection, THEME_TOKEN, TRANSACTION_TYPE, ThemeToken, TimePickerResourceStringsEN, TransactionEventOrigin, TransactionType, TreeGridFilteringStrategy, TreeGridFormattedValuesFilteringStrategy, TreeGridMatchingRecordsOnlyFilteringStrategy, TreeResourceStringsEN, Util, VerticalAlignment, WEEKDAYS, areEqualArrays, areSameMonth, calendarRange, changei18n, clamp, cloneArray, cloneHierarchicalArray, cloneValue, cloneValueCached, columnFieldPath, compareMaps, copyDescriptors, daysInWeek, first, flatten, formatToParts, generateMonth, getClosestActiveDate, getComponentCssSizeVar, getComponentSize, getComponentTheme, getCurrentResourceStrings, getHierarchy, getNextActiveDate, getPreviousActiveDate, getResizeObserver, getYearRange, intoChunks, isConstructor, isDate, isDateInRanges, isEqual, isHierarchyMatch, isLeftToRight, isNextMonth, isObject, isPreviousMonth, isTree, last, mergeObjects, modulo, normalizeURI, onResourceChangeHandle, parseDate, provideIgniteIntl, recreateExpression, recreateTree, recreateTreeFromFields, registerI18n, rem, resizeObservable, resolveNestedPath, reverseMapper, runAfterRenderOnce, showMessage, toCalendarDay, trackByIdentity, uniqueDates, Size$1 as ɵSize };
|
|
4395
|
-
export type { Action, AnimationPlayer, AnimationService, CalendarRangeParams, CancelableBrowserEventArgs, CancelableEventArgs, ColumnType, ConnectedFit, CustomDateRange, DatePartDeltas, DatePartInfo, DateRange, DateRangeDescriptor, DayInterval, DayParameter, EditorProvider, EntityType, FieldType, GridSelectionRange, GridStyleCSSProperty, GridTypeBase, HierarchicalState, HierarchicalTransaction, HierarchicalTransactionService, IActionStripResourceStrings, IBannerResourceStrings, IBaseCancelableBrowserEventArgs, IBaseCancelableEventArgs, IBaseEventArgs, ICalendarResourceStrings, ICarouselResourceStrings, IChipResourceStrings, IColumnEditorOptions, IColumnPipeArgs, IColumnSelectionState, IComboResourceStrings, IDataCloneStrategy, IDateParts, IDatePickerResourceStrings, IDateRangePickerResourceStrings, IExpressionTree, IFieldEditorOptions, IFieldPipeArgs, IFilteringExpression, IFilteringExpressionsTree, IFilteringOperation, IFilteringState, IFilteringStrategy, IGridGroupingStrategy, IGridMergeStrategy, IGridResourceStrings, IGridSortingStrategy, IGroupByExpandState, IGroupByKey, IGroupByRecord, IGroupByResult, IGroupingExpression, IGroupingState, IInputResourceStrings, IListResourceStrings, IMergeByResult, IMultiRowLayoutNode, IPaginatorResourceStrings, IPagingState, IPathSegment, IPositionStrategy, IQueryBuilderResourceStrings, IResourceStrings, IScrollStrategy, ISelectionKeyboardState, ISelectionNode, ISelectionPointerState, ISortingExpression, ISortingOptions, ISortingStrategy, ISummaryExpression, ISummaryRecord, ITimePickerResourceStrings, IToggleView, ITreeGridRecord, ITreeResourceStrings, IgcCalendarBaseEventMap, IgxFilterItem, IgxGestureEvent, IgxSummaryResult, IgxTheme, IgxTouchManagerCallbacks, IgxTouchManagerOptions, IgxTreeGridAPIService, KeyOfOrString, MRLColumnSizeInfo, MRLResizeColumnInfo, NgControlBackend, OverlayAnimationEventArgs, OverlayCancelableEventArgs, OverlayClosingEventArgs, OverlayCreateSettings, OverlayEventArgs, OverlaySettings, PositionSettings, RenderPhase, SelectionState, Size, State, StateUpdateEvent, Transaction, TransactionService, ValueWriteResult, WeekDays };
|
|
4404
|
+
export type { Action, AnimationPlayer, AnimationService, CalendarRangeParams, CancelableBrowserEventArgs, CancelableEventArgs, ColumnType, ConnectedFit, ControlStatus, CustomDateRange, DatePartDeltas, DatePartInfo, DateRange, DateRangeDescriptor, DayInterval, DayParameter, EditorProvider, EntityType, FieldType, GridSelectionRange, GridStyleCSSProperty, GridTypeBase, HierarchicalState, HierarchicalTransaction, HierarchicalTransactionService, IActionStripResourceStrings, IBannerResourceStrings, IBaseCancelableBrowserEventArgs, IBaseCancelableEventArgs, IBaseEventArgs, ICalendarResourceStrings, ICarouselResourceStrings, IChipResourceStrings, IColumnEditorOptions, IColumnPipeArgs, IColumnSelectionState, IComboResourceStrings, IDataCloneStrategy, IDateParts, IDatePickerResourceStrings, IDateRangePickerResourceStrings, IExpressionTree, IFieldEditorOptions, IFieldPipeArgs, IFilteringExpression, IFilteringExpressionsTree, IFilteringOperation, IFilteringState, IFilteringStrategy, IGridGroupingStrategy, IGridMergeStrategy, IGridResourceStrings, IGridSortingStrategy, IGroupByExpandState, IGroupByKey, IGroupByRecord, IGroupByResult, IGroupingExpression, IGroupingState, IInputResourceStrings, IListResourceStrings, IMergeByResult, IMultiRowLayoutNode, IPaginatorResourceStrings, IPagingState, IPathSegment, IPositionStrategy, IQueryBuilderResourceStrings, IResourceStrings, IScrollStrategy, ISelectionKeyboardState, ISelectionNode, ISelectionPointerState, ISortingExpression, ISortingOptions, ISortingStrategy, ISummaryExpression, ISummaryRecord, ITimePickerResourceStrings, IToggleView, ITreeGridRecord, ITreeResourceStrings, IgcCalendarBaseEventMap, IgxFilterItem, IgxGestureEvent, IgxSummaryResult, IgxTheme, IgxTouchManagerCallbacks, IgxTouchManagerOptions, IgxTreeGridAPIService, KeyOfOrString, MRLColumnSizeInfo, MRLResizeColumnInfo, NgControlBackend, OverlayAnimationEventArgs, OverlayCancelableEventArgs, OverlayClosingEventArgs, OverlayCreateSettings, OverlayEventArgs, OverlaySettings, PositionSettings, RenderPhase, SelectionState, Size, State, StateUpdateEvent, Transaction, TransactionService, ValueWriteResult, WeekDays };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { OnInit, AfterViewInit, OnDestroy, ElementRef, ChangeDetectorRef, Renderer2, InjectionToken, AfterContentChecked, QueryList } from '@angular/core';
|
|
3
3
|
import { NgModel, NgControl } from '@angular/forms';
|
|
4
|
-
import { IInputResourceStrings, IgxTheme } from 'igniteui-angular/core';
|
|
4
|
+
import { ControlStatus, IInputResourceStrings, IgxTheme } from 'igniteui-angular/core';
|
|
5
5
|
|
|
6
6
|
declare class IgxHintDirective implements OnInit {
|
|
7
7
|
/**
|
|
@@ -80,6 +80,19 @@ declare enum IgxInputState {
|
|
|
80
80
|
VALID = 1,
|
|
81
81
|
INVALID = 2
|
|
82
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Whether an editor may paint the success state.
|
|
85
|
+
*
|
|
86
|
+
* @hidden @internal
|
|
87
|
+
*/
|
|
88
|
+
type SuccessState = 'allowed' | 'suppressed';
|
|
89
|
+
/**
|
|
90
|
+
* Maps a control status to an editor state. A pending async rule has not answered
|
|
91
|
+
* yet, so it reads as initial rather than as an error.
|
|
92
|
+
*
|
|
93
|
+
* @hidden @internal
|
|
94
|
+
*/
|
|
95
|
+
declare function toInputState(status: ControlStatus, success: SuccessState): IgxInputState;
|
|
83
96
|
/**
|
|
84
97
|
* The `igxInput` directive creates single- or multiline text elements, covering common scenarios when dealing with form inputs.
|
|
85
98
|
*
|
|
@@ -261,6 +274,7 @@ declare class IgxInputDirective implements AfterViewInit, OnDestroy {
|
|
|
261
274
|
* @internal
|
|
262
275
|
*/
|
|
263
276
|
protected updateValidityState(): void;
|
|
277
|
+
private updateAriaRequired;
|
|
264
278
|
/**
|
|
265
279
|
* Gets whether the igxInput has a placeholder.
|
|
266
280
|
*
|
|
@@ -695,5 +709,5 @@ declare class IgxInputGroupModule {
|
|
|
695
709
|
static ɵinj: i0.ɵɵInjectorDeclaration<IgxInputGroupModule>;
|
|
696
710
|
}
|
|
697
711
|
|
|
698
|
-
export { IGX_INPUT_GROUP_DIRECTIVES, IGX_INPUT_GROUP_TYPE, IgxHintDirective, IgxInputDirective, IgxInputGroupBase, IgxInputGroupComponent, IgxInputGroupEnum, IgxInputGroupModule, IgxInputState, IgxLabelDirective, IgxPrefixDirective, IgxReadOnlyInputDirective, IgxSuffixDirective };
|
|
699
|
-
export type { IgxInputGroupType };
|
|
712
|
+
export { IGX_INPUT_GROUP_DIRECTIVES, IGX_INPUT_GROUP_TYPE, IgxHintDirective, IgxInputDirective, IgxInputGroupBase, IgxInputGroupComponent, IgxInputGroupEnum, IgxInputGroupModule, IgxInputState, IgxLabelDirective, IgxPrefixDirective, IgxReadOnlyInputDirective, IgxSuffixDirective, toInputState };
|
|
713
|
+
export type { IgxInputGroupType, SuccessState };
|
|
@@ -252,7 +252,6 @@ declare class IgxTimePickerComponent extends PickerBaseDirective implements IgxT
|
|
|
252
252
|
private _cancelButtonLabel;
|
|
253
253
|
private _itemsDelta;
|
|
254
254
|
private _statusChanges$;
|
|
255
|
-
private _ngControl;
|
|
256
255
|
private _control;
|
|
257
256
|
private _onChangeCallback;
|
|
258
257
|
private _onTouchedCallback;
|