@cdevhub/ngx-tw 0.2.0

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 (171) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +134 -0
  3. package/fesm2022/cdevhub-ngx-tw-accordion.mjs +108 -0
  4. package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -0
  5. package/fesm2022/cdevhub-ngx-tw-alert.mjs +240 -0
  6. package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -0
  7. package/fesm2022/cdevhub-ngx-tw-avatar.mjs +287 -0
  8. package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -0
  9. package/fesm2022/cdevhub-ngx-tw-badge.mjs +332 -0
  10. package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -0
  11. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +452 -0
  12. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -0
  13. package/fesm2022/cdevhub-ngx-tw-button.mjs +227 -0
  14. package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -0
  15. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +417 -0
  16. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -0
  17. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs +232 -0
  18. package/fesm2022/cdevhub-ngx-tw-calendar-testing.mjs.map +1 -0
  19. package/fesm2022/cdevhub-ngx-tw-calendar.mjs +4482 -0
  20. package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -0
  21. package/fesm2022/cdevhub-ngx-tw-card.mjs +157 -0
  22. package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -0
  23. package/fesm2022/cdevhub-ngx-tw-carousel.mjs +1454 -0
  24. package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -0
  25. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +593 -0
  26. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -0
  27. package/fesm2022/cdevhub-ngx-tw-code-block.mjs +228 -0
  28. package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -0
  29. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +510 -0
  30. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -0
  31. package/fesm2022/cdevhub-ngx-tw-combobox.mjs +1721 -0
  32. package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -0
  33. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +721 -0
  34. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -0
  35. package/fesm2022/cdevhub-ngx-tw-core.mjs +861 -0
  36. package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -0
  37. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +1558 -0
  38. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -0
  39. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +1833 -0
  40. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -0
  41. package/fesm2022/cdevhub-ngx-tw-dialog.mjs +693 -0
  42. package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -0
  43. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +331 -0
  44. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -0
  45. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +289 -0
  46. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -0
  47. package/fesm2022/cdevhub-ngx-tw-form-field.mjs +572 -0
  48. package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -0
  49. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +36 -0
  50. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -0
  51. package/fesm2022/cdevhub-ngx-tw-icon.mjs +278 -0
  52. package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -0
  53. package/fesm2022/cdevhub-ngx-tw-input.mjs +355 -0
  54. package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -0
  55. package/fesm2022/cdevhub-ngx-tw-item.mjs +241 -0
  56. package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -0
  57. package/fesm2022/cdevhub-ngx-tw-menu.mjs +433 -0
  58. package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -0
  59. package/fesm2022/cdevhub-ngx-tw-paginator.mjs +691 -0
  60. package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -0
  61. package/fesm2022/cdevhub-ngx-tw-popover.mjs +678 -0
  62. package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -0
  63. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +335 -0
  64. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -0
  65. package/fesm2022/cdevhub-ngx-tw-radio.mjs +708 -0
  66. package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -0
  67. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +319 -0
  68. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -0
  69. package/fesm2022/cdevhub-ngx-tw-select.mjs +1722 -0
  70. package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -0
  71. package/fesm2022/cdevhub-ngx-tw-separator.mjs +115 -0
  72. package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -0
  73. package/fesm2022/cdevhub-ngx-tw-sheet.mjs +768 -0
  74. package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -0
  75. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +149 -0
  76. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -0
  77. package/fesm2022/cdevhub-ngx-tw-slider.mjs +1147 -0
  78. package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -0
  79. package/fesm2022/cdevhub-ngx-tw-sort.mjs +346 -0
  80. package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -0
  81. package/fesm2022/cdevhub-ngx-tw-spinner.mjs +186 -0
  82. package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -0
  83. package/fesm2022/cdevhub-ngx-tw-split.mjs +1082 -0
  84. package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -0
  85. package/fesm2022/cdevhub-ngx-tw-stat.mjs +579 -0
  86. package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -0
  87. package/fesm2022/cdevhub-ngx-tw-stepper.mjs +443 -0
  88. package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -0
  89. package/fesm2022/cdevhub-ngx-tw-switch.mjs +391 -0
  90. package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -0
  91. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +315 -0
  92. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -0
  93. package/fesm2022/cdevhub-ngx-tw-table.mjs +994 -0
  94. package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -0
  95. package/fesm2022/cdevhub-ngx-tw-tabs.mjs +508 -0
  96. package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -0
  97. package/fesm2022/cdevhub-ngx-tw-textarea.mjs +147 -0
  98. package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -0
  99. package/fesm2022/cdevhub-ngx-tw-theme.mjs +178 -0
  100. package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -0
  101. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +1344 -0
  102. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -0
  103. package/fesm2022/cdevhub-ngx-tw-timeline.mjs +1136 -0
  104. package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -0
  105. package/fesm2022/cdevhub-ngx-tw-toast.mjs +1311 -0
  106. package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -0
  107. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +533 -0
  108. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -0
  109. package/fesm2022/cdevhub-ngx-tw.mjs +61 -0
  110. package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -0
  111. package/package.json +265 -0
  112. package/theme/_base.css +394 -0
  113. package/theme/_dark.css +510 -0
  114. package/theme/_high-contrast.css +290 -0
  115. package/theme/_semantic.css +317 -0
  116. package/theme/_typography.css +9 -0
  117. package/theme/index.css +54 -0
  118. package/types/cdevhub-ngx-tw-accordion.d.ts +48 -0
  119. package/types/cdevhub-ngx-tw-alert.d.ts +67 -0
  120. package/types/cdevhub-ngx-tw-avatar.d.ts +79 -0
  121. package/types/cdevhub-ngx-tw-badge.d.ts +94 -0
  122. package/types/cdevhub-ngx-tw-breadcrumbs.d.ts +227 -0
  123. package/types/cdevhub-ngx-tw-button.d.ts +74 -0
  124. package/types/cdevhub-ngx-tw-calendar-luxon.d.ts +200 -0
  125. package/types/cdevhub-ngx-tw-calendar-testing.d.ts +113 -0
  126. package/types/cdevhub-ngx-tw-calendar.d.ts +1704 -0
  127. package/types/cdevhub-ngx-tw-card.d.ts +48 -0
  128. package/types/cdevhub-ngx-tw-carousel.d.ts +406 -0
  129. package/types/cdevhub-ngx-tw-checkbox.d.ts +136 -0
  130. package/types/cdevhub-ngx-tw-code-block.d.ts +93 -0
  131. package/types/cdevhub-ngx-tw-collapsible.d.ts +151 -0
  132. package/types/cdevhub-ngx-tw-combobox.d.ts +389 -0
  133. package/types/cdevhub-ngx-tw-command-palette.d.ts +215 -0
  134. package/types/cdevhub-ngx-tw-core.d.ts +719 -0
  135. package/types/cdevhub-ngx-tw-date-picker.d.ts +317 -0
  136. package/types/cdevhub-ngx-tw-date-range-picker.d.ts +313 -0
  137. package/types/cdevhub-ngx-tw-dialog.d.ts +303 -0
  138. package/types/cdevhub-ngx-tw-empty-state.d.ts +104 -0
  139. package/types/cdevhub-ngx-tw-flip-card.d.ts +95 -0
  140. package/types/cdevhub-ngx-tw-form-field.d.ts +210 -0
  141. package/types/cdevhub-ngx-tw-icon-lucide.d.ts +29 -0
  142. package/types/cdevhub-ngx-tw-icon.d.ts +134 -0
  143. package/types/cdevhub-ngx-tw-input.d.ts +110 -0
  144. package/types/cdevhub-ngx-tw-item.d.ts +70 -0
  145. package/types/cdevhub-ngx-tw-menu.d.ts +99 -0
  146. package/types/cdevhub-ngx-tw-paginator.d.ts +305 -0
  147. package/types/cdevhub-ngx-tw-popover.d.ts +157 -0
  148. package/types/cdevhub-ngx-tw-progress-bar.d.ts +100 -0
  149. package/types/cdevhub-ngx-tw-radio.d.ts +174 -0
  150. package/types/cdevhub-ngx-tw-segmented-control.d.ts +66 -0
  151. package/types/cdevhub-ngx-tw-select.d.ts +384 -0
  152. package/types/cdevhub-ngx-tw-separator.d.ts +28 -0
  153. package/types/cdevhub-ngx-tw-sheet.d.ts +335 -0
  154. package/types/cdevhub-ngx-tw-skeleton.d.ts +52 -0
  155. package/types/cdevhub-ngx-tw-slider.d.ts +258 -0
  156. package/types/cdevhub-ngx-tw-sort.d.ts +136 -0
  157. package/types/cdevhub-ngx-tw-spinner.d.ts +50 -0
  158. package/types/cdevhub-ngx-tw-split.d.ts +265 -0
  159. package/types/cdevhub-ngx-tw-stat.d.ts +140 -0
  160. package/types/cdevhub-ngx-tw-stepper.d.ts +127 -0
  161. package/types/cdevhub-ngx-tw-switch.d.ts +88 -0
  162. package/types/cdevhub-ngx-tw-tab-nav.d.ts +107 -0
  163. package/types/cdevhub-ngx-tw-table.d.ts +479 -0
  164. package/types/cdevhub-ngx-tw-tabs.d.ts +121 -0
  165. package/types/cdevhub-ngx-tw-textarea.d.ts +62 -0
  166. package/types/cdevhub-ngx-tw-theme.d.ts +106 -0
  167. package/types/cdevhub-ngx-tw-time-picker.d.ts +303 -0
  168. package/types/cdevhub-ngx-tw-timeline.d.ts +278 -0
  169. package/types/cdevhub-ngx-tw-toast.d.ts +388 -0
  170. package/types/cdevhub-ngx-tw-tooltip.d.ts +95 -0
  171. package/types/cdevhub-ngx-tw.d.ts +49 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdevhub-ngx-tw-stat.mjs","sources":["../../../projects/ngx-tw/stat/stat.ts","../../../projects/ngx-tw/stat/cdevhub-ngx-tw-stat.ts"],"sourcesContent":["import {\n afterRenderEffect,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n type ElementRef,\n inject,\n input,\n Injector,\n signal,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { tv } from 'tailwind-variants';\nimport type { TwSize } from '@cdevhub/ngx-tw/core';\nimport { SkeletonComponent } from '@cdevhub/ngx-tw/skeleton';\n\n/** Surface treatment for the stat tile. */\nexport type StatVariant = 'plain' | 'outlined' | 'elevated' | 'filled';\n\n/** Direction of trend conveyed by the delta indicator. */\nexport type StatDeltaDirection = 'up' | 'down' | 'neutral';\n\n/** Display style of the trend delta. */\nexport type StatDeltaVariant = 'badge' | 'inline' | 'icon-only';\n\n// ── Slot marker directives (DOM projection) ───────────────────────────\n\n/** Label slot — short caption (\"Revenue\", \"Active users\"). Projected into `<dt>`. */\n@Directive({ selector: '[twStatLabel]' })\nexport class StatLabelDirective {}\n\n/** Value slot — the dominant numeric/text element. Projected into `<dd>`. */\n@Directive({ selector: '[twStatValue]' })\nexport class StatValueDirective {}\n\n/** Description slot — optional secondary text under the value. Projected into a second `<dd>`. */\n@Directive({ selector: '[twStatDescription]' })\nexport class StatDescriptionDirective {}\n\n/** Icon slot — optional leading icon. Triggers the icon-leading layout. */\n@Directive({ selector: '[twStatIcon]' })\nexport class StatIconDirective {}\n\n/** Footer slot — optional auxiliary region (sparklines, tags, metadata). Always renders, even during loading. */\n@Directive({ selector: '[twStatFooter]' })\nexport class StatFooterDirective {}\n\n// ── Stat tile tv() config ─────────────────────────────────────────────\n\nconst statTile = tv(\n {\n slots: {\n root: 'block text-fg',\n iconFlex: 'flex items-start gap-3',\n iconWrapper: 'shrink-0 text-fg-muted',\n contentStack: 'min-w-0 flex-1',\n dl: 'flex flex-col',\n label: 'text-fg-muted font-medium',\n valueRow: 'flex items-baseline gap-2 flex-wrap',\n value: 'text-fg block tabular-nums font-semibold',\n description: 'text-fg-muted',\n delta: 'inline-flex items-center',\n footer: 'mt-3 pt-3 border-t border-border',\n },\n variants: {\n variant: {\n plain: { root: 'bg-transparent' },\n outlined: { root: 'bg-surface border border-border rounded-lg' },\n elevated: {\n root: 'bg-surface-raised border border-border rounded-lg shadow hover:shadow-md transition-shadow duration-200 motion-reduce:transition-none',\n },\n filled: { root: 'bg-surface-muted rounded-lg' },\n },\n size: {\n xs: {\n root: 'p-2',\n dl: 'gap-1',\n label: 'text-2xs',\n value: 'text-xs',\n description: 'text-2xs',\n delta: 'mt-1',\n },\n sm: {\n root: 'p-3',\n dl: 'gap-1',\n label: 'text-xs',\n value: 'text-sm',\n description: 'text-xs',\n delta: 'mt-1',\n },\n md: {\n root: 'p-4',\n dl: 'gap-1.5',\n label: 'text-xs',\n value: 'text-base',\n description: 'text-xs',\n delta: 'mt-1',\n },\n // lg/xl `value` uses `text-base` per the KPI-value carve-out\n // (CLAUDE.md typography). The dominant numeric needs to outrank the\n // `text-sm` label/description in visual hierarchy.\n lg: {\n root: 'p-6',\n dl: 'gap-2',\n label: 'text-sm',\n value: 'text-base font-bold',\n description: 'text-sm',\n delta: 'mt-2',\n },\n xl: {\n root: 'p-8',\n dl: 'gap-2',\n label: 'text-sm',\n value: 'text-base font-extrabold',\n description: 'text-sm',\n delta: 'mt-2',\n },\n },\n },\n defaultVariants: {\n variant: 'outlined',\n size: 'md',\n },\n },\n { twMerge: true },\n);\n\n// ── Delta tv() config ─────────────────────────────────────────────────\n\nconst statDelta = tv(\n {\n slots: {\n root: 'relative inline-flex items-center gap-1 font-medium tabular-nums',\n icon: 'shrink-0',\n text: 'inline-flex items-center',\n comparison: 'text-fg-muted',\n },\n variants: {\n variant: {\n badge: {\n root: 'px-2 py-0.5 rounded-md text-xs',\n },\n inline: {\n root: 'text-xs',\n },\n 'icon-only': {\n // size-6 (24px) — square interactive-target scale at xs density per\n // CLAUDE.md icon sub-scale; here it just centres the chevron.\n root: 'justify-center size-6 rounded-md',\n // Text and comparison stay in the DOM so the composed aria-label\n // still picks them up; `sr-only` removes them visually.\n text: 'sr-only',\n comparison: 'sr-only',\n },\n },\n effectiveColor: {\n success: {},\n error: {},\n neutral: {},\n },\n },\n compoundVariants: [\n // ===== badge (soft chip) =====\n {\n variant: 'badge',\n effectiveColor: 'success',\n class: { root: 'bg-success-soft text-success-soft-fg' },\n },\n {\n variant: 'badge',\n effectiveColor: 'error',\n class: { root: 'bg-error-soft text-error-soft-fg' },\n },\n // Neutral pinned explicitly to surface/fg tokens (advisor: never use\n // `text-neutral-700` or template through neutral via -soft-fg chain).\n {\n variant: 'badge',\n effectiveColor: 'neutral',\n class: { root: 'bg-surface-muted text-fg-muted' },\n },\n\n // ===== inline (no chip) =====\n {\n variant: 'inline',\n effectiveColor: 'success',\n class: { root: 'text-success-700' },\n },\n {\n variant: 'inline',\n effectiveColor: 'error',\n class: { root: 'text-error-700' },\n },\n {\n variant: 'inline',\n effectiveColor: 'neutral',\n class: { root: 'text-fg-muted' },\n },\n\n // ===== icon-only =====\n {\n variant: 'icon-only',\n effectiveColor: 'success',\n class: { root: 'bg-success-soft text-success-soft-fg' },\n },\n {\n variant: 'icon-only',\n effectiveColor: 'error',\n class: { root: 'bg-error-soft text-error-soft-fg' },\n },\n {\n variant: 'icon-only',\n effectiveColor: 'neutral',\n class: { root: 'bg-surface-muted text-fg-muted' },\n },\n ],\n defaultVariants: {\n variant: 'badge',\n effectiveColor: 'neutral',\n },\n },\n { twMerge: true },\n);\n\n// ── Stat delta component ──────────────────────────────────────────────\n\n/**\n * Compact trend indicator — direction + projected delta text + optional\n * comparison label. Usable standalone or projected into a `<tw-stat>` tile.\n *\n * Sentiment is conveyed by both icon direction and color; consumers running\n * \"lower is better\" metrics (bounce rate, latency, churn) set `inverted` to\n * swap the success/error color mapping without changing the literal direction\n * or the announced verb.\n */\n@Component({\n selector: 'tw-stat-delta',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n role: 'img',\n '[class]': 'rootClasses()',\n '[attr.aria-label]': 'composedAriaLabel()',\n },\n template: `\n <svg\n [class]=\"iconClasses() + ' ' + iconSizeClass()\"\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n @switch (direction()) {\n @case ('up') { <path d=\"M4 10l4-4 4 4\" /> }\n @case ('down') { <path d=\"M4 6l4 4 4-4\" /> }\n @default { <path d=\"M3 8h10\" /> }\n }\n </svg>\n <span #textEl [class]=\"textClasses()\"><ng-content /></span>\n @if (comparisonLabel(); as comp) {\n <span [class]=\"comparisonClasses()\">{{ comp }}</span>\n }\n `,\n})\nexport class StatDeltaComponent {\n /** Direction of change. `'up'` renders an up-chevron and (by default) the `success` color; `'down'` renders a down-chevron and the `error` color; `'neutral'` renders a horizontal-line glyph and the neutral color. Defaults to `'neutral'`. */\n readonly direction = input<StatDeltaDirection>('neutral');\n\n /** When true, swaps success/error semantics so `down` reads as success and `up` reads as error — use for metrics where lower is better (bounce rate, error rate, latency, churn). `neutral` direction is unaffected. Defaults to `false`. */\n readonly inverted = input(false, { transform: booleanAttribute });\n\n /** Display style. `'badge'` (default) wraps the delta in a pill chip; `'inline'` is icon + text only with no chip; `'icon-only'` shows just the chevron for ultra-dense layouts. */\n readonly variant = input<StatDeltaVariant>('badge');\n\n /** Optional comparison label rendered next to the delta value (e.g. `\"vs last week\"`, `\"since launch\"`). Defaults to `undefined`. */\n readonly comparisonLabel = input<string>();\n\n /** Explicit accessible label. When omitted, the component composes one from `direction` + projected text + `comparisonLabel`. Override when projected content is purely symbolic or already localized. Defaults to `undefined`. */\n readonly ariaLabel = input<string>();\n\n /** @internal */\n protected readonly textEl = viewChild<ElementRef<HTMLElement>>('textEl');\n\n /** @internal */\n protected readonly projectedText = signal('');\n\n constructor() {\n const injector = inject(Injector);\n // Read the projected text via the wrapper span's textContent. textContent\n // is recursive across projected children, so this resolves the consumer's\n // string even when wrapped in arbitrary markup. afterRenderEffect runs\n // after each render so projection changes are captured.\n afterRenderEffect(\n () => {\n const el = this.textEl()?.nativeElement;\n if (!el) {\n this.projectedText.set('');\n return;\n }\n const text = (el.textContent ?? '').trim();\n this.projectedText.set(text);\n },\n { injector },\n );\n }\n\n /** @internal */\n protected readonly effectiveColor = computed<'success' | 'error' | 'neutral'>(() => {\n const dir = this.direction();\n if (dir === 'neutral') return 'neutral';\n const inv = this.inverted();\n if (dir === 'up') return inv ? 'error' : 'success';\n return inv ? 'success' : 'error';\n });\n\n /** @internal */\n protected readonly iconSizeClass = computed(() => {\n // Glyph sub-scale: size-3 (12px) at the badge/inline xs/sm density,\n // size-4 (16px) at md+. The delta lives inside text-xs, so size-3 holds.\n // Larger contexts (md / lg / xl on the parent tile) get size-4.\n return this.variant() === 'icon-only' ? 'size-4' : 'size-3';\n });\n\n /** @internal */\n protected readonly composedAriaLabel = computed(() => {\n const explicit = this.ariaLabel();\n if (explicit) return explicit;\n const dir = this.direction();\n const verb = dir === 'up' ? 'increased' : dir === 'down' ? 'decreased' : 'unchanged';\n const text = this.projectedText();\n const comp = this.comparisonLabel();\n const parts: string[] = [];\n if (text) {\n parts.push(`${verb} by ${text}`);\n } else {\n parts.push(verb);\n }\n if (comp) parts.push(comp);\n return parts.join(' ');\n });\n\n private readonly variantResult = computed(() =>\n statDelta({ variant: this.variant(), effectiveColor: this.effectiveColor() }),\n );\n\n protected readonly rootClasses = computed(() => this.variantResult().root());\n protected readonly iconClasses = computed(() => this.variantResult().icon());\n protected readonly textClasses = computed(() => this.variantResult().text());\n protected readonly comparisonClasses = computed(() => this.variantResult().comparison());\n}\n\n// ── Stat tile component ───────────────────────────────────────────────\n\n/**\n * KPI tile — a compact display tile surfacing a single key performance\n * indicator with an optional trend delta. Composes a `<dl>` / `<dt>` / `<dd>`\n * definition list internally so the label-to-value pairing is announced\n * naturally by assistive technology.\n *\n * Slots:\n * - `[twStatLabel]` — caption (rendered as `<dt>`).\n * - `[twStatValue]` — dominant value (rendered as `<dd>`).\n * - `[twStatDescription]` — optional secondary text (second `<dd>`).\n * - `[twStatIcon]` — optional leading icon (switches to icon-leading layout).\n * - `[twStatFooter]` — optional auxiliary region (sparklines, tags).\n * - `<tw-stat-delta>` — projected trend indicator alongside the value.\n *\n * Loading state replaces label/value/delta with `<tw-skeleton>` placeholders\n * sized to match the density. Footer always renders during loading so\n * consumers can compose their own skeleton charts.\n */\n@Component({\n selector: 'tw-stat',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [SkeletonComponent, NgTemplateOutlet],\n host: {\n '[class]': 'rootClasses()',\n // Permanent live region — `aria-busy` toggle alone signals state change\n // so assistive tech announces the resolved content on loading→loaded\n // without the live region being torn down mid-transition.\n 'aria-live': 'polite',\n '[attr.aria-busy]': 'loading() ? \"true\" : null',\n },\n template: `\n @if (iconLeading()) {\n <div [class]=\"iconFlexClasses()\">\n <div [class]=\"iconWrapperClasses()\">\n <ng-content select=\"[twStatIcon]\" />\n </div>\n <div [class]=\"contentStackClasses()\">\n <ng-container [ngTemplateOutlet]=\"dlBlock\" />\n </div>\n </div>\n } @else {\n <ng-container [ngTemplateOutlet]=\"dlBlock\" />\n }\n\n @if (hasFooter()) {\n <div [class]=\"footerClasses()\">\n <ng-content select=\"[twStatFooter]\" />\n </div>\n }\n\n <ng-template #dlBlock>\n <dl [class]=\"dlClasses()\">\n @if (loading()) {\n <dt [class]=\"labelClasses()\">\n <tw-skeleton width=\"40%\" height=\"0.75rem\" />\n </dt>\n } @else if (hasLabel()) {\n <dt [class]=\"labelClasses()\">\n <ng-content select=\"[twStatLabel]\" />\n </dt>\n }\n\n <dd [class]=\"valueRowClasses()\">\n @if (loading()) {\n <tw-skeleton [width]=\"loadingValueWidth()\" [height]=\"loadingValueHeight()\" />\n } @else if (hasValue()) {\n <span [class]=\"valueClasses()\">\n <ng-content select=\"[twStatValue]\" />\n </span>\n }\n\n @if (loading()) {\n <span [class]=\"deltaClasses()\">\n <tw-skeleton width=\"3rem\" height=\"1.25rem\" />\n </span>\n } @else if (hasDelta()) {\n <span [class]=\"deltaClasses()\">\n <ng-content select=\"tw-stat-delta\" />\n </span>\n }\n </dd>\n\n @if (!loading() && hasDescription()) {\n <dd [class]=\"descriptionClasses()\">\n <ng-content select=\"[twStatDescription]\" />\n </dd>\n }\n </dl>\n </ng-template>\n `,\n})\nexport class StatComponent {\n /** Surface treatment. `'plain'` removes border and background; `'outlined'` (default) adds a border on the surface token; `'elevated'` adds shadow and uses the raised surface; `'filled'` uses the muted surface with no border. */\n readonly variant = input<StatVariant>('outlined');\n\n /** Density scale — drives padding, internal gaps, value/label typography, and the skeleton placeholder dimensions. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** When true, replaces label, value, and delta regions with `<tw-skeleton>` placeholders and toggles `aria-busy=\"true\"` on the host. Projected footer content still renders. Defaults to `false`. */\n readonly loading = input(false, { transform: booleanAttribute });\n\n /** @internal */\n protected readonly labelSlot = contentChild(StatLabelDirective);\n /** @internal */\n protected readonly valueSlot = contentChild(StatValueDirective);\n /** @internal */\n protected readonly descriptionSlot = contentChild(StatDescriptionDirective);\n /** @internal */\n protected readonly iconSlot = contentChild(StatIconDirective);\n /** @internal */\n protected readonly footerSlot = contentChild(StatFooterDirective);\n /** @internal */\n protected readonly deltaSlot = contentChild(StatDeltaComponent);\n\n protected readonly hasLabel = computed(() => !!this.labelSlot());\n protected readonly hasValue = computed(() => !!this.valueSlot());\n protected readonly hasDescription = computed(() => !!this.descriptionSlot());\n protected readonly hasIcon = computed(() => !!this.iconSlot());\n protected readonly hasFooter = computed(() => !!this.footerSlot());\n protected readonly hasDelta = computed(() => !!this.deltaSlot());\n\n protected readonly iconLeading = computed(() => this.hasIcon());\n\n /** Skeleton width during loading state — scales with the size axis. */\n protected readonly loadingValueWidth = computed(() => {\n switch (this.size()) {\n case 'xs': return '4rem';\n case 'sm': return '5rem';\n case 'md': return '6rem';\n case 'lg': return '8rem';\n case 'xl': return '10rem';\n }\n });\n\n /** Skeleton height during loading state — matches the value font size. */\n protected readonly loadingValueHeight = computed(() => {\n switch (this.size()) {\n case 'xs': return '0.75rem';\n case 'sm': return '0.875rem';\n case 'md': return '1rem';\n case 'lg': return '1rem';\n case 'xl': return '1rem';\n }\n });\n\n private readonly variantResult = computed(() =>\n statTile({ variant: this.variant(), size: this.size() }),\n );\n\n protected readonly rootClasses = computed(() => this.variantResult().root());\n protected readonly iconFlexClasses = computed(() => this.variantResult().iconFlex());\n protected readonly iconWrapperClasses = computed(() => this.variantResult().iconWrapper());\n protected readonly contentStackClasses = computed(() => this.variantResult().contentStack());\n protected readonly dlClasses = computed(() => this.variantResult().dl());\n protected readonly labelClasses = computed(() => this.variantResult().label());\n protected readonly valueRowClasses = computed(() => this.variantResult().valueRow());\n protected readonly valueClasses = computed(() => this.variantResult().value());\n protected readonly descriptionClasses = computed(() => this.variantResult().description());\n protected readonly deltaClasses = computed(() => this.variantResult().delta());\n protected readonly footerClasses = computed(() => this.variantResult().footer());\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,443 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, inject, TemplateRef, Directive, contentChildren, ChangeDetectionStrategy, Component, DestroyRef, signal, computed } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import { NgTemplateOutlet } from '@angular/common';
5
+ import { LiveAnnouncer } from '@angular/cdk/a11y';
6
+ import * as i1 from '@angular/cdk/stepper';
7
+ import { CdkStepLabel, CdkStep, CdkStepper, STEPPER_GLOBAL_OPTIONS, STEP_STATE, CdkStepHeader, CdkStepperNext, CdkStepperPrevious } from '@angular/cdk/stepper';
8
+ export { STEPPER_GLOBAL_OPTIONS, STEP_STATE, StepperSelectionEvent } from '@angular/cdk/stepper';
9
+ import { tv } from 'tailwind-variants';
10
+
11
+ // ── tv() config ──
12
+ const stepperVariants = tv({
13
+ slots: {
14
+ root: 'flex',
15
+ header: 'flex',
16
+ stepItem: 'flex',
17
+ stepHeader: 'group relative inline-flex items-center gap-2 cursor-pointer transition-colors duration-normal motion-reduce:transition-none rounded-md focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 disabled:cursor-not-allowed',
18
+ stepIndicator: 'inline-flex items-center justify-center shrink-0 rounded-full font-medium transition-[color,background-color,border-color,box-shadow] duration-normal motion-reduce:transition-none',
19
+ stepNumber: 'leading-none',
20
+ stepIconSlot: 'inline-flex items-center justify-center',
21
+ stepLabelWrapper: 'flex flex-col min-w-0 text-left',
22
+ stepLabel: 'leading-tight',
23
+ stepDescription: 'text-xs text-fg-muted leading-tight mt-0.5',
24
+ stepOptionalHint: 'text-xs text-fg-subtle ml-1 font-normal',
25
+ stepConnector: 'shrink-0 transition-colors duration-normal motion-reduce:transition-none',
26
+ stepPanel: 'min-w-0',
27
+ },
28
+ variants: {
29
+ variant: {
30
+ default: {},
31
+ dot: {
32
+ stepNumber: 'hidden',
33
+ stepIconSlot: 'hidden',
34
+ },
35
+ simple: {
36
+ stepLabelWrapper: 'sr-only',
37
+ },
38
+ },
39
+ size: {
40
+ xs: {
41
+ stepIndicator: 'size-6 text-xs',
42
+ stepLabel: 'text-xs',
43
+ },
44
+ sm: {
45
+ stepIndicator: 'size-7 text-xs',
46
+ stepLabel: 'text-sm',
47
+ },
48
+ md: {
49
+ stepIndicator: 'size-8 text-sm',
50
+ stepLabel: 'text-sm',
51
+ },
52
+ // lg/xl step labels use `text-base` per the trigger font-size scale
53
+ // (CLAUDE.md typography). Steps are interactive trigger elements.
54
+ lg: {
55
+ stepIndicator: 'size-10 text-base',
56
+ stepLabel: 'text-base',
57
+ },
58
+ xl: {
59
+ stepIndicator: 'size-12 text-base',
60
+ stepLabel: 'text-base',
61
+ },
62
+ },
63
+ orientation: {
64
+ horizontal: {
65
+ root: 'flex-col w-full',
66
+ header: 'flex-row items-center w-full',
67
+ stepItem: 'flex-row items-center flex-1 last:flex-none',
68
+ stepConnector: 'flex-1 h-px mx-2',
69
+ stepLabelWrapper: 'ml-2',
70
+ stepPanel: 'mt-4 rounded-lg outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 motion-reduce:transition-none',
71
+ },
72
+ vertical: {
73
+ root: 'flex-col',
74
+ header: 'flex-col items-stretch',
75
+ stepItem: 'flex-col items-start w-full',
76
+ stepConnector: 'w-px min-h-6 ml-4 my-1 flex-1',
77
+ stepLabelWrapper: 'ml-3',
78
+ stepPanel: 'ml-11 mt-2 mb-4 rounded-lg outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500 motion-reduce:transition-none',
79
+ },
80
+ },
81
+ },
82
+ compoundVariants: [
83
+ // Dot variant indicator sizing
84
+ { variant: 'dot', size: 'xs', class: { stepIndicator: 'size-2' } },
85
+ { variant: 'dot', size: 'sm', class: { stepIndicator: 'size-2.5' } },
86
+ { variant: 'dot', size: 'md', class: { stepIndicator: 'size-2.5' } },
87
+ { variant: 'dot', size: 'lg', class: { stepIndicator: 'size-3' } },
88
+ { variant: 'dot', size: 'xl', class: { stepIndicator: 'size-3' } },
89
+ // Thicker connectors for lg / xl
90
+ {
91
+ orientation: 'horizontal',
92
+ size: 'lg',
93
+ class: { stepConnector: 'h-0.5' },
94
+ },
95
+ {
96
+ orientation: 'horizontal',
97
+ size: 'xl',
98
+ class: { stepConnector: 'h-0.5' },
99
+ },
100
+ { orientation: 'vertical', size: 'lg', class: { stepConnector: 'w-0.5' } },
101
+ { orientation: 'vertical', size: 'xl', class: { stepConnector: 'w-0.5' } },
102
+ ],
103
+ defaultVariants: {
104
+ variant: 'default',
105
+ size: 'md',
106
+ orientation: 'horizontal',
107
+ },
108
+ }, { twMerge: true });
109
+ const INDICATOR_PENDING = 'bg-surface-muted text-fg-muted border border-border';
110
+ const INDICATOR_DISABLED = 'bg-surface-muted text-fg-subtle border border-border opacity-60';
111
+ const INDICATOR_ERROR = 'bg-error-solid text-error-solid-fg border border-error-border-strong';
112
+ // Slot tokens own light/dark contrast — no `dark:`, no shade picks.
113
+ // The active-state ring uses `{role}-soft` (low-chroma in light, deep-tinted in
114
+ // dark) so the halo reads consistently against the surface in both modes.
115
+ const INDICATOR_ACTIVE = {
116
+ primary: 'bg-primary-solid text-primary-solid-fg border border-primary-border-strong ring-4 ring-primary-soft',
117
+ secondary: 'bg-secondary-solid text-secondary-solid-fg border border-secondary-border-strong ring-4 ring-secondary-soft',
118
+ accent: 'bg-accent-solid text-accent-solid-fg border border-accent-border-strong ring-4 ring-accent-soft',
119
+ neutral: 'bg-neutral-solid text-neutral-solid-fg border border-neutral-border-strong ring-4 ring-neutral-soft',
120
+ info: 'bg-info-solid text-info-solid-fg border border-info-border-strong ring-4 ring-info-soft',
121
+ success: 'bg-success-solid text-success-solid-fg border border-success-border-strong ring-4 ring-success-soft',
122
+ warning: 'bg-warning-solid text-warning-solid-fg border border-warning-border-strong ring-4 ring-warning-soft',
123
+ error: 'bg-error-solid text-error-solid-fg border border-error-border-strong ring-4 ring-error-soft',
124
+ };
125
+ const INDICATOR_COMPLETED = {
126
+ primary: 'bg-primary-solid text-primary-solid-fg border border-primary-border-strong',
127
+ secondary: 'bg-secondary-solid text-secondary-solid-fg border border-secondary-border-strong',
128
+ accent: 'bg-accent-solid text-accent-solid-fg border border-accent-border-strong',
129
+ neutral: 'bg-neutral-solid text-neutral-solid-fg border border-neutral-border-strong',
130
+ info: 'bg-info-solid text-info-solid-fg border border-info-border-strong',
131
+ success: 'bg-success-solid text-success-solid-fg border border-success-border-strong',
132
+ warning: 'bg-warning-solid text-warning-solid-fg border border-warning-border-strong',
133
+ error: 'bg-error-solid text-error-solid-fg border border-error-border-strong',
134
+ };
135
+ const LABEL_PENDING = 'text-fg-muted';
136
+ const LABEL_COMPLETED = 'text-fg';
137
+ const LABEL_DISABLED = 'text-fg-subtle';
138
+ const LABEL_ERROR = 'text-error-fg font-semibold';
139
+ const LABEL_ACTIVE = {
140
+ primary: 'text-primary-fg font-semibold',
141
+ secondary: 'text-secondary-fg font-semibold',
142
+ accent: 'text-accent-fg font-semibold',
143
+ neutral: 'text-fg font-semibold',
144
+ info: 'text-info-fg font-semibold',
145
+ success: 'text-success-fg font-semibold',
146
+ warning: 'text-warning-fg font-semibold',
147
+ error: 'text-error-fg font-semibold',
148
+ };
149
+ const CONNECTOR_DEFAULT = 'bg-border';
150
+ const CONNECTOR_ERROR = 'bg-error-border-strong';
151
+ const CONNECTOR_REACHED = {
152
+ primary: 'bg-primary-border-strong',
153
+ secondary: 'bg-secondary-border-strong',
154
+ accent: 'bg-accent-border-strong',
155
+ neutral: 'bg-neutral-border-strong',
156
+ info: 'bg-info-border-strong',
157
+ success: 'bg-success-border-strong',
158
+ warning: 'bg-warning-border-strong',
159
+ error: 'bg-error-border-strong',
160
+ };
161
+ function resolveIndicatorClasses(state, color) {
162
+ switch (state) {
163
+ case 'pending':
164
+ return INDICATOR_PENDING;
165
+ case 'disabled':
166
+ return INDICATOR_DISABLED;
167
+ case 'error':
168
+ return INDICATOR_ERROR;
169
+ case 'active':
170
+ return INDICATOR_ACTIVE[color];
171
+ case 'completed':
172
+ return INDICATOR_COMPLETED[color];
173
+ }
174
+ }
175
+ function resolveLabelClasses(state, color) {
176
+ switch (state) {
177
+ case 'pending':
178
+ return LABEL_PENDING;
179
+ case 'completed':
180
+ return LABEL_COMPLETED;
181
+ case 'disabled':
182
+ return LABEL_DISABLED;
183
+ case 'error':
184
+ return LABEL_ERROR;
185
+ case 'active':
186
+ return LABEL_ACTIVE[color];
187
+ }
188
+ }
189
+ function resolveConnectorClasses(state, color) {
190
+ if (state === 'error')
191
+ return CONNECTOR_ERROR;
192
+ if (state === 'completed' || state === 'active')
193
+ return CONNECTOR_REACHED[color];
194
+ return CONNECTOR_DEFAULT;
195
+ }
196
+ // ── StepperIconDirective ──
197
+ /**
198
+ * Structural-style directive on an `<ng-template>` that replaces the default
199
+ * indicator icon for a given step state.
200
+ */
201
+ class StepperIconDirective {
202
+ /** Step state this template overrides. Matches CDK's `StepState` values (`'number' | 'edit' | 'done' | 'error'`). */
203
+ state = input(undefined, ...(ngDevMode ? [{ debugName: "state" }] : /* istanbul ignore next */ []));
204
+ /** @internal */
205
+ templateRef = inject((TemplateRef));
206
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperIconDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
207
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.14", type: StepperIconDirective, isStandalone: true, selector: "ng-template[twStepperIcon]", inputs: { state: { classPropertyName: "state", publicName: "state", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
208
+ }
209
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperIconDirective, decorators: [{
210
+ type: Directive,
211
+ args: [{
212
+ selector: 'ng-template[twStepperIcon]',
213
+ }]
214
+ }], propDecorators: { state: [{ type: i0.Input, args: [{ isSignal: true, alias: "state", required: false }] }] } });
215
+ // ── StepLabelDirective ──
216
+ /**
217
+ * Structural-style directive on an `<ng-template>` used as a custom step header
218
+ * label. Consumers write `<ng-template twStepLabel>…</ng-template>` inside `<tw-step>`.
219
+ */
220
+ class StepLabelDirective extends CdkStepLabel {
221
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepLabelDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive });
222
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: StepLabelDirective, isStandalone: true, selector: "ng-template[twStepLabel]", providers: [{ provide: CdkStepLabel, useExisting: StepLabelDirective }], usesInheritance: true, ngImport: i0 });
223
+ }
224
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepLabelDirective, decorators: [{
225
+ type: Directive,
226
+ args: [{
227
+ selector: 'ng-template[twStepLabel]',
228
+ providers: [{ provide: CdkStepLabel, useExisting: StepLabelDirective }],
229
+ }]
230
+ }] });
231
+ // ── StepComponent ──
232
+ class StepComponent extends CdkStep {
233
+ /** Optional descriptive text shown under the step label in the `'default'` variant. */
234
+ description = input('', ...(ngDevMode ? [{ debugName: "description" }] : /* istanbul ignore next */ []));
235
+ /** @internal Custom indicator icon templates (one per state) projected into this step. */
236
+ iconTemplates = contentChildren(StepperIconDirective, ...(ngDevMode ? [{ debugName: "iconTemplates" }] : /* istanbul ignore next */ []));
237
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
238
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "21.2.14", type: StepComponent, isStandalone: true, selector: "tw-step", inputs: { description: { classPropertyName: "description", publicName: "description", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: CdkStep, useExisting: StepComponent }], queries: [{ propertyName: "iconTemplates", predicate: StepperIconDirective, isSignal: true }], exportAs: ["twStep"], usesInheritance: true, ngImport: i0, template: '<ng-template><ng-content/></ng-template>', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
239
+ }
240
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepComponent, decorators: [{
241
+ type: Component,
242
+ args: [{
243
+ selector: 'tw-step',
244
+ template: '<ng-template><ng-content/></ng-template>',
245
+ exportAs: 'twStep',
246
+ changeDetection: ChangeDetectionStrategy.OnPush,
247
+ providers: [{ provide: CdkStep, useExisting: StepComponent }],
248
+ }]
249
+ }], propDecorators: { description: [{ type: i0.Input, args: [{ isSignal: true, alias: "description", required: false }] }], iconTemplates: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => StepperIconDirective), { isSignal: true }] }] } });
250
+ // ── StepperComponent ──
251
+ class StepperComponent extends CdkStepper {
252
+ /** Visual style of the indicator strip. `'default'` = numbered circles, `'dot'` = compact filled dots, `'simple'` = indicators only (labels hidden visually). Defaults to `'default'`. */
253
+ variant = input('default', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
254
+ /** Semantic color for active and completed indicators and connectors. Defaults to `'primary'`. */
255
+ color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
256
+ /** Controls indicator size and label typography. Defaults to `'md'`. */
257
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
258
+ /** When true, steps with `hasError` render error styling, icon, and `aria-invalid`. Defaults to `true`. */
259
+ // TRUE-default: error states must be visible by default — silently swallowing
260
+ // a stepped flow's failure state is a UX regression. Consumers opt out per step.
261
+ showError = input(true, ...(ngDevMode ? [{ debugName: "showError" }] : /* istanbul ignore next */ []));
262
+ /** When true, clicking a navigable step header selects it. Set to `false` to only allow advancement via `twStepperNext` / `twStepperPrevious`. Defaults to `true`. */
263
+ // TRUE-default: free-navigation is the standard stepper UX; restricted flows
264
+ // (e.g. wizards that must complete in order) explicitly opt out.
265
+ headerInteractive = input(true, ...(ngDevMode ? [{ debugName: "headerInteractive" }] : /* istanbul ignore next */ []));
266
+ _liveAnnouncer = inject(LiveAnnouncer);
267
+ _destroyRef = inject(DestroyRef);
268
+ _globalOptions = inject(STEPPER_GLOBAL_OPTIONS, { optional: true });
269
+ /**
270
+ * CdkStepper exposes its state via class properties (selectedIndex,
271
+ * previousIndex, orientation), not signals. We mirror those into signals so
272
+ * templates can react via @if/@for and OnPush change detection works without
273
+ * manual `markForCheck`. Sync happens in the property setters and lifecycle
274
+ * hooks below — keep these mirrors in lock-step with the CDK fields.
275
+ */
276
+ _orientationSignal = signal('horizontal', ...(ngDevMode ? [{ debugName: "_orientationSignal" }] : /* istanbul ignore next */ []));
277
+ _selectedIndexSignal = signal(0, ...(ngDevMode ? [{ debugName: "_selectedIndexSignal" }] : /* istanbul ignore next */ []));
278
+ _previousIndexSignal = signal(0, ...(ngDevMode ? [{ debugName: "_previousIndexSignal" }] : /* istanbul ignore next */ []));
279
+ /** @internal Reactive mirror of CDK's `orientation` input. */
280
+ orientationValue = this._orientationSignal.asReadonly();
281
+ /** @internal Reactive mirror of CDK's `selectedIndex`. */
282
+ selectedIndexValue = this._selectedIndexSignal.asReadonly();
283
+ set orientation(value) {
284
+ super.orientation = value;
285
+ this._orientationSignal.set(value);
286
+ }
287
+ get orientation() {
288
+ return super.orientation;
289
+ }
290
+ _variantResult = computed(() => stepperVariants({
291
+ variant: this.variant(),
292
+ size: this.size(),
293
+ orientation: this._orientationSignal(),
294
+ }), ...(ngDevMode ? [{ debugName: "_variantResult" }] : /* istanbul ignore next */ []));
295
+ rootClasses = computed(() => this._variantResult().root(), ...(ngDevMode ? [{ debugName: "rootClasses" }] : /* istanbul ignore next */ []));
296
+ headerClasses = computed(() => this._variantResult().header(), ...(ngDevMode ? [{ debugName: "headerClasses" }] : /* istanbul ignore next */ []));
297
+ stepItemClasses = computed(() => this._variantResult().stepItem(), ...(ngDevMode ? [{ debugName: "stepItemClasses" }] : /* istanbul ignore next */ []));
298
+ stepHeaderClasses = computed(() => this._variantResult().stepHeader(), ...(ngDevMode ? [{ debugName: "stepHeaderClasses" }] : /* istanbul ignore next */ []));
299
+ stepIndicatorBaseClasses = computed(() => this._variantResult().stepIndicator(), ...(ngDevMode ? [{ debugName: "stepIndicatorBaseClasses" }] : /* istanbul ignore next */ []));
300
+ stepNumberClasses = computed(() => this._variantResult().stepNumber(), ...(ngDevMode ? [{ debugName: "stepNumberClasses" }] : /* istanbul ignore next */ []));
301
+ stepIconSlotClasses = computed(() => this._variantResult().stepIconSlot(), ...(ngDevMode ? [{ debugName: "stepIconSlotClasses" }] : /* istanbul ignore next */ []));
302
+ stepLabelWrapperClasses = computed(() => this._variantResult().stepLabelWrapper(), ...(ngDevMode ? [{ debugName: "stepLabelWrapperClasses" }] : /* istanbul ignore next */ []));
303
+ stepLabelBaseClasses = computed(() => this._variantResult().stepLabel(), ...(ngDevMode ? [{ debugName: "stepLabelBaseClasses" }] : /* istanbul ignore next */ []));
304
+ stepDescriptionClasses = computed(() => this._variantResult().stepDescription(), ...(ngDevMode ? [{ debugName: "stepDescriptionClasses" }] : /* istanbul ignore next */ []));
305
+ stepOptionalHintClasses = computed(() => this._variantResult().stepOptionalHint(), ...(ngDevMode ? [{ debugName: "stepOptionalHintClasses" }] : /* istanbul ignore next */ []));
306
+ stepConnectorBaseClasses = computed(() => this._variantResult().stepConnector(), ...(ngDevMode ? [{ debugName: "stepConnectorBaseClasses" }] : /* istanbul ignore next */ []));
307
+ stepPanelClasses = computed(() => this._variantResult().stepPanel(), ...(ngDevMode ? [{ debugName: "stepPanelClasses" }] : /* istanbul ignore next */ []));
308
+ panelAnimationClass = computed(() => {
309
+ if (this._orientationSignal() === 'vertical')
310
+ return null;
311
+ return this._selectedIndexSignal() >= this._previousIndexSignal()
312
+ ? 'step-panel-enter-forward'
313
+ : 'step-panel-enter-backward';
314
+ }, ...(ngDevMode ? [{ debugName: "panelAnimationClass" }] : /* istanbul ignore next */ []));
315
+ ngAfterViewInit() {
316
+ super.ngAfterViewInit();
317
+ this._orientationSignal.set(this.orientation);
318
+ this._selectedIndexSignal.set(this.selectedIndex);
319
+ this._previousIndexSignal.set(this.selectedIndex);
320
+ this.selectionChange
321
+ .pipe(takeUntilDestroyed(this._destroyRef))
322
+ .subscribe((event) => {
323
+ this._previousIndexSignal.set(event.previouslySelectedIndex);
324
+ this._selectedIndexSignal.set(event.selectedIndex);
325
+ this._orientationSignal.set(this.orientation);
326
+ const total = this.steps.length;
327
+ const label = event.selectedStep.label || `Step ${event.selectedIndex + 1}`;
328
+ this._liveAnnouncer.announce(`${label}, step ${event.selectedIndex + 1} of ${total}`);
329
+ });
330
+ }
331
+ /** @internal Typed view of projected steps. */
332
+ get twSteps() {
333
+ return this.steps.toArray();
334
+ }
335
+ /** @internal Resolves the visual state of a step for color/theming purposes. */
336
+ getStepStyleState(step, index) {
337
+ if (this.shouldRenderError(step))
338
+ return 'error';
339
+ if (index === this._selectedIndexSignal())
340
+ return 'active';
341
+ const itype = step.indicatorType();
342
+ if (itype === STEP_STATE.DONE || itype === STEP_STATE.EDIT)
343
+ return 'completed';
344
+ if (this.linear && !step.isNavigable())
345
+ return 'disabled';
346
+ return 'pending';
347
+ }
348
+ /** @internal */
349
+ getIndicatorClass(step, index) {
350
+ const state = this.getStepStyleState(step, index);
351
+ return `${this.stepIndicatorBaseClasses()} ${resolveIndicatorClasses(state, this.color())}`;
352
+ }
353
+ /** @internal */
354
+ getLabelClass(step, index) {
355
+ const state = this.getStepStyleState(step, index);
356
+ return `${this.stepLabelBaseClasses()} ${resolveLabelClasses(state, this.color())}`;
357
+ }
358
+ /** @internal */
359
+ getConnectorClass(step, index) {
360
+ const state = this.getStepStyleState(step, index);
361
+ return `${this.stepConnectorBaseClasses()} ${resolveConnectorClasses(state, this.color())}`;
362
+ }
363
+ /** @internal Resolves which indicator glyph to render for a step. */
364
+ getIndicatorType(step) {
365
+ if (this.shouldRenderError(step))
366
+ return STEP_STATE.ERROR;
367
+ return step.indicatorType();
368
+ }
369
+ /** @internal Looks up a consumer-supplied custom template for a given indicator state. */
370
+ resolveIconTemplate(step, state) {
371
+ const templates = step.iconTemplates();
372
+ const match = templates.find((t) => t.state() === state);
373
+ return match ? match.templateRef : null;
374
+ }
375
+ /** @internal Context supplied to custom icon templates. */
376
+ iconContext(index) {
377
+ return {
378
+ $implicit: {
379
+ index,
380
+ active: index === this._selectedIndexSignal(),
381
+ },
382
+ };
383
+ }
384
+ /** @internal Click handler for the step header button. */
385
+ onHeaderClick(step, index) {
386
+ if (!this.headerInteractive())
387
+ return;
388
+ if (!step.isNavigable())
389
+ return;
390
+ this.selectedIndex = index;
391
+ }
392
+ /** @internal Whether the stepper should render the error state for a step. */
393
+ shouldRenderError(step) {
394
+ if (!this.showError())
395
+ return false;
396
+ if (this._globalOptions?.showError === false)
397
+ return false;
398
+ return step.hasError;
399
+ }
400
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
401
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: StepperComponent, isStandalone: true, selector: "tw-stepper", inputs: { variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, showError: { classPropertyName: "showError", publicName: "showError", isSignal: true, isRequired: false, transformFunction: null }, headerInteractive: { classPropertyName: "headerInteractive", publicName: "headerInteractive", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "rootClasses()" } }, providers: [{ provide: CdkStepper, useExisting: StepperComponent }], exportAs: ["twStepper"], usesInheritance: true, ngImport: i0, template: "<!-- Header strip + inline panels (vertical) / header-only (horizontal) -->\n<div\n [class]=\"headerClasses()\"\n role=\"tablist\"\n [attr.aria-orientation]=\"orientationValue()\"\n (keydown)=\"_onKeydown($event)\"\n>\n @for (step of twSteps; track $index; let i = $index; let last = $last) {\n <div [class]=\"stepItemClasses()\">\n <!-- Step header button -->\n <button\n type=\"button\"\n cdkStepHeader\n role=\"tab\"\n [class]=\"stepHeaderClasses()\"\n [class.pointer-events-none]=\"!headerInteractive() || !step.isNavigable()\"\n [class.opacity-60]=\"!step.isNavigable()\"\n [id]=\"_getStepLabelId(i)\"\n [attr.aria-controls]=\"_getStepContentId(i)\"\n [attr.aria-selected]=\"selectedIndexValue() === i\"\n [attr.aria-current]=\"selectedIndexValue() === i ? 'step' : null\"\n [attr.aria-disabled]=\"!step.isNavigable() || null\"\n [attr.aria-invalid]=\"shouldRenderError(step) || null\"\n [attr.aria-label]=\"step.ariaLabel || null\"\n [attr.aria-labelledby]=\"step.ariaLabelledby || null\"\n (click)=\"onHeaderClick(step, i)\"\n >\n <!-- Indicator (number / icon / dot) -->\n <span [class]=\"getIndicatorClass(step, i)\">\n @let indicatorType = getIndicatorType(step);\n @let customIcon = resolveIconTemplate(step, indicatorType);\n\n @if (customIcon) {\n <span [class]=\"stepIconSlotClasses()\">\n <ng-container\n [ngTemplateOutlet]=\"customIcon\"\n [ngTemplateOutletContext]=\"iconContext(i)\"\n />\n </span>\n } @else {\n @switch (indicatorType) {\n @case ('number') {\n <span [class]=\"stepNumberClasses()\">{{ i + 1 }}</span>\n }\n @case ('done') {\n <span [class]=\"stepIconSlotClasses()\">\n <svg\n class=\"size-3/5 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n }\n @case ('edit') {\n <span [class]=\"stepIconSlotClasses()\">\n <svg\n class=\"size-3/5 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M13.586 3.586a2 2 0 1 1 2.828 2.828l-.793.793-2.828-2.828.793-.793Zm-2.207 2.207 2.828 2.828-7.07 7.071a2 2 0 0 1-.83.5l-3.086.926a.5.5 0 0 1-.62-.621l.926-3.086a2 2 0 0 1 .5-.83l7.352-7.788Z\"\n />\n </svg>\n </span>\n }\n @case ('error') {\n <span [class]=\"stepIconSlotClasses()\">\n <svg\n class=\"size-3/5 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm.75-11.25a.75.75 0 0 0-1.5 0v4.5a.75.75 0 0 0 1.5 0v-4.5ZM10 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n }\n }\n }\n </span>\n\n <!-- Label + description -->\n <span [class]=\"stepLabelWrapperClasses()\">\n <span [class]=\"getLabelClass(step, i)\">\n @if (step.stepLabel) {\n <ng-container [ngTemplateOutlet]=\"step.stepLabel.template\" />\n } @else {\n {{ step.label }}\n }\n @if (step.optional && !step.completed) {\n <span [class]=\"stepOptionalHintClasses()\">(Optional)</span>\n }\n </span>\n\n @if (step.description() && variant() === 'default') {\n <span [class]=\"stepDescriptionClasses()\">{{ step.description() }}</span>\n }\n\n @if (shouldRenderError(step) && step.errorMessage) {\n <span class=\"sr-only\">{{ step.errorMessage }}</span>\n }\n </span>\n </button>\n\n <!-- Connector (between step i and i+1) -->\n @if (!last) {\n <span\n [class]=\"getConnectorClass(step, i)\"\n aria-hidden=\"true\"\n ></span>\n }\n\n <!-- Vertical: panel is rendered inline under each selected step -->\n @if (orientationValue() === 'vertical' && selectedIndexValue() === i && step.content) {\n <div\n role=\"tabpanel\"\n [id]=\"_getStepContentId(i)\"\n [attr.aria-labelledby]=\"_getStepLabelId(i)\"\n [class]=\"stepPanelClasses()\"\n tabindex=\"0\"\n >\n <ng-container [ngTemplateOutlet]=\"step.content\" />\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Horizontal: single panel rendered below the strip -->\n@if (orientationValue() === 'horizontal') {\n @let activeStep = twSteps[selectedIndexValue()];\n @if (activeStep && activeStep.content) {\n <div\n role=\"tabpanel\"\n [id]=\"_getStepContentId(selectedIndexValue())\"\n [attr.aria-labelledby]=\"_getStepLabelId(selectedIndexValue())\"\n [class]=\"stepPanelClasses()\"\n [animate.enter]=\"panelAnimationClass()\"\n tabindex=\"0\"\n >\n <ng-container [ngTemplateOutlet]=\"activeStep.content\" />\n </div>\n }\n}\n", dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: CdkStepHeader, selector: "[cdkStepHeader]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
402
+ }
403
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperComponent, decorators: [{
404
+ type: Component,
405
+ args: [{ selector: 'tw-stepper', exportAs: 'twStepper', changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgTemplateOutlet, CdkStepHeader], providers: [{ provide: CdkStepper, useExisting: StepperComponent }], host: {
406
+ '[class]': 'rootClasses()',
407
+ }, template: "<!-- Header strip + inline panels (vertical) / header-only (horizontal) -->\n<div\n [class]=\"headerClasses()\"\n role=\"tablist\"\n [attr.aria-orientation]=\"orientationValue()\"\n (keydown)=\"_onKeydown($event)\"\n>\n @for (step of twSteps; track $index; let i = $index; let last = $last) {\n <div [class]=\"stepItemClasses()\">\n <!-- Step header button -->\n <button\n type=\"button\"\n cdkStepHeader\n role=\"tab\"\n [class]=\"stepHeaderClasses()\"\n [class.pointer-events-none]=\"!headerInteractive() || !step.isNavigable()\"\n [class.opacity-60]=\"!step.isNavigable()\"\n [id]=\"_getStepLabelId(i)\"\n [attr.aria-controls]=\"_getStepContentId(i)\"\n [attr.aria-selected]=\"selectedIndexValue() === i\"\n [attr.aria-current]=\"selectedIndexValue() === i ? 'step' : null\"\n [attr.aria-disabled]=\"!step.isNavigable() || null\"\n [attr.aria-invalid]=\"shouldRenderError(step) || null\"\n [attr.aria-label]=\"step.ariaLabel || null\"\n [attr.aria-labelledby]=\"step.ariaLabelledby || null\"\n (click)=\"onHeaderClick(step, i)\"\n >\n <!-- Indicator (number / icon / dot) -->\n <span [class]=\"getIndicatorClass(step, i)\">\n @let indicatorType = getIndicatorType(step);\n @let customIcon = resolveIconTemplate(step, indicatorType);\n\n @if (customIcon) {\n <span [class]=\"stepIconSlotClasses()\">\n <ng-container\n [ngTemplateOutlet]=\"customIcon\"\n [ngTemplateOutletContext]=\"iconContext(i)\"\n />\n </span>\n } @else {\n @switch (indicatorType) {\n @case ('number') {\n <span [class]=\"stepNumberClasses()\">{{ i + 1 }}</span>\n }\n @case ('done') {\n <span [class]=\"stepIconSlotClasses()\">\n <svg\n class=\"size-3/5 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M16.704 4.153a.75.75 0 0 1 .143 1.052l-8 10.5a.75.75 0 0 1-1.127.075l-4.5-4.5a.75.75 0 0 1 1.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 0 1 1.05-.143Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n }\n @case ('edit') {\n <span [class]=\"stepIconSlotClasses()\">\n <svg\n class=\"size-3/5 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M13.586 3.586a2 2 0 1 1 2.828 2.828l-.793.793-2.828-2.828.793-.793Zm-2.207 2.207 2.828 2.828-7.07 7.071a2 2 0 0 1-.83.5l-3.086.926a.5.5 0 0 1-.62-.621l.926-3.086a2 2 0 0 1 .5-.83l7.352-7.788Z\"\n />\n </svg>\n </span>\n }\n @case ('error') {\n <span [class]=\"stepIconSlotClasses()\">\n <svg\n class=\"size-3/5 shrink-0\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Zm.75-11.25a.75.75 0 0 0-1.5 0v4.5a.75.75 0 0 0 1.5 0v-4.5ZM10 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </span>\n }\n }\n }\n </span>\n\n <!-- Label + description -->\n <span [class]=\"stepLabelWrapperClasses()\">\n <span [class]=\"getLabelClass(step, i)\">\n @if (step.stepLabel) {\n <ng-container [ngTemplateOutlet]=\"step.stepLabel.template\" />\n } @else {\n {{ step.label }}\n }\n @if (step.optional && !step.completed) {\n <span [class]=\"stepOptionalHintClasses()\">(Optional)</span>\n }\n </span>\n\n @if (step.description() && variant() === 'default') {\n <span [class]=\"stepDescriptionClasses()\">{{ step.description() }}</span>\n }\n\n @if (shouldRenderError(step) && step.errorMessage) {\n <span class=\"sr-only\">{{ step.errorMessage }}</span>\n }\n </span>\n </button>\n\n <!-- Connector (between step i and i+1) -->\n @if (!last) {\n <span\n [class]=\"getConnectorClass(step, i)\"\n aria-hidden=\"true\"\n ></span>\n }\n\n <!-- Vertical: panel is rendered inline under each selected step -->\n @if (orientationValue() === 'vertical' && selectedIndexValue() === i && step.content) {\n <div\n role=\"tabpanel\"\n [id]=\"_getStepContentId(i)\"\n [attr.aria-labelledby]=\"_getStepLabelId(i)\"\n [class]=\"stepPanelClasses()\"\n tabindex=\"0\"\n >\n <ng-container [ngTemplateOutlet]=\"step.content\" />\n </div>\n }\n </div>\n }\n</div>\n\n<!-- Horizontal: single panel rendered below the strip -->\n@if (orientationValue() === 'horizontal') {\n @let activeStep = twSteps[selectedIndexValue()];\n @if (activeStep && activeStep.content) {\n <div\n role=\"tabpanel\"\n [id]=\"_getStepContentId(selectedIndexValue())\"\n [attr.aria-labelledby]=\"_getStepLabelId(selectedIndexValue())\"\n [class]=\"stepPanelClasses()\"\n [animate.enter]=\"panelAnimationClass()\"\n tabindex=\"0\"\n >\n <ng-container [ngTemplateOutlet]=\"activeStep.content\" />\n </div>\n }\n}\n" }]
408
+ }], propDecorators: { variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], showError: [{ type: i0.Input, args: [{ isSignal: true, alias: "showError", required: false }] }], headerInteractive: [{ type: i0.Input, args: [{ isSignal: true, alias: "headerInteractive", required: false }] }] } });
409
+ // ── Next / Previous directives (hostDirectives over CDK) ──
410
+ class StepperNextDirective {
411
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperNextDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
412
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: StepperNextDirective, isStandalone: true, selector: "button[twStepperNext]", hostDirectives: [{ directive: i1.CdkStepperNext, inputs: ["type", "type"] }], ngImport: i0 });
413
+ }
414
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperNextDirective, decorators: [{
415
+ type: Directive,
416
+ args: [{
417
+ selector: 'button[twStepperNext]',
418
+ hostDirectives: [{ directive: CdkStepperNext, inputs: ['type'] }],
419
+ }]
420
+ }] });
421
+ class StepperPreviousDirective {
422
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperPreviousDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
423
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.14", type: StepperPreviousDirective, isStandalone: true, selector: "button[twStepperPrevious]", hostDirectives: [{ directive: i1.CdkStepperPrevious, inputs: ["type", "type"] }], ngImport: i0 });
424
+ }
425
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: StepperPreviousDirective, decorators: [{
426
+ type: Directive,
427
+ args: [{
428
+ selector: 'button[twStepperPrevious]',
429
+ hostDirectives: [{ directive: CdkStepperPrevious, inputs: ['type'] }],
430
+ }]
431
+ }] });
432
+ // ── Provider helper ──
433
+ /** Provides app-wide stepper defaults via `STEPPER_GLOBAL_OPTIONS`. */
434
+ function provideTwStepperOptions(options) {
435
+ return [{ provide: STEPPER_GLOBAL_OPTIONS, useValue: options }];
436
+ }
437
+
438
+ /**
439
+ * Generated bundle index. Do not edit.
440
+ */
441
+
442
+ export { StepComponent, StepLabelDirective, StepperComponent, StepperIconDirective, StepperNextDirective, StepperPreviousDirective, provideTwStepperOptions };
443
+ //# sourceMappingURL=cdevhub-ngx-tw-stepper.mjs.map