@cdevhub/ngx-tw 0.2.1 → 0.3.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 (139) hide show
  1. package/README.md +264 -49
  2. package/fesm2022/cdevhub-ngx-tw-accordion.mjs +11 -7
  3. package/fesm2022/cdevhub-ngx-tw-accordion.mjs.map +1 -1
  4. package/fesm2022/cdevhub-ngx-tw-alert.mjs +43 -29
  5. package/fesm2022/cdevhub-ngx-tw-alert.mjs.map +1 -1
  6. package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs +103 -0
  7. package/fesm2022/cdevhub-ngx-tw-aspect-ratio.mjs.map +1 -0
  8. package/fesm2022/cdevhub-ngx-tw-avatar.mjs +56 -31
  9. package/fesm2022/cdevhub-ngx-tw-avatar.mjs.map +1 -1
  10. package/fesm2022/cdevhub-ngx-tw-badge.mjs +61 -35
  11. package/fesm2022/cdevhub-ngx-tw-badge.mjs.map +1 -1
  12. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs +154 -93
  13. package/fesm2022/cdevhub-ngx-tw-breadcrumbs.mjs.map +1 -1
  14. package/fesm2022/cdevhub-ngx-tw-button.mjs +24 -15
  15. package/fesm2022/cdevhub-ngx-tw-button.mjs.map +1 -1
  16. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs +3 -3
  17. package/fesm2022/cdevhub-ngx-tw-calendar-luxon.mjs.map +1 -1
  18. package/fesm2022/cdevhub-ngx-tw-calendar.mjs +408 -215
  19. package/fesm2022/cdevhub-ngx-tw-calendar.mjs.map +1 -1
  20. package/fesm2022/cdevhub-ngx-tw-card.mjs +33 -24
  21. package/fesm2022/cdevhub-ngx-tw-card.mjs.map +1 -1
  22. package/fesm2022/cdevhub-ngx-tw-carousel.mjs +144 -79
  23. package/fesm2022/cdevhub-ngx-tw-carousel.mjs.map +1 -1
  24. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs +99 -47
  25. package/fesm2022/cdevhub-ngx-tw-checkbox.mjs.map +1 -1
  26. package/fesm2022/cdevhub-ngx-tw-code-block.mjs +34 -20
  27. package/fesm2022/cdevhub-ngx-tw-code-block.mjs.map +1 -1
  28. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs +46 -29
  29. package/fesm2022/cdevhub-ngx-tw-collapsible.mjs.map +1 -1
  30. package/fesm2022/cdevhub-ngx-tw-combobox.mjs +195 -110
  31. package/fesm2022/cdevhub-ngx-tw-combobox.mjs.map +1 -1
  32. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs +140 -73
  33. package/fesm2022/cdevhub-ngx-tw-command-palette.mjs.map +1 -1
  34. package/fesm2022/cdevhub-ngx-tw-core.mjs +16 -11
  35. package/fesm2022/cdevhub-ngx-tw-core.mjs.map +1 -1
  36. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs +393 -149
  37. package/fesm2022/cdevhub-ngx-tw-date-picker.mjs.map +1 -1
  38. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs +305 -150
  39. package/fesm2022/cdevhub-ngx-tw-date-range-picker.mjs.map +1 -1
  40. package/fesm2022/cdevhub-ngx-tw-dialog.mjs +56 -43
  41. package/fesm2022/cdevhub-ngx-tw-dialog.mjs.map +1 -1
  42. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs +51 -33
  43. package/fesm2022/cdevhub-ngx-tw-empty-state.mjs.map +1 -1
  44. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs +905 -0
  45. package/fesm2022/cdevhub-ngx-tw-file-upload.mjs.map +1 -0
  46. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs +49 -26
  47. package/fesm2022/cdevhub-ngx-tw-flip-card.mjs.map +1 -1
  48. package/fesm2022/cdevhub-ngx-tw-form-field.mjs +133 -74
  49. package/fesm2022/cdevhub-ngx-tw-form-field.mjs.map +1 -1
  50. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs +2 -2
  51. package/fesm2022/cdevhub-ngx-tw-icon-lucide.mjs.map +1 -1
  52. package/fesm2022/cdevhub-ngx-tw-icon.mjs +28 -17
  53. package/fesm2022/cdevhub-ngx-tw-icon.mjs.map +1 -1
  54. package/fesm2022/cdevhub-ngx-tw-input.mjs +37 -21
  55. package/fesm2022/cdevhub-ngx-tw-input.mjs.map +1 -1
  56. package/fesm2022/cdevhub-ngx-tw-item.mjs +33 -24
  57. package/fesm2022/cdevhub-ngx-tw-item.mjs.map +1 -1
  58. package/fesm2022/cdevhub-ngx-tw-menu.mjs +63 -48
  59. package/fesm2022/cdevhub-ngx-tw-menu.mjs.map +1 -1
  60. package/fesm2022/cdevhub-ngx-tw-number-input.mjs +622 -0
  61. package/fesm2022/cdevhub-ngx-tw-number-input.mjs.map +1 -0
  62. package/fesm2022/cdevhub-ngx-tw-paginator.mjs +137 -71
  63. package/fesm2022/cdevhub-ngx-tw-paginator.mjs.map +1 -1
  64. package/fesm2022/cdevhub-ngx-tw-popover.mjs +101 -46
  65. package/fesm2022/cdevhub-ngx-tw-popover.mjs.map +1 -1
  66. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs +57 -30
  67. package/fesm2022/cdevhub-ngx-tw-progress-bar.mjs.map +1 -1
  68. package/fesm2022/cdevhub-ngx-tw-radio.mjs +108 -57
  69. package/fesm2022/cdevhub-ngx-tw-radio.mjs.map +1 -1
  70. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs +46 -26
  71. package/fesm2022/cdevhub-ngx-tw-segmented-control.mjs.map +1 -1
  72. package/fesm2022/cdevhub-ngx-tw-select.mjs +217 -122
  73. package/fesm2022/cdevhub-ngx-tw-select.mjs.map +1 -1
  74. package/fesm2022/cdevhub-ngx-tw-separator.mjs +21 -12
  75. package/fesm2022/cdevhub-ngx-tw-separator.mjs.map +1 -1
  76. package/fesm2022/cdevhub-ngx-tw-sheet.mjs +58 -44
  77. package/fesm2022/cdevhub-ngx-tw-sheet.mjs.map +1 -1
  78. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs +25 -14
  79. package/fesm2022/cdevhub-ngx-tw-skeleton.mjs.map +1 -1
  80. package/fesm2022/cdevhub-ngx-tw-slider.mjs +155 -79
  81. package/fesm2022/cdevhub-ngx-tw-slider.mjs.map +1 -1
  82. package/fesm2022/cdevhub-ngx-tw-sort.mjs +44 -25
  83. package/fesm2022/cdevhub-ngx-tw-sort.mjs.map +1 -1
  84. package/fesm2022/cdevhub-ngx-tw-spinner.mjs +29 -16
  85. package/fesm2022/cdevhub-ngx-tw-spinner.mjs.map +1 -1
  86. package/fesm2022/cdevhub-ngx-tw-split.mjs +72 -42
  87. package/fesm2022/cdevhub-ngx-tw-split.mjs.map +1 -1
  88. package/fesm2022/cdevhub-ngx-tw-stat.mjs +107 -64
  89. package/fesm2022/cdevhub-ngx-tw-stat.mjs.map +1 -1
  90. package/fesm2022/cdevhub-ngx-tw-stepper.mjs +113 -47
  91. package/fesm2022/cdevhub-ngx-tw-stepper.mjs.map +1 -1
  92. package/fesm2022/cdevhub-ngx-tw-switch.mjs +61 -32
  93. package/fesm2022/cdevhub-ngx-tw-switch.mjs.map +1 -1
  94. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs +88 -42
  95. package/fesm2022/cdevhub-ngx-tw-tab-nav.mjs.map +1 -1
  96. package/fesm2022/cdevhub-ngx-tw-table.mjs +266 -118
  97. package/fesm2022/cdevhub-ngx-tw-table.mjs.map +1 -1
  98. package/fesm2022/cdevhub-ngx-tw-tabs.mjs +101 -51
  99. package/fesm2022/cdevhub-ngx-tw-tabs.mjs.map +1 -1
  100. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs +798 -0
  101. package/fesm2022/cdevhub-ngx-tw-tags-input.mjs.map +1 -0
  102. package/fesm2022/cdevhub-ngx-tw-textarea.mjs +11 -7
  103. package/fesm2022/cdevhub-ngx-tw-textarea.mjs.map +1 -1
  104. package/fesm2022/cdevhub-ngx-tw-theme.mjs +22 -14
  105. package/fesm2022/cdevhub-ngx-tw-theme.mjs.map +1 -1
  106. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs +243 -95
  107. package/fesm2022/cdevhub-ngx-tw-time-picker.mjs.map +1 -1
  108. package/fesm2022/cdevhub-ngx-tw-timeline.mjs +149 -82
  109. package/fesm2022/cdevhub-ngx-tw-timeline.mjs.map +1 -1
  110. package/fesm2022/cdevhub-ngx-tw-toast.mjs +89 -55
  111. package/fesm2022/cdevhub-ngx-tw-toast.mjs.map +1 -1
  112. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs +50 -28
  113. package/fesm2022/cdevhub-ngx-tw-tooltip.mjs.map +1 -1
  114. package/fesm2022/cdevhub-ngx-tw-transfer.mjs +1129 -0
  115. package/fesm2022/cdevhub-ngx-tw-transfer.mjs.map +1 -0
  116. package/fesm2022/cdevhub-ngx-tw-tree.mjs +554 -0
  117. package/fesm2022/cdevhub-ngx-tw-tree.mjs.map +1 -0
  118. package/fesm2022/cdevhub-ngx-tw.mjs +7 -0
  119. package/fesm2022/cdevhub-ngx-tw.mjs.map +1 -1
  120. package/package.json +45 -20
  121. package/theme/index.css +10 -2
  122. package/types/cdevhub-ngx-tw-aspect-ratio.d.ts +40 -0
  123. package/types/cdevhub-ngx-tw-calendar.d.ts +39 -8
  124. package/types/cdevhub-ngx-tw-command-palette.d.ts +7 -0
  125. package/types/cdevhub-ngx-tw-date-picker.d.ts +36 -10
  126. package/types/cdevhub-ngx-tw-file-upload.d.ts +250 -0
  127. package/types/cdevhub-ngx-tw-form-field.d.ts +22 -3
  128. package/types/cdevhub-ngx-tw-icon-lucide.d.ts +21 -3
  129. package/types/cdevhub-ngx-tw-number-input.d.ts +130 -0
  130. package/types/cdevhub-ngx-tw-popover.d.ts +8 -0
  131. package/types/cdevhub-ngx-tw-stepper.d.ts +30 -2
  132. package/types/cdevhub-ngx-tw-tab-nav.d.ts +8 -0
  133. package/types/cdevhub-ngx-tw-table.d.ts +30 -1
  134. package/types/cdevhub-ngx-tw-tabs.d.ts +8 -0
  135. package/types/cdevhub-ngx-tw-tags-input.d.ts +217 -0
  136. package/types/cdevhub-ngx-tw-time-picker.d.ts +31 -6
  137. package/types/cdevhub-ngx-tw-transfer.d.ts +330 -0
  138. package/types/cdevhub-ngx-tw-tree.d.ts +189 -0
  139. package/types/cdevhub-ngx-tw.d.ts +7 -0
@@ -1 +1 @@
1
- {"version":3,"file":"cdevhub-ngx-tw-alert.mjs","sources":["../../../projects/ngx-tw/alert/alert.ts","../../../projects/ngx-tw/alert/cdevhub-ngx-tw-alert.ts"],"sourcesContent":["import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor } from '@cdevhub/ngx-tw/core';\n\n/** Visual style of the alert container. */\nexport type AlertVariant = 'solid' | 'outline' | 'soft';\n\n/** ARIA live-region politeness for the alert. Maps to the host `role`. */\nexport type AlertPoliteness = 'polite' | 'assertive' | 'off';\n\n/**\n * Alert variants use the semantic role slot tokens defined in\n * `projects/ngx-tw/theme/_semantic.css` (and redefined per-theme in\n * `_dark.css` / `_high-contrast.css`). The mapping role × variant → slots\n * is the same for every color, so the variant table is expressed as a single\n * function template over the role name — no per-role copy-paste, no shade\n * picks, no `dark:` overrides. Dark / high-contrast contrast is owned by the\n * theme tokens; components only consume slots.\n */\ninterface AlertSlotClasses {\n root: string;\n icon: string;\n title: string;\n content: string;\n dismiss: string;\n}\n\nfunction softSlots(role: TwColor): AlertSlotClasses {\n return {\n root: `bg-${role}-soft text-${role}-soft-fg-muted`,\n icon: `text-${role}-icon`,\n title: `text-${role}-soft-fg`,\n content: `text-${role}-soft-fg-muted`,\n dismiss: `text-${role}-icon hover:bg-${role}-soft-hover`,\n };\n}\n\nfunction outlineSlots(role: TwColor): AlertSlotClasses {\n return {\n root: `border-${role}-border text-${role}-soft-fg-muted`,\n icon: `text-${role}-icon`,\n title: `text-${role}-soft-fg`,\n content: `text-${role}-soft-fg-muted`,\n dismiss: `text-${role}-icon hover:bg-${role}-soft`,\n };\n}\n\nfunction solidSlots(role: TwColor): AlertSlotClasses {\n return {\n root: `bg-${role}-solid text-${role}-solid-fg`,\n icon: `text-${role}-solid-fg`,\n title: `text-${role}-solid-fg`,\n content: `text-${role}-solid-fg`,\n dismiss: `text-${role}-solid-fg/80 hover:bg-${role}-solid-hover`,\n };\n}\n\nconst ROLES: readonly TwColor[] = [\n 'primary', 'secondary', 'accent', 'neutral',\n 'info', 'success', 'warning', 'error',\n] as const;\n\nconst alertVariants = tv({\n slots: {\n root: 'relative flex gap-3 rounded-lg p-4 text-sm',\n icon: 'size-5 shrink-0 mt-0.5',\n title: 'text-sm font-semibold',\n content: 'text-sm',\n actions: 'flex items-center gap-2 mt-2',\n // size-3.5 inner glyph: half-step decorative — keeps the X visually centred\n // in the size-6 square-interactive target without dominating the button.\n dismiss:\n 'absolute top-2.5 right-2.5 inline-flex items-center justify-center size-6 rounded-md cursor-pointer transition-colors duration-normal motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500',\n },\n variants: {\n variant: {\n solid: { root: '' },\n outline: { root: 'border' },\n soft: { root: '' },\n },\n color: Object.fromEntries(ROLES.map((r) => [r, {}])) as Record<TwColor, Record<string, never>>,\n },\n compoundVariants: ROLES.flatMap((role) => [\n { variant: 'soft' as const, color: role, class: softSlots(role) },\n { variant: 'outline' as const, color: role, class: outlineSlots(role) },\n { variant: 'solid' as const, color: role, class: solidSlots(role) },\n ]),\n defaultVariants: {\n variant: 'soft',\n color: 'info',\n },\n}, {\n twMerge: true,\n});\n\n@Directive({\n selector: '[twAlertIcon]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertIconDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.iconClasses;\n}\n\n@Directive({\n selector: '[twAlertTitle]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertTitleDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.titleClasses;\n}\n\n@Directive({\n selector: '[twAlertContent]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertContentDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.contentClasses;\n}\n\n@Directive({\n selector: '[twAlertActions]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertActionsDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.actionsClasses;\n}\n\n@Component({\n selector: 'tw-alert',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[attr.role]': 'computedRole()',\n '[class]': 'rootClasses()',\n '[animate.leave]': '\"fade-out\"',\n },\n template: `\n @if (hasIcon()) {\n <ng-content select=\"[twAlertIcon]\" />\n }\n <div class=\"min-w-0 flex-1\">\n <ng-content select=\"[twAlertTitle]\" />\n <ng-content select=\"[twAlertContent]\" />\n <ng-content />\n <ng-content select=\"[twAlertActions]\" />\n </div>\n @if (dismissible()) {\n <button\n type=\"button\"\n [attr.aria-label]=\"dismissLabel()\"\n [class]=\"dismissClasses()\"\n (click)=\"dismissed.emit()\"\n >\n <!-- size-3.5 (14px) is the half-step between size-3 and size-4 — the only icon size that visually aligns with the alert title's text-sm metric inside the compact xs-density dismiss button. -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-3.5\">\n <path d=\"M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z\"/>\n </svg>\n </button>\n }\n `,\n})\nexport class AlertComponent {\n /** Controls the visual style of the alert. Defaults to `'soft'`. */\n readonly variant = input<AlertVariant>('soft');\n\n /** Sets the semantic color palette. Defaults to `'info'`. */\n readonly color = input<TwColor>('info');\n\n /** When true, renders a dismiss button. Defaults to `false`. */\n readonly dismissible = input(false, { transform: booleanAttribute });\n\n /**\n * Sets the ARIA live-region politeness. Maps to the host `role`:\n * `'assertive'` → `role=\"alert\"`, `'polite'` → `role=\"status\"`,\n * `'off'` → no role. Use `'off'` to suppress re-announcement when the\n * alert content updates after initial render — assistive tech treats the\n * alert as a static region rather than a live region. Defaults to `'polite'`.\n */\n readonly politeness = input<AlertPoliteness>('polite');\n\n /** Accessible label for the dismiss button. Override for localization. Defaults to `'Dismiss'`. */\n readonly dismissLabel = input<string>('Dismiss');\n\n /** Fires when the dismiss button is clicked. */\n readonly dismissed = output<void>();\n\n /** @internal */\n readonly iconDirective = contentChild(AlertIconDirective);\n\n readonly hasIcon = computed(() => !!this.iconDirective());\n\n readonly computedRole = computed(() => {\n switch (this.politeness()) {\n case 'assertive':\n return 'alert';\n case 'polite':\n return 'status';\n default:\n return null;\n }\n });\n\n private readonly variantResult = computed(() =>\n alertVariants({\n variant: this.variant(),\n color: this.color(),\n }),\n );\n\n readonly rootClasses = computed(() => {\n const base = this.variantResult().root();\n return this.dismissible() ? `${base} pr-10` : base;\n });\n\n readonly iconClasses = computed(() => this.variantResult().icon());\n readonly titleClasses = computed(() => this.variantResult().title());\n readonly contentClasses = computed(() => this.variantResult().content());\n readonly actionsClasses = computed(() => this.variantResult().actions());\n readonly dismissClasses = computed(() => this.variantResult().dismiss());\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cdevhub-ngx-tw-alert.mjs","sources":["../../../projects/ngx-tw/alert/alert.ts","../../../projects/ngx-tw/alert/cdevhub-ngx-tw-alert.ts"],"sourcesContent":["import {\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChild,\n Directive,\n inject,\n input,\n output,\n} from '@angular/core';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor } from '@cdevhub/ngx-tw/core';\n\n/** Visual style of the alert container. */\nexport type AlertVariant = 'solid' | 'outline' | 'soft';\n\n/** ARIA live-region politeness for the alert. Maps to the host `role`. */\nexport type AlertPoliteness = 'polite' | 'assertive' | 'off';\n\n/**\n * Alert variants use the semantic role slot tokens defined in\n * `projects/ngx-tw/theme/_semantic.css` (and redefined per-theme in\n * `_dark.css` / `_high-contrast.css`). The mapping role × variant → slots\n * is the same for every color, so the variant table is expressed as a single\n * function template over the role name — no per-role copy-paste, no shade\n * picks, no `dark:` overrides. Dark / high-contrast contrast is owned by the\n * theme tokens; components only consume slots.\n */\ninterface AlertSlotClasses {\n root: string;\n icon: string;\n title: string;\n content: string;\n dismiss: string;\n}\n\nfunction softSlots(role: TwColor): AlertSlotClasses {\n return {\n root: `bg-${role}-soft text-${role}-soft-fg-muted`,\n icon: `text-${role}-icon`,\n title: `text-${role}-soft-fg`,\n content: `text-${role}-soft-fg-muted`,\n dismiss: `text-${role}-icon hover:bg-${role}-soft-hover`,\n };\n}\n\nfunction outlineSlots(role: TwColor): AlertSlotClasses {\n return {\n root: `border-${role}-border text-${role}-soft-fg-muted`,\n icon: `text-${role}-icon`,\n title: `text-${role}-soft-fg`,\n content: `text-${role}-soft-fg-muted`,\n dismiss: `text-${role}-icon hover:bg-${role}-soft`,\n };\n}\n\nfunction solidSlots(role: TwColor): AlertSlotClasses {\n return {\n root: `bg-${role}-solid text-${role}-solid-fg`,\n icon: `text-${role}-solid-fg`,\n title: `text-${role}-solid-fg`,\n content: `text-${role}-solid-fg`,\n dismiss: `text-${role}-solid-fg/80 hover:bg-${role}-solid-hover`,\n };\n}\n\nconst ROLES: readonly TwColor[] = [\n 'primary', 'secondary', 'accent', 'neutral',\n 'info', 'success', 'warning', 'error',\n] as const;\n\nconst alertVariants = tv({\n slots: {\n root: 'relative flex gap-3 rounded-lg p-4 text-sm',\n icon: 'size-5 shrink-0 mt-0.5',\n title: 'text-sm font-semibold',\n content: 'text-sm',\n actions: 'flex items-center gap-2 mt-2',\n // size-3.5 inner glyph: half-step decorative — keeps the X visually centred\n // in the size-6 square-interactive target without dominating the button.\n dismiss:\n 'absolute top-2.5 right-2.5 inline-flex items-center justify-center size-6 rounded-md cursor-pointer transition-colors duration-normal motion-reduce:transition-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500',\n },\n variants: {\n variant: {\n solid: { root: '' },\n outline: { root: 'border' },\n soft: { root: '' },\n },\n color: Object.fromEntries(ROLES.map((r) => [r, {}])) as Record<TwColor, Record<string, never>>,\n },\n compoundVariants: ROLES.flatMap((role) => [\n { variant: 'soft' as const, color: role, class: softSlots(role) },\n { variant: 'outline' as const, color: role, class: outlineSlots(role) },\n { variant: 'solid' as const, color: role, class: solidSlots(role) },\n ]),\n defaultVariants: {\n variant: 'soft',\n color: 'info',\n },\n}, {\n twMerge: true,\n});\n\n@Directive({\n selector: '[twAlertIcon]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertIconDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.iconClasses;\n}\n\n@Directive({\n selector: '[twAlertTitle]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertTitleDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.titleClasses;\n}\n\n@Directive({\n selector: '[twAlertContent]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertContentDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.contentClasses;\n}\n\n@Directive({\n selector: '[twAlertActions]',\n host: {\n '[class]': 'classes()',\n },\n})\nexport class AlertActionsDirective {\n private readonly alert = inject(AlertComponent);\n readonly classes = this.alert.actionsClasses;\n}\n\n@Component({\n selector: 'tw-alert',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[attr.role]': 'computedRole()',\n '[class]': 'rootClasses()',\n '[animate.leave]': '\"fade-out\"',\n },\n template: `\n @if (hasIcon()) {\n <ng-content select=\"[twAlertIcon]\" />\n }\n <div class=\"min-w-0 flex-1\">\n <ng-content select=\"[twAlertTitle]\" />\n <ng-content select=\"[twAlertContent]\" />\n <ng-content />\n <ng-content select=\"[twAlertActions]\" />\n </div>\n @if (dismissible()) {\n <button\n type=\"button\"\n [attr.aria-label]=\"dismissLabel()\"\n [class]=\"dismissClasses()\"\n (click)=\"dismissed.emit()\"\n >\n <!-- size-3.5 (14px) is the half-step between size-3 and size-4 — the only icon size that visually aligns with the alert title's text-sm metric inside the compact xs-density dismiss button. -->\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 16 16\" fill=\"currentColor\" class=\"size-3.5\">\n <path d=\"M5.28 4.22a.75.75 0 0 0-1.06 1.06L6.94 8l-2.72 2.72a.75.75 0 1 0 1.06 1.06L8 9.06l2.72 2.72a.75.75 0 1 0 1.06-1.06L9.06 8l2.72-2.72a.75.75 0 0 0-1.06-1.06L8 6.94 5.28 4.22Z\"/>\n </svg>\n </button>\n }\n `,\n})\nexport class AlertComponent {\n /** Controls the visual style of the alert. Defaults to `'soft'`. */\n readonly variant = input<AlertVariant>('soft');\n\n /** Sets the semantic color palette. Defaults to `'info'`. */\n readonly color = input<TwColor>('info');\n\n /** When true, renders a dismiss button. Defaults to `false`. */\n readonly dismissible = input(false, { transform: booleanAttribute });\n\n /**\n * Sets the ARIA live-region politeness. Maps to the host `role`:\n * `'assertive'` → `role=\"alert\"`, `'polite'` → `role=\"status\"`,\n * `'off'` → no role. Use `'off'` to suppress re-announcement when the\n * alert content updates after initial render — assistive tech treats the\n * alert as a static region rather than a live region. Defaults to `'polite'`.\n */\n readonly politeness = input<AlertPoliteness>('polite');\n\n /** Accessible label for the dismiss button. Override for localization. Defaults to `'Dismiss'`. */\n readonly dismissLabel = input<string>('Dismiss');\n\n /** Fires when the dismiss button is clicked. */\n readonly dismissed = output<void>();\n\n /** @internal */\n readonly iconDirective = contentChild(AlertIconDirective);\n\n readonly hasIcon = computed(() => !!this.iconDirective());\n\n readonly computedRole = computed(() => {\n switch (this.politeness()) {\n case 'assertive':\n return 'alert';\n case 'polite':\n return 'status';\n default:\n return null;\n }\n });\n\n private readonly variantResult = computed(() =>\n alertVariants({\n variant: this.variant(),\n color: this.color(),\n }),\n );\n\n readonly rootClasses = computed(() => {\n const base = this.variantResult().root();\n return this.dismissible() ? `${base} pr-10` : base;\n });\n\n readonly iconClasses = computed(() => this.variantResult().icon());\n readonly titleClasses = computed(() => this.variantResult().title());\n readonly contentClasses = computed(() => this.variantResult().content());\n readonly actionsClasses = computed(() => this.variantResult().actions());\n readonly dismissClasses = computed(() => this.variantResult().dismiss());\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, Directive } from '@angular/core';
3
+
4
+ /**
5
+ * The aspect ratio applied when the input is absent, invalid, or non-positive.
6
+ * Uses the spaced CSS form so every applied value (fallback and normalized
7
+ * ratios alike) is rendered consistently.
8
+ */
9
+ const DEFAULT_RATIO = '1 / 1';
10
+ /**
11
+ * Normalizes a single ratio side: returns the numeric value when it parses as a
12
+ * finite number greater than zero, otherwise `null`. Uses `Number()` (not
13
+ * `parseFloat`) so partial-numeric garbage like `'16px'` is rejected rather than
14
+ * silently truncated to `16`.
15
+ */
16
+ function positiveOrNull(part) {
17
+ const n = Number(part.trim());
18
+ return Number.isFinite(n) && n > 0 ? n : null;
19
+ }
20
+ /**
21
+ * Coerces an aspect-ratio input into a valid CSS `aspect-ratio` string, or the
22
+ * default when the value is invalid. Every output is normalized to the uniform
23
+ * `'<w> / <h>'` form: a bare number `n` becomes `'n / 1'` (equivalent CSS), and
24
+ * ratio strings using `/` or `:` are validated on both sides and joined with
25
+ * `' / '`.
26
+ */
27
+ function coerceRatio(value) {
28
+ if (typeof value === 'number') {
29
+ return Number.isFinite(value) && value > 0 ? `${value} / 1` : DEFAULT_RATIO;
30
+ }
31
+ const trimmed = value.trim();
32
+ if (trimmed === '') {
33
+ return DEFAULT_RATIO;
34
+ }
35
+ // Ratio form: '16/9' or '16:9' (CSS rejects the colon, so normalize to '/').
36
+ if (trimmed.includes('/') || trimmed.includes(':')) {
37
+ const parts = trimmed.split(/[/:]/);
38
+ if (parts.length !== 2) {
39
+ return DEFAULT_RATIO;
40
+ }
41
+ const w = positiveOrNull(parts[0]);
42
+ const h = positiveOrNull(parts[1]);
43
+ return w !== null && h !== null ? `${w} / ${h}` : DEFAULT_RATIO;
44
+ }
45
+ // Plain numeric string: '1.5' → '1.5 / 1'.
46
+ const single = positiveOrNull(trimmed);
47
+ return single !== null ? `${single} / 1` : DEFAULT_RATIO;
48
+ }
49
+ /**
50
+ * Sets the native CSS `aspect-ratio` property on its host element, standardizing
51
+ * the `aspect-[16/9]` pattern consumers otherwise hand-roll across cards,
52
+ * thumbnails, video, and image grids.
53
+ *
54
+ * The directive sets **only** `aspect-ratio` — it does not set `width`,
55
+ * `display`, or any other layout property (matching Tailwind's `aspect-*`
56
+ * utility). Block-level hosts already fill their container width; for replaced
57
+ * elements (`<img>`, `<video>`) pair it with `w-full` / `object-cover` so the
58
+ * box has a definite cross-axis size.
59
+ *
60
+ * Purely presentational: it adds no `role` or `aria-*` and leaves the host
61
+ * media's own accessibility (`alt`, `aria-*`, `title`) untouched.
62
+ *
63
+ * @example
64
+ * ```html
65
+ * <div twAspectRatio class="w-full bg-surface-muted"></div>
66
+ * <img twAspectRatio="16/9" class="w-full object-cover rounded-lg" [src]="thumb" alt="Preview" />
67
+ * <div [twAspectRatio]="4 / 3" class="w-full"></div>
68
+ * <video twAspectRatio="21:9" class="w-full" [src]="clip"></video>
69
+ * ```
70
+ */
71
+ class AspectRatioDirective {
72
+ /**
73
+ * Sets the host's aspect ratio. Accepts a unitless number (e.g. `1.7777`) or a
74
+ * ratio string using `/` or `:` (e.g. `'16/9'` or `'16:9'`). The value is
75
+ * normalized to CSS `'<w> / <h>'` form (a bare number `n` becomes `'n / 1'`).
76
+ * Invalid or non-positive values fall back to the default. Defaults to a
77
+ * square (`1 / 1`).
78
+ */
79
+ twAspectRatio = input(DEFAULT_RATIO, /* @ts-ignore */
80
+ ...(ngDevMode ? [{ debugName: "twAspectRatio" }] : /* istanbul ignore next */ []));
81
+ /** The coerced, CSS-valid `aspect-ratio` value applied to the host. */
82
+ ratio = computed(() => coerceRatio(this.twAspectRatio()), /* @ts-ignore */
83
+ ...(ngDevMode ? [{ debugName: "ratio" }] : /* istanbul ignore next */ []));
84
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AspectRatioDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
85
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.7", type: AspectRatioDirective, isStandalone: true, selector: "[twAspectRatio]", inputs: { twAspectRatio: { classPropertyName: "twAspectRatio", publicName: "twAspectRatio", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.aspect-ratio": "ratio()" } }, exportAs: ["twAspectRatio"], ngImport: i0 });
86
+ }
87
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AspectRatioDirective, decorators: [{
88
+ type: Directive,
89
+ args: [{
90
+ selector: '[twAspectRatio]',
91
+ exportAs: 'twAspectRatio',
92
+ host: {
93
+ '[style.aspect-ratio]': 'ratio()',
94
+ },
95
+ }]
96
+ }], propDecorators: { twAspectRatio: [{ type: i0.Input, args: [{ isSignal: true, alias: "twAspectRatio", required: false }] }] } });
97
+
98
+ /**
99
+ * Generated bundle index. Do not edit.
100
+ */
101
+
102
+ export { AspectRatioDirective };
103
+ //# sourceMappingURL=cdevhub-ngx-tw-aspect-ratio.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdevhub-ngx-tw-aspect-ratio.mjs","sources":["../../../projects/ngx-tw/aspect-ratio/aspect-ratio.ts","../../../projects/ngx-tw/aspect-ratio/cdevhub-ngx-tw-aspect-ratio.ts"],"sourcesContent":["import {\n Directive,\n computed,\n input,\n} from '@angular/core';\n\n/**\n * The aspect ratio applied when the input is absent, invalid, or non-positive.\n * Uses the spaced CSS form so every applied value (fallback and normalized\n * ratios alike) is rendered consistently.\n */\nconst DEFAULT_RATIO = '1 / 1';\n\n/**\n * Normalizes a single ratio side: returns the numeric value when it parses as a\n * finite number greater than zero, otherwise `null`. Uses `Number()` (not\n * `parseFloat`) so partial-numeric garbage like `'16px'` is rejected rather than\n * silently truncated to `16`.\n */\nfunction positiveOrNull(part: string): number | null {\n const n = Number(part.trim());\n return Number.isFinite(n) && n > 0 ? n : null;\n}\n\n/**\n * Coerces an aspect-ratio input into a valid CSS `aspect-ratio` string, or the\n * default when the value is invalid. Every output is normalized to the uniform\n * `'<w> / <h>'` form: a bare number `n` becomes `'n / 1'` (equivalent CSS), and\n * ratio strings using `/` or `:` are validated on both sides and joined with\n * `' / '`.\n */\nfunction coerceRatio(value: number | string): string {\n if (typeof value === 'number') {\n return Number.isFinite(value) && value > 0 ? `${value} / 1` : DEFAULT_RATIO;\n }\n\n const trimmed = value.trim();\n if (trimmed === '') {\n return DEFAULT_RATIO;\n }\n\n // Ratio form: '16/9' or '16:9' (CSS rejects the colon, so normalize to '/').\n if (trimmed.includes('/') || trimmed.includes(':')) {\n const parts = trimmed.split(/[/:]/);\n if (parts.length !== 2) {\n return DEFAULT_RATIO;\n }\n const w = positiveOrNull(parts[0]);\n const h = positiveOrNull(parts[1]);\n return w !== null && h !== null ? `${w} / ${h}` : DEFAULT_RATIO;\n }\n\n // Plain numeric string: '1.5' → '1.5 / 1'.\n const single = positiveOrNull(trimmed);\n return single !== null ? `${single} / 1` : DEFAULT_RATIO;\n}\n\n/**\n * Sets the native CSS `aspect-ratio` property on its host element, standardizing\n * the `aspect-[16/9]` pattern consumers otherwise hand-roll across cards,\n * thumbnails, video, and image grids.\n *\n * The directive sets **only** `aspect-ratio` — it does not set `width`,\n * `display`, or any other layout property (matching Tailwind's `aspect-*`\n * utility). Block-level hosts already fill their container width; for replaced\n * elements (`<img>`, `<video>`) pair it with `w-full` / `object-cover` so the\n * box has a definite cross-axis size.\n *\n * Purely presentational: it adds no `role` or `aria-*` and leaves the host\n * media's own accessibility (`alt`, `aria-*`, `title`) untouched.\n *\n * @example\n * ```html\n * <div twAspectRatio class=\"w-full bg-surface-muted\"></div>\n * <img twAspectRatio=\"16/9\" class=\"w-full object-cover rounded-lg\" [src]=\"thumb\" alt=\"Preview\" />\n * <div [twAspectRatio]=\"4 / 3\" class=\"w-full\"></div>\n * <video twAspectRatio=\"21:9\" class=\"w-full\" [src]=\"clip\"></video>\n * ```\n */\n@Directive({\n selector: '[twAspectRatio]',\n exportAs: 'twAspectRatio',\n host: {\n '[style.aspect-ratio]': 'ratio()',\n },\n})\nexport class AspectRatioDirective {\n /**\n * Sets the host's aspect ratio. Accepts a unitless number (e.g. `1.7777`) or a\n * ratio string using `/` or `:` (e.g. `'16/9'` or `'16:9'`). The value is\n * normalized to CSS `'<w> / <h>'` form (a bare number `n` becomes `'n / 1'`).\n * Invalid or non-positive values fall back to the default. Defaults to a\n * square (`1 / 1`).\n */\n readonly twAspectRatio = input<number | string>(DEFAULT_RATIO);\n\n /** The coerced, CSS-valid `aspect-ratio` value applied to the host. */\n readonly ratio = computed(() => coerceRatio(this.twAspectRatio()));\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAMA;;;;AAIG;AACH,MAAM,aAAa,GAAG,OAAO;AAE7B;;;;;AAKG;AACH,SAAS,cAAc,CAAC,IAAY,EAAA;IAClC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;AAC7B,IAAA,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI;AAC/C;AAEA;;;;;;AAMG;AACH,SAAS,WAAW,CAAC,KAAsB,EAAA;AACzC,IAAA,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;QAC7B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,CAAC,GAAG,GAAG,KAAK,CAAA,IAAA,CAAM,GAAG,aAAa;IAC7E;AAEA,IAAA,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE;AAC5B,IAAA,IAAI,OAAO,KAAK,EAAE,EAAE;AAClB,QAAA,OAAO,aAAa;IACtB;;AAGA,IAAA,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;QAClD,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;AACnC,QAAA,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE;AACtB,YAAA,OAAO,aAAa;QACtB;QACA,MAAM,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,MAAM,CAAC,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAClC,QAAA,OAAO,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA,CAAE,GAAG,aAAa;IACjE;;AAGA,IAAA,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC;AACtC,IAAA,OAAO,MAAM,KAAK,IAAI,GAAG,CAAA,EAAG,MAAM,CAAA,IAAA,CAAM,GAAG,aAAa;AAC1D;AAEA;;;;;;;;;;;;;;;;;;;;;AAqBG;MAQU,oBAAoB,CAAA;AAC/B;;;;;;AAMG;IACM,aAAa,GAAG,KAAK,CAAkB,aAAa;sFAAC;;AAGrD,IAAA,KAAK,GAAG,QAAQ,CAAC,MAAM,WAAW,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;8EAAC;uGAXvD,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAApB,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,EAAA,aAAA,EAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,UAAA,EAAA,eAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,oBAAA,EAAA,SAAA,EAAA,EAAA,EAAA,QAAA,EAAA,CAAA,eAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAPhC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,iBAAiB;AAC3B,oBAAA,QAAQ,EAAE,eAAe;AACzB,oBAAA,IAAI,EAAE;AACJ,wBAAA,sBAAsB,EAAE,SAAS;AAClC,qBAAA;AACF,iBAAA;;;ACrFD;;AAEG;;;;"}
@@ -62,17 +62,23 @@ const statusColorMap = {
62
62
  };
63
63
  class AvatarComponent {
64
64
  /** URL of the avatar image. When set, renders an `<img>`. Falls back to initials or projected content on load error. Defaults to `null`. */
65
- src = input(null, ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
65
+ src = input(null, /* @ts-ignore */
66
+ ...(ngDevMode ? [{ debugName: "src" }] : /* istanbul ignore next */ []));
66
67
  /** Alt text for the avatar image. Also used as `aria-label` for non-image avatars. Defaults to `''`. */
67
- alt = input('', ...(ngDevMode ? [{ debugName: "alt" }] : /* istanbul ignore next */ []));
68
+ alt = input('', /* @ts-ignore */
69
+ ...(ngDevMode ? [{ debugName: "alt" }] : /* istanbul ignore next */ []));
68
70
  /** Text initials displayed when no image is available (1-2 characters). Rendered uppercase regardless of input casing. Defaults to `null`. */
69
- initials = input(null, ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
71
+ initials = input(null, /* @ts-ignore */
72
+ ...(ngDevMode ? [{ debugName: "initials" }] : /* istanbul ignore next */ []));
70
73
  /** Semantic color for the initials/icon background. Only applies when no image is shown. Defaults to `'neutral'`. */
71
- color = input('neutral', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
74
+ color = input('neutral', /* @ts-ignore */
75
+ ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
72
76
  /** Controls the avatar dimensions. Defaults to `'md'`. */
73
- size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
77
+ size = input('md', /* @ts-ignore */
78
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
74
79
  /** Bundles decorative axes: `rounded` (shape) and `status` (indicator dot). Defaults to `{ rounded: 'full', status: null }`. */
75
- appearance = input({}, ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
80
+ appearance = input({}, /* @ts-ignore */
81
+ ...(ngDevMode ? [{ debugName: "appearance" }] : /* istanbul ignore next */ []));
76
82
  /** Fires when the avatar image fails to load. Payload is the native `Event` from the `<img>` `error` event. */
77
83
  imageError = output();
78
84
  /** @internal */
@@ -83,7 +89,8 @@ class AvatarComponent {
83
89
  * host `[attr.hidden]` binding so the group's effect stays declarative
84
90
  * (no direct `style.display` mutation).
85
91
  */
86
- groupHidden = signal(false, ...(ngDevMode ? [{ debugName: "groupHidden" }] : /* istanbul ignore next */ []));
92
+ groupHidden = signal(false, /* @ts-ignore */
93
+ ...(ngDevMode ? [{ debugName: "groupHidden" }] : /* istanbul ignore next */ []));
87
94
  groupSize = inject(AVATAR_GROUP_SIZE, { optional: true });
88
95
  constructor() {
89
96
  if (isDevMode()) {
@@ -94,9 +101,12 @@ class AvatarComponent {
94
101
  });
95
102
  }
96
103
  }
97
- resolvedSize = computed(() => this.groupSize ? this.groupSize() : this.size(), ...(ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []));
98
- resolvedRounded = computed(() => this.appearance().rounded ?? 'full', ...(ngDevMode ? [{ debugName: "resolvedRounded" }] : /* istanbul ignore next */ []));
99
- resolvedStatus = computed(() => this.appearance().status ?? null, ...(ngDevMode ? [{ debugName: "resolvedStatus" }] : /* istanbul ignore next */ []));
104
+ resolvedSize = computed(() => this.groupSize ? this.groupSize() : this.size(), /* @ts-ignore */
105
+ ...(ngDevMode ? [{ debugName: "resolvedSize" }] : /* istanbul ignore next */ []));
106
+ resolvedRounded = computed(() => this.appearance().rounded ?? 'full', /* @ts-ignore */
107
+ ...(ngDevMode ? [{ debugName: "resolvedRounded" }] : /* istanbul ignore next */ []));
108
+ resolvedStatus = computed(() => this.appearance().status ?? null, /* @ts-ignore */
109
+ ...(ngDevMode ? [{ debugName: "resolvedStatus" }] : /* istanbul ignore next */ []));
100
110
  imageLoaded = linkedSignal({ ...(ngDevMode ? { debugName: "imageLoaded" } : /* istanbul ignore next */ {}), source: this.src,
101
111
  computation: () => null });
102
112
  displayMode = computed(() => {
@@ -105,29 +115,36 @@ class AvatarComponent {
105
115
  if (this.initials())
106
116
  return 'initials';
107
117
  return 'fallback';
108
- }, ...(ngDevMode ? [{ debugName: "displayMode" }] : /* istanbul ignore next */ []));
118
+ }, /* @ts-ignore */
119
+ ...(ngDevMode ? [{ debugName: "displayMode" }] : /* istanbul ignore next */ []));
109
120
  variantResult = computed(() => avatarVariants({
110
121
  size: this.resolvedSize(),
111
122
  rounded: this.resolvedRounded(),
112
123
  color: this.color(),
113
- }), ...(ngDevMode ? [{ debugName: "variantResult" }] : /* istanbul ignore next */ []));
114
- rootClasses = computed(() => this.variantResult().root(), ...(ngDevMode ? [{ debugName: "rootClasses" }] : /* istanbul ignore next */ []));
115
- imgClasses = computed(() => this.variantResult().img(), ...(ngDevMode ? [{ debugName: "imgClasses" }] : /* istanbul ignore next */ []));
116
- initialsClasses = computed(() => this.variantResult().initials(), ...(ngDevMode ? [{ debugName: "initialsClasses" }] : /* istanbul ignore next */ []));
117
- fallbackClasses = computed(() => this.variantResult().fallback(), ...(ngDevMode ? [{ debugName: "fallbackClasses" }] : /* istanbul ignore next */ []));
124
+ }), /* @ts-ignore */
125
+ ...(ngDevMode ? [{ debugName: "variantResult" }] : /* istanbul ignore next */ []));
126
+ rootClasses = computed(() => this.variantResult().root(), /* @ts-ignore */
127
+ ...(ngDevMode ? [{ debugName: "rootClasses" }] : /* istanbul ignore next */ []));
128
+ imgClasses = computed(() => this.variantResult().img(), /* @ts-ignore */
129
+ ...(ngDevMode ? [{ debugName: "imgClasses" }] : /* istanbul ignore next */ []));
130
+ initialsClasses = computed(() => this.variantResult().initials(), /* @ts-ignore */
131
+ ...(ngDevMode ? [{ debugName: "initialsClasses" }] : /* istanbul ignore next */ []));
132
+ fallbackClasses = computed(() => this.variantResult().fallback(), /* @ts-ignore */
133
+ ...(ngDevMode ? [{ debugName: "fallbackClasses" }] : /* istanbul ignore next */ []));
118
134
  statusClasses = computed(() => {
119
135
  const base = this.variantResult().status();
120
136
  const statusValue = this.resolvedStatus();
121
137
  if (!statusValue)
122
138
  return base;
123
139
  return `${base} ${statusColorMap[statusValue]}`;
124
- }, ...(ngDevMode ? [{ debugName: "statusClasses" }] : /* istanbul ignore next */ []));
140
+ }, /* @ts-ignore */
141
+ ...(ngDevMode ? [{ debugName: "statusClasses" }] : /* istanbul ignore next */ []));
125
142
  onImageError(event) {
126
143
  this.imageLoaded.set(false);
127
144
  this.imageError.emit(event);
128
145
  }
129
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
130
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AvatarComponent, isStandalone: true, selector: "tw-avatar", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", 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 }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageError: "imageError" }, host: { properties: { "class": "rootClasses()", "attr.role": "displayMode() !== \"image\" ? \"img\" : null", "attr.aria-label": "displayMode() !== \"image\" && alt() ? alt() : null", "attr.aria-hidden": "displayMode() !== \"image\" && !alt() ? \"true\" : null", "attr.hidden": "groupHidden() ? \"\" : null" } }, ngImport: i0, template: `
146
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AvatarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
147
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: AvatarComponent, isStandalone: true, selector: "tw-avatar", inputs: { src: { classPropertyName: "src", publicName: "src", isSignal: true, isRequired: false, transformFunction: null }, alt: { classPropertyName: "alt", publicName: "alt", isSignal: true, isRequired: false, transformFunction: null }, initials: { classPropertyName: "initials", publicName: "initials", 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 }, appearance: { classPropertyName: "appearance", publicName: "appearance", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { imageError: "imageError" }, host: { properties: { "class": "rootClasses()", "attr.role": "displayMode() !== \"image\" ? \"img\" : null", "attr.aria-label": "displayMode() !== \"image\" && alt() ? alt() : null", "attr.aria-hidden": "displayMode() !== \"image\" && !alt() ? \"true\" : null", "attr.hidden": "groupHidden() ? \"\" : null" } }, ngImport: i0, template: `
131
148
  @switch (displayMode()) {
132
149
  @case ('image') {
133
150
  <img
@@ -154,7 +171,7 @@ class AvatarComponent {
154
171
  }
155
172
  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
156
173
  }
157
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AvatarComponent, decorators: [{
174
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AvatarComponent, decorators: [{
158
175
  type: Component,
159
176
  args: [{
160
177
  selector: 'tw-avatar',
@@ -206,37 +223,45 @@ const groupOverlapMap = {
206
223
  };
207
224
  class AvatarGroupComponent {
208
225
  /** Sets the size for all child avatars. Individual avatar size inputs are ignored when inside a group. Defaults to `'md'`. */
209
- size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
226
+ size = input('md', /* @ts-ignore */
227
+ ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
210
228
  /** Maximum number of avatars to display. Remaining count is shown as a "+N" overflow indicator. Defaults to `null` (show all). */
211
- max = input(null, ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
229
+ max = input(null, /* @ts-ignore */
230
+ ...(ngDevMode ? [{ debugName: "max" }] : /* istanbul ignore next */ []));
212
231
  /** Accessible label for the avatar group. Defaults to `'Avatar group'` (English) — override for localisation. */
213
- ariaLabel = input('Avatar group', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
214
- avatars = contentChildren(AvatarComponent, ...(ngDevMode ? [{ debugName: "avatars" }] : /* istanbul ignore next */ []));
232
+ ariaLabel = input('Avatar group', /* @ts-ignore */
233
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
234
+ avatars = contentChildren(AvatarComponent, /* @ts-ignore */
235
+ ...(ngDevMode ? [{ debugName: "avatars" }] : /* istanbul ignore next */ []));
215
236
  overflowCount = computed(() => {
216
237
  const all = this.avatars();
217
238
  const maxVal = this.max();
218
239
  if (maxVal === null || maxVal >= all.length)
219
240
  return 0;
220
241
  return all.length - maxVal;
221
- }, ...(ngDevMode ? [{ debugName: "overflowCount" }] : /* istanbul ignore next */ []));
242
+ }, /* @ts-ignore */
243
+ ...(ngDevMode ? [{ debugName: "overflowCount" }] : /* istanbul ignore next */ []));
222
244
  hostClasses = computed(() => {
223
245
  const s = this.size();
224
246
  return `inline-flex items-center [&>tw-avatar]:ring-2 [&>tw-avatar]:ring-surface ${groupOverlapMap[s]}`;
225
- }, ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
247
+ }, /* @ts-ignore */
248
+ ...(ngDevMode ? [{ debugName: "hostClasses" }] : /* istanbul ignore next */ []));
226
249
  overflowClasses = computed(() => {
227
250
  const s = this.size();
228
251
  const sizeClasses = avatarVariants({ size: s, rounded: 'full', color: 'neutral' });
229
252
  return `${sizeClasses.root()} bg-surface-muted text-fg-muted font-medium ring-2 ring-surface`;
230
- }, ...(ngDevMode ? [{ debugName: "overflowClasses" }] : /* istanbul ignore next */ []));
253
+ }, /* @ts-ignore */
254
+ ...(ngDevMode ? [{ debugName: "overflowClasses" }] : /* istanbul ignore next */ []));
231
255
  visibilityEffect = effect(() => {
232
256
  const all = this.avatars();
233
257
  const maxVal = this.max();
234
258
  all.forEach((avatar, index) => {
235
259
  avatar.groupHidden.set(maxVal !== null && index >= maxVal);
236
260
  });
237
- }, ...(ngDevMode ? [{ debugName: "visibilityEffect" }] : /* istanbul ignore next */ []));
238
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AvatarGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
239
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: AvatarGroupComponent, isStandalone: true, selector: "tw-avatar-group", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "class": "hostClasses()", "attr.aria-label": "ariaLabel()" } }, providers: [
261
+ }, /* @ts-ignore */
262
+ ...(ngDevMode ? [{ debugName: "visibilityEffect" }] : /* istanbul ignore next */ []));
263
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AvatarGroupComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
264
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.7", type: AvatarGroupComponent, isStandalone: true, selector: "tw-avatar-group", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "group" }, properties: { "class": "hostClasses()", "attr.aria-label": "ariaLabel()" } }, providers: [
240
265
  {
241
266
  provide: AVATAR_GROUP_SIZE,
242
267
  useFactory: () => {
@@ -251,7 +276,7 @@ class AvatarGroupComponent {
251
276
  }
252
277
  `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
253
278
  }
254
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: AvatarGroupComponent, decorators: [{
279
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImport: i0, type: AvatarGroupComponent, decorators: [{
255
280
  type: Component,
256
281
  args: [{
257
282
  selector: 'tw-avatar-group',
@@ -1 +1 @@
1
- {"version":3,"file":"cdevhub-ngx-tw-avatar.mjs","sources":["../../../projects/ngx-tw/avatar/avatar.ts","../../../projects/ngx-tw/avatar/cdevhub-ngx-tw-avatar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChildren,\n effect,\n ElementRef,\n InjectionToken,\n inject,\n input,\n isDevMode,\n linkedSignal,\n output,\n signal,\n} from '@angular/core';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor, TwSize } from '@cdevhub/ngx-tw/core';\n\n/** Status indicator for the avatar. */\nexport type AvatarStatus = 'online' | 'busy' | 'away' | 'offline';\n\n/** Border radius shape for the avatar. */\nexport type AvatarRounded = 'full' | 'lg' | 'none';\n\n/** Decorative axes bundled into a single avatar input. */\nexport interface AvatarAppearance {\n /** Border-radius shape. Defaults to `'full'`. */\n rounded?: AvatarRounded;\n /** Status indicator dot. Defaults to `null` (no indicator). */\n status?: AvatarStatus | null;\n}\n\n/**\n * Injection token used by `AvatarGroupComponent` to propagate its size\n * to child avatars. When present, overrides the individual avatar's `size` input.\n */\nexport const AVATAR_GROUP_SIZE = new InjectionToken<() => TwSize>('AVATAR_GROUP_SIZE');\n\nconst avatarVariants = tv({\n slots: {\n root: 'relative inline-flex items-center justify-center overflow-hidden shrink-0',\n img: 'size-full object-cover',\n initials: 'font-medium select-none uppercase',\n // size-[60%]: keeps the fallback glyph proportional to the avatar; no Tailwind size token expresses a percentage of parent.\n // Container scale — avatars are surfaces, not glyphs (see CLAUDE.md icon sizing).\n // The fallback child glyph is sized as a percentage of the avatar container\n // so it scales proportionally across every TwSize.\n fallback: 'size-[60%] text-fg-subtle',\n status: 'absolute rounded-full ring-2 ring-surface',\n },\n variants: {\n size: {\n xs: { root: 'size-6 text-xs', status: 'size-2' },\n sm: { root: 'size-8 text-xs', status: 'size-2' },\n md: { root: 'size-10 text-sm', status: 'size-2.5' },\n lg: { root: 'size-12 text-sm', status: 'size-3' },\n // Container scale — avatars are surfaces, not glyphs (see CLAUDE.md icon sizing).\n // The xl avatar lands at 64px, which sits above the glyph scale's ceiling\n // (size-10 / 40px) because avatars host imagery, initials, or icon glyphs.\n xl: { root: 'size-16 text-base', status: 'size-3' },\n },\n rounded: {\n full: { root: 'rounded-full', status: 'bottom-0 right-0' },\n lg: { root: 'rounded-lg', status: '-bottom-0.5 -right-0.5' },\n none: { root: 'rounded-none', status: '-bottom-0.5 -right-0.5' },\n },\n color: {\n primary: { root: 'bg-primary-100 text-primary-700' },\n secondary: { root: 'bg-secondary-100 text-secondary-700' },\n accent: { root: 'bg-accent-100 text-accent-700' },\n neutral: { root: 'bg-surface-muted text-fg-muted' },\n info: { root: 'bg-info-100 text-info-700' },\n success: { root: 'bg-success-100 text-success-700' },\n warning: { root: 'bg-warning-100 text-warning-700' },\n error: { root: 'bg-error-100 text-error-700' },\n },\n },\n defaultVariants: {\n size: 'md',\n rounded: 'full',\n color: 'neutral',\n },\n}, {\n twMerge: true,\n});\n\nconst statusColorMap: Record<AvatarStatus, string> = {\n online: 'bg-success-500',\n busy: 'bg-error-500',\n away: 'bg-warning-500',\n offline: 'bg-fg-subtle',\n};\n\n@Component({\n selector: 'tw-avatar',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'rootClasses()',\n '[attr.role]': 'displayMode() !== \"image\" ? \"img\" : null',\n '[attr.aria-label]': 'displayMode() !== \"image\" && alt() ? alt() : null',\n // Only hide non-image avatars without alt text from AT. Image-mode avatars\n // expose their `alt` attribute directly on the underlying `<img>`; hiding\n // the host would suppress the image from assistive tech entirely.\n '[attr.aria-hidden]': 'displayMode() !== \"image\" && !alt() ? \"true\" : null',\n '[attr.hidden]': 'groupHidden() ? \"\" : null',\n },\n template: `\n @switch (displayMode()) {\n @case ('image') {\n <img\n [src]=\"src()\"\n [alt]=\"alt()\"\n [class]=\"imgClasses()\"\n (load)=\"imageLoaded.set(true)\"\n (error)=\"onImageError($event)\"\n />\n }\n @case ('initials') {\n <span [class]=\"initialsClasses()\">{{ initials() }}</span>\n }\n @case ('fallback') {\n <ng-content>\n <svg [class]=\"fallbackClasses()\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z\" clip-rule=\"evenodd\" />\n </svg>\n </ng-content>\n }\n }\n @if (resolvedStatus()) {\n <span [class]=\"statusClasses()\" aria-hidden=\"true\"></span>\n }\n `,\n})\nexport class AvatarComponent {\n /** URL of the avatar image. When set, renders an `<img>`. Falls back to initials or projected content on load error. Defaults to `null`. */\n readonly src = input<string | null>(null);\n\n /** Alt text for the avatar image. Also used as `aria-label` for non-image avatars. Defaults to `''`. */\n readonly alt = input('');\n\n /** Text initials displayed when no image is available (1-2 characters). Rendered uppercase regardless of input casing. Defaults to `null`. */\n readonly initials = input<string | null>(null);\n\n /** Semantic color for the initials/icon background. Only applies when no image is shown. Defaults to `'neutral'`. */\n readonly color = input<TwColor>('neutral');\n\n /** Controls the avatar dimensions. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Bundles decorative axes: `rounded` (shape) and `status` (indicator dot). Defaults to `{ rounded: 'full', status: null }`. */\n readonly appearance = input<AvatarAppearance>({});\n\n /** Fires when the avatar image fails to load. Payload is the native `Event` from the `<img>` `error` event. */\n readonly imageError = output<Event>();\n\n /** @internal */\n readonly elementRef = inject(ElementRef<HTMLElement>);\n\n /**\n * @internal\n * Toggled by `AvatarGroupComponent` to hide overflow avatars. Drives the\n * host `[attr.hidden]` binding so the group's effect stays declarative\n * (no direct `style.display` mutation).\n */\n readonly groupHidden = signal(false);\n\n private readonly groupSize = inject(AVATAR_GROUP_SIZE, { optional: true });\n\n constructor() {\n if (isDevMode()) {\n effect(() => {\n if (this.displayMode() === 'image' && !this.alt()) {\n console.warn(\n '<tw-avatar> rendered as image without alt text — provide alt for accessibility',\n );\n }\n });\n }\n }\n\n readonly resolvedSize = computed(() => this.groupSize ? this.groupSize() : this.size());\n readonly resolvedRounded = computed<AvatarRounded>(() => this.appearance().rounded ?? 'full');\n readonly resolvedStatus = computed<AvatarStatus | null>(() => this.appearance().status ?? null);\n\n readonly imageLoaded = linkedSignal<string | null, boolean | null>({\n source: this.src,\n computation: () => null,\n });\n\n readonly displayMode = computed<'image' | 'initials' | 'fallback'>(() => {\n if (this.src() && this.imageLoaded() !== false) return 'image';\n if (this.initials()) return 'initials';\n return 'fallback';\n });\n\n private readonly variantResult = computed(() =>\n avatarVariants({\n size: this.resolvedSize(),\n rounded: this.resolvedRounded(),\n color: this.color(),\n }),\n );\n\n readonly rootClasses = computed(() => this.variantResult().root());\n readonly imgClasses = computed(() => this.variantResult().img());\n readonly initialsClasses = computed(() => this.variantResult().initials());\n readonly fallbackClasses = computed(() => this.variantResult().fallback());\n\n readonly statusClasses = computed(() => {\n const base = this.variantResult().status();\n const statusValue = this.resolvedStatus();\n if (!statusValue) return base;\n return `${base} ${statusColorMap[statusValue]}`;\n });\n\n protected onImageError(event: Event): void {\n this.imageLoaded.set(false);\n this.imageError.emit(event);\n }\n}\n\nconst groupOverlapMap: Record<TwSize, string> = {\n xs: '[&>tw-avatar+tw-avatar]:-ml-1.5 [&>tw-avatar+span]:-ml-1.5',\n sm: '[&>tw-avatar+tw-avatar]:-ml-1.5 [&>tw-avatar+span]:-ml-1.5',\n md: '[&>tw-avatar+tw-avatar]:-ml-2 [&>tw-avatar+span]:-ml-2',\n lg: '[&>tw-avatar+tw-avatar]:-ml-3 [&>tw-avatar+span]:-ml-3',\n xl: '[&>tw-avatar+tw-avatar]:-ml-3 [&>tw-avatar+span]:-ml-3',\n};\n\n@Component({\n selector: 'tw-avatar-group',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: AVATAR_GROUP_SIZE,\n useFactory: () => {\n const group = inject(AvatarGroupComponent);\n return () => group.size();\n },\n },\n ],\n host: {\n role: 'group',\n '[class]': 'hostClasses()',\n '[attr.aria-label]': 'ariaLabel()',\n },\n template: `\n <ng-content />\n @if (overflowCount() > 0) {\n <span [class]=\"overflowClasses()\">+{{ overflowCount() }}</span>\n }\n `,\n})\nexport class AvatarGroupComponent {\n /** Sets the size for all child avatars. Individual avatar size inputs are ignored when inside a group. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Maximum number of avatars to display. Remaining count is shown as a \"+N\" overflow indicator. Defaults to `null` (show all). */\n readonly max = input<number | null>(null);\n\n /** Accessible label for the avatar group. Defaults to `'Avatar group'` (English) — override for localisation. */\n readonly ariaLabel = input('Avatar group');\n\n private readonly avatars = contentChildren(AvatarComponent);\n\n readonly overflowCount = computed(() => {\n const all = this.avatars();\n const maxVal = this.max();\n if (maxVal === null || maxVal >= all.length) return 0;\n return all.length - maxVal;\n });\n\n readonly hostClasses = computed(() => {\n const s = this.size();\n return `inline-flex items-center [&>tw-avatar]:ring-2 [&>tw-avatar]:ring-surface ${groupOverlapMap[s]}`;\n });\n\n readonly overflowClasses = computed(() => {\n const s = this.size();\n const sizeClasses = avatarVariants({ size: s, rounded: 'full', color: 'neutral' });\n return `${sizeClasses.root()} bg-surface-muted text-fg-muted font-medium ring-2 ring-surface`;\n });\n\n private readonly visibilityEffect = effect(() => {\n const all = this.avatars();\n const maxVal = this.max();\n all.forEach((avatar, index) => {\n avatar.groupHidden.set(maxVal !== null && index >= maxVal);\n });\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cdevhub-ngx-tw-avatar.mjs","sources":["../../../projects/ngx-tw/avatar/avatar.ts","../../../projects/ngx-tw/avatar/cdevhub-ngx-tw-avatar.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n contentChildren,\n effect,\n ElementRef,\n InjectionToken,\n inject,\n input,\n isDevMode,\n linkedSignal,\n output,\n signal,\n} from '@angular/core';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor, TwSize } from '@cdevhub/ngx-tw/core';\n\n/** Status indicator for the avatar. */\nexport type AvatarStatus = 'online' | 'busy' | 'away' | 'offline';\n\n/** Border radius shape for the avatar. */\nexport type AvatarRounded = 'full' | 'lg' | 'none';\n\n/** Decorative axes bundled into a single avatar input. */\nexport interface AvatarAppearance {\n /** Border-radius shape. Defaults to `'full'`. */\n rounded?: AvatarRounded;\n /** Status indicator dot. Defaults to `null` (no indicator). */\n status?: AvatarStatus | null;\n}\n\n/**\n * Injection token used by `AvatarGroupComponent` to propagate its size\n * to child avatars. When present, overrides the individual avatar's `size` input.\n */\nexport const AVATAR_GROUP_SIZE = new InjectionToken<() => TwSize>('AVATAR_GROUP_SIZE');\n\nconst avatarVariants = tv({\n slots: {\n root: 'relative inline-flex items-center justify-center overflow-hidden shrink-0',\n img: 'size-full object-cover',\n initials: 'font-medium select-none uppercase',\n // size-[60%]: keeps the fallback glyph proportional to the avatar; no Tailwind size token expresses a percentage of parent.\n // Container scale — avatars are surfaces, not glyphs (see CLAUDE.md icon sizing).\n // The fallback child glyph is sized as a percentage of the avatar container\n // so it scales proportionally across every TwSize.\n fallback: 'size-[60%] text-fg-subtle',\n status: 'absolute rounded-full ring-2 ring-surface',\n },\n variants: {\n size: {\n xs: { root: 'size-6 text-xs', status: 'size-2' },\n sm: { root: 'size-8 text-xs', status: 'size-2' },\n md: { root: 'size-10 text-sm', status: 'size-2.5' },\n lg: { root: 'size-12 text-sm', status: 'size-3' },\n // Container scale — avatars are surfaces, not glyphs (see CLAUDE.md icon sizing).\n // The xl avatar lands at 64px, which sits above the glyph scale's ceiling\n // (size-10 / 40px) because avatars host imagery, initials, or icon glyphs.\n xl: { root: 'size-16 text-base', status: 'size-3' },\n },\n rounded: {\n full: { root: 'rounded-full', status: 'bottom-0 right-0' },\n lg: { root: 'rounded-lg', status: '-bottom-0.5 -right-0.5' },\n none: { root: 'rounded-none', status: '-bottom-0.5 -right-0.5' },\n },\n color: {\n primary: { root: 'bg-primary-100 text-primary-700' },\n secondary: { root: 'bg-secondary-100 text-secondary-700' },\n accent: { root: 'bg-accent-100 text-accent-700' },\n neutral: { root: 'bg-surface-muted text-fg-muted' },\n info: { root: 'bg-info-100 text-info-700' },\n success: { root: 'bg-success-100 text-success-700' },\n warning: { root: 'bg-warning-100 text-warning-700' },\n error: { root: 'bg-error-100 text-error-700' },\n },\n },\n defaultVariants: {\n size: 'md',\n rounded: 'full',\n color: 'neutral',\n },\n}, {\n twMerge: true,\n});\n\nconst statusColorMap: Record<AvatarStatus, string> = {\n online: 'bg-success-500',\n busy: 'bg-error-500',\n away: 'bg-warning-500',\n offline: 'bg-fg-subtle',\n};\n\n@Component({\n selector: 'tw-avatar',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'rootClasses()',\n '[attr.role]': 'displayMode() !== \"image\" ? \"img\" : null',\n '[attr.aria-label]': 'displayMode() !== \"image\" && alt() ? alt() : null',\n // Only hide non-image avatars without alt text from AT. Image-mode avatars\n // expose their `alt` attribute directly on the underlying `<img>`; hiding\n // the host would suppress the image from assistive tech entirely.\n '[attr.aria-hidden]': 'displayMode() !== \"image\" && !alt() ? \"true\" : null',\n '[attr.hidden]': 'groupHidden() ? \"\" : null',\n },\n template: `\n @switch (displayMode()) {\n @case ('image') {\n <img\n [src]=\"src()\"\n [alt]=\"alt()\"\n [class]=\"imgClasses()\"\n (load)=\"imageLoaded.set(true)\"\n (error)=\"onImageError($event)\"\n />\n }\n @case ('initials') {\n <span [class]=\"initialsClasses()\">{{ initials() }}</span>\n }\n @case ('fallback') {\n <ng-content>\n <svg [class]=\"fallbackClasses()\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-hidden=\"true\">\n <path fill-rule=\"evenodd\" d=\"M7.5 6a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM3.751 20.105a8.25 8.25 0 0 1 16.498 0 .75.75 0 0 1-.437.695A18.683 18.683 0 0 1 12 22.5c-2.786 0-5.433-.608-7.812-1.7a.75.75 0 0 1-.437-.695Z\" clip-rule=\"evenodd\" />\n </svg>\n </ng-content>\n }\n }\n @if (resolvedStatus()) {\n <span [class]=\"statusClasses()\" aria-hidden=\"true\"></span>\n }\n `,\n})\nexport class AvatarComponent {\n /** URL of the avatar image. When set, renders an `<img>`. Falls back to initials or projected content on load error. Defaults to `null`. */\n readonly src = input<string | null>(null);\n\n /** Alt text for the avatar image. Also used as `aria-label` for non-image avatars. Defaults to `''`. */\n readonly alt = input('');\n\n /** Text initials displayed when no image is available (1-2 characters). Rendered uppercase regardless of input casing. Defaults to `null`. */\n readonly initials = input<string | null>(null);\n\n /** Semantic color for the initials/icon background. Only applies when no image is shown. Defaults to `'neutral'`. */\n readonly color = input<TwColor>('neutral');\n\n /** Controls the avatar dimensions. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Bundles decorative axes: `rounded` (shape) and `status` (indicator dot). Defaults to `{ rounded: 'full', status: null }`. */\n readonly appearance = input<AvatarAppearance>({});\n\n /** Fires when the avatar image fails to load. Payload is the native `Event` from the `<img>` `error` event. */\n readonly imageError = output<Event>();\n\n /** @internal */\n readonly elementRef = inject(ElementRef<HTMLElement>);\n\n /**\n * @internal\n * Toggled by `AvatarGroupComponent` to hide overflow avatars. Drives the\n * host `[attr.hidden]` binding so the group's effect stays declarative\n * (no direct `style.display` mutation).\n */\n readonly groupHidden = signal(false);\n\n private readonly groupSize = inject(AVATAR_GROUP_SIZE, { optional: true });\n\n constructor() {\n if (isDevMode()) {\n effect(() => {\n if (this.displayMode() === 'image' && !this.alt()) {\n console.warn(\n '<tw-avatar> rendered as image without alt text — provide alt for accessibility',\n );\n }\n });\n }\n }\n\n readonly resolvedSize = computed(() => this.groupSize ? this.groupSize() : this.size());\n readonly resolvedRounded = computed<AvatarRounded>(() => this.appearance().rounded ?? 'full');\n readonly resolvedStatus = computed<AvatarStatus | null>(() => this.appearance().status ?? null);\n\n readonly imageLoaded = linkedSignal<string | null, boolean | null>({\n source: this.src,\n computation: () => null,\n });\n\n readonly displayMode = computed<'image' | 'initials' | 'fallback'>(() => {\n if (this.src() && this.imageLoaded() !== false) return 'image';\n if (this.initials()) return 'initials';\n return 'fallback';\n });\n\n private readonly variantResult = computed(() =>\n avatarVariants({\n size: this.resolvedSize(),\n rounded: this.resolvedRounded(),\n color: this.color(),\n }),\n );\n\n readonly rootClasses = computed(() => this.variantResult().root());\n readonly imgClasses = computed(() => this.variantResult().img());\n readonly initialsClasses = computed(() => this.variantResult().initials());\n readonly fallbackClasses = computed(() => this.variantResult().fallback());\n\n readonly statusClasses = computed(() => {\n const base = this.variantResult().status();\n const statusValue = this.resolvedStatus();\n if (!statusValue) return base;\n return `${base} ${statusColorMap[statusValue]}`;\n });\n\n protected onImageError(event: Event): void {\n this.imageLoaded.set(false);\n this.imageError.emit(event);\n }\n}\n\nconst groupOverlapMap: Record<TwSize, string> = {\n xs: '[&>tw-avatar+tw-avatar]:-ml-1.5 [&>tw-avatar+span]:-ml-1.5',\n sm: '[&>tw-avatar+tw-avatar]:-ml-1.5 [&>tw-avatar+span]:-ml-1.5',\n md: '[&>tw-avatar+tw-avatar]:-ml-2 [&>tw-avatar+span]:-ml-2',\n lg: '[&>tw-avatar+tw-avatar]:-ml-3 [&>tw-avatar+span]:-ml-3',\n xl: '[&>tw-avatar+tw-avatar]:-ml-3 [&>tw-avatar+span]:-ml-3',\n};\n\n@Component({\n selector: 'tw-avatar-group',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: AVATAR_GROUP_SIZE,\n useFactory: () => {\n const group = inject(AvatarGroupComponent);\n return () => group.size();\n },\n },\n ],\n host: {\n role: 'group',\n '[class]': 'hostClasses()',\n '[attr.aria-label]': 'ariaLabel()',\n },\n template: `\n <ng-content />\n @if (overflowCount() > 0) {\n <span [class]=\"overflowClasses()\">+{{ overflowCount() }}</span>\n }\n `,\n})\nexport class AvatarGroupComponent {\n /** Sets the size for all child avatars. Individual avatar size inputs are ignored when inside a group. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Maximum number of avatars to display. Remaining count is shown as a \"+N\" overflow indicator. Defaults to `null` (show all). */\n readonly max = input<number | null>(null);\n\n /** Accessible label for the avatar group. Defaults to `'Avatar group'` (English) — override for localisation. */\n readonly ariaLabel = input('Avatar group');\n\n private readonly avatars = contentChildren(AvatarComponent);\n\n readonly overflowCount = computed(() => {\n const all = this.avatars();\n const maxVal = this.max();\n if (maxVal === null || maxVal >= all.length) return 0;\n return all.length - maxVal;\n });\n\n readonly hostClasses = computed(() => {\n const s = this.size();\n return `inline-flex items-center [&>tw-avatar]:ring-2 [&>tw-avatar]:ring-surface ${groupOverlapMap[s]}`;\n });\n\n readonly overflowClasses = computed(() => {\n const s = this.size();\n const sizeClasses = avatarVariants({ size: s, rounded: 'full', color: 'neutral' });\n return `${sizeClasses.root()} bg-surface-muted text-fg-muted font-medium ring-2 ring-surface`;\n });\n\n private readonly visibilityEffect = effect(() => {\n const all = this.avatars();\n const maxVal = this.max();\n all.forEach((avatar, index) => {\n avatar.groupHidden.set(maxVal !== null && index >= maxVal);\n });\n });\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}