@egose/shadcn-theme-ng 0.6.0 → 0.6.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.
- package/README.md +119 -1
- package/autocomplete/fesm2022/autocomplete.mjs +14 -4
- package/autocomplete/types/autocomplete.d.ts +4 -1
- package/checkbox/README.md +6 -2
- package/checkbox/fesm2022/checkbox.mjs +11 -7
- package/checkbox/types/checkbox.d.ts +6 -4
- package/combobox/fesm2022/combobox.mjs +13 -7
- package/combobox/types/combobox.d.ts +8 -2
- package/data-table/README.md +11 -1
- package/data-table/fesm2022/data-table.mjs +64 -18
- package/data-table/types/data-table.d.ts +25 -6
- package/date-picker/README.md +41 -9
- package/date-picker/fesm2022/date-picker.mjs +265 -59
- package/date-picker/types/date-picker.d.ts +58 -27
- package/form-autocomplete/README.md +4 -2
- package/form-autocomplete/fesm2022/form-autocomplete.mjs +19 -6
- package/form-autocomplete/types/form-autocomplete.d.ts +9 -3
- package/form-combobox/README.md +4 -2
- package/form-combobox/fesm2022/form-combobox.mjs +23 -6
- package/form-combobox/types/form-combobox.d.ts +10 -3
- package/form-input-otp/README.md +7 -5
- package/form-input-otp/fesm2022/form-input-otp.mjs +20 -8
- package/form-input-otp/types/form-input-otp.d.ts +9 -3
- package/form-searchable-multiselect/README.md +15 -1
- package/form-searchable-multiselect/fesm2022/form-searchable-multiselect.mjs +15 -3
- package/form-searchable-multiselect/types/form-searchable-multiselect.d.ts +9 -1
- package/form-slider/README.md +3 -1
- package/form-slider/fesm2022/form-slider.mjs +19 -6
- package/form-slider/types/form-slider.d.ts +9 -3
- package/form-toggle/README.md +22 -18
- package/form-toggle/fesm2022/form-toggle.mjs +22 -9
- package/form-toggle/types/form-toggle.d.ts +6 -2
- package/input-otp/README.md +33 -9
- package/input-otp/fesm2022/input-otp.mjs +127 -11
- package/input-otp/types/input-otp.d.ts +24 -4
- package/package.json +1 -1
- package/pagination/README.md +21 -12
- package/pagination/fesm2022/pagination.mjs +73 -65
- package/pagination/types/pagination.d.ts +21 -8
- package/phone-input/README.md +16 -0
- package/phone-input/fesm2022/phone-input.mjs +41 -3
- package/phone-input/types/phone-input.d.ts +5 -2
- package/searchable-multiselect/README.md +62 -40
- package/searchable-multiselect/fesm2022/searchable-multiselect.mjs +59 -32
- package/searchable-multiselect/types/searchable-multiselect.d.ts +23 -6
- package/slider/fesm2022/slider.mjs +9 -5
- package/slider/types/slider.d.ts +6 -2
- package/stepper/README.md +39 -19
- package/stepper/fesm2022/stepper.mjs +64 -12
- package/stepper/types/stepper.d.ts +12 -1
package/stepper/README.md
CHANGED
|
@@ -123,20 +123,38 @@ Lazy body (attached only when the step is first selected):
|
|
|
123
123
|
|
|
124
124
|
### `HlmStepper` — selector `hlm-stepper` (component, extends `CdkStepper`)
|
|
125
125
|
|
|
126
|
-
| Input | Type | Default | Description
|
|
127
|
-
| ----------------------- | ------------------------------- | ----------------------- |
|
|
128
|
-
| `orientation` | forwarded to `CdkStepper` | — | `'horizontal' \| 'vertical'`.
|
|
129
|
-
| `linear` | forwarded to `CdkStepper` | — |
|
|
130
|
-
| `selectedIndex` | forwarded to `CdkStepper` | — | Controlled selected-step index.
|
|
131
|
-
| `labelPosition` | `'end' \| 'bottom'` | `'end'` | Horizontal layout: label beside vs. below the indicator.
|
|
132
|
-
| `headerPosition` | `'top' \| 'bottom'` | `'top'` | Horizontal layout: headers above vs. below the content panel.
|
|
133
|
-
| `indicatorMode` | `'number' \| 'state' \| 'icon'` | from config (`'state'`) | Indicator rendering (see below).
|
|
134
|
-
| `stepperAriaLabel` | `string \| null` | `'Progress'` | `aria-label` for the tablist (ignored when labelledby is set).
|
|
135
|
-
| `stepperAriaLabelledby` | `string \| null` | `null` | `aria-labelledby` for the tablist.
|
|
136
|
-
| `animationsEnabled` | `boolean` | from config (`true`) | Toggle step transitions per instance.
|
|
137
|
-
| `animationDuration` | `number` (ms) | from config (`300`) | Transition duration per instance.
|
|
138
|
-
|
|
139
|
-
`next()`
|
|
126
|
+
| Input | Type | Default | Description |
|
|
127
|
+
| ----------------------- | ------------------------------- | ----------------------- | ------------------------------------------------------------------- |
|
|
128
|
+
| `orientation` | forwarded to `CdkStepper` | — | `'horizontal' \| 'vertical'`. |
|
|
129
|
+
| `linear` | forwarded to `CdkStepper` | — | CDK checks preceding steps, honoring optional/completion overrides. |
|
|
130
|
+
| `selectedIndex` | forwarded to `CdkStepper` | — | Controlled selected-step index. |
|
|
131
|
+
| `labelPosition` | `'end' \| 'bottom'` | `'end'` | Horizontal layout: label beside vs. below the indicator. |
|
|
132
|
+
| `headerPosition` | `'top' \| 'bottom'` | `'top'` | Horizontal layout: headers above vs. below the content panel. |
|
|
133
|
+
| `indicatorMode` | `'number' \| 'state' \| 'icon'` | from config (`'state'`) | Indicator rendering (see below). |
|
|
134
|
+
| `stepperAriaLabel` | `string \| null` | `'Progress'` | `aria-label` for the tablist (ignored when labelledby is set). |
|
|
135
|
+
| `stepperAriaLabelledby` | `string \| null` | `null` | `aria-labelledby` for the tablist. |
|
|
136
|
+
| `animationsEnabled` | `boolean` | from config (`true`) | Toggle step transitions per instance. |
|
|
137
|
+
| `animationDuration` | `number` (ms) | from config (`300`) | Transition duration per instance. |
|
|
138
|
+
|
|
139
|
+
`next()` and `button[hlmStepperNext]` call `markAllAsTouched()` + `updateValueAndValidity()` on the current classic reactive-forms `stepControl` before delegating navigation to CDK. This preserves touch/validation feedback even when navigation is denied, and also runs for optional, completed, and non-linear steps. Signal-form Fields are passed through to CDK without this classic-control touch pass.
|
|
140
|
+
|
|
141
|
+
CDK determines eligibility for Next, header selection, and direct index changes:
|
|
142
|
+
|
|
143
|
+
- In linear mode, all preceding required steps must satisfy CDK's interaction and validation rules. Invalid or pending controls block advancement unless their step is optional or explicitly `[completed]="true"`.
|
|
144
|
+
- Optional steps can be skipped while invalid or pending. Explicit completion also permits advancement in those states.
|
|
145
|
+
- Without a `stepControl`, CDK uses `completed` (by default, whether the step was interacted with). Explicit `[completed]="false"` blocks a required control-less step. With a control, CDK uses its validation state; `[completed]="false"` does not veto an otherwise valid, interacted control.
|
|
146
|
+
- Non-linear navigation is not blocked by invalid/pending forms. CDK's backward-navigation `editable` rule still applies.
|
|
147
|
+
|
|
148
|
+
Header/direct selection retains CDK's interaction behavior and does not run Next's form-touch/revalidation pass. Next revalidation can restart a validator attached to the current control, so pending eligibility is evaluated after that pass.
|
|
149
|
+
|
|
150
|
+
Header `aria-disabled`, disabled styling and active state preview the same transition that CDK will attempt, in both orientations:
|
|
151
|
+
|
|
152
|
+
- An unvisited destination is enabled when its predecessors permit entry; the destination's own incomplete/invalid control does not block entry. A completed destination cannot bypass a blocked predecessor.
|
|
153
|
+
- The preview accounts for CDK marking the **current** step interacted on an attempt to leave it. It does not mark steps interacted while rendering. Other unvisited required predecessors still block skipping ahead unless optional or explicitly completed.
|
|
154
|
+
- Backward selection requires the destination's `editable` input and, in linear mode, eligible predecessors **before that destination**. The current step's invalid/pending state does not itself prevent going back.
|
|
155
|
+
- The selected header stays enabled as a no-op, including vertically; selecting it neither collapses the panel nor marks the step interacted.
|
|
156
|
+
|
|
157
|
+
Actual clicks and Enter/Space selection remain delegated to CDK. Disabled headers remain discoverable by keyboard focus; attempted keyboard selection cannot change the selected index, but retains CDK's current-step interaction notification. Header attempts do not touch or revalidate form controls. Classic-form status notifications (including async validator completion) refresh the affordance; Signal Field validity is read reactively.
|
|
140
158
|
|
|
141
159
|
### `HlmStep` — selector `hlm-step` (component, extends `CdkStep`)
|
|
142
160
|
|
|
@@ -145,7 +163,9 @@ Lazy body (attached only when the step is first selected):
|
|
|
145
163
|
| `label` | forwarded to `CdkStep` | — | Step title (string, or rich template via `hlmStepLabel`). |
|
|
146
164
|
| `icon` | `string \| null` | `null` | Icon name rendered when `indicatorMode="icon"`. |
|
|
147
165
|
| `stepControl` | forwarded to `CdkStep` | — | Form group driving `linear` validation. |
|
|
148
|
-
| `optional` | forwarded to `CdkStep` | — |
|
|
166
|
+
| `optional` | forwarded to `CdkStep` | — | Permits skipping in linear mode and shows an "Optional" caption. |
|
|
167
|
+
| `completed` | forwarded to `CdkStep` | — | Explicit completion override; see CDK navigation rules above. |
|
|
168
|
+
| `editable` | forwarded to `CdkStep` | `true` | Allows returning to this step; enforced in linear and non-linear modes. |
|
|
149
169
|
| `errorMessage` | forwarded to `CdkStep` | — | Header error caption when the step state is `error`. |
|
|
150
170
|
| `hasError` | forwarded to `CdkStep` | — | Forces the error state (pair with `STEPPER_GLOBAL_OPTIONS` `showError`). |
|
|
151
171
|
| `tooltip` | `string \| TemplateRef<unknown> \| null` | `null` (falls back to the full string label) | Styled header tooltip override; rich templates allowed. |
|
|
@@ -263,7 +283,7 @@ export class DemoResponsive {
|
|
|
263
283
|
|
|
264
284
|
### 4. Linear stepper with validation
|
|
265
285
|
|
|
266
|
-
With `linear`,
|
|
286
|
+
With `linear`, required steps normally need valid, non-pending controls before advancing. `HlmStepper.next()` marks the current step form touched first; optional and explicitly completed steps follow the exceptions above:
|
|
267
287
|
|
|
268
288
|
```ts
|
|
269
289
|
import { Component, inject } from '@angular/core';
|
|
@@ -361,9 +381,9 @@ Steps using `<ng-template hlmStepLabel>` have no string to fall back to — pass
|
|
|
361
381
|
|
|
362
382
|
- 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`.
|
|
363
383
|
- Vertical headers use `role="button"` with `aria-expanded` / `aria-current="step"`.
|
|
364
|
-
- Keyboard: `
|
|
365
|
-
-
|
|
366
|
-
-
|
|
384
|
+
- Keyboard: CDK manages roving `tabIndex`, horizontal Left/Right (direction-aware), vertical Up/Down, Home/End, wrapping, and Enter/Space activation. Focus movement does not select a step. Disabled headers can receive keyboard focus so their labels and unavailable state remain discoverable.
|
|
385
|
+
- Headers that CDK cannot select get matching `aria-disabled="true"` and `data-disabled="true"` pointer/opacity styling, including non-editable backward destinations in non-linear mode. Explain in the label why a step is unavailable. Eligible unvisited destinations and the selected header are not disabled.
|
|
386
|
+
- Next marks classic form controls touched so applications can display validation feedback. Associate error text with the relevant controls; touching alone does not guarantee a screen-reader announcement.
|
|
367
387
|
|
|
368
388
|
## Theming / CSS variables
|
|
369
389
|
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, TemplateRef, Directive, ViewContainerRef, DestroyRef, input, booleanAttribute, contentChild, effect, untracked, ChangeDetectionStrategy, Component, InjectionToken, numberAttribute, computed, signal, NgModule } from '@angular/core';
|
|
2
|
+
import { inject, TemplateRef, Directive, ViewContainerRef, DestroyRef, input, booleanAttribute, contentChild, effect, untracked, ChangeDetectionStrategy, Component, InjectionToken, numberAttribute, computed, QueryList, signal, ViewChildren, NgModule } from '@angular/core';
|
|
3
3
|
import { TemplatePortal, CdkPortalOutlet } from '@angular/cdk/portal';
|
|
4
4
|
import * as i1 from '@angular/cdk/stepper';
|
|
5
5
|
import { CdkStepLabel, CdkStep, CdkStepHeader, CdkStepper, CdkStepperModule, CdkStepperNext, CdkStepperPrevious } from '@angular/cdk/stepper';
|
|
6
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
7
|
import { NgTemplateOutlet } from '@angular/common';
|
|
7
8
|
import { NgIcon, provideIcons } from '@ng-icons/core';
|
|
8
9
|
import { lucideCircleAlert, lucideCheck } from '@ng-icons/lucide';
|
|
9
10
|
import { buttonVariants } from '@egose/shadcn-theme-ng/button';
|
|
10
11
|
import { classes, hlm } from '@egose/shadcn-theme-ng/utils';
|
|
11
|
-
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
12
12
|
import { HlmTooltip } from '@egose/shadcn-theme-ng/tooltip';
|
|
13
13
|
import { cva } from 'class-variance-authority';
|
|
14
14
|
import { tap } from 'rxjs/operators';
|
|
@@ -42,6 +42,41 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
42
42
|
class HlmStep extends CdkStep {
|
|
43
43
|
_viewContainerRef = inject(ViewContainerRef);
|
|
44
44
|
_destroyRef = inject(DestroyRef);
|
|
45
|
+
_hasCompletionOverride = false;
|
|
46
|
+
_controlSubscription;
|
|
47
|
+
ngOnChanges() {
|
|
48
|
+
super.ngOnChanges();
|
|
49
|
+
this._controlSubscription?.unsubscribe();
|
|
50
|
+
const control = this.stepControl;
|
|
51
|
+
if (control && typeof control !== 'function') {
|
|
52
|
+
// Classic form status getters are not reactive template dependencies, unlike Signal Fields.
|
|
53
|
+
this._controlSubscription = control.statusChanges
|
|
54
|
+
.pipe(takeUntilDestroyed(this._destroyRef))
|
|
55
|
+
.subscribe(() => this._stepper._stateChanged());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
get completed() {
|
|
59
|
+
return super.completed;
|
|
60
|
+
}
|
|
61
|
+
set completed(value) {
|
|
62
|
+
// Track input presence through the supported accessor, not CDK's internal override field.
|
|
63
|
+
this._hasCompletionOverride = value != null;
|
|
64
|
+
super.completed = value;
|
|
65
|
+
}
|
|
66
|
+
/** @internal Read-only preview of CDK's predecessor check after leaving the current step. */
|
|
67
|
+
_canExit(leaving) {
|
|
68
|
+
if (this.optional || this.completed) {
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
const interacted = this.interacted || leaving;
|
|
72
|
+
const control = this.stepControl;
|
|
73
|
+
if (!control) {
|
|
74
|
+
return interacted && !this._hasCompletionOverride;
|
|
75
|
+
}
|
|
76
|
+
const invalid = typeof control === 'function' ? control().invalid() : control.invalid;
|
|
77
|
+
const pending = typeof control === 'function' ? control().pending() : control.pending;
|
|
78
|
+
return interacted && !invalid && !pending;
|
|
79
|
+
}
|
|
45
80
|
icon = input(null, /* @ts-ignore */
|
|
46
81
|
...(ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []));
|
|
47
82
|
/** Styled header tooltip override. Falls back to the full string label when unset. */
|
|
@@ -81,7 +116,7 @@ class HlmStep extends CdkStep {
|
|
|
81
116
|
provide: CdkStep,
|
|
82
117
|
useExisting: HlmStep,
|
|
83
118
|
},
|
|
84
|
-
], queries: [{ propertyName: "stepLabelContent", first: true, predicate: HlmStepLabel, descendants: true, isSignal: true }, { propertyName: "_lazyContent", first: true, predicate: HlmStepContent, descendants: true, isSignal: true }], exportAs: ["hlmStep"], usesInheritance: true, ngImport: i0, template: `
|
|
119
|
+
], queries: [{ propertyName: "stepLabelContent", first: true, predicate: HlmStepLabel, descendants: true, isSignal: true }, { propertyName: "_lazyContent", first: true, predicate: HlmStepContent, descendants: true, isSignal: true }], exportAs: ["hlmStep"], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: `
|
|
85
120
|
<ng-template>
|
|
86
121
|
<ng-content></ng-content>
|
|
87
122
|
<ng-template [cdkPortalOutlet]="portal"></ng-template>
|
|
@@ -244,6 +279,8 @@ const stepTransition = cva('', {
|
|
|
244
279
|
});
|
|
245
280
|
class HlmStepper extends CdkStepper {
|
|
246
281
|
_config = injectHlmStepperConfig();
|
|
282
|
+
// Headers are rendered in this component's view, not in CDK's projected content query.
|
|
283
|
+
_stepHeader = new QueryList();
|
|
247
284
|
labelPosition = input('end', /* @ts-ignore */
|
|
248
285
|
...(ngDevMode ? [{ debugName: "labelPosition" }] : /* istanbul ignore next */ []));
|
|
249
286
|
headerPosition = input('top', /* @ts-ignore */
|
|
@@ -271,23 +308,35 @@ class HlmStepper extends CdkStepper {
|
|
|
271
308
|
}), takeUntilDestroyed())
|
|
272
309
|
.subscribe();
|
|
273
310
|
}
|
|
311
|
+
/** Touch and revalidate the current reactive form, then let CDK decide whether navigation is allowed. */
|
|
274
312
|
next() {
|
|
275
313
|
const stepControl = this.selected?.stepControl;
|
|
276
314
|
if (stepControl && typeof stepControl !== 'function') {
|
|
277
|
-
//
|
|
278
|
-
// Signal `Field` controls expose validity through invocation and need no touch pass.
|
|
315
|
+
// Preserve validation feedback for classic controls. Signal Fields are handled by CDK.
|
|
279
316
|
stepControl.markAllAsTouched();
|
|
280
317
|
stepControl.updateValueAndValidity();
|
|
281
318
|
}
|
|
282
|
-
|
|
283
|
-
if (this.linear && invalid) {
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
319
|
+
// CDK applies optional/completion overrides and checks all preceding controls, including pending ones.
|
|
286
320
|
super.next();
|
|
287
321
|
}
|
|
288
322
|
stepIcon(step) {
|
|
289
323
|
return step instanceof HlmStep ? step.icon() : null;
|
|
290
324
|
}
|
|
325
|
+
/** Preview selection without touching forms or marking steps interacted; activation stays with CDK. */
|
|
326
|
+
_isHeaderEnabled(step) {
|
|
327
|
+
const index = step.index();
|
|
328
|
+
if (index === this.selectedIndex) {
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
331
|
+
if (index < this.selectedIndex && !step.editable) {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
return (!this.linear ||
|
|
335
|
+
this.steps
|
|
336
|
+
.toArray()
|
|
337
|
+
.slice(0, index)
|
|
338
|
+
.every((previous) => previous instanceof HlmStep && previous._canExit(previous === this.selected)));
|
|
339
|
+
}
|
|
291
340
|
_headerTooltip(step) {
|
|
292
341
|
const override = step instanceof HlmStep ? step.tooltip() : null;
|
|
293
342
|
if (override === null || override === undefined) {
|
|
@@ -327,7 +376,7 @@ class HlmStepper extends CdkStepper {
|
|
|
327
376
|
return hlm("ms-4 overflow-hidden ps-6", showConnector && "border-s", this.animationsEnabled() && this.selectedIndex === index && stepTransition({ motion: 'enter-bottom' }));
|
|
328
377
|
}
|
|
329
378
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmStepper, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
330
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: HlmStepper, isStandalone: true, selector: "hlm-stepper", inputs: { labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", isSignal: true, isRequired: false, transformFunction: null }, headerPosition: { classPropertyName: "headerPosition", publicName: "headerPosition", isSignal: true, isRequired: false, transformFunction: null }, indicatorMode: { classPropertyName: "indicatorMode", publicName: "indicatorMode", isSignal: true, isRequired: false, transformFunction: null }, stepperAriaLabel: { classPropertyName: "stepperAriaLabel", publicName: "stepperAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, stepperAriaLabelledby: { classPropertyName: "stepperAriaLabelledby", publicName: "stepperAriaLabelledby", isSignal: true, isRequired: false, transformFunction: null }, animationsEnabled: { classPropertyName: "animationsEnabled", publicName: "animationsEnabled", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: CdkStepper, useExisting: HlmStepper }], usesInheritance: true, ngImport: i0, template: "\n @switch (orientation) {\n @case ('horizontal') {\n <div class=\"flex w-full flex-col gap-6\">\n @if (headerPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n } @else {\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n }\n </div>\n }\n\n @case ('vertical') {\n <div class=\"flex w-full flex-col gap-3\">\n @for (step of steps; track step; let i = $index) {\n <div class=\"flex flex-col gap-2\">\n <ng-container [ngTemplateOutlet]=\"stepHeaderTemplate\" [ngTemplateOutletContext]=\"{ step: step }\" />\n\n <div\n [class]=\"_gridContainerClass(selectedIndex === i)\"\n [style.transition-duration.ms]=\"animationDuration()\"\n >\n <section\n [class]=\"_verticalStepClass(!$last, i)\"\n role=\"region\"\n [id]=\"_getStepContentId(i)\"\n [attr.aria-labelledby]=\"_getStepLabelId(i)\"\n >\n <ng-container [ngTemplateOutlet]=\"step.content\" />\n </section>\n </div>\n\n @if (!$last) {\n <div class=\"ms-4 h-6 w-px\" aria-hidden=\"true\">\n <span [class]=\"_connectorClass(step.index())\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n\n <ng-template #stepHeaderTemplate let-step=\"step\">\n <hlm-step-header\n cdkStepHeader\n class=\"min-w-0\"\n (click)=\"step.select()\"\n (keydown)=\"_onKeydown($event)\"\n [tabIndex]=\"_getFocusIndex() === step.index() ? 0 : -1\"\n [id]=\"_getStepLabelId(step.index())\"\n [attr.role]=\"orientation === 'horizontal' ? 'tab' : 'button'\"\n [attr.aria-posinset]=\"orientation === 'horizontal' ? step.index() + 1 : null\"\n [attr.aria-setsize]=\"orientation === 'horizontal' ? steps.length : null\"\n [attr.aria-selected]=\"orientation === 'horizontal' ? step.isSelected() : null\"\n [attr.aria-current]=\"orientation === 'vertical' && step.isSelected() ? 'step' : null\"\n [attr.aria-expanded]=\"orientation === 'vertical' ? step.isSelected() : null\"\n [attr.aria-controls]=\"_getStepContentId(step.index())\"\n [attr.aria-label]=\"step.ariaLabel || null\"\n [attr.aria-labelledby]=\"!step.ariaLabel && step.ariaLabelledby ? step.ariaLabelledby : null\"\n [attr.aria-disabled]=\"
|
|
379
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: HlmStepper, isStandalone: true, selector: "hlm-stepper", inputs: { labelPosition: { classPropertyName: "labelPosition", publicName: "labelPosition", isSignal: true, isRequired: false, transformFunction: null }, headerPosition: { classPropertyName: "headerPosition", publicName: "headerPosition", isSignal: true, isRequired: false, transformFunction: null }, indicatorMode: { classPropertyName: "indicatorMode", publicName: "indicatorMode", isSignal: true, isRequired: false, transformFunction: null }, stepperAriaLabel: { classPropertyName: "stepperAriaLabel", publicName: "stepperAriaLabel", isSignal: true, isRequired: false, transformFunction: null }, stepperAriaLabelledby: { classPropertyName: "stepperAriaLabelledby", publicName: "stepperAriaLabelledby", isSignal: true, isRequired: false, transformFunction: null }, animationsEnabled: { classPropertyName: "animationsEnabled", publicName: "animationsEnabled", isSignal: true, isRequired: false, transformFunction: null }, animationDuration: { classPropertyName: "animationDuration", publicName: "animationDuration", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: CdkStepper, useExisting: HlmStepper }], viewQueries: [{ propertyName: "_stepHeader", predicate: CdkStepHeader, descendants: true }], usesInheritance: true, ngImport: i0, template: "\n @switch (orientation) {\n @case ('horizontal') {\n <div class=\"flex w-full flex-col gap-6\">\n @if (headerPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n } @else {\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n }\n </div>\n }\n\n @case ('vertical') {\n <div class=\"flex w-full flex-col gap-3\">\n @for (step of steps; track step; let i = $index) {\n <div class=\"flex flex-col gap-2\">\n <ng-container [ngTemplateOutlet]=\"stepHeaderTemplate\" [ngTemplateOutletContext]=\"{ step: step }\" />\n\n <div\n [class]=\"_gridContainerClass(selectedIndex === i)\"\n [style.transition-duration.ms]=\"animationDuration()\"\n >\n <section\n [class]=\"_verticalStepClass(!$last, i)\"\n role=\"region\"\n [id]=\"_getStepContentId(i)\"\n [attr.aria-labelledby]=\"_getStepLabelId(i)\"\n >\n <ng-container [ngTemplateOutlet]=\"step.content\" />\n </section>\n </div>\n\n @if (!$last) {\n <div class=\"ms-4 h-6 w-px\" aria-hidden=\"true\">\n <span [class]=\"_connectorClass(step.index())\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n\n <ng-template #stepHeaderTemplate let-step=\"step\">\n @let enabled = _isHeaderEnabled(step);\n <hlm-step-header\n cdkStepHeader\n class=\"min-w-0\"\n (click)=\"step.select()\"\n (keydown)=\"_onKeydown($event)\"\n [tabIndex]=\"_getFocusIndex() === step.index() ? 0 : -1\"\n [id]=\"_getStepLabelId(step.index())\"\n [attr.role]=\"orientation === 'horizontal' ? 'tab' : 'button'\"\n [attr.aria-posinset]=\"orientation === 'horizontal' ? step.index() + 1 : null\"\n [attr.aria-setsize]=\"orientation === 'horizontal' ? steps.length : null\"\n [attr.aria-selected]=\"orientation === 'horizontal' ? step.isSelected() : null\"\n [attr.aria-current]=\"orientation === 'vertical' && step.isSelected() ? 'step' : null\"\n [attr.aria-expanded]=\"orientation === 'vertical' ? step.isSelected() : null\"\n [attr.aria-controls]=\"_getStepContentId(step.index())\"\n [attr.aria-label]=\"step.ariaLabel || null\"\n [attr.aria-labelledby]=\"!step.ariaLabel && step.ariaLabelledby ? step.ariaLabelledby : null\"\n [attr.aria-disabled]=\"enabled ? null : 'true'\"\n [index]=\"step.index()\"\n [state]=\"step.indicatorType()\"\n [label]=\"step.stepLabelContent() || step.label\"\n [selected]=\"step.isSelected()\"\n [reached]=\"step.index() < selectedIndex\"\n [active]=\"enabled\"\n [optional]=\"step.optional\"\n [errorMessage]=\"step.errorMessage\"\n [disabled]=\"!enabled\"\n [labelPosition]=\"orientation === 'horizontal' ? labelPosition() : 'end'\"\n [indicatorMode]=\"indicatorMode()\"\n [icon]=\"stepIcon(step)\"\n [hlmTooltip]=\"_headerTooltip(step)\"\n [position]=\"_headerTooltipPosition(step)\"\n [tooltipDisabled]=\"_headerTooltipDisabled(step)\"\n />\n </ng-template>\n\n <ng-template #horizontalStepsTemplate let-steps=\"steps\">\n <ol\n class=\"flex w-full items-center\"\n role=\"tablist\"\n aria-orientation=\"horizontal\"\n [attr.aria-label]=\"stepperAriaLabelledby() ? null : (stepperAriaLabel() ?? null)\"\n [attr.aria-labelledby]=\"stepperAriaLabelledby()\"\n >\n @for (step of steps; track step) {\n <li class=\"flex min-w-0 items-center\">\n <ng-container [ngTemplateOutlet]=\"stepHeaderTemplate\" [ngTemplateOutletContext]=\"{ step: step }\" />\n </li>\n\n @if (!$last) {\n <li class=\"mx-3 flex min-w-8 flex-1 items-center\" aria-hidden=\"true\">\n <span class=\"bg-border relative h-px w-full overflow-hidden rounded\">\n <span\n class=\"bg-primary absolute inset-y-0 inset-s-0 transition-[width] duration-200\"\n [style.width.%]=\"step.index() < selectedIndex ? 100 : 0\"\n ></span>\n </span>\n </li>\n }\n }\n </ol>\n </ng-template>\n\n <ng-template #horizontalPanelTemplate>\n <div class=\"relative min-h-0 overflow-hidden\">\n @for (activeIndex of [selectedIndex]; track activeIndex) {\n <section\n role=\"tabpanel\"\n [id]=\"_getStepContentId(activeIndex)\"\n [attr.aria-labelledby]=\"_getStepLabelId(activeIndex)\"\n [style.animation-duration.ms]=\"animationDuration()\"\n [animate.enter]=\"animationsEnabled() ? _enterAnimationClass() : ''\"\n [animate.leave]=\"animationsEnabled() ? _leaveAnimationClass() : ''\"\n >\n <ng-container [ngTemplateOutlet]=\"steps.get(activeIndex)?.content\" />\n </section>\n }\n </div>\n </ng-template>\n ", isInline: true, dependencies: [{ kind: "ngmodule", type: CdkStepperModule }, { kind: "directive", type: i1.CdkStepHeader, selector: "[cdkStepHeader]" }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: HlmStepHeader, selector: "hlm-step-header", inputs: ["state", "label", "errorMessage", "index", "selected", "reached", "active", "optional", "disabled", "icon", "indicatorMode", "labelPosition"] }, { kind: "directive", type: HlmTooltip, selector: "[hlmTooltip]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
331
380
|
}
|
|
332
381
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HlmStepper, decorators: [{
|
|
333
382
|
type: Component,
|
|
@@ -336,9 +385,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
336
385
|
imports: [CdkStepperModule, NgTemplateOutlet, HlmStepHeader, HlmTooltip],
|
|
337
386
|
providers: [{ provide: CdkStepper, useExisting: HlmStepper }],
|
|
338
387
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
339
|
-
template: "\n @switch (orientation) {\n @case ('horizontal') {\n <div class=\"flex w-full flex-col gap-6\">\n @if (headerPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n } @else {\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n }\n </div>\n }\n\n @case ('vertical') {\n <div class=\"flex w-full flex-col gap-3\">\n @for (step of steps; track step; let i = $index) {\n <div class=\"flex flex-col gap-2\">\n <ng-container [ngTemplateOutlet]=\"stepHeaderTemplate\" [ngTemplateOutletContext]=\"{ step: step }\" />\n\n <div\n [class]=\"_gridContainerClass(selectedIndex === i)\"\n [style.transition-duration.ms]=\"animationDuration()\"\n >\n <section\n [class]=\"_verticalStepClass(!$last, i)\"\n role=\"region\"\n [id]=\"_getStepContentId(i)\"\n [attr.aria-labelledby]=\"_getStepLabelId(i)\"\n >\n <ng-container [ngTemplateOutlet]=\"step.content\" />\n </section>\n </div>\n\n @if (!$last) {\n <div class=\"ms-4 h-6 w-px\" aria-hidden=\"true\">\n <span [class]=\"_connectorClass(step.index())\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n\n <ng-template #stepHeaderTemplate let-step=\"step\">\n <hlm-step-header\n cdkStepHeader\n class=\"min-w-0\"\n (click)=\"step.select()\"\n (keydown)=\"_onKeydown($event)\"\n [tabIndex]=\"_getFocusIndex() === step.index() ? 0 : -1\"\n [id]=\"_getStepLabelId(step.index())\"\n [attr.role]=\"orientation === 'horizontal' ? 'tab' : 'button'\"\n [attr.aria-posinset]=\"orientation === 'horizontal' ? step.index() + 1 : null\"\n [attr.aria-setsize]=\"orientation === 'horizontal' ? steps.length : null\"\n [attr.aria-selected]=\"orientation === 'horizontal' ? step.isSelected() : null\"\n [attr.aria-current]=\"orientation === 'vertical' && step.isSelected() ? 'step' : null\"\n [attr.aria-expanded]=\"orientation === 'vertical' ? step.isSelected() : null\"\n [attr.aria-controls]=\"_getStepContentId(step.index())\"\n [attr.aria-label]=\"step.ariaLabel || null\"\n [attr.aria-labelledby]=\"!step.ariaLabel && step.ariaLabelledby ? step.ariaLabelledby : null\"\n [attr.aria-disabled]=\"
|
|
388
|
+
template: "\n @switch (orientation) {\n @case ('horizontal') {\n <div class=\"flex w-full flex-col gap-6\">\n @if (headerPosition() === 'top') {\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n } @else {\n <ng-container [ngTemplateOutlet]=\"horizontalPanelTemplate\" />\n <ng-container [ngTemplateOutlet]=\"horizontalStepsTemplate\" [ngTemplateOutletContext]=\"{ steps: steps }\" />\n }\n </div>\n }\n\n @case ('vertical') {\n <div class=\"flex w-full flex-col gap-3\">\n @for (step of steps; track step; let i = $index) {\n <div class=\"flex flex-col gap-2\">\n <ng-container [ngTemplateOutlet]=\"stepHeaderTemplate\" [ngTemplateOutletContext]=\"{ step: step }\" />\n\n <div\n [class]=\"_gridContainerClass(selectedIndex === i)\"\n [style.transition-duration.ms]=\"animationDuration()\"\n >\n <section\n [class]=\"_verticalStepClass(!$last, i)\"\n role=\"region\"\n [id]=\"_getStepContentId(i)\"\n [attr.aria-labelledby]=\"_getStepLabelId(i)\"\n >\n <ng-container [ngTemplateOutlet]=\"step.content\" />\n </section>\n </div>\n\n @if (!$last) {\n <div class=\"ms-4 h-6 w-px\" aria-hidden=\"true\">\n <span [class]=\"_connectorClass(step.index())\"></span>\n </div>\n }\n </div>\n }\n </div>\n }\n }\n\n <ng-template #stepHeaderTemplate let-step=\"step\">\n @let enabled = _isHeaderEnabled(step);\n <hlm-step-header\n cdkStepHeader\n class=\"min-w-0\"\n (click)=\"step.select()\"\n (keydown)=\"_onKeydown($event)\"\n [tabIndex]=\"_getFocusIndex() === step.index() ? 0 : -1\"\n [id]=\"_getStepLabelId(step.index())\"\n [attr.role]=\"orientation === 'horizontal' ? 'tab' : 'button'\"\n [attr.aria-posinset]=\"orientation === 'horizontal' ? step.index() + 1 : null\"\n [attr.aria-setsize]=\"orientation === 'horizontal' ? steps.length : null\"\n [attr.aria-selected]=\"orientation === 'horizontal' ? step.isSelected() : null\"\n [attr.aria-current]=\"orientation === 'vertical' && step.isSelected() ? 'step' : null\"\n [attr.aria-expanded]=\"orientation === 'vertical' ? step.isSelected() : null\"\n [attr.aria-controls]=\"_getStepContentId(step.index())\"\n [attr.aria-label]=\"step.ariaLabel || null\"\n [attr.aria-labelledby]=\"!step.ariaLabel && step.ariaLabelledby ? step.ariaLabelledby : null\"\n [attr.aria-disabled]=\"enabled ? null : 'true'\"\n [index]=\"step.index()\"\n [state]=\"step.indicatorType()\"\n [label]=\"step.stepLabelContent() || step.label\"\n [selected]=\"step.isSelected()\"\n [reached]=\"step.index() < selectedIndex\"\n [active]=\"enabled\"\n [optional]=\"step.optional\"\n [errorMessage]=\"step.errorMessage\"\n [disabled]=\"!enabled\"\n [labelPosition]=\"orientation === 'horizontal' ? labelPosition() : 'end'\"\n [indicatorMode]=\"indicatorMode()\"\n [icon]=\"stepIcon(step)\"\n [hlmTooltip]=\"_headerTooltip(step)\"\n [position]=\"_headerTooltipPosition(step)\"\n [tooltipDisabled]=\"_headerTooltipDisabled(step)\"\n />\n </ng-template>\n\n <ng-template #horizontalStepsTemplate let-steps=\"steps\">\n <ol\n class=\"flex w-full items-center\"\n role=\"tablist\"\n aria-orientation=\"horizontal\"\n [attr.aria-label]=\"stepperAriaLabelledby() ? null : (stepperAriaLabel() ?? null)\"\n [attr.aria-labelledby]=\"stepperAriaLabelledby()\"\n >\n @for (step of steps; track step) {\n <li class=\"flex min-w-0 items-center\">\n <ng-container [ngTemplateOutlet]=\"stepHeaderTemplate\" [ngTemplateOutletContext]=\"{ step: step }\" />\n </li>\n\n @if (!$last) {\n <li class=\"mx-3 flex min-w-8 flex-1 items-center\" aria-hidden=\"true\">\n <span class=\"bg-border relative h-px w-full overflow-hidden rounded\">\n <span\n class=\"bg-primary absolute inset-y-0 inset-s-0 transition-[width] duration-200\"\n [style.width.%]=\"step.index() < selectedIndex ? 100 : 0\"\n ></span>\n </span>\n </li>\n }\n }\n </ol>\n </ng-template>\n\n <ng-template #horizontalPanelTemplate>\n <div class=\"relative min-h-0 overflow-hidden\">\n @for (activeIndex of [selectedIndex]; track activeIndex) {\n <section\n role=\"tabpanel\"\n [id]=\"_getStepContentId(activeIndex)\"\n [attr.aria-labelledby]=\"_getStepLabelId(activeIndex)\"\n [style.animation-duration.ms]=\"animationDuration()\"\n [animate.enter]=\"animationsEnabled() ? _enterAnimationClass() : ''\"\n [animate.leave]=\"animationsEnabled() ? _leaveAnimationClass() : ''\"\n >\n <ng-container [ngTemplateOutlet]=\"steps.get(activeIndex)?.content\" />\n </section>\n }\n </div>\n </ng-template>\n ",
|
|
340
389
|
}]
|
|
341
|
-
}], ctorParameters: () => [], propDecorators: {
|
|
390
|
+
}], ctorParameters: () => [], propDecorators: { _stepHeader: [{
|
|
391
|
+
type: ViewChildren,
|
|
392
|
+
args: [CdkStepHeader]
|
|
393
|
+
}], labelPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPosition", required: false }] }], headerPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerPosition", required: false }] }], indicatorMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "indicatorMode", required: false }] }], stepperAriaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepperAriaLabel", required: false }] }], stepperAriaLabelledby: [{ type: i0.Input, args: [{ isSignal: true, alias: "stepperAriaLabelledby", required: false }] }], animationsEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationsEnabled", required: false }] }], animationDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationDuration", required: false }] }] } });
|
|
342
394
|
|
|
343
395
|
/** Button that moves to the next step in a stepper workflow. */
|
|
344
396
|
class HlmStepperNext extends CdkStepperNext {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _angular_core from '@angular/core';
|
|
2
|
-
import { ValueProvider, TemplateRef } from '@angular/core';
|
|
2
|
+
import { ValueProvider, TemplateRef, QueryList } from '@angular/core';
|
|
3
3
|
import { TemplatePortal } from '@angular/cdk/portal';
|
|
4
4
|
import { CdkStepLabel, CdkStep, CdkStepHeader, CdkStepper, CdkStepperNext, CdkStepperPrevious } from '@angular/cdk/stepper';
|
|
5
5
|
|
|
@@ -23,6 +23,13 @@ declare function injectHlmStepperConfig(): HlmStepperConfig;
|
|
|
23
23
|
declare class HlmStep extends CdkStep {
|
|
24
24
|
private readonly _viewContainerRef;
|
|
25
25
|
private readonly _destroyRef;
|
|
26
|
+
private _hasCompletionOverride;
|
|
27
|
+
private _controlSubscription?;
|
|
28
|
+
ngOnChanges(): void;
|
|
29
|
+
get completed(): boolean;
|
|
30
|
+
set completed(value: boolean);
|
|
31
|
+
/** @internal Read-only preview of CDK's predecessor check after leaving the current step. */
|
|
32
|
+
_canExit(leaving: boolean): boolean;
|
|
26
33
|
readonly icon: _angular_core.InputSignal<string | null>;
|
|
27
34
|
/** Styled header tooltip override. Falls back to the full string label when unset. */
|
|
28
35
|
readonly tooltip: _angular_core.InputSignal<string | TemplateRef<unknown> | null>;
|
|
@@ -77,6 +84,7 @@ declare class HlmStepHeader extends CdkStepHeader {
|
|
|
77
84
|
|
|
78
85
|
declare class HlmStepper extends CdkStepper {
|
|
79
86
|
private readonly _config;
|
|
87
|
+
_stepHeader: QueryList<CdkStepHeader>;
|
|
80
88
|
readonly labelPosition: _angular_core.InputSignal<HlmStepperLabelPosition>;
|
|
81
89
|
readonly headerPosition: _angular_core.InputSignal<HlmStepperHeaderPosition>;
|
|
82
90
|
readonly indicatorMode: _angular_core.InputSignal<HlmStepperIndicatorMode>;
|
|
@@ -87,8 +95,11 @@ declare class HlmStepper extends CdkStepper {
|
|
|
87
95
|
protected readonly _animationDirection: _angular_core.WritableSignal<"forward" | "backward">;
|
|
88
96
|
protected readonly _hasSelectionChanged: _angular_core.WritableSignal<boolean>;
|
|
89
97
|
constructor();
|
|
98
|
+
/** Touch and revalidate the current reactive form, then let CDK decide whether navigation is allowed. */
|
|
90
99
|
next(): void;
|
|
91
100
|
protected stepIcon(step: CdkStep): string | null;
|
|
101
|
+
/** Preview selection without touching forms or marking steps interacted; activation stays with CDK. */
|
|
102
|
+
protected _isHeaderEnabled(step: HlmStep): boolean;
|
|
92
103
|
protected _headerTooltip(step: CdkStep): string | TemplateRef<void> | null;
|
|
93
104
|
protected _headerTooltipPosition(step: CdkStep): HlmStepTooltipPosition;
|
|
94
105
|
protected _headerTooltipDisabled(step: CdkStep): boolean;
|