@egose/shadcn-theme-ng 0.5.1 → 0.5.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.
@@ -36,6 +36,14 @@ class EgFormCheckbox {
36
36
  ...(ngDevMode ? [{ debugName: "_status" }] : /* istanbul ignore next */ []));
37
37
  _submitted = signal(false, /* @ts-ignore */
38
38
  ...(ngDevMode ? [{ debugName: "_submitted" }] : /* istanbul ignore next */ []));
39
+ /**
40
+ * `touched`/`dirty` are plain flags with no observable: a stepper surfacing
41
+ * errors via `markAllAsTouched()` (no status change, no submit) would
42
+ * otherwise stay invisible under OnPush. Polled in `ngDoCheck` so the
43
+ * computed below recomputes on interaction changes too.
44
+ */
45
+ _interacted = signal(false, /* @ts-ignore */
46
+ ...(ngDevMode ? [{ debugName: "_interacted" }] : /* istanbul ignore next */ []));
39
47
  _trackedControl = null;
40
48
  _controlSub = null;
41
49
  // Classes
@@ -107,10 +115,9 @@ class EgFormCheckbox {
107
115
  showError = computed(() => {
108
116
  this._status();
109
117
  this._submitted();
118
+ this._interacted();
110
119
  const control = this.formGroupDirective.form.get(this.controlName());
111
- return (!!this.resolvedError() &&
112
- !!control?.invalid &&
113
- (control.dirty || control.touched || this._submitted()));
120
+ return !!this.resolvedError() && !!control?.invalid && (this._interacted() || this._submitted());
114
121
  }, /* @ts-ignore */
115
122
  ...(ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []));
116
123
  describedBy() {
@@ -136,11 +143,14 @@ class EgFormCheckbox {
136
143
  const control = this.formGroupDirective.form.get(this.controlName()) ?? null;
137
144
  if (control !== this._trackedControl) {
138
145
  this._trackControl();
146
+ return;
139
147
  }
140
- else if (control && this._status() !== control.status) {
141
- // Fallback poll: catches status changes missed by the subscription
142
- // (e.g. control replaced without re-init).
143
- this._status.set(control.status);
148
+ if (control) {
149
+ if (this._status() !== control.status)
150
+ this._status.set(control.status);
151
+ const interacted = control.touched || control.dirty;
152
+ if (this._interacted() !== interacted)
153
+ this._interacted.set(interacted);
144
154
  }
145
155
  }
146
156
  ngOnDestroy() {
@@ -153,6 +163,7 @@ class EgFormCheckbox {
153
163
  const control = this.formGroupDirective.form.get(this.controlName()) ?? null;
154
164
  this._trackedControl = control;
155
165
  this._status.set(control?.status ?? null);
166
+ this._interacted.set(!!control && (control.touched || control.dirty));
156
167
  if (control) {
157
168
  this._controlSub = control.statusChanges.subscribe((status) => {
158
169
  if (this._status() !== status)
@@ -20,6 +20,13 @@ declare class EgFormCheckbox implements DoCheck, AfterContentInit, OnDestroy {
20
20
  */
21
21
  private readonly _status;
22
22
  private readonly _submitted;
23
+ /**
24
+ * `touched`/`dirty` are plain flags with no observable: a stepper surfacing
25
+ * errors via `markAllAsTouched()` (no status change, no submit) would
26
+ * otherwise stay invisible under OnPush. Polled in `ngDoCheck` so the
27
+ * computed below recomputes on interaction changes too.
28
+ */
29
+ private readonly _interacted;
23
30
  private _trackedControl;
24
31
  private _controlSub;
25
32
  readonly userClass: _angular_core.InputSignal<ClassValue>;
@@ -21,6 +21,14 @@ class EgFormField {
21
21
  */
22
22
  submittedSignal = signal(false, /* @ts-ignore */
23
23
  ...(ngDevMode ? [{ debugName: "submittedSignal" }] : /* istanbul ignore next */ []));
24
+ /**
25
+ * `touched`/`dirty` are plain flags with no observable: surfacing errors via
26
+ * `markAllAsTouched()` (e.g. a stepper blocking `Next` without changing the
27
+ * control status) would otherwise stay invisible under OnPush. Polled in
28
+ * `ngDoCheck` so `hasError` recomputes on interaction changes too.
29
+ */
30
+ interactedSignal = signal(false, /* @ts-ignore */
31
+ ...(ngDevMode ? [{ debugName: "interactedSignal" }] : /* istanbul ignore next */ []));
24
32
  sub = new Subscription();
25
33
  ngAfterContentInit() {
26
34
  const ctrlDir = this.control();
@@ -29,32 +37,41 @@ class EgFormField {
29
37
  this.statusSignal.set(status);
30
38
  }));
31
39
  this.statusSignal.set(ctrlDir.control.status);
40
+ this.interactedSignal.set(ctrlDir.control.touched || ctrlDir.control.dirty);
32
41
  }
33
42
  }
34
43
  ngDoCheck() {
35
44
  const submitted = !!this.formGroupDirective?.submitted;
36
45
  if (this.submittedSignal() !== submitted)
37
46
  this.submittedSignal.set(submitted);
47
+ // NOTE: `control` itself may still be unset on the first pass (this hook
48
+ // runs before the content child's setup), so optional-chain everything.
49
+ const ctrl = this.control()?.control ?? null;
50
+ if (ctrl) {
51
+ const interacted = ctrl.touched || ctrl.dirty;
52
+ if (this.interactedSignal() !== interacted)
53
+ this.interactedSignal.set(interacted);
54
+ }
38
55
  }
39
56
  ngOnDestroy() {
40
57
  this.sub.unsubscribe();
41
58
  }
42
59
  hasError = computed(() => {
43
- const ctrlDir = this.control();
44
- if (!ctrlDir)
60
+ const ctrl = this.control()?.control ?? null;
61
+ if (!ctrl)
45
62
  return false;
46
63
  this.statusSignal();
47
64
  this.submittedSignal();
48
- return (!!ctrlDir.control.errors &&
49
- (ctrlDir.control.touched || ctrlDir.control.dirty || !!this.formGroupDirective?.submitted));
65
+ this.interactedSignal();
66
+ return !!ctrl.errors && (this.interactedSignal() || this.submittedSignal());
50
67
  }, /* @ts-ignore */
51
68
  ...(ngDevMode ? [{ debugName: "hasError" }] : /* istanbul ignore next */ []));
52
69
  firstErrorKey = computed(() => {
53
- const ctrlDir = this.control();
54
- if (!ctrlDir || !ctrlDir.control.errors)
70
+ const ctrl = this.control()?.control ?? null;
71
+ if (!ctrl?.errors)
55
72
  return null;
56
73
  this.statusSignal();
57
- return Object.keys(ctrlDir.control.errors)[0] ?? null;
74
+ return Object.keys(ctrl.errors)[0] ?? null;
58
75
  }, /* @ts-ignore */
59
76
  ...(ngDevMode ? [{ debugName: "firstErrorKey" }] : /* istanbul ignore next */ []));
60
77
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormField, deps: [], target: i0.ɵɵFactoryTarget.Component });
@@ -16,6 +16,13 @@ declare class EgFormField implements AfterContentInit, DoCheck, OnDestroy {
16
16
  * even when the control was never touched/dirty.
17
17
  */
18
18
  private submittedSignal;
19
+ /**
20
+ * `touched`/`dirty` are plain flags with no observable: surfacing errors via
21
+ * `markAllAsTouched()` (e.g. a stepper blocking `Next` without changing the
22
+ * control status) would otherwise stay invisible under OnPush. Polled in
23
+ * `ngDoCheck` so `hasError` recomputes on interaction changes too.
24
+ */
25
+ private interactedSignal;
19
26
  private sub;
20
27
  ngAfterContentInit(): void;
21
28
  ngDoCheck(): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@egose/shadcn-theme-ng",
3
- "version": "0.5.1",
3
+ "version": "0.5.2",
4
4
  "description": "Angular shadcn UI theme",
5
5
  "author": "Junmin Ahn",
6
6
  "bundles": [