@egose/shadcn-theme-ng-tw 0.4.0 → 0.5.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.
Files changed (47) hide show
  1. package/README.md +1 -1
  2. package/form-autocomplete/fesm2022/form-autocomplete.mjs +7 -6
  3. package/form-autocomplete/types/form-autocomplete.d.ts +1 -0
  4. package/form-checkbox/README.md +4 -4
  5. package/form-checkbox/fesm2022/form-checkbox.mjs +84 -12
  6. package/form-checkbox/types/form-checkbox.d.ts +33 -5
  7. package/form-combobox/fesm2022/form-combobox.mjs +7 -6
  8. package/form-combobox/types/form-combobox.d.ts +1 -0
  9. package/form-date-picker/fesm2022/form-date-picker.mjs +7 -6
  10. package/form-date-picker/types/form-date-picker.d.ts +1 -0
  11. package/form-date-picker-multi/fesm2022/form-date-picker-multi.mjs +7 -6
  12. package/form-date-picker-multi/types/form-date-picker-multi.d.ts +1 -0
  13. package/form-date-range-picker/fesm2022/form-date-range-picker.mjs +7 -6
  14. package/form-date-range-picker/types/form-date-range-picker.d.ts +1 -0
  15. package/form-field/fesm2022/form-field.mjs +18 -1
  16. package/form-field/types/form-field.d.ts +48 -2
  17. package/form-input-otp/fesm2022/form-input-otp.mjs +6 -5
  18. package/form-input-otp/types/form-input-otp.d.ts +1 -0
  19. package/form-month-year-picker/fesm2022/form-month-year-picker.mjs +7 -6
  20. package/form-month-year-picker/types/form-month-year-picker.d.ts +1 -0
  21. package/form-native-select/fesm2022/form-native-select.mjs +6 -5
  22. package/form-native-select/types/form-native-select.d.ts +1 -0
  23. package/form-phone-input/fesm2022/form-phone-input.mjs +6 -5
  24. package/form-phone-input/types/form-phone-input.d.ts +1 -0
  25. package/form-radio-group/fesm2022/form-radio-group.mjs +6 -5
  26. package/form-radio-group/types/form-radio-group.d.ts +1 -0
  27. package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +6 -5
  28. package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +1 -0
  29. package/form-select/fesm2022/form-select.mjs +6 -5
  30. package/form-select/types/form-select.d.ts +1 -0
  31. package/form-slider/fesm2022/form-slider.mjs +6 -5
  32. package/form-slider/types/form-slider.d.ts +1 -0
  33. package/form-switch/fesm2022/form-switch.mjs +6 -5
  34. package/form-switch/types/form-switch.d.ts +1 -0
  35. package/form-text-input/fesm2022/form-text-input.mjs +6 -5
  36. package/form-text-input/types/form-text-input.d.ts +1 -0
  37. package/form-textarea/fesm2022/form-textarea.mjs +6 -5
  38. package/form-textarea/types/form-textarea.d.ts +1 -0
  39. package/form-toggle/fesm2022/form-toggle.mjs +8 -5
  40. package/form-toggle/types/form-toggle.d.ts +1 -0
  41. package/form-toggle-group/fesm2022/form-toggle-group.mjs +6 -5
  42. package/form-toggle-group/types/form-toggle-group.d.ts +1 -0
  43. package/package.json +5 -1
  44. package/stepper/README.md +353 -0
  45. package/stepper/fesm2022/stepper.mjs +686 -0
  46. package/stepper/package.json +24 -0
  47. package/stepper/types/stepper.d.ts +116 -0
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, input, computed, Component } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormGroupDirective, ReactiveFormsModule, ControlContainer } from '@angular/forms';
5
- import { injectEgFormErrorMessages, HlmFormIdGenerator, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
5
+ import { injectEgFormErrorMessages, HlmFormIdGenerator, injectEgFormSharedConfig, resolveEgFormError, HlmFormField, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng-tw/label';
7
7
  import { HlmInput } from '@egose/shadcn-theme-ng-tw/input';
8
8
  import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
@@ -20,6 +20,7 @@ class EgFormTextarea {
20
20
  _errorMessages = injectEgFormErrorMessages();
21
21
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-textarea');
22
22
  _config = injectEgFormTextareaConfig();
23
+ _shared = injectEgFormSharedConfig();
23
24
  // General props
24
25
  label = input(undefined, /* @ts-ignore */
25
26
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
@@ -110,13 +111,13 @@ class EgFormTextarea {
110
111
  // Computed class bindings (library base < global config < per-instance)
111
112
  $userClass = computed(() => hlm('tw:w-full', this.userClass()), /* @ts-ignore */
112
113
  ...(ngDevMode ? [{ debugName: "$userClass" }] : /* istanbul ignore next */ []));
113
- $labelClass = computed(() => hlm('tw:mb-1 tw:gap-0', this._config.labelClass, this.labelClass()), /* @ts-ignore */
114
+ $labelClass = computed(() => hlm('tw:mb-1 tw:gap-0', this._shared.labelClass, this._config.labelClass, this.labelClass()), /* @ts-ignore */
114
115
  ...(ngDevMode ? [{ debugName: "$labelClass" }] : /* istanbul ignore next */ []));
115
- $textareaClass = computed(() => hlm('tw:mb-1', this._config.textareaClass, this.textareaClass()), /* @ts-ignore */
116
+ $textareaClass = computed(() => hlm('tw:mb-1', this._shared.textareaClass, this._config.textareaClass, this.textareaClass()), /* @ts-ignore */
116
117
  ...(ngDevMode ? [{ debugName: "$textareaClass" }] : /* istanbul ignore next */ []));
117
- $errorClass = computed(() => hlm('tw:mt-0', this._config.errorClass, this.errorClass()), /* @ts-ignore */
118
+ $errorClass = computed(() => hlm('tw:mt-0', this._shared.errorClass, this._config.errorClass, this.errorClass()), /* @ts-ignore */
118
119
  ...(ngDevMode ? [{ debugName: "$errorClass" }] : /* istanbul ignore next */ []));
119
- $hintClass = computed(() => hlm('tw:mt-0', this._config.hintClass, this.hintClass()), /* @ts-ignore */
120
+ $hintClass = computed(() => hlm('tw:mt-0', this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
120
121
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
121
122
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
122
123
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormTextarea, isStandalone: true, selector: "eg-form-textarea", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, autoError: { classPropertyName: "autoError", publicName: "autoError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, maxlength: { classPropertyName: "maxlength", publicName: "maxlength", isSignal: true, isRequired: false, transformFunction: null }, minlength: { classPropertyName: "minlength", publicName: "minlength", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, cols: { classPropertyName: "cols", publicName: "cols", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, textareaClass: { classPropertyName: "textareaClass", publicName: "textareaClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: `
@@ -7,6 +7,7 @@ declare class EgFormTextarea {
7
7
  private readonly _errorMessages;
8
8
  private readonly generatedId;
9
9
  private readonly _config;
10
+ private readonly _shared;
10
11
  label: _angular_core.InputSignal<string | undefined>;
11
12
  controlId: _angular_core.InputSignal<string | undefined>;
12
13
  controlName: _angular_core.InputSignal<string>;
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, forwardRef, Injector, DestroyRef, input, booleanAttribute, computed, signal, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
4
  import { NG_VALUE_ACCESSOR, FormGroupDirective, FormControlName } from '@angular/forms';
5
- import { HlmFormIdGenerator, injectEgFormErrorMessages, resolveEgFormError, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
5
+ import { HlmFormIdGenerator, injectEgFormSharedConfig, injectEgFormErrorMessages, resolveEgFormError, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
6
6
  import { HlmLabel } from '@egose/shadcn-theme-ng-tw/label';
7
7
  import { HlmToggle } from '@egose/shadcn-theme-ng-tw/toggle';
8
8
  import { hlm } from '@egose/shadcn-theme-ng-tw/utils';
@@ -32,6 +32,7 @@ const EG_FORM_TOGGLE_VALUE_ACCESSOR = {
32
32
  class EgFormToggle {
33
33
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-toggle');
34
34
  _config = injectEgFormToggleConfig();
35
+ _shared = injectEgFormSharedConfig();
35
36
  _injector = inject(Injector);
36
37
  _destroyRef = inject(DestroyRef);
37
38
  _formGroupDirective = inject(FormGroupDirective, { optional: true });
@@ -152,16 +153,18 @@ class EgFormToggle {
152
153
  ...(ngDevMode ? [{ debugName: "errorClass" }] : /* istanbul ignore next */ []));
153
154
  hintClass = input('', /* @ts-ignore */
154
155
  ...(ngDevMode ? [{ debugName: "hintClass" }] : /* istanbul ignore next */ []));
155
- // Computed classes (library base < global config < per-instance)
156
+ // Computed classes (library base < shared global < component global < per-instance).
157
+ // Note: toggle keeps its own CVA/error-hint behavior; only the shared
158
+ // label/error/hint styling slots are picked up (toggleClass stays local).
156
159
  $userClass = computed(() => hlm('tw:w-full', this.userClass()), /* @ts-ignore */
157
160
  ...(ngDevMode ? [{ debugName: "$userClass" }] : /* istanbul ignore next */ []));
158
161
  $toggleClass = computed(() => hlm(this._config.toggleClass, this.toggleClass()), /* @ts-ignore */
159
162
  ...(ngDevMode ? [{ debugName: "$toggleClass" }] : /* istanbul ignore next */ []));
160
- $labelClass = computed(() => hlm(this._config.labelClass, this.labelClass()), /* @ts-ignore */
163
+ $labelClass = computed(() => hlm(this._shared.labelClass, this._config.labelClass, this.labelClass()), /* @ts-ignore */
161
164
  ...(ngDevMode ? [{ debugName: "$labelClass" }] : /* istanbul ignore next */ []));
162
- $errorClass = computed(() => hlm('tw:mt-0', this._config.errorClass, this.errorClass()), /* @ts-ignore */
165
+ $errorClass = computed(() => hlm('tw:mt-0', this._shared.errorClass, this._config.errorClass, this.errorClass()), /* @ts-ignore */
163
166
  ...(ngDevMode ? [{ debugName: "$errorClass" }] : /* istanbul ignore next */ []));
164
- $hintClass = computed(() => hlm('tw:mt-0', this._config.hintClass, this.hintClass()), /* @ts-ignore */
167
+ $hintClass = computed(() => hlm('tw:mt-0', this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
165
168
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
166
169
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
167
170
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormToggle, isStandalone: true, selector: "eg-form-toggle", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, autoError: { classPropertyName: "autoError", publicName: "autoError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, toggleClass: { classPropertyName: "toggleClass", publicName: "toggleClass", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [EG_FORM_TOGGLE_VALUE_ACCESSOR, provideIcons({ lucideCheck })], ngImport: i0, template: `
@@ -20,6 +20,7 @@ declare const EG_FORM_TOGGLE_VALUE_ACCESSOR: {
20
20
  declare class EgFormToggle implements ControlValueAccessor, AfterViewInit, DoCheck {
21
21
  private readonly generatedId;
22
22
  private readonly _config;
23
+ private readonly _shared;
23
24
  private readonly _injector;
24
25
  private readonly _destroyRef;
25
26
  private readonly _formGroupDirective;
@@ -2,7 +2,7 @@ import * as i0 from '@angular/core';
2
2
  import { InjectionToken, inject, input, computed, Component } from '@angular/core';
3
3
  import * as i1 from '@angular/forms';
4
4
  import { FormGroupDirective, ReactiveFormsModule, ControlContainer } from '@angular/forms';
5
- import { injectEgFormErrorMessages, HlmFormIdGenerator, resolveEgFormError, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
5
+ import { injectEgFormErrorMessages, HlmFormIdGenerator, injectEgFormSharedConfig, resolveEgFormError, HlmError, HlmHint } from '@egose/shadcn-theme-ng-tw/form-field';
6
6
  import { EgFormField } from '@egose/shadcn-theme-ng-tw/form-field-simple';
7
7
  import { HlmLabel } from '@egose/shadcn-theme-ng-tw/label';
8
8
  import { HlmToggleGroup, HlmToggleGroupItem } from '@egose/shadcn-theme-ng-tw/toggle-group';
@@ -21,6 +21,7 @@ class EgFormToggleGroup {
21
21
  _errorMessages = injectEgFormErrorMessages();
22
22
  generatedId = inject(HlmFormIdGenerator).generate('eg-form-toggle-group');
23
23
  _config = injectEgFormToggleGroupConfig();
24
+ _shared = injectEgFormSharedConfig();
24
25
  label = input(undefined, /* @ts-ignore */
25
26
  ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
26
27
  controlId = input(undefined, /* @ts-ignore */
@@ -108,13 +109,13 @@ class EgFormToggleGroup {
108
109
  // Computed classes (library base < global config < per-instance)
109
110
  $userClass = computed(() => hlm('tw:w-full', this.userClass()), /* @ts-ignore */
110
111
  ...(ngDevMode ? [{ debugName: "$userClass" }] : /* istanbul ignore next */ []));
111
- $labelClass = computed(() => hlm('tw:mb-1', this._config.labelClass, this.labelClass()), /* @ts-ignore */
112
+ $labelClass = computed(() => hlm('tw:mb-1', this._shared.labelClass, this._config.labelClass, this.labelClass()), /* @ts-ignore */
112
113
  ...(ngDevMode ? [{ debugName: "$labelClass" }] : /* istanbul ignore next */ []));
113
- $groupClass = computed(() => hlm(this._config.groupClass, this.groupClass()), /* @ts-ignore */
114
+ $groupClass = computed(() => hlm(this._shared.groupClass, this._config.groupClass, this.groupClass()), /* @ts-ignore */
114
115
  ...(ngDevMode ? [{ debugName: "$groupClass" }] : /* istanbul ignore next */ []));
115
- $errorClass = computed(() => hlm('tw:mt-0', this._config.errorClass, this.errorClass()), /* @ts-ignore */
116
+ $errorClass = computed(() => hlm('tw:mt-0', this._shared.errorClass, this._config.errorClass, this.errorClass()), /* @ts-ignore */
116
117
  ...(ngDevMode ? [{ debugName: "$errorClass" }] : /* istanbul ignore next */ []));
117
- $hintClass = computed(() => hlm('tw:mt-0', this._config.hintClass, this.hintClass()), /* @ts-ignore */
118
+ $hintClass = computed(() => hlm('tw:mt-0', this._shared.hintClass, this._config.hintClass, this.hintClass()), /* @ts-ignore */
118
119
  ...(ngDevMode ? [{ debugName: "$hintClass" }] : /* istanbul ignore next */ []));
119
120
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: EgFormToggleGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
120
121
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: EgFormToggleGroup, isStandalone: true, selector: "eg-form-toggle-group", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, controlId: { classPropertyName: "controlId", publicName: "controlId", isSignal: true, isRequired: false, transformFunction: null }, controlName: { classPropertyName: "controlName", publicName: "controlName", isSignal: true, isRequired: false, transformFunction: null }, error: { classPropertyName: "error", publicName: "error", isSignal: true, isRequired: false, transformFunction: null }, autoError: { classPropertyName: "autoError", publicName: "autoError", isSignal: true, isRequired: false, transformFunction: null }, hint: { classPropertyName: "hint", publicName: "hint", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, userClass: { classPropertyName: "userClass", publicName: "class", isSignal: true, isRequired: false, transformFunction: null }, labelClass: { classPropertyName: "labelClass", publicName: "labelClass", isSignal: true, isRequired: false, transformFunction: null }, groupClass: { classPropertyName: "groupClass", publicName: "groupClass", isSignal: true, isRequired: false, transformFunction: null }, errorClass: { classPropertyName: "errorClass", publicName: "errorClass", isSignal: true, isRequired: false, transformFunction: null }, hintClass: { classPropertyName: "hintClass", publicName: "hintClass", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "$userClass()" } }, providers: [{ provide: ControlContainer, useExisting: FormGroupDirective }], ngImport: i0, template: `
@@ -12,6 +12,7 @@ declare class EgFormToggleGroup {
12
12
  private readonly _errorMessages;
13
13
  private readonly generatedId;
14
14
  private readonly _config;
15
+ private readonly _shared;
15
16
  label: _angular_core.InputSignal<string | undefined>;
16
17
  controlId: _angular_core.InputSignal<string | undefined>;
17
18
  controlName: _angular_core.InputSignal<string>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@egose/shadcn-theme-ng-tw",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "description": "Angular shadcn UI theme",
5
5
  "author": "Junmin Ahn",
6
6
  "bundles": [
@@ -350,6 +350,10 @@
350
350
  "types": "./spinner/types/spinner.d.ts",
351
351
  "default": "./spinner/fesm2022/spinner.mjs"
352
352
  },
353
+ "./stepper": {
354
+ "types": "./stepper/types/stepper.d.ts",
355
+ "default": "./stepper/fesm2022/stepper.mjs"
356
+ },
353
357
  "./switch": {
354
358
  "types": "./switch/types/switch.d.ts",
355
359
  "default": "./switch/fesm2022/switch.mjs"
@@ -0,0 +1,353 @@
1
+ # Stepper (`@egose/shadcn-theme-ng/stepper`)
2
+
3
+ Multi-step workflow navigation, ported from the spartan stepper blocks. This subpath ships seven pieces — `HlmStepper` (root), `HlmStep` (step), `HlmStepHeader` (clickable header with indicator), `HlmStepLabel` (rich label template), `HlmStepContent` (lazy body), `HlmStepperNext` / `HlmStepperPrevious` (navigation buttons) — plus `provideHlmStepperConfig` / `injectHlmStepperConfig` for global defaults. All are thin shadcn-styled components over Angular CDK's `@angular/cdk/stepper` primitives (`CdkStepper`, `CdkStep`, `CdkStepHeader`, `CdkStepLabel`).
4
+
5
+ > **Ships as:** `@egose/shadcn-theme-ng/stepper` and `@egose/shadcn-theme-ng-tw/stepper` (the `tw:`-prefixed Tailwind variant). See the [package README](../../README.md) for install steps, peer dependencies, Tailwind setup, and testing/release guidance. Do not publish this project directory independently.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ # Plain Tailwind (no prefix)
11
+ npm install @egose/shadcn-theme-ng
12
+
13
+ # Or the tw:-prefixed variant
14
+ npm install @egose/shadcn-theme-ng-tw
15
+ ```
16
+
17
+ `@angular/cdk` (stepper, portal) arrives via the package peer dependencies. See the [package README](../../README.md) for the full peer-dependency table.
18
+
19
+ ## Imports
20
+
21
+ All public symbols are re-exported from `projects/stepper/src/public-api.ts`:
22
+
23
+ ```ts
24
+ import {
25
+ HlmStep,
26
+ HlmStepContent,
27
+ HlmStepHeader,
28
+ HlmStepLabel,
29
+ HlmStepper,
30
+ HlmStepperImports,
31
+ HlmStepperModule,
32
+ HlmStepperNext,
33
+ HlmStepperPrevious,
34
+ injectHlmStepperConfig,
35
+ provideHlmStepperConfig,
36
+ } from '@egose/shadcn-theme-ng/stepper';
37
+ // tw variant: swap to '@egose/shadcn-theme-ng-tw/stepper'
38
+ ```
39
+
40
+ Standalone-component usage (preferred):
41
+
42
+ ```ts
43
+ import { Component } from '@angular/core';
44
+ import { HlmStepperImports } from '@egose/shadcn-theme-ng/stepper';
45
+
46
+ @Component({
47
+ selector: 'app-demo',
48
+ standalone: true,
49
+ imports: [...HlmStepperImports],
50
+ template: `<!-- stepper markup here -->`,
51
+ })
52
+ export class DemoComponent {}
53
+ ```
54
+
55
+ NgModule usage:
56
+
57
+ ```ts
58
+ import { NgModule } from '@angular/core';
59
+ import { HlmStepperModule } from '@egose/shadcn-theme-ng/stepper';
60
+
61
+ @NgModule({ imports: [HlmStepperModule] })
62
+ export class FeatureModule {}
63
+ ```
64
+
65
+ | Symbol | Kind | Description |
66
+ | ------------------------ | ------------- | ------------------------------------------------------------------------ |
67
+ | `HlmStepper` | Component | Root: `<hlm-stepper>` — extends `CdkStepper`. |
68
+ | `HlmStep` | Component | Step: `<hlm-step label="…">` — extends `CdkStep`, adds `icon` input. |
69
+ | `HlmStepHeader` | Component | Header: `<hlm-step-header>` — extends `CdkStepHeader`, renders indicator. |
70
+ | `HlmStepLabel` | Directive | Rich label: `<ng-template hlmStepLabel>` — extends `CdkStepLabel`. |
71
+ | `HlmStepContent` | Directive | Lazy body: `<ng-template hlmStepContent>` — attached on first selection. |
72
+ | `HlmStepperNext` | Directive | Next button: `button[hlmStepperNext]` — extends `CdkStepperNext`. |
73
+ | `HlmStepperPrevious` | Directive | Back button: `button[hlmStepperPrevious]` — extends `CdkStepperPrevious`. |
74
+ | `HlmStepperImports` | `const` array | All seven, spread into `imports: [...]`. |
75
+ | `HlmStepperModule` | NgModule | Imports + re-exports all seven. |
76
+ | `provideHlmStepperConfig`| Function | Global defaults for animations + indicator mode. |
77
+ | `injectHlmStepperConfig` | Function | Reads the (optionally provided) global config. |
78
+
79
+ ## Anatomy / Structure
80
+
81
+ ```html
82
+ <hlm-stepper>
83
+ <hlm-step label="Step One">
84
+ <p>Content 1</p>
85
+ <button hlmBtn hlmStepperNext>Next</button>
86
+ </hlm-step>
87
+
88
+ <hlm-step label="Step Two">
89
+ <p>Content 2</p>
90
+ <button hlmBtn variant="outline" hlmStepperPrevious>Back</button>
91
+ <button hlmBtn hlmStepperNext>Next</button>
92
+ </hlm-step>
93
+
94
+ <hlm-step label="Step Three">
95
+ <p>Content 3</p>
96
+ <button hlmBtn variant="outline" hlmStepperPrevious>Back</button>
97
+ <button hlmBtn>Finish</button>
98
+ </hlm-step>
99
+ </hlm-stepper>
100
+ ```
101
+
102
+ Rich label via template (takes precedence over the `label` string):
103
+
104
+ ```html
105
+ <hlm-step [stepControl]="form">
106
+ <ng-template hlmStepLabel>Security</ng-template>
107
+ <!-- … -->
108
+ </hlm-step>
109
+ ```
110
+
111
+ Lazy body (attached only when the step is first selected):
112
+
113
+ ```html
114
+ <hlm-step label="Analytics">
115
+ <ng-template hlmStepContent>
116
+ <p>Heavy content…</p>
117
+ </ng-template>
118
+ </hlm-step>
119
+ ```
120
+
121
+ ## API reference
122
+
123
+ ### `HlmStepper` — selector `hlm-stepper` (component, extends `CdkStepper`)
124
+
125
+ | Input | Type | Default | Description |
126
+ | -------------------- | ----------------------------- | ---------- | ------------------------------------------------------------------ |
127
+ | `orientation` | forwarded to `CdkStepper` | — | `'horizontal' \| 'vertical'`. |
128
+ | `linear` | forwarded to `CdkStepper` | — | Current step must be valid (via `stepControl`) before advancing. |
129
+ | `selectedIndex` | forwarded to `CdkStepper` | — | Controlled selected-step index. |
130
+ | `labelPosition` | `'end' \| 'bottom'` | `'end'` | Horizontal layout: label beside vs. below the indicator. |
131
+ | `headerPosition` | `'top' \| 'bottom'` | `'top'` | Horizontal layout: headers above vs. below the content panel. |
132
+ | `indicatorMode` | `'number' \| 'state' \| 'icon'` | from config (`'state'`) | Indicator rendering (see below). |
133
+ | `stepperAriaLabel` | `string \| null` | `'Progress'` | `aria-label` for the tablist (ignored when labelledby is set). |
134
+ | `stepperAriaLabelledby` | `string \| null` | `null` | `aria-labelledby` for the tablist. |
135
+ | `animationsEnabled` | `boolean` | from config (`true`) | Toggle step transitions per instance. |
136
+ | `animationDuration` | `number` (ms) | from config (`300`) | Transition duration per instance. |
137
+
138
+ `next()` is overridden to `markAllAsTouched()` + `updateValueAndValidity()` on the current `stepControl` first, so linear steppers surface validation errors before denying the transition.
139
+
140
+ ### `HlmStep` — selector `hlm-step` (component, extends `CdkStep`)
141
+
142
+ | Input | Type | Default | Description |
143
+ | ------------- | ---------------- | ------- | -------------------------------------------------------- |
144
+ | `label` | forwarded to `CdkStep` | — | Step title (string, or rich template via `hlmStepLabel`). |
145
+ | `icon` | `string \| null` | `null` | Icon name rendered when `indicatorMode="icon"`. |
146
+ | `stepControl` | forwarded to `CdkStep` | — | Form group driving `linear` validation. |
147
+ | `optional` | forwarded to `CdkStep` | — | Shows an "Optional" caption in the header. |
148
+ | `errorMessage`| forwarded to `CdkStep` | — | Header error caption when the step state is `error`. |
149
+ | `hasError` | forwarded to `CdkStep` | — | Forces the error state (pair with `STEPPER_GLOBAL_OPTIONS` `showError`). |
150
+
151
+ ### `HlmStepHeader` — selector `hlm-step-header` (component, extends `CdkStepHeader`)
152
+
153
+ Usually rendered by `HlmStepper` itself; use directly only for custom layouts.
154
+
155
+ | Input | Type | Default | Description |
156
+ | --------------- | ------------------------------------------- | ------- | -------------------------------------------- |
157
+ | `index` | `number` | `0` | Step index (drives the number indicator). |
158
+ | `state` | `StepState` | `'number'` | CDK step state (`number`, `edit`, `done`, `error`, …). |
159
+ | `label` | `HlmStepLabel \| string \| null` | `null` | Resolved label content. |
160
+ | `selected` / `reached` / `active` | `boolean` | `false` | Visual state flags. |
161
+ | `optional` / `disabled` | `boolean` | `false` | Optional caption / disabled styling. |
162
+ | `icon` | `string \| null` | `null` | Icon name for `indicatorMode="icon"`. |
163
+ | `indicatorMode` | `'number' \| 'state' \| 'icon'` | from config (`'state'`) | Indicator rendering. |
164
+ | `labelPosition` | `'end' \| 'bottom'` | `'end'` | Label beside vs. below the indicator. |
165
+ | `errorMessage` | `string` | `''` | Error caption shown when `state === 'error'`.|
166
+
167
+ Indicator modes: `number` always renders `1, 2, 3`; `state` (default) renders a check icon for selected/reached steps and an alert icon for errors; `icon` renders the per-step `icon` name (provide icons via `@ng-icons/core` `provideIcons` in your app).
168
+
169
+ ### `HlmStepperNext` / `HlmStepperPrevious` — `button[hlmStepperNext]` / `button[hlmStepperPrevious]`
170
+
171
+ No inputs/outputs. Thin extensions of `CdkStepperNext` / `CdkStepperPrevious` (sets `type` binding + `touch-action: manipulation`). Pair with `hlmBtn` for styling.
172
+
173
+ ### Global config
174
+
175
+ ```ts
176
+ import { provideHlmStepperConfig } from '@egose/shadcn-theme-ng/stepper';
177
+
178
+ @Component({
179
+ // ...
180
+ providers: [provideHlmStepperConfig({ animationEnabled: true, animationDuration: 300, defaultIndicatorMode: 'state' })],
181
+ })
182
+ export class FeatureComponent {}
183
+ ```
184
+
185
+ Per-instance `animationsEnabled`, `animationDuration`, and `indicatorMode` inputs override the global defaults.
186
+
187
+ ## Examples
188
+
189
+ ### 1. Basic horizontal stepper
190
+
191
+ ```ts
192
+ import { Component } from '@angular/core';
193
+ import { HlmButtonImports } from '@egose/shadcn-theme-ng/button';
194
+ import { HlmStepperImports } from '@egose/shadcn-theme-ng/stepper';
195
+
196
+ @Component({
197
+ selector: 'demo-basic',
198
+ standalone: true,
199
+ imports: [...HlmStepperImports, ...HlmButtonImports],
200
+ template: `
201
+ <hlm-stepper>
202
+ <hlm-step label="Step One">
203
+ <p>Content 1</p>
204
+ <button hlmBtn hlmStepperNext>Next</button>
205
+ </hlm-step>
206
+ <hlm-step label="Step Two">
207
+ <p>Content 2</p>
208
+ <button hlmBtn variant="outline" hlmStepperPrevious>Back</button>
209
+ <button hlmBtn hlmStepperNext>Next</button>
210
+ </hlm-step>
211
+ <hlm-step label="Step Three">
212
+ <p>Content 3</p>
213
+ <button hlmBtn variant="outline" hlmStepperPrevious>Back</button>
214
+ <button hlmBtn>Finish</button>
215
+ </hlm-step>
216
+ </hlm-stepper>
217
+ `,
218
+ })
219
+ export class DemoBasic {}
220
+ ```
221
+
222
+ ### 2. Vertical orientation
223
+
224
+ ```html
225
+ <hlm-stepper orientation="vertical">
226
+ <hlm-step label="Campaign"><!-- … --></hlm-step>
227
+ <hlm-step label="Audience"><!-- … --></hlm-step>
228
+ <hlm-step label="Review"><!-- … --></hlm-step>
229
+ </hlm-stepper>
230
+ ```
231
+
232
+ Use vertical when content is dense or horizontal space is limited.
233
+
234
+ ### 3. Responsive orientation via `BreakpointObserver`
235
+
236
+ ```ts
237
+ import { BreakpointObserver } from '@angular/cdk/layout';
238
+ import { Component, computed, inject } from '@angular/core';
239
+ import { toSignal } from '@angular/core/rxjs-interop';
240
+ import { map } from 'rxjs/operators';
241
+
242
+ @Component({ /* … */ })
243
+ export class DemoResponsive {
244
+ private readonly _breakpoints = inject(BreakpointObserver);
245
+ private readonly _isSmall = toSignal(
246
+ this._breakpoints.observe('(max-width: 767.98px)').pipe(map((s) => s.matches)),
247
+ { initialValue: false },
248
+ );
249
+ protected readonly orientation = computed(() => (this._isSmall() ? 'vertical' : 'horizontal'));
250
+ }
251
+ ```
252
+
253
+ ```html
254
+ <hlm-stepper [orientation]="orientation()"><!-- … --></hlm-stepper>
255
+ ```
256
+
257
+ ### 4. Linear stepper with validation
258
+
259
+ With `linear`, the current step must be valid before advancing — `HlmStepper.next()` marks the step form touched first:
260
+
261
+ ```ts
262
+ import { Component, inject } from '@angular/core';
263
+ import { FormBuilder, ReactiveFormsModule, Validators } from '@angular/forms';
264
+
265
+ @Component({ /* …, imports: [ReactiveFormsModule, ...HlmStepperImports, ...HlmButtonImports] */ })
266
+ export class DemoLinear {
267
+ private readonly _fb = inject(FormBuilder);
268
+ protected readonly identity = this._fb.group({ name: ['', Validators.required] });
269
+ }
270
+ ```
271
+
272
+ ```html
273
+ <hlm-stepper [linear]="true">
274
+ <hlm-step [stepControl]="identity" label="Identity">
275
+ <form [formGroup]="identity">
276
+ <input hlmInput formControlName="name" placeholder="Required before continuing" />
277
+ <button hlmBtn hlmStepperNext>Next</button>
278
+ </form>
279
+ </hlm-step>
280
+ <hlm-step label="Review"><!-- … --></hlm-step>
281
+ </hlm-stepper>
282
+ ```
283
+
284
+ ### 5. Error states
285
+
286
+ Enable `showError` through `STEPPER_GLOBAL_OPTIONS` to surface a step's error message in its header:
287
+
288
+ ```ts
289
+ import { STEPPER_GLOBAL_OPTIONS } from '@angular/cdk/stepper';
290
+
291
+ @Component({
292
+ providers: [{ provide: STEPPER_GLOBAL_OPTIONS, useValue: { showError: true } }],
293
+ /* … */
294
+ })
295
+ export class DemoError {}
296
+ ```
297
+
298
+ ```html
299
+ <hlm-step
300
+ [stepControl]="contact"
301
+ [hasError]="contact.invalid && contact.touched"
302
+ errorMessage="Enter a valid work email before continuing."
303
+ label="Contact"
304
+ >
305
+ <!-- … -->
306
+ </hlm-step>
307
+ ```
308
+
309
+ ### 6. Layout controls
310
+
311
+ ```html
312
+ <hlm-stepper labelPosition="bottom" headerPosition="bottom"><!-- … --></hlm-stepper>
313
+ ```
314
+
315
+ `labelPosition` moves horizontal labels below the indicator; `headerPosition="bottom"` moves the header row below the content panel.
316
+
317
+ ### 7. Animation controls
318
+
319
+ ```html
320
+ <hlm-stepper [animationsEnabled]="true" [animationDuration]="300"><!-- … --></hlm-stepper>
321
+ ```
322
+
323
+ Or set global defaults with `provideHlmStepperConfig` and override per instance.
324
+
325
+ ### 8. Indicator modes
326
+
327
+ ```html
328
+ <hlm-stepper indicatorMode="number"><!-- always 1, 2, 3 --></hlm-stepper>
329
+ <hlm-stepper indicatorMode="state"><!-- default: check / alert icons --></hlm-stepper>
330
+ <hlm-stepper indicatorMode="icon">
331
+ <hlm-step label="Profile" icon="lucideUser"><!-- … --></hlm-step>
332
+ </hlm-stepper>
333
+ ```
334
+
335
+ Per-step `icon` names resolve through `@ng-icons/core` — register them with `provideIcons` in your app.
336
+
337
+ ## Accessibility notes
338
+
339
+ - Horizontal headers get `role="tab"` semantics inside a `role="tablist"` (labelled `Progress` by default — override with `stepperAriaLabel` / `stepperAriaLabelledby`); panels get `role="tabpanel"` wired via `aria-labelledby` / `aria-controls`.
340
+ - Vertical headers use `role="button"` with `aria-expanded` / `aria-current="step"`.
341
+ - Keyboard: `HlmStepper` inherits CDK arrow-key navigation (`_onKeydown`). Headers are focusable via roving `tabIndex`.
342
+ - Disabled steps (`linear` + not navigable) get `aria-disabled` and `data-disabled` styling — explain in the label why a step is unavailable.
343
+ - In `linear` mode, failed validation marks fields touched so screen readers announce the errors.
344
+
345
+ ## Theming / CSS variables
346
+
347
+ Headers follow `buttonVariants({ size: 'icon-sm' })` (`default` when selected/reached, `outline` otherwise, `destructive` on error) with `data-disabled` opacity handling. Connectors use `bg-primary` once reached, `bg-border` otherwise. Follows your shadcn theme automatically; extend via `class` (merged through `classes()` on headers) or the layout/indicator inputs.
348
+
349
+ ## Related subpaths
350
+
351
+ - `@egose/shadcn-theme-ng/button` — `buttonVariants` powers the step indicators; `hlmBtn` styles the nav buttons.
352
+ - `@egose/shadcn-theme-ng/input` / `@egose/shadcn-theme-ng/label` / `@egose/shadcn-theme-ng/field` — form controls inside linear steps.
353
+ - `@egose/shadcn-theme-ng/card` — rich content panels.