@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-sort.mjs","sources":["../../../projects/ngx-tw/sort/sort.ts","../../../projects/ngx-tw/sort/sort-header.ts","../../../projects/ngx-tw/sort/sort-header.html","../../../projects/ngx-tw/sort/cdevhub-ngx-tw-sort.ts"],"sourcesContent":["import {\n Directive,\n input,\n isDevMode,\n model,\n output,\n} from '@angular/core';\nimport { TW_SORT_HANDLE } from '@cdevhub/ngx-tw/core';\n\n/** Sort direction. `null` represents the cleared (unsorted) state. */\nexport type SortDirection = 'asc' | 'desc' | null;\n\n/** Shape that `SortHeaderComponent` implements when registering with a parent `SortDirective`. */\nexport interface TwSortable {\n /** Unique id identifying the column or field this header sorts. */\n readonly id: string;\n /** Header-level starting direction. `undefined` falls back to the parent directive's `start`. */\n readonly start: 'asc' | 'desc' | undefined;\n /** Header-level override for disabling the cleared state in the cycle. `undefined` falls back to the parent directive's `disableClear`. */\n readonly disableClear: boolean | undefined;\n /** Whether this header is disabled. */\n readonly disabled: boolean;\n}\n\n/** Payload emitted by `SortDirective.sortChange` whenever a user interaction changes the sort state. */\nexport interface TwSortEvent {\n /** The new active header id, or `null` when the sort was cleared. */\n active: string | null;\n /** The new sort direction. */\n direction: SortDirection;\n /** Snapshot of the previous state, before this change. */\n previous: {\n /** Previous active header id. */\n active: string | null;\n /** Previous sort direction. */\n direction: SortDirection;\n };\n}\n\n/**\n * Returns the direction cycle for a given starting direction and disable-clear flag.\n * @internal Exported for unit tests; not part of the public API.\n */\nexport function getSortDirectionCycle(\n start: 'asc' | 'desc',\n disableClear: boolean,\n): SortDirection[] {\n const cycle: SortDirection[] = start === 'desc' ? ['desc', 'asc'] : ['asc', 'desc'];\n if (!disableClear) cycle.push(null);\n return cycle;\n}\n\n/**\n * Container directive that holds the current sort state (`active` id + `direction`) and\n * coordinates with child `SortHeaderComponent` instances. Compose with any rendering layer —\n * tables, lists, custom grids — by placing child headers inside an element marked `[twSort]`.\n *\n * @remarks\n * **`tw*` input/output aliases.** Every `input()` / `output()` / `model()` on this directive\n * carries a `tw*` alias (e.g. `'twSortActive'`, `'twSortDirection'`, `'twSortChange'`). The\n * aliases namespace bindings under the directive selector so they cannot collide with\n * attributes the host element already owns (a `<table>` consumer binding `[active]` would\n * otherwise be ambiguous). This mirrors Angular Material's `mat*` aliasing precedent on\n * `MatSort`. Compodoc surfaces both the field name and the alias; consumer templates MUST\n * bind via the aliased name (`[twSortActive]`, `(twSortChange)`, …). Removing an alias is a\n * breaking API change requiring a major version bump.\n */\n@Directive({\n selector: '[twSort]',\n exportAs: 'twSort',\n host: {\n 'class': 'tw-sort',\n },\n providers: [{ provide: TW_SORT_HANDLE, useExisting: SortDirective }],\n})\nexport class SortDirective {\n /** The id of the currently sorted header, or `null` when nothing is sorted. Two-way bindable via `[(twSortActive)]`. Defaults to `null`. */\n readonly active = model<string | null>(null, { alias: 'twSortActive' });\n\n /** Current sort direction. `null` represents the cleared state. Two-way bindable via `[(twSortDirection)]`. Defaults to `null`. */\n readonly direction = model<SortDirection>(null, { alias: 'twSortDirection' });\n\n /** Starting direction used when a header becomes active for the first time. Per-header `start` overrides this. Defaults to `'asc'`. */\n readonly start = input<'asc' | 'desc'>('asc', { alias: 'twSortStart' });\n\n /** When true, the direction cycle skips the cleared (`null`) state — headers toggle between `'asc'` and `'desc'` only. Per-header `disableClear` overrides this. Defaults to `false`. */\n readonly disableClear = input<boolean>(false, { alias: 'twSortDisableClear' });\n\n /** When true, all child sort headers are disabled. Defaults to `false`. */\n readonly disabled = input<boolean>(false, { alias: 'twSortDisabled' });\n\n /** Fires whenever the user changes `active` or `direction` by interacting with a header. Programmatic writes to `[(twSortActive)]` / `[(twSortDirection)]` do NOT emit. */\n readonly sortChange = output<TwSortEvent>({ alias: 'twSortChange' });\n\n private readonly sortableIds = new Set<string>();\n\n /** Registers a header id so duplicates can be detected. Called by `SortHeaderComponent` on init. Throws in dev mode if another header with the same id is already registered. */\n register(id: string): void {\n if (isDevMode()) {\n if (!id) {\n throw new Error('tw-sort-header must be provided with a unique id.');\n }\n if (this.sortableIds.has(id)) {\n throw new Error(\n `Cannot have two tw-sort-header elements with the same id (${id}).`,\n );\n }\n }\n this.sortableIds.add(id);\n }\n\n /** Deregisters a header id. Called on destroy. */\n deregister(id: string): void {\n this.sortableIds.delete(id);\n }\n\n /** Cycles the direction for the given header and emits `sortChange`. No-op when the directive or the header is disabled. */\n sort(sortable: TwSortable): void {\n if (this.disabled() || sortable.disabled) return;\n\n const previousActive = this.active();\n const previousDirection = this.direction();\n\n let nextActive: string | null;\n let nextDirection: SortDirection;\n\n if (previousActive !== sortable.id) {\n nextActive = sortable.id;\n nextDirection = sortable.start ?? this.start();\n } else {\n nextDirection = this.getNextSortDirection(sortable);\n nextActive = nextDirection === null ? null : sortable.id;\n }\n\n this.active.set(nextActive);\n this.direction.set(nextDirection);\n\n this.sortChange.emit({\n active: nextActive,\n direction: nextDirection,\n previous: {\n active: previousActive,\n direction: previousDirection,\n },\n });\n }\n\n /** Returns the next direction in the cycle for the given header, based on the current state and header/parent overrides. */\n getNextSortDirection(sortable: TwSortable): SortDirection {\n const start = sortable.start ?? this.start();\n const disableClear = sortable.disableClear ?? this.disableClear();\n const cycle = getSortDirectionCycle(start, disableClear);\n\n // If the header is not currently active, the next direction is the starting one.\n if (this.active() !== sortable.id) {\n return start;\n }\n\n const currentIndex = cycle.indexOf(this.direction());\n if (currentIndex < 0) {\n return start;\n }\n return cycle[(currentIndex + 1) % cycle.length] as SortDirection;\n }\n}\n","import {\n type AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n type ElementRef,\n inject,\n input,\n isDevMode,\n type OnDestroy,\n type OnInit,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { AriaDescriber, FocusMonitor } from '@angular/cdk/a11y';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor, TwSize } from '@cdevhub/ngx-tw/core';\nimport { SortDirective, type SortDirection, type TwSortable } from './sort';\n\nfunction snapshot(self: SortHeaderComponent): TwSortable {\n return {\n id: self.id(),\n start: self.start(),\n disableClear: self.disableClear(),\n disabled: self.isDisabled(),\n };\n}\n\n/** Position of the sort arrow relative to the header label. */\nexport type TwSortArrowPosition = 'before' | 'after';\n\n// ── Static per-color maps (Tailwind v4 requires literal class strings for its JIT scanner). ──\n\nconst ARROW_ACTIVE_COLOR: Record<TwColor, string> = {\n primary: 'text-primary-600',\n secondary: 'text-secondary-600',\n accent: 'text-accent-600',\n neutral: 'text-fg',\n info: 'text-info-600',\n success: 'text-success-600',\n warning: 'text-warning-600',\n error: 'text-error-600',\n};\n\n// ── tv() config ──\n\nconst sortHeaderVariants = tv(\n {\n slots: {\n host: 'group select-none',\n container:\n 'inline-flex items-center gap-1.5 cursor-pointer rounded-md font-medium text-fg transition-colors duration-normal motion-reduce:transition-none hover:bg-surface-muted focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary-500',\n label: 'min-w-0',\n arrow:\n 'inline-flex shrink-0 items-center justify-center transition-opacity duration-normal motion-reduce:transition-none',\n arrowIcon:\n 'shrink-0 transition-transform duration-normal motion-reduce:transition-none',\n },\n variants: {\n size: {\n xs: {\n container: 'px-2 py-1 text-xs',\n // `size-3.5` half-step: only icon size aligning with text-xs without\n // dominating it; codified per CLAUDE.md.\n arrowIcon: 'size-3.5',\n },\n sm: {\n container: 'px-2.5 py-1.5 text-sm',\n arrowIcon: 'size-4',\n },\n md: {\n container: 'px-3 py-2 text-sm',\n arrowIcon: 'size-4',\n },\n lg: {\n container: 'px-4 py-2.5 text-base',\n arrowIcon: 'size-5',\n },\n xl: {\n container: 'px-5 py-3 text-base',\n arrowIcon: 'size-5',\n },\n },\n active: {\n true: {\n container: 'text-fg',\n arrow: 'opacity-100',\n },\n false: {\n container: 'text-fg-muted',\n arrow:\n 'opacity-0 group-hover:opacity-50 group-focus-within:opacity-50',\n },\n },\n direction: {\n asc: { arrowIcon: 'rotate-180' },\n desc: { arrowIcon: 'rotate-0' },\n none: { arrowIcon: 'rotate-0' },\n },\n disabled: {\n true: {\n host: 'opacity-50 pointer-events-none',\n container: 'cursor-not-allowed',\n },\n false: {},\n },\n },\n defaultVariants: {\n size: 'md',\n active: false,\n direction: 'none',\n disabled: false,\n },\n },\n { twMerge: true },\n);\n\n/**\n * Turns any element (e.g., `<th>`, `<div>`, `<button>`) into a sortable header under a parent\n * `SortDirective`. Renders the projected label plus an arrow that reflects the current direction.\n * Triggers a sort cycle on click or Enter/Space.\n */\n@Component({\n selector: '[tw-sort-header]',\n exportAs: 'twSortHeader',\n changeDetection: ChangeDetectionStrategy.OnPush,\n imports: [NgTemplateOutlet],\n templateUrl: './sort-header.html',\n host: {\n '[class]': 'hostClasses()',\n '[attr.aria-sort]': 'ariaSort()',\n '[attr.aria-disabled]': 'isDisabled() ? \"true\" : null',\n '(click)': 'handleClick()',\n '(keydown)': 'handleKeydown($event)',\n },\n})\nexport class SortHeaderComponent implements OnInit, AfterViewInit, OnDestroy {\n /** Unique id for this header. Required — identifies the field/column this header sorts. */\n readonly id = input.required<string>();\n\n /** Overrides the parent directive's `start` for this header only. `undefined` inherits from the parent. */\n readonly start = input<'asc' | 'desc' | undefined>(undefined);\n\n /** Overrides the parent directive's `disableClear` for this header only. `undefined` inherits from the parent. */\n readonly disableClear = input<boolean | undefined>(undefined);\n\n /** When true, this header is disabled — clicks and keyboard activation are ignored. Defaults to `false`. */\n readonly headerDisabled = input<boolean>(false, { alias: 'disabled' });\n\n /** Whether the sort arrow renders `'before'` or `'after'` the projected label. Defaults to `'after'`. */\n readonly arrowPosition = input<TwSortArrowPosition>('after');\n\n /** Semantic color used to tint the arrow when this header is active. Defaults to `'primary'`. */\n readonly color = input<TwColor>('primary');\n\n /** Controls padding and font size. Uses the shared `TwSize` scale. Defaults to `'md'`. */\n readonly size = input<TwSize>('md');\n\n /** Accessible description applied via `AriaDescriber` so screen readers announce the sort action alongside the header text. Defaults to `'Sort'`. */\n readonly sortActionDescription = input<string>('Sort');\n\n private readonly parent = inject(SortDirective, { optional: true });\n private readonly focusMonitor = inject(FocusMonitor);\n private readonly ariaDescriber = inject(AriaDescriber, { optional: true });\n\n private readonly containerRef =\n viewChild<ElementRef<HTMLElement>>('container');\n\n private _describedBy: string | null = null;\n\n constructor() {\n if (!this.parent && isDevMode()) {\n throw new Error(\n 'tw-sort-header must be placed within a parent element with the twSort directive.',\n );\n }\n\n // Reactive: re-tags the host whenever `sortActionDescription` (a public\n // signal input) changes; consumers may swap the description at runtime for\n // i18n / state-driven copy. Cleanup runs in `ngOnDestroy`. Not a one-shot\n // `afterNextRender`: that would freeze the description at first render and\n // silently ignore subsequent rebinds.\n effect(() => {\n const description = this.sortActionDescription();\n const el = this.containerRef()?.nativeElement;\n if (!el || !this.ariaDescriber) return;\n if (this._describedBy) {\n this.ariaDescriber.removeDescription(el, this._describedBy);\n }\n this.ariaDescriber.describe(el, description);\n this._describedBy = description;\n });\n }\n\n // ── Derived signals ──\n\n /** Whether this header is currently the active (sorted) header. */\n readonly isActive = computed(\n () => this.parent?.active() === this.id(),\n );\n\n /** Whether this header is disabled via its own input or the parent directive's `disabled`. */\n readonly isDisabled = computed(\n () => this.headerDisabled() || (this.parent?.disabled() ?? false),\n );\n\n /** Active direction for *this* header (null when not active). */\n readonly effectiveDirection = computed<SortDirection>(() =>\n this.isActive() ? (this.parent?.direction() ?? null) : null,\n );\n\n /** `aria-sort` value: `'ascending' | 'descending' | 'none'`. */\n readonly ariaSort = computed(() => {\n const d = this.effectiveDirection();\n if (d === 'asc') return 'ascending';\n if (d === 'desc') return 'descending';\n return 'none';\n });\n\n /** Whether the arrow element should render. Active headers always render; inactive render when not disabled so hover reveals the affordance. */\n readonly renderArrow = computed(() => this.isActive() || !this.isDisabled());\n\n // ── Variant class computation ──\n\n private readonly variantResult = computed(() =>\n sortHeaderVariants({\n size: this.size(),\n active: this.isActive(),\n direction: this.effectiveDirection() ?? 'none',\n disabled: this.isDisabled(),\n }),\n );\n\n /** @internal */\n readonly hostClasses = computed(() => this.variantResult().host());\n\n /** @internal */\n readonly containerClasses = computed(() => this.variantResult().container());\n\n /** @internal */\n readonly labelClasses = computed(() => this.variantResult().label());\n\n /** @internal */\n readonly arrowClasses = computed(() => {\n const base = this.variantResult().arrow();\n if (!this.isActive()) return base;\n return `${base} ${ARROW_ACTIVE_COLOR[this.color()]}`;\n });\n\n /** @internal */\n readonly arrowIconClasses = computed(() => this.variantResult().arrowIcon());\n\n // ── Lifecycle ──\n\n ngOnInit(): void {\n this.parent?.register(this.id());\n }\n\n ngAfterViewInit(): void {\n const el = this.containerRef()?.nativeElement;\n if (el) {\n this.focusMonitor.monitor(el, true);\n }\n }\n\n ngOnDestroy(): void {\n const el = this.containerRef()?.nativeElement;\n if (el) {\n this.focusMonitor.stopMonitoring(el);\n if (this._describedBy && this.ariaDescriber) {\n this.ariaDescriber.removeDescription(el, this._describedBy);\n }\n }\n this.parent?.deregister(this.id());\n }\n\n // ── Event handlers ──\n\n /** @internal */\n handleClick(): void {\n if (this.isDisabled()) return;\n this.parent?.sort(snapshot(this));\n }\n\n /** @internal */\n handleKeydown(event: KeyboardEvent): void {\n if (this.isDisabled()) return;\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n this.parent?.sort(snapshot(this));\n }\n }\n}\n","<div\n #container\n [class]=\"containerClasses()\"\n [attr.role]=\"isDisabled() ? null : 'button'\"\n [attr.tabindex]=\"isDisabled() ? null : 0\"\n>\n @if (arrowPosition() === 'before' && renderArrow()) {\n <ng-container *ngTemplateOutlet=\"arrow\" />\n }\n <span [class]=\"labelClasses()\"><ng-content /></span>\n @if (arrowPosition() === 'after' && renderArrow()) {\n <ng-container *ngTemplateOutlet=\"arrow\" />\n }\n</div>\n\n<ng-template #arrow>\n <span [class]=\"arrowClasses()\" data-tw-sort-arrow>\n <ng-content select=\"[twSortHeaderIcon]\">\n <svg\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n [class]=\"arrowIconClasses()\"\n >\n <path\n fill-rule=\"evenodd\"\n d=\"M5.22 8.22a.75.75 0 0 1 1.06 0L10 11.94l3.72-3.72a.75.75 0 1 1 1.06 1.06l-4.25 4.25a.75.75 0 0 1-1.06 0L5.22 9.28a.75.75 0 0 1 0-1.06Z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </ng-content>\n </span>\n</ng-template>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,186 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, computed, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { tv } from 'tailwind-variants';
4
+
5
+ const spinnerVariants = tv({
6
+ slots: {
7
+ root: 'relative inline-flex items-center justify-center shrink-0 align-middle',
8
+ svg: 'size-full animate-spin motion-reduce:animate-none',
9
+ track: '',
10
+ stroke: '',
11
+ dots: 'inline-flex items-center justify-center gap-1 size-full',
12
+ bars: 'inline-flex items-end justify-center gap-1 size-full',
13
+ bar: 'tw-spinner-bar',
14
+ dot: 'tw-spinner-dot',
15
+ srLabel: 'sr-only',
16
+ },
17
+ variants: {
18
+ color: {
19
+ current: {},
20
+ primary: { root: 'text-primary-500' },
21
+ secondary: { root: 'text-secondary-500' },
22
+ accent: { root: 'text-accent-500' },
23
+ neutral: { root: 'text-fg-muted' },
24
+ info: { root: 'text-info-500' },
25
+ success: { root: 'text-success-500' },
26
+ warning: { root: 'text-warning-500' },
27
+ error: { root: 'text-error-500' },
28
+ },
29
+ size: {
30
+ xs: { root: 'size-3' },
31
+ sm: { root: 'size-4' },
32
+ md: { root: 'size-5' },
33
+ lg: { root: 'size-6' },
34
+ xl: { root: 'size-8' },
35
+ inherit: { root: 'size-[1em]' },
36
+ },
37
+ },
38
+ defaultVariants: {
39
+ color: 'current',
40
+ size: 'md',
41
+ },
42
+ }, {
43
+ twMerge: true,
44
+ });
45
+ /**
46
+ * Indeterminate loading indicator.
47
+ *
48
+ * Designed to compose inside other ngx-tw components:
49
+ * - Inside `<button twButton [loading]="true">` — inherits the button's text color via `color="current"`.
50
+ * - Inside `<tw-form-field>` as `twSuffix` — indicates async validation / pending load.
51
+ * - Inline with text using `size="inherit"` — scales with the surrounding font.
52
+ * - Centered inside cards or overlay wrappers for region-level loading states.
53
+ *
54
+ * @example
55
+ * ```html
56
+ * <tw-spinner />
57
+ * <tw-spinner color="success" size="lg" />
58
+ * <tw-spinner twSuffix size="sm" label="Validating email" />
59
+ * ```
60
+ */
61
+ class SpinnerComponent {
62
+ /** Controls the visual style of the spinner. Defaults to `'circular'`. */
63
+ variant = input('circular', ...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
64
+ /** Semantic color. `'current'` inherits the surrounding text color — required for composition inside buttons and form-field prefix/suffix slots. Defaults to `'current'`. */
65
+ color = input('current', ...(ngDevMode ? [{ debugName: "color" }] : /* istanbul ignore next */ []));
66
+ /** Sets the spinner dimensions. `'inherit'` sizes the spinner to `1em` so it matches the surrounding font size (useful for inline text indicators). Defaults to `'md'`. */
67
+ size = input('md', ...(ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []));
68
+ /** When true, renders a subtle ring behind the rotating stroke. Without the track ring the spinner reads as a partial arc, not a loading indicator. Only applies to the `'circular'` variant. Defaults to `true`. */
69
+ track = input(true, ...(ngDevMode ? [{ debugName: "track" }] : /* istanbul ignore next */ []));
70
+ /** Accessible label announced by assistive technology. Rendered in a visually hidden span. Defaults to `'Loading'`. */
71
+ label = input('Loading', ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
72
+ variantResult = computed(() => spinnerVariants({ color: this.color(), size: this.size() }), ...(ngDevMode ? [{ debugName: "variantResult" }] : /* istanbul ignore next */ []));
73
+ rootClasses = computed(() => this.variantResult().root(), ...(ngDevMode ? [{ debugName: "rootClasses" }] : /* istanbul ignore next */ []));
74
+ svgClasses = computed(() => this.variantResult().svg(), ...(ngDevMode ? [{ debugName: "svgClasses" }] : /* istanbul ignore next */ []));
75
+ dotsClasses = computed(() => this.variantResult().dots(), ...(ngDevMode ? [{ debugName: "dotsClasses" }] : /* istanbul ignore next */ []));
76
+ dotClasses = computed(() => this.variantResult().dot(), ...(ngDevMode ? [{ debugName: "dotClasses" }] : /* istanbul ignore next */ []));
77
+ barsClasses = computed(() => this.variantResult().bars(), ...(ngDevMode ? [{ debugName: "barsClasses" }] : /* istanbul ignore next */ []));
78
+ barClasses = computed(() => this.variantResult().bar(), ...(ngDevMode ? [{ debugName: "barClasses" }] : /* istanbul ignore next */ []));
79
+ srLabelClasses = computed(() => this.variantResult().srLabel(), ...(ngDevMode ? [{ debugName: "srLabelClasses" }] : /* istanbul ignore next */ []));
80
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SpinnerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
81
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.14", type: SpinnerComponent, isStandalone: true, selector: "tw-spinner", 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 }, track: { classPropertyName: "track", publicName: "track", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "status", "aria-live": "polite" }, properties: { "class": "rootClasses()" } }, ngImport: i0, template: `
82
+ @switch (variant()) {
83
+ @case ('circular') {
84
+ <svg [class]="svgClasses()" viewBox="0 0 24 24" fill="none" aria-hidden="true">
85
+ @if (track()) {
86
+ <circle
87
+ cx="12"
88
+ cy="12"
89
+ r="10"
90
+ stroke="currentColor"
91
+ stroke-width="3"
92
+ opacity="0.2"
93
+ />
94
+ }
95
+ <circle
96
+ cx="12"
97
+ cy="12"
98
+ r="10"
99
+ stroke="currentColor"
100
+ stroke-width="3"
101
+ stroke-linecap="round"
102
+ stroke-dasharray="60"
103
+ stroke-dashoffset="40"
104
+ />
105
+ </svg>
106
+ }
107
+ @case ('dots') {
108
+ <span [class]="dotsClasses()" aria-hidden="true">
109
+ <span [class]="dotClasses()" style="animation-delay: -0.3s"></span>
110
+ <span [class]="dotClasses()" style="animation-delay: -0.15s"></span>
111
+ <span [class]="dotClasses()"></span>
112
+ </span>
113
+ }
114
+ @case ('bars') {
115
+ <span [class]="barsClasses()" aria-hidden="true">
116
+ <span [class]="barClasses()" style="animation-delay: -0.4s"></span>
117
+ <span [class]="barClasses()" style="animation-delay: -0.2s"></span>
118
+ <span [class]="barClasses()"></span>
119
+ </span>
120
+ }
121
+ }
122
+ <span [class]="srLabelClasses()">{{ label() }}</span>
123
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
124
+ }
125
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: SpinnerComponent, decorators: [{
126
+ type: Component,
127
+ args: [{
128
+ selector: 'tw-spinner',
129
+ changeDetection: ChangeDetectionStrategy.OnPush,
130
+ host: {
131
+ 'role': 'status',
132
+ 'aria-live': 'polite',
133
+ '[class]': 'rootClasses()',
134
+ },
135
+ template: `
136
+ @switch (variant()) {
137
+ @case ('circular') {
138
+ <svg [class]="svgClasses()" viewBox="0 0 24 24" fill="none" aria-hidden="true">
139
+ @if (track()) {
140
+ <circle
141
+ cx="12"
142
+ cy="12"
143
+ r="10"
144
+ stroke="currentColor"
145
+ stroke-width="3"
146
+ opacity="0.2"
147
+ />
148
+ }
149
+ <circle
150
+ cx="12"
151
+ cy="12"
152
+ r="10"
153
+ stroke="currentColor"
154
+ stroke-width="3"
155
+ stroke-linecap="round"
156
+ stroke-dasharray="60"
157
+ stroke-dashoffset="40"
158
+ />
159
+ </svg>
160
+ }
161
+ @case ('dots') {
162
+ <span [class]="dotsClasses()" aria-hidden="true">
163
+ <span [class]="dotClasses()" style="animation-delay: -0.3s"></span>
164
+ <span [class]="dotClasses()" style="animation-delay: -0.15s"></span>
165
+ <span [class]="dotClasses()"></span>
166
+ </span>
167
+ }
168
+ @case ('bars') {
169
+ <span [class]="barsClasses()" aria-hidden="true">
170
+ <span [class]="barClasses()" style="animation-delay: -0.4s"></span>
171
+ <span [class]="barClasses()" style="animation-delay: -0.2s"></span>
172
+ <span [class]="barClasses()"></span>
173
+ </span>
174
+ }
175
+ }
176
+ <span [class]="srLabelClasses()">{{ label() }}</span>
177
+ `,
178
+ }]
179
+ }], 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 }] }], track: [{ type: i0.Input, args: [{ isSignal: true, alias: "track", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
180
+
181
+ /**
182
+ * Generated bundle index. Do not edit.
183
+ */
184
+
185
+ export { SpinnerComponent };
186
+ //# sourceMappingURL=cdevhub-ngx-tw-spinner.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdevhub-ngx-tw-spinner.mjs","sources":["../../../projects/ngx-tw/spinner/spinner.ts","../../../projects/ngx-tw/spinner/cdevhub-ngx-tw-spinner.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n input,\n} from '@angular/core';\nimport { tv } from 'tailwind-variants';\nimport type { TwColor, TwSize } from '@cdevhub/ngx-tw/core';\n\n/** Visual style of the spinner. */\nexport type SpinnerVariant = 'circular' | 'dots' | 'bars';\n\n/** Semantic color for the spinner. `'current'` inherits from parent `currentColor`. */\nexport type SpinnerColor = TwColor | 'current';\n\n/** Size of the spinner. `'inherit'` sizes the spinner to `1em` so it scales with the surrounding font. */\nexport type SpinnerSize = TwSize | 'inherit';\n\nconst spinnerVariants = tv({\n slots: {\n root: 'relative inline-flex items-center justify-center shrink-0 align-middle',\n svg: 'size-full animate-spin motion-reduce:animate-none',\n track: '',\n stroke: '',\n dots: 'inline-flex items-center justify-center gap-1 size-full',\n bars: 'inline-flex items-end justify-center gap-1 size-full',\n bar: 'tw-spinner-bar',\n dot: 'tw-spinner-dot',\n srLabel: 'sr-only',\n },\n variants: {\n color: {\n current: {},\n primary: { root: 'text-primary-500' },\n secondary: { root: 'text-secondary-500' },\n accent: { root: 'text-accent-500' },\n neutral: { root: 'text-fg-muted' },\n info: { root: 'text-info-500' },\n success: { root: 'text-success-500' },\n warning: { root: 'text-warning-500' },\n error: { root: 'text-error-500' },\n },\n size: {\n xs: { root: 'size-3' },\n sm: { root: 'size-4' },\n md: { root: 'size-5' },\n lg: { root: 'size-6' },\n xl: { root: 'size-8' },\n inherit: { root: 'size-[1em]' },\n },\n },\n defaultVariants: {\n color: 'current',\n size: 'md',\n },\n}, {\n twMerge: true,\n});\n\n/**\n * Indeterminate loading indicator.\n *\n * Designed to compose inside other ngx-tw components:\n * - Inside `<button twButton [loading]=\"true\">` — inherits the button's text color via `color=\"current\"`.\n * - Inside `<tw-form-field>` as `twSuffix` — indicates async validation / pending load.\n * - Inline with text using `size=\"inherit\"` — scales with the surrounding font.\n * - Centered inside cards or overlay wrappers for region-level loading states.\n *\n * @example\n * ```html\n * <tw-spinner />\n * <tw-spinner color=\"success\" size=\"lg\" />\n * <tw-spinner twSuffix size=\"sm\" label=\"Validating email\" />\n * ```\n */\n@Component({\n selector: 'tw-spinner',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n 'role': 'status',\n 'aria-live': 'polite',\n '[class]': 'rootClasses()',\n },\n template: `\n @switch (variant()) {\n @case ('circular') {\n <svg [class]=\"svgClasses()\" viewBox=\"0 0 24 24\" fill=\"none\" aria-hidden=\"true\">\n @if (track()) {\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n opacity=\"0.2\"\n />\n }\n <circle\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n stroke-width=\"3\"\n stroke-linecap=\"round\"\n stroke-dasharray=\"60\"\n stroke-dashoffset=\"40\"\n />\n </svg>\n }\n @case ('dots') {\n <span [class]=\"dotsClasses()\" aria-hidden=\"true\">\n <span [class]=\"dotClasses()\" style=\"animation-delay: -0.3s\"></span>\n <span [class]=\"dotClasses()\" style=\"animation-delay: -0.15s\"></span>\n <span [class]=\"dotClasses()\"></span>\n </span>\n }\n @case ('bars') {\n <span [class]=\"barsClasses()\" aria-hidden=\"true\">\n <span [class]=\"barClasses()\" style=\"animation-delay: -0.4s\"></span>\n <span [class]=\"barClasses()\" style=\"animation-delay: -0.2s\"></span>\n <span [class]=\"barClasses()\"></span>\n </span>\n }\n }\n <span [class]=\"srLabelClasses()\">{{ label() }}</span>\n `,\n})\nexport class SpinnerComponent {\n /** Controls the visual style of the spinner. Defaults to `'circular'`. */\n readonly variant = input<SpinnerVariant>('circular');\n\n /** Semantic color. `'current'` inherits the surrounding text color — required for composition inside buttons and form-field prefix/suffix slots. Defaults to `'current'`. */\n readonly color = input<SpinnerColor>('current');\n\n /** Sets the spinner dimensions. `'inherit'` sizes the spinner to `1em` so it matches the surrounding font size (useful for inline text indicators). Defaults to `'md'`. */\n readonly size = input<SpinnerSize>('md');\n\n /** When true, renders a subtle ring behind the rotating stroke. Without the track ring the spinner reads as a partial arc, not a loading indicator. Only applies to the `'circular'` variant. Defaults to `true`. */\n readonly track = input(true);\n\n /** Accessible label announced by assistive technology. Rendered in a visually hidden span. Defaults to `'Loading'`. */\n readonly label = input('Loading');\n\n private readonly variantResult = computed(() =>\n spinnerVariants({ color: this.color(), size: this.size() }),\n );\n\n readonly rootClasses = computed(() => this.variantResult().root());\n readonly svgClasses = computed(() => this.variantResult().svg());\n readonly dotsClasses = computed(() => this.variantResult().dots());\n readonly dotClasses = computed(() => this.variantResult().dot());\n readonly barsClasses = computed(() => this.variantResult().bars());\n readonly barClasses = computed(() => this.variantResult().bar());\n readonly srLabelClasses = computed(() => this.variantResult().srLabel());\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}