iss-ctrl 0.0.20 → 0.0.21

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 (25) hide show
  1. package/fesm2022/{iss-ctrl-iss-ctrl-BnwwafES.mjs → iss-ctrl-iss-ctrl-BKu6a5HF.mjs} +645 -591
  2. package/fesm2022/iss-ctrl-iss-ctrl-BKu6a5HF.mjs.map +1 -0
  3. package/fesm2022/{iss-ctrl-load-event-BcWMow3s.mjs → iss-ctrl-load-event-bOt6IlIo.mjs} +3 -3
  4. package/fesm2022/{iss-ctrl-load-event-BcWMow3s.mjs.map → iss-ctrl-load-event-bOt6IlIo.mjs.map} +1 -1
  5. package/fesm2022/{iss-ctrl-load-options-event-sTdrxJYn.mjs → iss-ctrl-load-options-event-CxyAyNMe.mjs} +3 -3
  6. package/fesm2022/{iss-ctrl-load-options-event-sTdrxJYn.mjs.map → iss-ctrl-load-options-event-CxyAyNMe.mjs.map} +1 -1
  7. package/fesm2022/{iss-ctrl-load-value-event-BG9zEexV.mjs → iss-ctrl-load-value-event-DJKJ5S3h.mjs} +3 -3
  8. package/fesm2022/{iss-ctrl-load-value-event-BG9zEexV.mjs.map → iss-ctrl-load-value-event-DJKJ5S3h.mjs.map} +1 -1
  9. package/fesm2022/{iss-ctrl-note.field-DyOSzuIi.mjs → iss-ctrl-note.field-B_Lbp28X.mjs} +2 -2
  10. package/fesm2022/{iss-ctrl-note.field-DyOSzuIi.mjs.map → iss-ctrl-note.field-B_Lbp28X.mjs.map} +1 -1
  11. package/fesm2022/{iss-ctrl-replace-api-keys-CzJkn7fK.mjs → iss-ctrl-replace-api-keys-C0XYQW4i.mjs} +2 -2
  12. package/fesm2022/{iss-ctrl-replace-api-keys-CzJkn7fK.mjs.map → iss-ctrl-replace-api-keys-C0XYQW4i.mjs.map} +1 -1
  13. package/fesm2022/{iss-ctrl-set-value-event-B800MsyP.mjs → iss-ctrl-set-value-event-CgXhi0Bv.mjs} +2 -2
  14. package/fesm2022/{iss-ctrl-set-value-event-B800MsyP.mjs.map → iss-ctrl-set-value-event-CgXhi0Bv.mjs.map} +1 -1
  15. package/fesm2022/{iss-ctrl-table.field-CJmtpHsh.mjs → iss-ctrl-table.field-B5FxF6hn.mjs} +2 -2
  16. package/fesm2022/{iss-ctrl-table.field-CJmtpHsh.mjs.map → iss-ctrl-table.field-B5FxF6hn.mjs.map} +1 -1
  17. package/fesm2022/{iss-ctrl-trigger-based-on-json-value-C5x0hyWn.mjs → iss-ctrl-trigger-based-on-json-value-2v1kLVHZ.mjs} +2 -2
  18. package/fesm2022/{iss-ctrl-trigger-based-on-json-value-C5x0hyWn.mjs.map → iss-ctrl-trigger-based-on-json-value-2v1kLVHZ.mjs.map} +1 -1
  19. package/fesm2022/{iss-ctrl-user-picker.field-CJqIvkMM.mjs → iss-ctrl-user-picker.field-BH63sZ-X.mjs} +2 -2
  20. package/fesm2022/{iss-ctrl-user-picker.field-CJqIvkMM.mjs.map → iss-ctrl-user-picker.field-BH63sZ-X.mjs.map} +1 -1
  21. package/fesm2022/iss-ctrl.mjs +1 -1
  22. package/package.json +1 -1
  23. package/types/iss-ctrl.d.ts +20 -2
  24. package/upgrade.scss +30 -18
  25. package/fesm2022/iss-ctrl-iss-ctrl-BnwwafES.mjs.map +0 -1
@@ -1,11 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { InputSignal, WritableSignal, OutputEmitterRef, OnInit, OnDestroy, Signal, Type, DestroyRef, StaticProvider, InjectionToken, PipeTransform, Injector, Provider } from '@angular/core';
3
- import { ControlValueAccessor, Validator, FormControl, AbstractControl, ValidationErrors, FormGroup, ValidatorFn, AsyncValidatorFn, ControlContainer } from '@angular/forms';
3
+ import { ControlValueAccessor, Validator, FormControl, AbstractControl, ValidationErrors, NgControl, FormGroup, ValidatorFn, AsyncValidatorFn, ControlContainer } from '@angular/forms';
4
+ import { ErrorStateMatcher, MatDateFormats, NativeDateAdapter } from '@angular/material/core';
4
5
  import { MatChipInputEvent } from '@angular/material/chips';
5
6
  import { MatDatepickerInputEvent } from '@angular/material/datepicker';
6
7
  import { PhoneNumber } from 'libphonenumber-js/mobile';
7
8
  import { Observable, BehaviorSubject } from 'rxjs';
8
- import { MatDateFormats, NativeDateAdapter } from '@angular/material/core';
9
9
 
10
10
  interface Option {
11
11
  value: string;
@@ -64,6 +64,7 @@ interface Hint {
64
64
  * ```
65
65
  */
66
66
  declare class ControlBase implements ControlValueAccessor, Validator {
67
+ #private;
67
68
  /**
68
69
  * Name of this control inside the surrounding `FormGroup`.
69
70
  */
@@ -118,12 +119,28 @@ declare class ControlBase implements ControlValueAccessor, Validator {
118
119
  */
119
120
  onChange: OutputEmitterRef<any>;
120
121
  protected ctrl: FormControl;
122
+ /**
123
+ * Error state for the inner `mat-form-field`, derived from the **host** control.
124
+ *
125
+ * Material reads `errorState` off the `NgControl` bound to its own `matInput` — here that is
126
+ * {@link ControlBase.ctrl}, which carries no validators and is therefore always valid. Every
127
+ * error a consumer cares about (the field config's validators plus the control's own
128
+ * {@link ControlBase.validate}) lives on the host control instead, so without this matcher an
129
+ * invalid `iss-ctrl-*` would keep rendering the valid outline. Bind it on the `matInput` as
130
+ * `[errorStateMatcher]="errorStateMatcher"`.
131
+ */
132
+ protected errorStateMatcher: ErrorStateMatcher;
121
133
  registerOnChange(fn: () => void): void;
122
134
  registerOnTouched(fn: () => void): void;
123
135
  setDisabledState(isDisabled: boolean): void;
124
136
  writeValue(value: string | FormData | Date | null): void;
125
137
  markAsTouched(): void;
126
138
  validate(control: AbstractControl): ValidationErrors | null;
139
+ /**
140
+ * The `NgControl` this component is bound to from the outside (`formControlName`,
141
+ * `[formControl]` or `[ngModel]`), or `null` when it is used without one.
142
+ */
143
+ protected hostControl(): NgControl | null;
127
144
  /**
128
145
  * Whether the control currently holds no value.
129
146
  *
@@ -813,6 +830,7 @@ declare class SelectControl extends ControlBase implements OnDestroy {
813
830
  clearSelection(): void;
814
831
  toggleAllSelection(): void;
815
832
  ngOnDestroy(): void;
833
+ protected isEmpty(): boolean;
816
834
  static ɵfac: i0.ɵɵFactoryDeclaration<SelectControl, never>;
817
835
  static ɵcmp: i0.ɵɵComponentDeclaration<SelectControl, "iss-ctrl-select", never, { "options": { "alias": "options"; "required": true; "isSignal": true; }; "height": { "alias": "height"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; }, { "onQueryChange": "onQueryChange"; }, ["optionTemplate", "cardViewerTemplate"], ["label"], true, never>;
818
836
  }
package/upgrade.scss CHANGED
@@ -74,35 +74,47 @@ mat-form-field.mat-mdc-form-field.mat-focused
74
74
  --placeholder-fc: var(--dark-gray) !important;
75
75
  }
76
76
 
77
-
78
- // Outline states. Focus is not a state: while the user is in a field the outline keeps the
79
- // colour it had before the caret arrived, so the only thing the outline reports is validity.
77
+ // Outline states.
80
78
  //
81
- // --input-border-idle snapshots the field's resting border on the mat-form-field element, which
82
- // is also where per-instance overrides such as .filter-input redefine it so a field with a
83
- // custom resting border keeps that one while focused instead of falling back to the default.
79
+ // Two audiences share this stylesheet: the iss-ctrl controls, whose outline reports validity,
80
+ // and every other mat-form-field in the consuming app, which keeps the basic-ui behaviour it
81
+ // had before. Only the .iss-ctrl block below may be unscoped-looking everything outside it
82
+ // lands on app markup too, so it stays as it was.
83
+
84
+ // Global. Focus is not a state: a focused field keeps the outline it had before the caret
85
+ // arrived rather than turning Material's purple.
84
86
  mat-form-field {
85
87
  --input-border-idle: var(--input-border-active, 1px solid var(--black));
88
+ --input-border-valid: 1px solid var(--black);
86
89
  }
87
90
 
88
91
  mat-form-field.mat-mdc-form-field .mdc-text-field--focused {
89
92
  --input-border-active: var(--input-border-idle);
90
93
  }
91
94
 
92
- // An empty field rests on the plain border, and stays there while the caret is in it. The base
93
- // stylesheet keys that off Material's mat-form-field-hide-placeholder, which Material drops as
94
- // soon as the field is focused — so the emptiness comes from the control itself instead, through
95
- // the iss-ctrl-empty host class that ControlBase.isEmpty() reflects.
96
- .iss-ctrl-empty > mat-form-field.mat-mdc-form-field .mdc-text-field {
95
+ // The child combinator keeps an invalid *form* ancestor from painting every field inside it red.
96
+ .ng-touched.ng-invalid > mat-form-field.mat-mdc-form-field .mdc-text-field {
97
+ --input-border-active: var(--input-border-invalid);
98
+ }
99
+
100
+ // iss-ctrl controls only, via the class ControlBase puts on every control host. Here the outline
101
+ // reports validity and nothing else: light while the value is not yet good, dark once it is,
102
+ // red once the user has left an invalid field behind.
103
+ .iss-ctrl > mat-form-field.mat-mdc-form-field .mdc-text-field,
104
+ .iss-ctrl > mat-form-field.mat-mdc-form-field .mdc-text-field--focused {
97
105
  --input-border-active: var(--input-border);
98
106
  }
99
107
 
100
- // Red belongs to a field the user has actually left in a bad state. Angular puts ng-touched and
101
- // ng-invalid on the control host (iss-ctrl-*) the same condition <iss-validation-message-viewer>
102
- // uses — and that is the only reliable signal here: the mat control is bound to the control's
103
- // internal FormControl, which carries no validators, so Material's own --invalid state stays off
104
- // for everything but the errors it raises itself (a datepicker parse/min/max failure, say).
105
- // The child combinator keeps an invalid *form* ancestor from painting every field inside it red.
106
- .ng-touched.ng-invalid > mat-form-field.mat-mdc-form-field .mdc-text-field {
108
+ // :not(.iss-ctrl-empty) is what keeps an untouched optional field out of the dark state: empty
109
+ // and optional is ng-valid too, and should still read as resting rather than as complete.
110
+ .iss-ctrl.ng-valid:not(.iss-ctrl-empty) > mat-form-field.mat-mdc-form-field .mdc-text-field {
111
+ --input-border-active: var(--input-border-valid);
112
+ }
113
+
114
+ // Angular puts ng-touched and ng-invalid on the control host — the same condition
115
+ // <iss-validation-message-viewer> uses. It stays necessary alongside Material's own --invalid
116
+ // state: ControlBase.errorStateMatcher reports the host control to the mat control, but a
117
+ // control used without a host NgControl still has only these classes to go on.
118
+ .iss-ctrl.ng-touched.ng-invalid > mat-form-field.mat-mdc-form-field .mdc-text-field {
107
119
  --input-border-active: var(--input-border-invalid);
108
120
  }