@spartan-ng/cli 0.0.1-alpha.657 → 0.0.1-alpha.659

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 (64) hide show
  1. package/package.json +1 -1
  2. package/src/generators/healthcheck/generator.js +2 -0
  3. package/src/generators/healthcheck/generator.js.map +1 -1
  4. package/src/generators/healthcheck/healthchecks/hlm-form-field.d.ts +2 -0
  5. package/src/generators/healthcheck/healthchecks/hlm-form-field.js +35 -0
  6. package/src/generators/healthcheck/healthchecks/hlm-form-field.js.map +1 -0
  7. package/src/generators/migrate-form-field/compat.d.ts +2 -0
  8. package/src/generators/migrate-form-field/compat.js +6 -0
  9. package/src/generators/migrate-form-field/compat.js.map +1 -0
  10. package/src/generators/migrate-form-field/generator.d.ts +4 -0
  11. package/src/generators/migrate-form-field/generator.js +60 -0
  12. package/src/generators/migrate-form-field/generator.js.map +1 -0
  13. package/src/generators/migrate-form-field/schema.d.ts +4 -0
  14. package/src/generators/migrate-form-field/schema.json +19 -0
  15. package/src/generators/ui/libs/autocomplete/files/lib/hlm-autocomplete-input.ts.template +9 -4
  16. package/src/generators/ui/libs/badge/files/lib/hlm-badge.ts.template +7 -8
  17. package/src/generators/ui/libs/card/files/lib/hlm-card-action.ts.template +1 -1
  18. package/src/generators/ui/libs/card/files/lib/hlm-card-content.ts.template +1 -1
  19. package/src/generators/ui/libs/card/files/lib/hlm-card-description.ts.template +1 -1
  20. package/src/generators/ui/libs/card/files/lib/hlm-card-footer.ts.template +1 -4
  21. package/src/generators/ui/libs/card/files/lib/hlm-card-header.ts.template +1 -1
  22. package/src/generators/ui/libs/card/files/lib/hlm-card-title.ts.template +1 -1
  23. package/src/generators/ui/libs/card/files/lib/hlm-card.ts.template +1 -4
  24. package/src/generators/ui/libs/checkbox/files/lib/hlm-checkbox.ts.template +18 -2
  25. package/src/generators/ui/libs/combobox/files/lib/hlm-combobox-chip-input.ts.template +1 -1
  26. package/src/generators/ui/libs/combobox/files/lib/hlm-combobox-chips.ts.template +22 -7
  27. package/src/generators/ui/libs/combobox/files/lib/hlm-combobox-input.ts.template +8 -4
  28. package/src/generators/ui/libs/combobox/files/lib/hlm-combobox-trigger.ts.template +10 -1
  29. package/src/generators/ui/libs/date-picker/files/lib/hlm-date-picker-multi.ts.template +38 -5
  30. package/src/generators/ui/libs/date-picker/files/lib/hlm-date-picker.ts.template +36 -6
  31. package/src/generators/ui/libs/date-picker/files/lib/hlm-date-range-picker.ts.template +33 -4
  32. package/src/generators/ui/libs/field/files/index.ts.template +3 -3
  33. package/src/generators/ui/libs/field/files/lib/hlm-field-content.ts.template +1 -1
  34. package/src/generators/ui/libs/field/files/lib/hlm-field-description.ts.template +40 -2
  35. package/src/generators/ui/libs/field/files/lib/hlm-field-error.ts.template +89 -27
  36. package/src/generators/ui/libs/field/files/lib/hlm-field-group.ts.template +1 -1
  37. package/src/generators/ui/libs/field/files/lib/hlm-field-legend.ts.template +2 -2
  38. package/src/generators/ui/libs/field/files/lib/hlm-field.ts.template +9 -6
  39. package/src/generators/ui/libs/input/files/lib/hlm-input.ts.template +10 -69
  40. package/src/generators/ui/libs/input-group/files/lib/hlm-input-group.ts.template +15 -5
  41. package/src/generators/ui/libs/label/files/lib/hlm-label.ts.template +4 -1
  42. package/src/generators/ui/libs/native-select/files/lib/hlm-native-select.ts.template +32 -13
  43. package/src/generators/ui/libs/radio-group/files/lib/hlm-radio-group.ts.template +18 -2
  44. package/src/generators/ui/libs/radio-group/files/lib/hlm-radio.ts.template +16 -1
  45. package/src/generators/ui/libs/select/files/lib/hlm-select-trigger.ts.template +5 -2
  46. package/src/generators/ui/libs/slider/files/lib/hlm-slider.ts.template +3 -4
  47. package/src/generators/ui/libs/textarea/files/lib/hlm-textarea.ts.template +10 -71
  48. package/src/generators/ui/primitive-deps.js +0 -1
  49. package/src/generators/ui/primitive-deps.js.map +1 -1
  50. package/src/generators/ui/primitives.d.ts +1 -1
  51. package/src/generators/ui/style-luma.css +1365 -0
  52. package/src/generators/ui/style-lyra.css +24 -24
  53. package/src/generators/ui/style-maia.css +24 -24
  54. package/src/generators/ui/style-mira.css +24 -24
  55. package/src/generators/ui/style-nova.css +24 -24
  56. package/src/generators/ui/style-vega.css +24 -24
  57. package/src/generators/ui/supported-ui-libraries.json +54 -56
  58. package/src/generators/ui/libs/form-field/files/index.ts.template +0 -9
  59. package/src/generators/ui/libs/form-field/files/lib/hlm-error.ts.template +0 -12
  60. package/src/generators/ui/libs/form-field/files/lib/hlm-form-field.ts.template +0 -39
  61. package/src/generators/ui/libs/form-field/files/lib/hlm-hint.ts.template +0 -12
  62. package/src/generators/ui/libs/form-field/generator.d.ts +0 -3
  63. package/src/generators/ui/libs/form-field/generator.js +0 -9
  64. package/src/generators/ui/libs/form-field/generator.js.map +0 -1
@@ -5,19 +5,20 @@ import {
5
5
  Component,
6
6
  computed,
7
7
  forwardRef,
8
+ inject,
8
9
  input,
9
10
  linkedSignal,
10
11
  model,
11
12
  output,
12
13
  } from '@angular/core';
13
- import { type ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
14
+ import { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms';
14
15
  import { NgIcon, provideIcons } from '@ng-icons/core';
15
16
  import { lucideChevronDown } from '@ng-icons/lucide';
16
- import type { ChangeFn, TouchFn } from '@spartan-ng/brain/forms';
17
+ import { BrnFieldControl, provideBrnLabelable } from '@spartan-ng/brain/field';
18
+ import { type ChangeFn, type TouchFn } from '@spartan-ng/brain/forms';
17
19
  import { classes, hlm } from '<%- importAlias %>/utils';
18
20
  import type { ClassValue } from 'clsx';
19
21
 
20
- // TODO support BrnFormFieldControl
21
22
  export const HLM_NATIVE_SELECT_VALUE_ACCESSOR = {
22
23
  provide: NG_VALUE_ACCESSOR,
23
24
  useExisting: forwardRef(() => HlmNativeSelect),
@@ -27,8 +28,13 @@ export const HLM_NATIVE_SELECT_VALUE_ACCESSOR = {
27
28
  @Component({
28
29
  selector: 'hlm-native-select',
29
30
  imports: [NgIcon],
30
- providers: [HLM_NATIVE_SELECT_VALUE_ACCESSOR, provideIcons({ lucideChevronDown })],
31
+ providers: [
32
+ HLM_NATIVE_SELECT_VALUE_ACCESSOR,
33
+ provideIcons({ lucideChevronDown }),
34
+ provideBrnLabelable(HlmNativeSelect),
35
+ ],
31
36
  changeDetection: ChangeDetectionStrategy.OnPush,
37
+ hostDirectives: [BrnFieldControl],
32
38
  host: {
33
39
  'data-slot': 'native-select-wrapper',
34
40
  '[attr.data-size]': 'size()',
@@ -36,10 +42,14 @@ export const HLM_NATIVE_SELECT_VALUE_ACCESSOR = {
36
42
  template: `
37
43
  <select
38
44
  data-slot="native-select"
39
- [id]="_selectId()"
45
+ [id]="selectId()"
40
46
  [class]="_computedSelectClass()"
41
47
  [attr.data-size]="size()"
42
- [attr.aria-invalid]="ariaInvalid() ? 'true' : null"
48
+ [attr.aria-invalid]="_ariaInvalid() ? 'true' : null"
49
+ [attr.data-invalid]="_ariaInvalid() ? 'true' : null"
50
+ [attr.data-dirty]="_dirty?.() ? 'true' : null"
51
+ [attr.data-touched]="_touched?.() ? 'true' : null"
52
+ [attr.data-matches-spartan-invalid]="_spartanInvalid?.() ? 'true' : null"
43
53
  [value]="value()"
44
54
  [disabled]="_disabled()"
45
55
  (change)="_valueChanged($event)"
@@ -57,19 +67,18 @@ export const HLM_NATIVE_SELECT_VALUE_ACCESSOR = {
57
67
  `,
58
68
  })
59
69
  export class HlmNativeSelect implements ControlValueAccessor {
60
- private static _id = 0;
70
+ private readonly _fieldControl = inject(BrnFieldControl, { optional: true });
61
71
 
62
- public readonly selectId = input<string>('');
72
+ private static _id = 0;
63
73
 
64
- protected readonly _selectId = computed(() => this.selectId() || `hlm-native-select-${HlmNativeSelect._id++}`);
74
+ public readonly selectId = input<string>(`hlm-native-select-${HlmNativeSelect._id++}`);
65
75
 
66
76
  public readonly selectClass = input<ClassValue>('');
67
77
 
68
78
  protected readonly _computedSelectClass = computed(() =>
69
79
  hlm(
70
80
  'border-input placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 h-9 w-full min-w-0 appearance-none rounded-md border bg-transparent py-1 pr-8 pl-2.5 text-sm shadow-xs transition-[color,box-shadow] outline-none select-none focus-visible:ring-3 disabled:pointer-events-none disabled:cursor-not-allowed data-[size=sm]:h-8',
71
- // TODO support BrnFormFieldControl
72
- 'aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 aria-invalid:ring-3',
81
+ 'data-[matches-spartan-invalid=true]:ring-destructive/20 dark:data-[matches-spartan-invalid=true]:ring-destructive/40 data-[matches-spartan-invalid=true]:border-destructive dark:data-[matches-spartan-invalid=true]:border-destructive/50 data-[matches-spartan-invalid=true]:ring-3',
73
82
  this.selectClass(),
74
83
  ),
75
84
  );
@@ -89,11 +98,14 @@ export class HlmNativeSelect implements ControlValueAccessor {
89
98
 
90
99
  protected readonly _disabled = linkedSignal(this.disabled);
91
100
 
92
- public readonly ariaInvalid = input<boolean, BooleanInput>(false, {
93
- transform: booleanAttribute,
101
+ /** Manual override for aria-invalid. When not set, auto-detects from the parent autocomplete error state. */
102
+ public readonly ariaInvalidOverride = input<boolean | undefined, BooleanInput>(undefined, {
103
+ transform: (v: BooleanInput) => (v === '' || v === undefined ? undefined : booleanAttribute(v)),
94
104
  alias: 'aria-invalid',
95
105
  });
96
106
 
107
+ protected readonly _ariaInvalid = computed(() => this.ariaInvalidOverride() ?? this._invalid?.());
108
+
97
109
  public readonly value = model<string | null>('');
98
110
 
99
111
  public readonly valueChange = output<string | null>();
@@ -101,6 +113,13 @@ export class HlmNativeSelect implements ControlValueAccessor {
101
113
  protected _onChange?: ChangeFn<string | null>;
102
114
  protected _onTouched?: TouchFn;
103
115
 
116
+ public readonly labelableId = this.selectId;
117
+
118
+ protected readonly _invalid = this._fieldControl?.invalid;
119
+ protected readonly _touched = this._fieldControl?.touched;
120
+ protected readonly _dirty = this._fieldControl?.dirty;
121
+ protected readonly _spartanInvalid = this._fieldControl?.spartanInvalid;
122
+
104
123
  constructor() {
105
124
  classes(() => 'group/native-select relative w-fit has-[select:disabled]:opacity-50');
106
125
  }
@@ -1,6 +1,8 @@
1
- import { Directive } from '@angular/core';
1
+ import { computed, Directive, inject, input } from '@angular/core';
2
+ import { BrnFieldControlDescribedBy } from '@spartan-ng/brain/field';
2
3
  import { BrnRadioGroup } from '@spartan-ng/brain/radio-group';
3
4
  import { classes } from '<%- importAlias %>/utils';
5
+ import type { ClassValue } from 'clsx';
4
6
 
5
7
  @Directive({
6
8
  selector: '[hlmRadioGroup],hlm-radio-group',
@@ -10,13 +12,27 @@ import { classes } from '<%- importAlias %>/utils';
10
12
  inputs: ['name', 'value', 'disabled', 'required'],
11
13
  outputs: ['valueChange'],
12
14
  },
15
+ BrnFieldControlDescribedBy,
13
16
  ],
14
17
  host: {
15
18
  'data-slot': 'radio-group',
19
+ '[attr.aria-invalid]': '_ariaInvalid() ? "true" : null',
20
+ '[attr.data-invalid]': '_ariaInvalid() ? "true" : null',
21
+ '[attr.data-dirty]': '_dirty() ? "true" : null',
22
+ '[attr.data-touched]': '_touched() ? "true" : null',
16
23
  },
17
24
  })
18
25
  export class HlmRadioGroup {
26
+ public readonly userClass = input<ClassValue>('', { alias: 'class' });
27
+ private readonly _brnRadioGroup = inject(BrnRadioGroup);
28
+ protected readonly _ariaInvalid = computed(() => this._brnRadioGroup.controlState?.()?.invalid);
29
+
30
+ protected readonly _touched = computed(() => this._brnRadioGroup.controlState?.()?.touched);
31
+ protected readonly _dirty = computed(() => this._brnRadioGroup.controlState?.()?.dirty);
32
+
33
+ protected readonly _errorState = computed(() => this._brnRadioGroup.controlState?.()?.spartanInvalid);
34
+
19
35
  constructor() {
20
- classes(() => 'grid gap-3');
36
+ classes(() => ['grid gap-3', this.userClass(), this._errorState() ? 'data-[invalid=true]:text-destructive' : '']);
21
37
  }
22
38
  }
@@ -14,7 +14,7 @@ import {
14
14
  PLATFORM_ID,
15
15
  Renderer2,
16
16
  } from '@angular/core';
17
- import { BrnRadio, type BrnRadioChange } from '@spartan-ng/brain/radio-group';
17
+ import { BrnRadio, BrnRadioGroup, type BrnRadioChange } from '@spartan-ng/brain/radio-group';
18
18
  import { hlm } from '<%- importAlias %>/utils';
19
19
  import type { ClassValue } from 'clsx';
20
20
 
@@ -37,6 +37,11 @@ import type { ClassValue } from 'clsx';
37
37
  [value]="value()"
38
38
  [required]="required()"
39
39
  [disabled]="disabled()"
40
+ [attr.aria-invalid]="_ariaInvalid() ? 'true' : null"
41
+ [attr.data-invalid]="_ariaInvalid() ? 'true' : null"
42
+ [attr.data-dirty]="_dirty() ? 'true' : null"
43
+ [attr.data-touched]="_touched() ? 'true' : null"
44
+ [attr.data-matches-spartan-invalid]="_groupSpartanInvalid() ? 'true' : null"
40
45
  [aria-label]="ariaLabel()"
41
46
  [aria-labelledby]="ariaLabelledby()"
42
47
  [aria-describedby]="ariaDescribedby()"
@@ -52,6 +57,15 @@ export class HlmRadio<T = unknown> {
52
57
  private readonly _renderer = inject(Renderer2);
53
58
  private readonly _elementRef = inject(ElementRef);
54
59
  private readonly _isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
60
+ private readonly _radioGroup = inject(BrnRadioGroup, { optional: true });
61
+
62
+ protected readonly _ariaInvalid = computed(() => this._radioGroup?.controlState?.()?.invalid);
63
+
64
+ protected readonly _touched = computed(() => this._radioGroup?.controlState?.()?.touched);
65
+ protected readonly _dirty = computed(() => this._radioGroup?.controlState?.()?.dirty);
66
+ protected readonly _groupSpartanInvalid = computed(() => this._radioGroup?.controlState?.()?.spartanInvalid);
67
+
68
+ protected readonly _errorStateClass = computed(() => (this._groupSpartanInvalid() ? 'text-destructive' : ''));
55
69
 
56
70
  public readonly userClass = input<ClassValue>('', { alias: 'class' });
57
71
  protected readonly _computedClass = computed(() =>
@@ -59,6 +73,7 @@ export class HlmRadio<T = unknown> {
59
73
  'group relative flex items-center gap-x-3',
60
74
  'data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50',
61
75
  this.userClass(),
76
+ this._errorStateClass(),
62
77
  ),
63
78
  );
64
79
 
@@ -1,19 +1,21 @@
1
1
  import { ChangeDetectionStrategy, Component, computed, input } from '@angular/core';
2
2
  import { NgIcon, provideIcons } from '@ng-icons/core';
3
3
  import { lucideChevronDown } from '@ng-icons/lucide';
4
+ import { BrnFieldControlDescribedBy } from '@spartan-ng/brain/field';
4
5
  import { BrnSelectTrigger, BrnSelectTriggerWrapper } from '@spartan-ng/brain/select';
5
6
  import { hlm } from '<%- importAlias %>/utils';
6
7
  import type { ClassValue } from 'clsx';
7
8
 
8
9
  @Component({
9
10
  selector: 'hlm-select-trigger',
10
- imports: [NgIcon, BrnSelectTrigger],
11
+ imports: [NgIcon, BrnSelectTrigger, BrnFieldControlDescribedBy],
11
12
  providers: [provideIcons({ lucideChevronDown })],
12
13
  changeDetection: ChangeDetectionStrategy.OnPush,
13
14
  hostDirectives: [BrnSelectTriggerWrapper],
14
15
  template: `
15
16
  <button
16
17
  brnSelectTrigger
18
+ brnFieldControlDescribedBy
17
19
  [id]="buttonId()"
18
20
  [class]="_computedClass()"
19
21
  [attr.data-size]="size()"
@@ -30,7 +32,8 @@ export class HlmSelectTrigger {
30
32
  public readonly userClass = input<ClassValue>('', { alias: 'class' });
31
33
  protected readonly _computedClass = computed(() =>
32
34
  hlm(
33
- "border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:aria-invalid:border-destructive/50 flex w-full items-center justify-between gap-1.5 rounded-md border bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:ring-3 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0 [&_ng-icon:not([class*='text-'])]:text-base",
35
+ "border-input data-placeholder:text-muted-foreground dark:bg-input/30 dark:hover:bg-input/50 focus-visible:border-ring focus-visible:ring-ring/50 flex w-full items-center justify-between gap-1.5 rounded-md border bg-transparent py-2 pr-2 pl-2.5 text-sm whitespace-nowrap shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-3 disabled:cursor-not-allowed disabled:opacity-50 data-[size=default]:h-9 data-[size=sm]:h-8 *:data-[slot=select-value]:line-clamp-1 *:data-[slot=select-value]:flex *:data-[slot=select-value]:items-center *:data-[slot=select-value]:gap-1.5 [&_ng-icon]:pointer-events-none [&_ng-icon]:shrink-0 [&_ng-icon:not([class*='text-'])]:text-base",
36
+ 'data-[matches-spartan-invalid=true]:ring-destructive/20 dark:data-[matches-spartan-invalid=true]:ring-destructive/40 data-[matches-spartan-invalid=true]:border-destructive dark:data-[matches-spartan-invalid=true]:border-destructive/50 data-[matches-spartan-invalid=true]:ring-3',
34
37
  this.userClass(),
35
38
  ),
36
39
  );
@@ -72,9 +72,8 @@ export class HlmSlider {
72
72
  protected readonly _slider = injectBrnSlider();
73
73
 
74
74
  constructor() {
75
- classes(
76
- () =>
77
- 'group flex w-full touch-none flex-col select-none data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-row data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
78
- );
75
+ classes(() => [
76
+ 'group flex w-full touch-none flex-col select-none data-vertical:h-full data-vertical:min-h-40 data-vertical:w-auto data-vertical:flex-row data-[disabled]:pointer-events-none data-[disabled]:opacity-50',
77
+ ]);
79
78
  }
80
79
  }
@@ -1,29 +1,15 @@
1
- import {
2
- computed,
3
- Directive,
4
- type DoCheck,
5
- effect,
6
- forwardRef,
7
- inject,
8
- Injector,
9
- input,
10
- linkedSignal,
11
- signal,
12
- untracked,
13
- } from '@angular/core';
14
- import { FormGroupDirective, NgControl, NgForm } from '@angular/forms';
15
- import { BrnFormFieldControl } from '@spartan-ng/brain/form-field';
16
- import { ErrorStateMatcher, ErrorStateTracker } from '@spartan-ng/brain/forms';
1
+ import { Directive, input } from '@angular/core';
2
+ import { BrnFieldControlDescribedBy } from '@spartan-ng/brain/field';
3
+ import { BrnTextarea } from '@spartan-ng/brain/textarea';
17
4
  import { classes } from '<%- importAlias %>/utils';
18
5
  import { cva, type VariantProps } from 'class-variance-authority';
19
- import { ClassValue } from 'clsx';
20
6
 
21
7
  export const textareaVariants = cva(
22
8
  'border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 dark:bg-input/30 flex [field-sizing:content] min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm',
23
9
  {
24
10
  variants: {
25
11
  error: {
26
- auto: '[&.ng-invalid.ng-touched]:border-destructive [&.ng-invalid.ng-touched]:ring-destructive/20 dark:[&.ng-invalid.ng-touched]:ring-destructive/40',
12
+ auto: 'data-[matches-spartan-invalid=true]:border-destructive data-[matches-spartan-invalid=true]:ring-destructive/20 dark:data-[matches-spartan-invalid=true]:ring-destructive/40',
27
13
  true: 'border-destructive focus-visible:border-destructive focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40',
28
14
  },
29
15
  },
@@ -36,65 +22,18 @@ type TextareaVariants = VariantProps<typeof textareaVariants>;
36
22
 
37
23
  @Directive({
38
24
  selector: '[hlmTextarea]',
39
- providers: [
40
- {
41
- provide: BrnFormFieldControl,
42
- useExisting: forwardRef(() => HlmTextarea),
43
- },
44
- ],
25
+ hostDirectives: [{ directive: BrnTextarea, inputs: ['id'] }, BrnFieldControlDescribedBy],
45
26
  host: {
46
27
  'data-slot': 'textarea',
47
28
  },
48
29
  })
49
- export class HlmTextarea implements BrnFormFieldControl, DoCheck {
50
- private readonly _injector = inject(Injector);
51
- private readonly _additionalClasses = signal<ClassValue>('');
52
-
53
- private readonly _errorStateTracker: ErrorStateTracker;
54
-
55
- private readonly _defaultErrorStateMatcher = inject(ErrorStateMatcher);
56
- private readonly _parentForm = inject(NgForm, { optional: true });
57
- private readonly _parentFormGroup = inject(FormGroupDirective, { optional: true });
58
-
30
+ export class HlmTextarea {
31
+ /** Controls the error visual state of the textarea.
32
+ * Defaults to 'auto', which infers the state from the associated form control.
33
+ */
59
34
  public readonly error = input<TextareaVariants['error']>('auto');
60
35
 
61
- protected readonly _state = linkedSignal(() => ({ error: this.error() }));
62
-
63
- public readonly ngControl: NgControl | null = this._injector.get(NgControl, null);
64
-
65
- public readonly errorState = computed(() => this._errorStateTracker.errorState());
66
-
67
36
  constructor() {
68
- classes(() => [textareaVariants({ error: this._state().error }), this._additionalClasses()]);
69
-
70
- this._errorStateTracker = new ErrorStateTracker(
71
- this._defaultErrorStateMatcher,
72
- this.ngControl,
73
- this._parentFormGroup,
74
- this._parentForm,
75
- );
76
-
77
- effect(() => {
78
- const error = this._errorStateTracker.errorState();
79
- untracked(() => {
80
- if (this.ngControl) {
81
- const shouldShowError = error && this.ngControl.invalid && (this.ngControl.touched || this.ngControl.dirty);
82
- this._errorStateTracker.errorState.set(shouldShowError ? true : false);
83
- this.setError(shouldShowError ? true : 'auto');
84
- }
85
- });
86
- });
87
- }
88
-
89
- ngDoCheck() {
90
- this._errorStateTracker.updateErrorState();
91
- }
92
-
93
- public setError(error: TextareaVariants['error']): void {
94
- this._state.set({ error });
95
- }
96
-
97
- public setClass(classes: string): void {
98
- this._additionalClasses.set(classes);
37
+ classes(() => textareaVariants({ error: this.error() }));
99
38
  }
100
39
  }
@@ -25,7 +25,6 @@ exports.primitiveDependencies = {
25
25
  'dropdown-menu': ['utils', 'icon'],
26
26
  empty: ['utils'],
27
27
  field: ['utils', 'label', 'separator'],
28
- 'form-field': ['utils'],
29
28
  'hover-card': ['utils'],
30
29
  icon: [],
31
30
  input: ['utils'],
@@ -1 +1 @@
1
- {"version":3,"file":"primitive-deps.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/generators/ui/primitive-deps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"primitive-deps.js","sourceRoot":"","sources":["../../../../../../libs/cli/src/generators/ui/primitive-deps.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- export type Primitive = 'accordion' | 'alert' | 'alert-dialog' | 'aspect-ratio' | 'autocomplete' | 'avatar' | 'badge' | 'breadcrumb' | 'button' | 'button-group' | 'calendar' | 'card' | 'carousel' | 'checkbox' | 'collapsible' | 'combobox' | 'command' | 'context-menu' | 'date-picker' | 'dialog' | 'dropdown-menu' | 'empty' | 'field' | 'form-field' | 'hover-card' | 'icon' | 'input' | 'input-group' | 'input-otp' | 'item' | 'kbd' | 'label' | 'menubar' | 'native-select' | 'navigation-menu' | 'pagination' | 'popover' | 'progress' | 'radio-group' | 'resizable' | 'scroll-area' | 'select' | 'separator' | 'sheet' | 'sidebar' | 'skeleton' | 'slider' | 'sonner' | 'spinner' | 'switch' | 'table' | 'tabs' | 'textarea' | 'toggle' | 'toggle-group' | 'tooltip' | 'typography' | 'utils';
1
+ export type Primitive = 'accordion' | 'alert' | 'alert-dialog' | 'aspect-ratio' | 'autocomplete' | 'avatar' | 'badge' | 'breadcrumb' | 'button' | 'button-group' | 'calendar' | 'card' | 'carousel' | 'checkbox' | 'collapsible' | 'combobox' | 'command' | 'context-menu' | 'date-picker' | 'dialog' | 'dropdown-menu' | 'empty' | 'field' | 'hover-card' | 'icon' | 'input' | 'input-group' | 'input-otp' | 'item' | 'kbd' | 'label' | 'menubar' | 'native-select' | 'navigation-menu' | 'pagination' | 'popover' | 'progress' | 'radio-group' | 'resizable' | 'scroll-area' | 'select' | 'separator' | 'sheet' | 'sidebar' | 'skeleton' | 'slider' | 'sonner' | 'spinner' | 'switch' | 'table' | 'tabs' | 'textarea' | 'toggle' | 'toggle-group' | 'tooltip' | 'typography' | 'utils';