@ngneers/controls 0.0.1-next.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 (186) hide show
  1. package/fesm2022/ngneers-controls-accordion.mjs +234 -0
  2. package/fesm2022/ngneers-controls-accordion.mjs.map +1 -0
  3. package/fesm2022/ngneers-controls-api-ng.mjs +959 -0
  4. package/fesm2022/ngneers-controls-api-ng.mjs.map +1 -0
  5. package/fesm2022/ngneers-controls-api-resize.mjs +712 -0
  6. package/fesm2022/ngneers-controls-api-resize.mjs.map +1 -0
  7. package/fesm2022/ngneers-controls-api.mjs +347 -0
  8. package/fesm2022/ngneers-controls-api.mjs.map +1 -0
  9. package/fesm2022/ngneers-controls-avatar.mjs +77 -0
  10. package/fesm2022/ngneers-controls-avatar.mjs.map +1 -0
  11. package/fesm2022/ngneers-controls-base.mjs +620 -0
  12. package/fesm2022/ngneers-controls-base.mjs.map +1 -0
  13. package/fesm2022/ngneers-controls-breadcrumb.mjs +100 -0
  14. package/fesm2022/ngneers-controls-breadcrumb.mjs.map +1 -0
  15. package/fesm2022/ngneers-controls-button-group.mjs +110 -0
  16. package/fesm2022/ngneers-controls-button-group.mjs.map +1 -0
  17. package/fesm2022/ngneers-controls-button.mjs +83 -0
  18. package/fesm2022/ngneers-controls-button.mjs.map +1 -0
  19. package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs +74 -0
  20. package/fesm2022/ngneers-controls-calendar-time-CJT5AFlA.mjs.map +1 -0
  21. package/fesm2022/ngneers-controls-calendar.mjs +801 -0
  22. package/fesm2022/ngneers-controls-calendar.mjs.map +1 -0
  23. package/fesm2022/ngneers-controls-checkbox.mjs +63 -0
  24. package/fesm2022/ngneers-controls-checkbox.mjs.map +1 -0
  25. package/fesm2022/ngneers-controls-chip.mjs +55 -0
  26. package/fesm2022/ngneers-controls-chip.mjs.map +1 -0
  27. package/fesm2022/ngneers-controls-default-icons.mjs +82 -0
  28. package/fesm2022/ngneers-controls-default-icons.mjs.map +1 -0
  29. package/fesm2022/ngneers-controls-defer.mjs +72 -0
  30. package/fesm2022/ngneers-controls-defer.mjs.map +1 -0
  31. package/fesm2022/ngneers-controls-dialog.mjs +407 -0
  32. package/fesm2022/ngneers-controls-dialog.mjs.map +1 -0
  33. package/fesm2022/ngneers-controls-directives.mjs +498 -0
  34. package/fesm2022/ngneers-controls-directives.mjs.map +1 -0
  35. package/fesm2022/ngneers-controls-drawer.mjs +271 -0
  36. package/fesm2022/ngneers-controls-drawer.mjs.map +1 -0
  37. package/fesm2022/ngneers-controls-edit-inplace.mjs +127 -0
  38. package/fesm2022/ngneers-controls-edit-inplace.mjs.map +1 -0
  39. package/fesm2022/ngneers-controls-errors.mjs +329 -0
  40. package/fesm2022/ngneers-controls-errors.mjs.map +1 -0
  41. package/fesm2022/ngneers-controls-filter.mjs +708 -0
  42. package/fesm2022/ngneers-controls-filter.mjs.map +1 -0
  43. package/fesm2022/ngneers-controls-hint.mjs +153 -0
  44. package/fesm2022/ngneers-controls-hint.mjs.map +1 -0
  45. package/fesm2022/ngneers-controls-i18n-translations-de.mjs +170 -0
  46. package/fesm2022/ngneers-controls-i18n-translations-de.mjs.map +1 -0
  47. package/fesm2022/ngneers-controls-i18n-translations-en.mjs +170 -0
  48. package/fesm2022/ngneers-controls-i18n-translations-en.mjs.map +1 -0
  49. package/fesm2022/ngneers-controls-i18n.mjs +57 -0
  50. package/fesm2022/ngneers-controls-i18n.mjs.map +1 -0
  51. package/fesm2022/ngneers-controls-icon.mjs +195 -0
  52. package/fesm2022/ngneers-controls-icon.mjs.map +1 -0
  53. package/fesm2022/ngneers-controls-inplace.mjs +150 -0
  54. package/fesm2022/ngneers-controls-inplace.mjs.map +1 -0
  55. package/fesm2022/ngneers-controls-input-field.mjs +165 -0
  56. package/fesm2022/ngneers-controls-input-field.mjs.map +1 -0
  57. package/fesm2022/ngneers-controls-input.mjs +72 -0
  58. package/fesm2022/ngneers-controls-input.mjs.map +1 -0
  59. package/fesm2022/ngneers-controls-item-view.mjs +473 -0
  60. package/fesm2022/ngneers-controls-item-view.mjs.map +1 -0
  61. package/fesm2022/ngneers-controls-list-box.mjs +281 -0
  62. package/fesm2022/ngneers-controls-list-box.mjs.map +1 -0
  63. package/fesm2022/ngneers-controls-mask-input.mjs +888 -0
  64. package/fesm2022/ngneers-controls-mask-input.mjs.map +1 -0
  65. package/fesm2022/ngneers-controls-menu.mjs +371 -0
  66. package/fesm2022/ngneers-controls-menu.mjs.map +1 -0
  67. package/fesm2022/ngneers-controls-message.mjs +30 -0
  68. package/fesm2022/ngneers-controls-message.mjs.map +1 -0
  69. package/fesm2022/ngneers-controls-number-input.mjs +366 -0
  70. package/fesm2022/ngneers-controls-number-input.mjs.map +1 -0
  71. package/fesm2022/ngneers-controls-paginator.mjs +129 -0
  72. package/fesm2022/ngneers-controls-paginator.mjs.map +1 -0
  73. package/fesm2022/ngneers-controls-popover.mjs +215 -0
  74. package/fesm2022/ngneers-controls-popover.mjs.map +1 -0
  75. package/fesm2022/ngneers-controls-progress.mjs +98 -0
  76. package/fesm2022/ngneers-controls-progress.mjs.map +1 -0
  77. package/fesm2022/ngneers-controls-radio.mjs +152 -0
  78. package/fesm2022/ngneers-controls-radio.mjs.map +1 -0
  79. package/fesm2022/ngneers-controls-roving-focus.mjs +323 -0
  80. package/fesm2022/ngneers-controls-roving-focus.mjs.map +1 -0
  81. package/fesm2022/ngneers-controls-scroll-shadow.mjs +65 -0
  82. package/fesm2022/ngneers-controls-scroll-shadow.mjs.map +1 -0
  83. package/fesm2022/ngneers-controls-scroller.mjs +308 -0
  84. package/fesm2022/ngneers-controls-scroller.mjs.map +1 -0
  85. package/fesm2022/ngneers-controls-select-button.mjs +58 -0
  86. package/fesm2022/ngneers-controls-select-button.mjs.map +1 -0
  87. package/fesm2022/ngneers-controls-select.mjs +417 -0
  88. package/fesm2022/ngneers-controls-select.mjs.map +1 -0
  89. package/fesm2022/ngneers-controls-slider.mjs +167 -0
  90. package/fesm2022/ngneers-controls-slider.mjs.map +1 -0
  91. package/fesm2022/ngneers-controls-snackbar.mjs +414 -0
  92. package/fesm2022/ngneers-controls-snackbar.mjs.map +1 -0
  93. package/fesm2022/ngneers-controls-spin-buttons.mjs +126 -0
  94. package/fesm2022/ngneers-controls-spin-buttons.mjs.map +1 -0
  95. package/fesm2022/ngneers-controls-spinner.mjs +184 -0
  96. package/fesm2022/ngneers-controls-spinner.mjs.map +1 -0
  97. package/fesm2022/ngneers-controls-splitter.mjs +604 -0
  98. package/fesm2022/ngneers-controls-splitter.mjs.map +1 -0
  99. package/fesm2022/ngneers-controls-state.mjs +185 -0
  100. package/fesm2022/ngneers-controls-state.mjs.map +1 -0
  101. package/fesm2022/ngneers-controls-switch.mjs +39 -0
  102. package/fesm2022/ngneers-controls-switch.mjs.map +1 -0
  103. package/fesm2022/ngneers-controls-table.mjs +2634 -0
  104. package/fesm2022/ngneers-controls-table.mjs.map +1 -0
  105. package/fesm2022/ngneers-controls-tabs.mjs +336 -0
  106. package/fesm2022/ngneers-controls-tabs.mjs.map +1 -0
  107. package/fesm2022/ngneers-controls-tag.mjs +30 -0
  108. package/fesm2022/ngneers-controls-tag.mjs.map +1 -0
  109. package/fesm2022/ngneers-controls-toast.mjs +350 -0
  110. package/fesm2022/ngneers-controls-toast.mjs.map +1 -0
  111. package/fesm2022/ngneers-controls-toggle-button.mjs +70 -0
  112. package/fesm2022/ngneers-controls-toggle-button.mjs.map +1 -0
  113. package/fesm2022/ngneers-controls-tooltip.mjs +506 -0
  114. package/fesm2022/ngneers-controls-tooltip.mjs.map +1 -0
  115. package/fesm2022/ngneers-controls-tree.mjs +599 -0
  116. package/fesm2022/ngneers-controls-tree.mjs.map +1 -0
  117. package/fesm2022/ngneers-controls-upload.mjs +377 -0
  118. package/fesm2022/ngneers-controls-upload.mjs.map +1 -0
  119. package/fesm2022/ngneers-controls-utils-ng.mjs +411 -0
  120. package/fesm2022/ngneers-controls-utils-ng.mjs.map +1 -0
  121. package/fesm2022/ngneers-controls-utils.mjs +261 -0
  122. package/fesm2022/ngneers-controls-utils.mjs.map +1 -0
  123. package/fesm2022/ngneers-controls.mjs +6 -0
  124. package/fesm2022/ngneers-controls.mjs.map +1 -0
  125. package/package.json +302 -0
  126. package/types/ngneers-controls-accordion.d.ts +139 -0
  127. package/types/ngneers-controls-api-ng.d.ts +364 -0
  128. package/types/ngneers-controls-api-resize.d.ts +318 -0
  129. package/types/ngneers-controls-api.d.ts +145 -0
  130. package/types/ngneers-controls-avatar.d.ts +54 -0
  131. package/types/ngneers-controls-base.d.ts +277 -0
  132. package/types/ngneers-controls-breadcrumb.d.ts +272 -0
  133. package/types/ngneers-controls-button-group.d.ts +46 -0
  134. package/types/ngneers-controls-button.d.ts +48 -0
  135. package/types/ngneers-controls-calendar.d.ts +466 -0
  136. package/types/ngneers-controls-checkbox.d.ts +40 -0
  137. package/types/ngneers-controls-chip.d.ts +202 -0
  138. package/types/ngneers-controls-default-icons.d.ts +5 -0
  139. package/types/ngneers-controls-defer.d.ts +48 -0
  140. package/types/ngneers-controls-dialog.d.ts +399 -0
  141. package/types/ngneers-controls-directives.d.ts +171 -0
  142. package/types/ngneers-controls-drawer.d.ts +308 -0
  143. package/types/ngneers-controls-edit-inplace.d.ts +263 -0
  144. package/types/ngneers-controls-errors.d.ts +155 -0
  145. package/types/ngneers-controls-filter.d.ts +609 -0
  146. package/types/ngneers-controls-hint.d.ts +88 -0
  147. package/types/ngneers-controls-i18n-translations-de.d.ts +164 -0
  148. package/types/ngneers-controls-i18n-translations-en.d.ts +164 -0
  149. package/types/ngneers-controls-i18n.d.ts +186 -0
  150. package/types/ngneers-controls-icon.d.ts +68 -0
  151. package/types/ngneers-controls-inplace.d.ts +98 -0
  152. package/types/ngneers-controls-input-field.d.ts +248 -0
  153. package/types/ngneers-controls-input.d.ts +30 -0
  154. package/types/ngneers-controls-item-view.d.ts +215 -0
  155. package/types/ngneers-controls-list-box.d.ts +334 -0
  156. package/types/ngneers-controls-mask-input.d.ts +434 -0
  157. package/types/ngneers-controls-menu.d.ts +192 -0
  158. package/types/ngneers-controls-message.d.ts +21 -0
  159. package/types/ngneers-controls-number-input.d.ts +146 -0
  160. package/types/ngneers-controls-paginator.d.ts +255 -0
  161. package/types/ngneers-controls-popover.d.ts +116 -0
  162. package/types/ngneers-controls-progress.d.ts +49 -0
  163. package/types/ngneers-controls-radio.d.ts +91 -0
  164. package/types/ngneers-controls-roving-focus.d.ts +107 -0
  165. package/types/ngneers-controls-scroll-shadow.d.ts +25 -0
  166. package/types/ngneers-controls-scroller.d.ts +151 -0
  167. package/types/ngneers-controls-select-button.d.ts +51 -0
  168. package/types/ngneers-controls-select.d.ts +409 -0
  169. package/types/ngneers-controls-slider.d.ts +57 -0
  170. package/types/ngneers-controls-snackbar.d.ts +330 -0
  171. package/types/ngneers-controls-spin-buttons.d.ts +69 -0
  172. package/types/ngneers-controls-spinner.d.ts +117 -0
  173. package/types/ngneers-controls-splitter.d.ts +465 -0
  174. package/types/ngneers-controls-state.d.ts +102 -0
  175. package/types/ngneers-controls-switch.d.ts +18 -0
  176. package/types/ngneers-controls-table.d.ts +3127 -0
  177. package/types/ngneers-controls-tabs.d.ts +118 -0
  178. package/types/ngneers-controls-tag.d.ts +21 -0
  179. package/types/ngneers-controls-toast.d.ts +298 -0
  180. package/types/ngneers-controls-toggle-button.d.ts +48 -0
  181. package/types/ngneers-controls-tooltip.d.ts +189 -0
  182. package/types/ngneers-controls-tree.d.ts +409 -0
  183. package/types/ngneers-controls-upload.d.ts +347 -0
  184. package/types/ngneers-controls-utils-ng.d.ts +129 -0
  185. package/types/ngneers-controls-utils.d.ts +130 -0
  186. package/types/ngneers-controls.d.ts +2 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngneers-controls-paginator.mjs","sources":["../../src/paginator/paginator.ts","../../src/paginator/paginator.html","../../src/paginator/ngneers-controls-paginator.ts"],"sourcesContent":["import { NgStyle, NgClass } from '@angular/common';\nimport {\n booleanAttribute,\n Component,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n} from '@angular/core';\nimport { NgnTemplate } from '@ngneers/controls/api/ng';\nimport { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';\nimport { NgnButton } from '@ngneers/controls/button';\nimport { I18n } from '@ngneers/controls/i18n';\nimport { NgnIcon } from '@ngneers/controls/icon';\nimport { NgnInputField } from '@ngneers/controls/input-field';\nimport { NgnItemView } from '@ngneers/controls/item-view';\nimport { NgnSelect } from '@ngneers/controls/select';\nimport { throwExp } from '@ngneers/controls/utils';\nimport { paginatorControlTemplate } from '@ngneers/controls-themes/templates/paginator';\n\nimport type { PaginationState } from './types';\nimport type { NgnItem } from '@ngneers/controls/api';\n\n/**\n * @category control\n */\n@Component({\n selector: 'ngn-paginator',\n templateUrl: './paginator.html',\n imports: [\n NgnButton,\n NgnIcon,\n NgnItemView,\n NgnSelect,\n NgnTemplate,\n NgStyle,\n NgnPt,\n NgnInputField,\n NgClass,\n ],\n providers: [provideSelf(NgnPaginator)],\n})\nexport class NgnPaginator extends NgnBase<'paginator'> {\n protected readonly theme = this.injectThemeTemplate(paginatorControlTemplate, 'root');\n protected readonly i18n = inject(I18n).translations;\n\n /**\n * Total number of items to paginate.\n */\n public readonly totalItems = input.required<number>();\n /**\n * Number of items per page. If not set, the first value from {@link possiblePageSizes} is used.\n */\n public readonly pageSize = model<number>();\n /**\n * Possible page sizes to choose from.\n * @default [5, 10, 25, 50]\n */\n public readonly possiblePageSizes = input([5, 10, 25, 50], {\n transform: (sizes: number[]) => sizes.sort((a, b) => a - b),\n });\n /**\n * If set to `true`, the page size selector will be hidden and the page size cannot be changed by the user.\n * @default false\n */\n public readonly fixedPageSize = input(false, { transform: booleanAttribute });\n\n protected readonly appliedPageSize = computed(\n () =>\n this.pageSize() ||\n this.possiblePageSizes()[0] ||\n throwExp('NgnPaginator', 'At least one page size must be provided')\n );\n protected readonly pageCount = computed(() =>\n Math.ceil(this.totalItems() / this.appliedPageSize())\n );\n protected readonly pages = computed(() =>\n Array.from({ length: this.pageCount() }, (_, i) => ({ page: i }))\n );\n protected readonly pageSizeOptions = computed<NgnItem[]>(() =>\n this.possiblePageSizes().map(size => ({\n label: size.toString(),\n value: size,\n }))\n );\n\n /**\n * Emits the current pagination state whenever the page or page size changes.\n */\n public readonly value = output<PaginationState>();\n /**\n * Current page index (zero-based).\n * @default 0\n */\n public readonly page = model(0);\n\n constructor() {\n super();\n effect(() => {\n const page = this.page();\n const pageSize = this.appliedPageSize();\n this.value.emit({\n page: {\n current: page,\n size: pageSize,\n },\n slice: {\n skip: page * pageSize,\n take: pageSize,\n },\n });\n });\n }\n\n protected previousPage(event: PointerEvent): void {\n const amount = event.shiftKey ? 10 : event.ctrlKey ? 100 : 1;\n const newPage = Math.max(this.page() - amount, 0);\n this.page.set(newPage);\n }\n\n protected nextPage(event: PointerEvent): void {\n const amount = event.shiftKey ? 10 : event.ctrlKey ? 100 : 1;\n const newPage = Math.min(this.page() + amount, this.pageCount() - 1);\n this.page.set(newPage);\n }\n\n protected getButtonFontStyles(page: number): {\n [klass: string]: string;\n } {\n function getFontSizeMultiplier() {\n const charCount = (page + 1).toString().length;\n if (charCount <= 2) {\n return 1;\n }\n return Math.pow(0.85, charCount - 2);\n }\n\n return {\n fontSize: `${getFontSizeMultiplier()}em`,\n width: 'calc(1rem + 2 * var(--padding))',\n height: 'calc(1rem + 2 * var(--padding))',\n lineHeight: '0',\n };\n }\n}\n","<button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"this\"\n [ptDep]=\"'previous'\"\n [attr.aria-label]=\"i18n['paginator_previousPage']()\"\n (click)=\"previousPage($event)\"\n>\n <ngn-icon [defaultIcon]=\"'paginator-previous'\" />\n</button>\n\n<ngn-item-view\n #itemView\n [ptInt]=\"this\"\n [ptDep]=\"'item-view'\"\n [items]=\"pages()\"\n [idField]=\"'page'\"\n [overflowStrategy]=\"'aroundIndex'\"\n [overflowStrategyFreezeCount]=\"1\"\n [overflowStrategyIndex]=\"page()\"\n [sameWidthItems]=\"true\"\n>\n <ng-template #item let-item [ngnTemplate]=\"itemView.templateTypes.item\">\n @let buttonStyles = getButtonFontStyles(item.page);\n <button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"this\"\n [ptDep]=\"'page-number'\"\n [ngStyle]=\"buttonStyles\"\n [attr.aria-current]=\"page() === item.page ? 'page' : null\"\n [ngClass]=\"\n theme.classes({\n 'active-page': page() === item.page,\n })\n \"\n (click)=\"page.set(item.page)\"\n >\n {{ item.page + 1 }}\n </button>\n </ng-template>\n <ng-template #overflow let-item [ngnTemplate]=\"itemView.templateTypes.overflow\">\n <button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"this\"\n [ptDep]=\"'overflow'\"\n style=\"opacity: 0.5\"\n disabled\n >\n ...\n </button>\n </ng-template>\n</ngn-item-view>\n\n<button\n ngnButton\n [kind]=\"'icon'\"\n [ptInt]=\"this\"\n [ptDep]=\"'next'\"\n [attr.aria-label]=\"i18n['paginator_nextPage']()\"\n (click)=\"nextPage($event)\"\n>\n <ngn-icon [defaultIcon]=\"'paginator-next'\" />\n</button>\n\n@if (!fixedPageSize()) {\n <ngn-input-field [ptInt]=\"this\" [ptClass]=\"'page-size-options'\">\n <ngn-select\n [options]=\"pageSizeOptions()\"\n [value]=\"appliedPageSize()\"\n (valueChange)=\"pageSize.set($event)\"\n />\n </ngn-input-field>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,215 @@
1
+ import * as i0 from '@angular/core';
2
+ import { contentChild, Directive, output, model, input, booleanAttribute, viewChild, computed, signal, inject, Injector, ChangeDetectorRef, untracked, Component } from '@angular/core';
3
+ import { toPopoverCloseBy, autoPositionElement } from '@ngneers/controls/api/ng';
4
+ import { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';
5
+ import { NgnDefer } from '@ngneers/controls/defer';
6
+ import { computedWithPrevious, explicitAfterRenderEffect } from '@ngneers/controls/utils-ng';
7
+ import { popoverControlTemplate } from '@ngneers/controls-themes/templates/popover';
8
+
9
+ /**
10
+ * Template projection for {@link NgnPopover}, extracted into a dedicated base class so the
11
+ * component itself stays focused on positioning and open/close behavior.
12
+ */
13
+ class PopoverTemplates extends NgnBase {
14
+ /**
15
+ * User-provided lazy content, projected via an `<ng-template #lazy>` inside the popover.
16
+ * Rendered only once the popover first opens.
17
+ */
18
+ lazyContent = contentChild('lazy', /* @ts-ignore */
19
+ ...(ngDevMode ? [{ debugName: "lazyContent" }] : /* istanbul ignore next */ []));
20
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PopoverTemplates, deps: null, target: i0.ɵɵFactoryTarget.Directive });
21
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.0.5", type: PopoverTemplates, isStandalone: true, queries: [{ propertyName: "lazyContent", first: true, predicate: ["lazy"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0 });
22
+ }
23
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: PopoverTemplates, decorators: [{
24
+ type: Directive
25
+ }], propDecorators: { lazyContent: [{ type: i0.ContentChild, args: ['lazy', { isSignal: true }] }] } });
26
+
27
+ /**
28
+ * @category control
29
+ */
30
+ class NgnPopover extends PopoverTemplates {
31
+ theme = this.injectThemeTemplate(popoverControlTemplate);
32
+ /**
33
+ * Emits when the popover has fully closed.
34
+ */
35
+ closed = output();
36
+ /**
37
+ * Emits when the popover is closed.
38
+ */
39
+ closing = output();
40
+ /**
41
+ * Shows or hides the popover.
42
+ *
43
+ * You probably want to react to openChange events from outside to update your variable accordingly.
44
+ */
45
+ open = model(false, /* @ts-ignore */
46
+ ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
47
+ /**
48
+ * The element to which the popover is anchored.
49
+ */
50
+ anchor = input.required(/* @ts-ignore */
51
+ ...(ngDevMode ? [{ debugName: "anchor" }] : /* istanbul ignore next */ []));
52
+ /**
53
+ * The popover options.
54
+ */
55
+ options = input(/* @ts-ignore */
56
+ ...(ngDevMode ? [undefined, { debugName: "options" }] : /* istanbul ignore next */ []));
57
+ /**
58
+ * Set to true for scrollable/shrink-able content
59
+ */
60
+ hasShrinkableContent = input(false, { ...(ngDevMode ? { debugName: "hasShrinkableContent" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
61
+ /**
62
+ * How the popover closes depending on user interaction.
63
+ * @default any
64
+ */
65
+ closeBy = input('any', /* @ts-ignore */
66
+ ...(ngDevMode ? [{ debugName: "closeBy" }] : /* istanbul ignore next */ []));
67
+ _content = viewChild.required('content');
68
+ closeByPopover = computed(() => toPopoverCloseBy(this.closeBy()), /* @ts-ignore */
69
+ ...(ngDevMode ? [{ debugName: "closeByPopover" }] : /* istanbul ignore next */ []));
70
+ isFullyClosed = signal(true, /* @ts-ignore */
71
+ ...(ngDevMode ? [{ debugName: "isFullyClosed" }] : /* istanbul ignore next */ []));
72
+ _skipEmitCloseEvent = false;
73
+ _triggeredByInput = false;
74
+ // Set by `onToggle` when the open state changed because the popover itself
75
+ // toggled (native show/hide). The `[open]` effect then skips re-running
76
+ // show()/hide() for that echo — otherwise the redundant show() schedules a
77
+ // second deferred `togglePopover(true)` that can re-open the popover right
78
+ // after a quick close (e.g. Enter then Escape). The effect still reacts to
79
+ // genuine external `[open]` input changes.
80
+ _internalToggle = false;
81
+ appliedOptions = computed(() => ({
82
+ cache: false,
83
+ ...this.options(),
84
+ }), /* @ts-ignore */
85
+ ...(ngDevMode ? [{ debugName: "appliedOptions" }] : /* istanbul ignore next */ []));
86
+ _injector = inject(Injector);
87
+ _cdr = inject(ChangeDetectorRef);
88
+ _popoverRef = viewChild.required('popover');
89
+ _popover = computed(() => this._popoverRef().nativeElement, /* @ts-ignore */
90
+ ...(ngDevMode ? [{ debugName: "_popover" }] : /* istanbul ignore next */ []));
91
+ _autoPos = computedWithPrevious(prev => {
92
+ prev?.stop();
93
+ const popoverEl = this._popover();
94
+ if (!popoverEl) {
95
+ return undefined;
96
+ }
97
+ return autoPositionElement(this.anchor(), popoverEl, {
98
+ injector: this._injector,
99
+ stopped: true,
100
+ sizeConstraints: this.appliedOptions()?.sizeConstraints,
101
+ placement: this.appliedOptions()?.placement,
102
+ offset: this.appliedOptions()?.padding,
103
+ hasShrinkableContent: this.hasShrinkableContent(),
104
+ });
105
+ });
106
+ constructor() {
107
+ super();
108
+ explicitAfterRenderEffect([this.open], ([open]) => {
109
+ // Ignore the echo from our own onToggle-driven open change; only react to
110
+ // external `[open]` input changes.
111
+ if (this._internalToggle) {
112
+ this._internalToggle = false;
113
+ return;
114
+ }
115
+ if (!open) {
116
+ this._triggeredByInput = true;
117
+ this.hide();
118
+ }
119
+ if (open) {
120
+ this._triggeredByInput = true;
121
+ this.show();
122
+ }
123
+ });
124
+ }
125
+ /**
126
+ * Opens the popover. Alternatively, you can also set the {@link open} input to `true`.
127
+ */
128
+ show() {
129
+ untracked(() => {
130
+ if (this.open() && !this._triggeredByInput) {
131
+ return;
132
+ }
133
+ this._triggeredByInput = false;
134
+ this.isFullyClosed.set(false);
135
+ this._cdr.detectChanges();
136
+ requestAnimationFrame(() => {
137
+ this._autoPos()?.start();
138
+ this._popover().togglePopover(true);
139
+ });
140
+ });
141
+ }
142
+ /**
143
+ * Closes the popover. Alternatively, you can also set the {@link open} input to `false`.
144
+ */
145
+ hide(emitCloseEvent = true) {
146
+ untracked(() => {
147
+ if (!this.open() && !this._triggeredByInput) {
148
+ return;
149
+ }
150
+ this._triggeredByInput = false;
151
+ this._skipEmitCloseEvent = !emitCloseEvent;
152
+ this._autoPos()?.stop();
153
+ this._popover().togglePopover(false);
154
+ });
155
+ }
156
+ /**
157
+ * Toggles the popover open or closed. Alternatively, you can also set the {@link open} input accordingly.
158
+ */
159
+ toggle() {
160
+ if (untracked(this.open)) {
161
+ this.hide();
162
+ }
163
+ else {
164
+ this.show();
165
+ }
166
+ }
167
+ onToggle(event) {
168
+ const evt = event;
169
+ // Mark this open-state change as internal so the `[open]` effect doesn't
170
+ // echo it back into another show()/hide().
171
+ this._internalToggle = true;
172
+ if (evt.newState === 'closed') {
173
+ this.open.set(false);
174
+ if (this._skipEmitCloseEvent) {
175
+ this._skipEmitCloseEvent = false;
176
+ }
177
+ else {
178
+ this.closing.emit();
179
+ }
180
+ this._autoPos()?.stop();
181
+ requestAnimationFrame(() => {
182
+ const allAnimationsDone = Promise.all(this._content()
183
+ .nativeElement.getAnimations()
184
+ .map(x => x.finished));
185
+ allAnimationsDone
186
+ .then(() => {
187
+ this.isFullyClosed.set(true);
188
+ this.closed.emit();
189
+ })
190
+ .catch(() => {
191
+ // ignore cancelled animation
192
+ });
193
+ });
194
+ }
195
+ else {
196
+ this.open.set(true);
197
+ this.isFullyClosed.set(false);
198
+ }
199
+ }
200
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnPopover, deps: [], target: i0.ɵɵFactoryTarget.Component });
201
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.0.5", type: NgnPopover, isStandalone: true, selector: "ngn-popover", inputs: { open: { classPropertyName: "open", publicName: "open", isSignal: true, isRequired: false, transformFunction: null }, anchor: { classPropertyName: "anchor", publicName: "anchor", isSignal: true, isRequired: true, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, hasShrinkableContent: { classPropertyName: "hasShrinkableContent", publicName: "hasShrinkableContent", isSignal: true, isRequired: false, transformFunction: null }, closeBy: { classPropertyName: "closeBy", publicName: "closeBy", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { closed: "closed", closing: "closing", open: "openChange" }, host: { listeners: { "click": "$event.stopPropagation()" } }, providers: [provideSelf(NgnPopover)], viewQueries: [{ propertyName: "_content", first: true, predicate: ["content"], descendants: true, isSignal: true }, { propertyName: "_popoverRef", first: true, predicate: ["popover"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div\n [ptInt]=\"this\"\n [ptClass]=\"'root'\"\n #popover\n [attr.popover]=\"closeByPopover()\"\n (toggle)=\"onToggle($event)\"\n [style.min-height]=\"\n hasShrinkableContent()\n ? (this.appliedOptions().sizeConstraints?.minHeight ?? null)\n : 'fit-content'\n \"\n>\n <div\n #content\n [ptInt]=\"this\"\n [ptClass]=\"{\n content: true,\n 'content-closing': !this.open() && !this.isFullyClosed(),\n }\"\n [style.min-height]=\"hasShrinkableContent() ? null : 'fit-content'\"\n >\n <ngn-defer\n [lazyContent]=\"lazyContent()\"\n [open]=\"open() || !isFullyClosed()\"\n [cache]=\"appliedOptions().cache\"\n >\n <ng-content></ng-content>\n </ngn-defer>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }, { kind: "component", type: NgnDefer, selector: "ngn-defer", inputs: ["lazyContent", "lazyContentContext", "open", "lazy", "cache", "hiddenOnClosed"] }] });
202
+ }
203
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnPopover, decorators: [{
204
+ type: Component,
205
+ args: [{ selector: 'ngn-popover', imports: [NgnPt, NgnDefer], providers: [provideSelf(NgnPopover)], host: {
206
+ '(click)': '$event.stopPropagation()',
207
+ }, template: "<div\n [ptInt]=\"this\"\n [ptClass]=\"'root'\"\n #popover\n [attr.popover]=\"closeByPopover()\"\n (toggle)=\"onToggle($event)\"\n [style.min-height]=\"\n hasShrinkableContent()\n ? (this.appliedOptions().sizeConstraints?.minHeight ?? null)\n : 'fit-content'\n \"\n>\n <div\n #content\n [ptInt]=\"this\"\n [ptClass]=\"{\n content: true,\n 'content-closing': !this.open() && !this.isFullyClosed(),\n }\"\n [style.min-height]=\"hasShrinkableContent() ? null : 'fit-content'\"\n >\n <ngn-defer\n [lazyContent]=\"lazyContent()\"\n [open]=\"open() || !isFullyClosed()\"\n [cache]=\"appliedOptions().cache\"\n >\n <ng-content></ng-content>\n </ngn-defer>\n </div>\n</div>\n" }]
208
+ }], ctorParameters: () => [], propDecorators: { closed: [{ type: i0.Output, args: ["closed"] }], closing: [{ type: i0.Output, args: ["closing"] }], open: [{ type: i0.Input, args: [{ isSignal: true, alias: "open", required: false }] }, { type: i0.Output, args: ["openChange"] }], anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: true }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], hasShrinkableContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "hasShrinkableContent", required: false }] }], closeBy: [{ type: i0.Input, args: [{ isSignal: true, alias: "closeBy", required: false }] }], _content: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }], _popoverRef: [{ type: i0.ViewChild, args: ['popover', { isSignal: true }] }] } });
209
+
210
+ /**
211
+ * Generated bundle index. Do not edit.
212
+ */
213
+
214
+ export { NgnPopover };
215
+ //# sourceMappingURL=ngneers-controls-popover.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngneers-controls-popover.mjs","sources":["../../src/popover/popover-templates.ts","../../src/popover/popover.ts","../../src/popover/popover.html","../../src/popover/ngneers-controls-popover.ts"],"sourcesContent":["import { contentChild, Directive, TemplateRef } from '@angular/core';\nimport { NgnBase } from '@ngneers/controls/base';\n\n/**\n * Template projection for {@link NgnPopover}, extracted into a dedicated base class so the\n * component itself stays focused on positioning and open/close behavior.\n */\n@Directive()\nexport abstract class PopoverTemplates extends NgnBase<'popover'> {\n /**\n * User-provided lazy content, projected via an `<ng-template #lazy>` inside the popover.\n * Rendered only once the popover first opens.\n */\n protected readonly lazyContent = contentChild<TemplateRef<unknown>>('lazy');\n}\n","import {\n booleanAttribute,\n ChangeDetectorRef,\n Component,\n computed,\n ElementRef,\n inject,\n Injector,\n input,\n model,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport {\n type PopoverCloseBy,\n toPopoverCloseBy,\n autoPositionElement,\n type AutoPositioningHandle,\n type Openable,\n type Anchor,\n} from '@ngneers/controls/api/ng';\nimport { provideSelf, NgnPt } from '@ngneers/controls/base';\nimport { NgnDefer } from '@ngneers/controls/defer';\nimport { computedWithPrevious, explicitAfterRenderEffect } from '@ngneers/controls/utils-ng';\nimport { popoverControlTemplate } from '@ngneers/controls-themes/templates/popover';\n\nimport { PopoverTemplates } from './popover-templates';\n\nimport type { PopoverOptions } from './types';\n\n/**\n * @category control\n */\n@Component({\n selector: 'ngn-popover',\n templateUrl: './popover.html',\n imports: [NgnPt, NgnDefer],\n providers: [provideSelf(NgnPopover)],\n host: {\n '(click)': '$event.stopPropagation()',\n },\n})\nexport class NgnPopover extends PopoverTemplates implements Openable {\n protected readonly theme = this.injectThemeTemplate(popoverControlTemplate);\n\n /**\n * Emits when the popover has fully closed.\n */\n public readonly closed = output();\n /**\n * Emits when the popover is closed.\n */\n public readonly closing = output();\n /**\n * Shows or hides the popover.\n *\n * You probably want to react to openChange events from outside to update your variable accordingly.\n */\n public readonly open = model<boolean>(false);\n /**\n * The element to which the popover is anchored.\n */\n public readonly anchor = input.required<Anchor>();\n /**\n * The popover options.\n */\n public readonly options = input<PopoverOptions>();\n /**\n * Set to true for scrollable/shrink-able content\n */\n public readonly hasShrinkableContent = input(false, { transform: booleanAttribute });\n /**\n * How the popover closes depending on user interaction.\n * @default any\n */\n public readonly closeBy = input<PopoverCloseBy>('any');\n\n protected readonly _content = viewChild.required<ElementRef<HTMLElement>>('content');\n protected readonly closeByPopover = computed(() => toPopoverCloseBy(this.closeBy()));\n protected readonly isFullyClosed = signal(true);\n\n private _skipEmitCloseEvent = false;\n private _triggeredByInput = false;\n // Set by `onToggle` when the open state changed because the popover itself\n // toggled (native show/hide). The `[open]` effect then skips re-running\n // show()/hide() for that echo — otherwise the redundant show() schedules a\n // second deferred `togglePopover(true)` that can re-open the popover right\n // after a quick close (e.g. Enter then Escape). The effect still reacts to\n // genuine external `[open]` input changes.\n private _internalToggle = false;\n\n protected readonly appliedOptions = computed(() => ({\n cache: false,\n ...this.options(),\n }));\n\n private readonly _injector = inject(Injector);\n private readonly _cdr = inject(ChangeDetectorRef);\n private readonly _popoverRef = viewChild.required<ElementRef<HTMLElement>>('popover');\n private readonly _popover = computed(() => this._popoverRef().nativeElement);\n private readonly _autoPos = computedWithPrevious<AutoPositioningHandle | undefined>(prev => {\n prev?.stop();\n const popoverEl = this._popover();\n if (!popoverEl) {\n return undefined;\n }\n return autoPositionElement(this.anchor(), popoverEl, {\n injector: this._injector,\n stopped: true,\n sizeConstraints: this.appliedOptions()?.sizeConstraints,\n placement: this.appliedOptions()?.placement,\n offset: this.appliedOptions()?.padding,\n hasShrinkableContent: this.hasShrinkableContent(),\n });\n });\n\n constructor() {\n super();\n\n explicitAfterRenderEffect([this.open], ([open]) => {\n // Ignore the echo from our own onToggle-driven open change; only react to\n // external `[open]` input changes.\n if (this._internalToggle) {\n this._internalToggle = false;\n return;\n }\n if (!open) {\n this._triggeredByInput = true;\n this.hide();\n }\n if (open) {\n this._triggeredByInput = true;\n this.show();\n }\n });\n }\n\n /**\n * Opens the popover. Alternatively, you can also set the {@link open} input to `true`.\n */\n public show() {\n untracked(() => {\n if (this.open() && !this._triggeredByInput) {\n return;\n }\n this._triggeredByInput = false;\n this.isFullyClosed.set(false);\n this._cdr.detectChanges();\n requestAnimationFrame(() => {\n this._autoPos()?.start();\n this._popover().togglePopover(true);\n });\n });\n }\n\n /**\n * Closes the popover. Alternatively, you can also set the {@link open} input to `false`.\n */\n public hide(emitCloseEvent = true) {\n untracked(() => {\n if (!this.open() && !this._triggeredByInput) {\n return;\n }\n this._triggeredByInput = false;\n this._skipEmitCloseEvent = !emitCloseEvent;\n this._autoPos()?.stop();\n this._popover().togglePopover(false);\n });\n }\n\n /**\n * Toggles the popover open or closed. Alternatively, you can also set the {@link open} input accordingly.\n */\n public toggle() {\n if (untracked(this.open)) {\n this.hide();\n } else {\n this.show();\n }\n }\n\n protected onToggle(event: Event) {\n const evt = event as ToggleEvent;\n // Mark this open-state change as internal so the `[open]` effect doesn't\n // echo it back into another show()/hide().\n this._internalToggle = true;\n if (evt.newState === 'closed') {\n this.open.set(false);\n\n if (this._skipEmitCloseEvent) {\n this._skipEmitCloseEvent = false;\n } else {\n this.closing.emit();\n }\n this._autoPos()?.stop();\n\n requestAnimationFrame(() => {\n const allAnimationsDone = Promise.all(\n this._content()\n .nativeElement.getAnimations()\n .map(x => x.finished)\n );\n allAnimationsDone\n .then(() => {\n this.isFullyClosed.set(true);\n this.closed.emit();\n })\n .catch(() => {\n // ignore cancelled animation\n });\n });\n } else {\n this.open.set(true);\n this.isFullyClosed.set(false);\n }\n }\n}\n","<div\n [ptInt]=\"this\"\n [ptClass]=\"'root'\"\n #popover\n [attr.popover]=\"closeByPopover()\"\n (toggle)=\"onToggle($event)\"\n [style.min-height]=\"\n hasShrinkableContent()\n ? (this.appliedOptions().sizeConstraints?.minHeight ?? null)\n : 'fit-content'\n \"\n>\n <div\n #content\n [ptInt]=\"this\"\n [ptClass]=\"{\n content: true,\n 'content-closing': !this.open() && !this.isFullyClosed(),\n }\"\n [style.min-height]=\"hasShrinkableContent() ? null : 'fit-content'\"\n >\n <ngn-defer\n [lazyContent]=\"lazyContent()\"\n [open]=\"open() || !isFullyClosed()\"\n [cache]=\"appliedOptions().cache\"\n >\n <ng-content></ng-content>\n </ngn-defer>\n </div>\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,98 @@
1
+ import * as i0 from '@angular/core';
2
+ import { input, booleanAttribute, computed, Component } from '@angular/core';
3
+ import { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';
4
+ import { progressControlTemplate } from '@ngneers/controls-themes/templates/progress';
5
+
6
+ const TAU = Math.PI * 2;
7
+ /**
8
+ * @category control
9
+ */
10
+ class NgnProgress extends NgnBase {
11
+ theme = this.injectThemeTemplate(progressControlTemplate, {
12
+ root: true,
13
+ indeterminate: () => this.indeterminate(),
14
+ circular: () => this.circular(),
15
+ });
16
+ /**
17
+ * The current progress value, clamped to the 0-100 range.
18
+ * @default 0
19
+ */
20
+ value = input(0, /* @ts-ignore */
21
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
22
+ /**
23
+ * Whether the progress indicator is indeterminate (animated, no fixed value).
24
+ * @default false
25
+ */
26
+ indeterminate = input(false, { ...(ngDevMode ? { debugName: "indeterminate" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
27
+ /**
28
+ * Whether the progress indicator renders as a circle instead of a bar.
29
+ * @default false
30
+ */
31
+ circular = input(false, { ...(ngDevMode ? { debugName: "circular" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
32
+ /**
33
+ * Radius of the circular progress indicator, in px. Only applies when {@link circular} is `true`.
34
+ * @default 40
35
+ */
36
+ radius = input(40, /* @ts-ignore */
37
+ ...(ngDevMode ? [{ debugName: "radius" }] : /* istanbul ignore next */ []));
38
+ /**
39
+ * Thickness of the circular progress indicator stroke, in px. Only applies when {@link circular} is `true`.
40
+ * @default 8
41
+ */
42
+ thickness = input(8, /* @ts-ignore */
43
+ ...(ngDevMode ? [{ debugName: "thickness" }] : /* istanbul ignore next */ []));
44
+ safeValue = computed(() => Math.min(Math.max(this.value(), 0), 100), /* @ts-ignore */
45
+ ...(ngDevMode ? [{ debugName: "safeValue" }] : /* istanbul ignore next */ []));
46
+ safeRadius = computed(() => Math.max(this.radius(), 0), /* @ts-ignore */
47
+ ...(ngDevMode ? [{ debugName: "safeRadius" }] : /* istanbul ignore next */ []));
48
+ safeThickness = computed(() => Math.max(this.thickness(), 1), /* @ts-ignore */
49
+ ...(ngDevMode ? [{ debugName: "safeThickness" }] : /* istanbul ignore next */ []));
50
+ svgSize = computed(() => {
51
+ // Full size of the SVG in px.
52
+ return this.safeRadius() * 2 + this.safeThickness();
53
+ }, /* @ts-ignore */
54
+ ...(ngDevMode ? [{ debugName: "svgSize" }] : /* istanbul ignore next */ []));
55
+ svgCenter = computed(() => this.svgSize() / 2, /* @ts-ignore */
56
+ ...(ngDevMode ? [{ debugName: "svgCenter" }] : /* istanbul ignore next */ []));
57
+ circumference = computed(() => TAU * this.safeRadius(), /* @ts-ignore */
58
+ ...(ngDevMode ? [{ debugName: "circumference" }] : /* istanbul ignore next */ []));
59
+ strokeDasharray = computed(() => {
60
+ const circumference = this.circumference();
61
+ // Arc length for indeterminate mode.
62
+ if (this.indeterminate()) {
63
+ return `${circumference * 0.28} ${circumference}`;
64
+ }
65
+ return `${circumference}`;
66
+ }, /* @ts-ignore */
67
+ ...(ngDevMode ? [{ debugName: "strokeDasharray" }] : /* istanbul ignore next */ []));
68
+ strokeDashoffset = computed(() => {
69
+ const circumference = this.circumference();
70
+ if (this.indeterminate()) {
71
+ return `${circumference * 0.72}`;
72
+ }
73
+ return `${circumference * (1 - this.safeValue() / 100)}`;
74
+ }, /* @ts-ignore */
75
+ ...(ngDevMode ? [{ debugName: "strokeDashoffset" }] : /* istanbul ignore next */ []));
76
+ constructor() {
77
+ super();
78
+ }
79
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnProgress, deps: [], target: i0.ɵɵFactoryTarget.Component });
80
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NgnProgress, isStandalone: true, selector: "ngn-progress", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, indeterminate: { classPropertyName: "indeterminate", publicName: "indeterminate", isSignal: true, isRequired: false, transformFunction: null }, circular: { classPropertyName: "circular", publicName: "circular", isSignal: true, isRequired: false, transformFunction: null }, radius: { classPropertyName: "radius", publicName: "radius", isSignal: true, isRequired: false, transformFunction: null }, thickness: { classPropertyName: "thickness", publicName: "thickness", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "progressbar" }, properties: { "attr.aria-valuemin": "0", "attr.aria-valuemax": "100", "attr.aria-valuenow": "indeterminate() ? null : safeValue()", "style.--progress.%": "indeterminate() ? null : safeValue()" } }, providers: [provideSelf(NgnProgress)], usesInheritance: true, ngImport: i0, template: "@if (circular()) {\n <svg\n [attr.width]=\"svgSize()\"\n [attr.height]=\"svgSize()\"\n [attr.viewBox]=\"'0 0 ' + svgSize() + ' ' + svgSize()\"\n [ptInt]=\"this\"\n [ptClass]=\"'svg'\"\n >\n <circle\n [attr.cx]=\"svgCenter()\"\n [attr.cy]=\"svgCenter()\"\n [attr.r]=\"safeRadius()\"\n [attr.stroke-width]=\"safeThickness()\"\n fill=\"none\"\n [ptInt]=\"this\"\n [ptClass]=\"'track'\"\n />\n <circle\n [attr.cx]=\"svgCenter()\"\n [attr.cy]=\"svgCenter()\"\n [attr.r]=\"safeRadius()\"\n [attr.stroke-width]=\"safeThickness()\"\n fill=\"none\"\n [attr.stroke-dasharray]=\"strokeDasharray()\"\n [attr.stroke-dashoffset]=\"strokeDashoffset()\"\n [ptInt]=\"this\"\n [ptClass]=\"'fill'\"\n />\n </svg>\n} @else {\n <div [ptInt]=\"this\" [ptClass]=\"'track'\" [style.height.px]=\"safeThickness()\">\n <div [ptInt]=\"this\" [ptClass]=\"'fill'\"></div>\n @if (indeterminate()) {\n <div [ptInt]=\"this\" [ptClass]=\"'fill2'\"></div>\n }\n </div>\n}\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }] });
81
+ }
82
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnProgress, decorators: [{
83
+ type: Component,
84
+ args: [{ selector: 'ngn-progress', imports: [NgnPt], providers: [provideSelf(NgnProgress)], host: {
85
+ role: 'progressbar',
86
+ '[attr.aria-valuemin]': '0',
87
+ '[attr.aria-valuemax]': '100',
88
+ '[attr.aria-valuenow]': 'indeterminate() ? null : safeValue()',
89
+ '[style.--progress.%]': 'indeterminate() ? null : safeValue()',
90
+ }, template: "@if (circular()) {\n <svg\n [attr.width]=\"svgSize()\"\n [attr.height]=\"svgSize()\"\n [attr.viewBox]=\"'0 0 ' + svgSize() + ' ' + svgSize()\"\n [ptInt]=\"this\"\n [ptClass]=\"'svg'\"\n >\n <circle\n [attr.cx]=\"svgCenter()\"\n [attr.cy]=\"svgCenter()\"\n [attr.r]=\"safeRadius()\"\n [attr.stroke-width]=\"safeThickness()\"\n fill=\"none\"\n [ptInt]=\"this\"\n [ptClass]=\"'track'\"\n />\n <circle\n [attr.cx]=\"svgCenter()\"\n [attr.cy]=\"svgCenter()\"\n [attr.r]=\"safeRadius()\"\n [attr.stroke-width]=\"safeThickness()\"\n fill=\"none\"\n [attr.stroke-dasharray]=\"strokeDasharray()\"\n [attr.stroke-dashoffset]=\"strokeDashoffset()\"\n [ptInt]=\"this\"\n [ptClass]=\"'fill'\"\n />\n </svg>\n} @else {\n <div [ptInt]=\"this\" [ptClass]=\"'track'\" [style.height.px]=\"safeThickness()\">\n <div [ptInt]=\"this\" [ptClass]=\"'fill'\"></div>\n @if (indeterminate()) {\n <div [ptInt]=\"this\" [ptClass]=\"'fill2'\"></div>\n }\n </div>\n}\n" }]
91
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], indeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminate", required: false }] }], circular: [{ type: i0.Input, args: [{ isSignal: true, alias: "circular", required: false }] }], radius: [{ type: i0.Input, args: [{ isSignal: true, alias: "radius", required: false }] }], thickness: [{ type: i0.Input, args: [{ isSignal: true, alias: "thickness", required: false }] }] } });
92
+
93
+ /**
94
+ * Generated bundle index. Do not edit.
95
+ */
96
+
97
+ export { NgnProgress };
98
+ //# sourceMappingURL=ngneers-controls-progress.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngneers-controls-progress.mjs","sources":["../../src/progress/progress.ts","../../src/progress/progress.html","../../src/progress/ngneers-controls-progress.ts"],"sourcesContent":["import { Component, input, computed, booleanAttribute } from '@angular/core';\nimport { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';\nimport { progressControlTemplate } from '@ngneers/controls-themes/templates/progress';\n\nconst TAU = Math.PI * 2;\n\n/**\n * @category control\n */\n@Component({\n selector: 'ngn-progress',\n templateUrl: './progress.html',\n imports: [NgnPt],\n providers: [provideSelf(NgnProgress)],\n host: {\n role: 'progressbar',\n '[attr.aria-valuemin]': '0',\n '[attr.aria-valuemax]': '100',\n '[attr.aria-valuenow]': 'indeterminate() ? null : safeValue()',\n '[style.--progress.%]': 'indeterminate() ? null : safeValue()',\n },\n})\nexport class NgnProgress extends NgnBase<'progress'> {\n protected readonly theme = this.injectThemeTemplate(progressControlTemplate, {\n root: true,\n indeterminate: () => this.indeterminate(),\n circular: () => this.circular(),\n });\n\n /**\n * The current progress value, clamped to the 0-100 range.\n * @default 0\n */\n public readonly value = input<number>(0);\n /**\n * Whether the progress indicator is indeterminate (animated, no fixed value).\n * @default false\n */\n public readonly indeterminate = input(false, { transform: booleanAttribute });\n /**\n * Whether the progress indicator renders as a circle instead of a bar.\n * @default false\n */\n public readonly circular = input(false, { transform: booleanAttribute });\n\n /**\n * Radius of the circular progress indicator, in px. Only applies when {@link circular} is `true`.\n * @default 40\n */\n public readonly radius = input<number>(40);\n\n /**\n * Thickness of the circular progress indicator stroke, in px. Only applies when {@link circular} is `true`.\n * @default 8\n */\n public readonly thickness = input<number>(8);\n\n protected readonly safeValue = computed(() => Math.min(Math.max(this.value(), 0), 100));\n\n protected readonly safeRadius = computed(() => Math.max(this.radius(), 0));\n protected readonly safeThickness = computed(() => Math.max(this.thickness(), 1));\n\n protected readonly svgSize = computed(() => {\n // Full size of the SVG in px.\n return this.safeRadius() * 2 + this.safeThickness();\n });\n\n protected readonly svgCenter = computed(() => this.svgSize() / 2);\n\n protected readonly circumference = computed(() => TAU * this.safeRadius());\n\n protected readonly strokeDasharray = computed(() => {\n const circumference = this.circumference();\n // Arc length for indeterminate mode.\n if (this.indeterminate()) {\n return `${circumference * 0.28} ${circumference}`;\n }\n return `${circumference}`;\n });\n\n protected readonly strokeDashoffset = computed(() => {\n const circumference = this.circumference();\n if (this.indeterminate()) {\n return `${circumference * 0.72}`;\n }\n return `${circumference * (1 - this.safeValue() / 100)}`;\n });\n\n constructor() {\n super();\n }\n}\n","@if (circular()) {\n <svg\n [attr.width]=\"svgSize()\"\n [attr.height]=\"svgSize()\"\n [attr.viewBox]=\"'0 0 ' + svgSize() + ' ' + svgSize()\"\n [ptInt]=\"this\"\n [ptClass]=\"'svg'\"\n >\n <circle\n [attr.cx]=\"svgCenter()\"\n [attr.cy]=\"svgCenter()\"\n [attr.r]=\"safeRadius()\"\n [attr.stroke-width]=\"safeThickness()\"\n fill=\"none\"\n [ptInt]=\"this\"\n [ptClass]=\"'track'\"\n />\n <circle\n [attr.cx]=\"svgCenter()\"\n [attr.cy]=\"svgCenter()\"\n [attr.r]=\"safeRadius()\"\n [attr.stroke-width]=\"safeThickness()\"\n fill=\"none\"\n [attr.stroke-dasharray]=\"strokeDasharray()\"\n [attr.stroke-dashoffset]=\"strokeDashoffset()\"\n [ptInt]=\"this\"\n [ptClass]=\"'fill'\"\n />\n </svg>\n} @else {\n <div [ptInt]=\"this\" [ptClass]=\"'track'\" [style.height.px]=\"safeThickness()\">\n <div [ptInt]=\"this\" [ptClass]=\"'fill'\"></div>\n @if (indeterminate()) {\n <div [ptInt]=\"this\" [ptClass]=\"'fill2'\"></div>\n }\n </div>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,152 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, inject, signal, DestroyRef, effect, Component, input, booleanAttribute, computed } from '@angular/core';
3
+ import { ValueControlBase, provideSelf, NgnBase, NgnPt } from '@ngneers/controls/base';
4
+ import * as i1 from '@ngneers/controls/roving-focus';
5
+ import { NgnRovingGroup, NgnRovingItem } from '@ngneers/controls/roving-focus';
6
+ import { radioGroupControlTemplate } from '@ngneers/controls-themes/templates/radio-group';
7
+ import { radioControlTemplate } from '@ngneers/controls-themes/templates/radio';
8
+
9
+ const NGN_RADIO_GROUP = new InjectionToken('NGN_RADIO_GROUP');
10
+
11
+ /**
12
+ * A themed radio group. Owns the selected {@link value}; the individual
13
+ * `ngn-radio` children projected inside are presentational and report their
14
+ * payload up through {@link register}.
15
+ *
16
+ * Keyboard handling and roving tab order are delegated to `NgnRovingGroup`
17
+ * (applied as a host directive). Selection follows focus: moving the roving
18
+ * active item (arrows / Home / End / pointer) selects it, matching native
19
+ * radio-group behavior.
20
+ *
21
+ * @category control
22
+ */
23
+ class NgnRadioGroup extends ValueControlBase {
24
+ theme = this.injectThemeTemplate(radioGroupControlTemplate, {
25
+ root: true,
26
+ invalid: () => this.invalid(),
27
+ });
28
+ /** The roving-focus host directive that drives keyboard/tab coordination. */
29
+ roving = inject(NgnRovingGroup);
30
+ _radios = signal([], /* @ts-ignore */
31
+ ...(ngDevMode ? [{ debugName: "_radios" }] : /* istanbul ignore next */ []));
32
+ register(ref) {
33
+ this._radios.update(list => (list.includes(ref) ? list : [...list, ref]));
34
+ }
35
+ unregister(ref) {
36
+ this._radios.update(list => list.filter(r => r !== ref));
37
+ }
38
+ constructor() {
39
+ super();
40
+ // Selection follows focus: the roving group emits only on genuine
41
+ // navigation/activation (never on mount or plain Tab-in), so wiring value
42
+ // here gives native "arrow selects" behavior without spurious writes.
43
+ const sub = this.roving.activeItemChange.subscribe(index => {
44
+ if (this.readonly() || this.disabled()) {
45
+ return;
46
+ }
47
+ const element = this.roving.items()[index]?.element;
48
+ const radio = this._radios().find(r => r.element === element);
49
+ if (!radio || radio.disabled()) {
50
+ return;
51
+ }
52
+ this.value.set(radio.value());
53
+ this.touched.set(true);
54
+ });
55
+ inject(DestroyRef).onDestroy(() => sub.unsubscribe());
56
+ // Keep the roving tab stop on the selected radio so Tab-in lands on the
57
+ // checked option (native behavior). Disabled radios are skipped so a
58
+ // selected-but-disabled option never becomes the tab stop. `syncActiveIndex`
59
+ // updates the tab stop silently — no emit, no focus move — so a programmatic
60
+ // `value` change never yanks DOM focus into the group.
61
+ effect(() => {
62
+ const items = this.roving.items();
63
+ if (!items.length) {
64
+ return;
65
+ }
66
+ const radios = this._radios();
67
+ const value = this.value();
68
+ const index = items.findIndex(item => {
69
+ const radio = radios.find(r => r.element === item.element);
70
+ return radio ? !radio.disabled() && radio.value() === value : false;
71
+ });
72
+ if (index >= 0) {
73
+ this.roving.syncActiveIndex(index);
74
+ }
75
+ });
76
+ }
77
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnRadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
78
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.0.5", type: NgnRadioGroup, isStandalone: true, selector: "ngn-radio-group", host: { attributes: { "role": "radiogroup" }, properties: { "attr.aria-label": "label()", "attr.aria-labelledby": "labelledBy()", "attr.aria-orientation": "roving.orientation()", "attr.aria-invalid": "invalid() ? 'true' : null", "attr.aria-disabled": "disabled() ? 'true' : null" } }, providers: [provideSelf(NgnRadioGroup), { provide: NGN_RADIO_GROUP, useExisting: NgnRadioGroup }], usesInheritance: true, hostDirectives: [{ directive: i1.NgnRovingGroup, inputs: ["orientation", "orientation", "rovingWrap", "rovingWrap"] }], ngImport: i0, template: "<ng-content />\n" });
79
+ }
80
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnRadioGroup, decorators: [{
81
+ type: Component,
82
+ args: [{ selector: 'ngn-radio-group', hostDirectives: [{ directive: NgnRovingGroup, inputs: ['orientation', 'rovingWrap'] }], providers: [provideSelf(NgnRadioGroup), { provide: NGN_RADIO_GROUP, useExisting: NgnRadioGroup }], host: {
83
+ role: 'radiogroup',
84
+ '[attr.aria-label]': 'label()',
85
+ '[attr.aria-labelledby]': 'labelledBy()',
86
+ '[attr.aria-orientation]': 'roving.orientation()',
87
+ '[attr.aria-invalid]': "invalid() ? 'true' : null",
88
+ '[attr.aria-disabled]': "disabled() ? 'true' : null",
89
+ }, template: "<ng-content />\n" }]
90
+ }], ctorParameters: () => [] });
91
+
92
+ /**
93
+ * A single radio option. Must be projected inside an `ngn-radio-group`, which
94
+ * owns the selected value — this control only contributes its {@link value}
95
+ * payload and renders the themed dot. The label is authored via content
96
+ * projection (`<ngn-radio [value]="…">Label</ngn-radio>`) with an optional
97
+ * {@link label} input fallback.
98
+ *
99
+ * @category control
100
+ */
101
+ class NgnRadio extends NgnBase {
102
+ theme = this.injectThemeTemplate(radioControlTemplate, {
103
+ root: true,
104
+ });
105
+ /** The payload this radio selects into the enclosing group. */
106
+ value = input.required(/* @ts-ignore */
107
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
108
+ /** Disables this individual option. */
109
+ disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
110
+ /** Optional accessible label; overrides projected content for the a11y name. */
111
+ label = input(null, /* @ts-ignore */
112
+ ...(ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []));
113
+ _group = inject(NGN_RADIO_GROUP);
114
+ _rovingItem = inject(NgnRovingItem);
115
+ /** Whether this radio is the currently selected option in its group. */
116
+ checked = computed(() => this._group.value() === this.value(), /* @ts-ignore */
117
+ ...(ngDevMode ? [{ debugName: "checked" }] : /* istanbul ignore next */ []));
118
+ /** Disabled if this option or the whole group is disabled. */
119
+ effectiveDisabled = computed(() => this.disabled() || this._group.disabled(), /* @ts-ignore */
120
+ ...(ngDevMode ? [{ debugName: "effectiveDisabled" }] : /* istanbul ignore next */ []));
121
+ constructor() {
122
+ super();
123
+ // Feed the roving-focus item so keyboard nav / pointer activation skip a
124
+ // disabled radio.
125
+ effect(() => this._rovingItem.disabled.set(this.effectiveDisabled()));
126
+ const ref = {
127
+ element: this.element.nativeElement,
128
+ value: this.value,
129
+ disabled: this.effectiveDisabled,
130
+ };
131
+ this._group.register(ref);
132
+ inject(DestroyRef).onDestroy(() => this._group.unregister(ref));
133
+ }
134
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnRadio, deps: [], target: i0.ɵɵFactoryTarget.Component });
135
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.0.5", type: NgnRadio, isStandalone: true, selector: "ngn-radio", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "radio" }, properties: { "attr.aria-checked": "checked()", "attr.aria-disabled": "effectiveDisabled() ? 'true' : null", "attr.aria-label": "label()" } }, providers: [provideSelf(NgnRadio)], usesInheritance: true, hostDirectives: [{ directive: i1.NgnRovingItem }], ngImport: i0, template: "<span\n [ptInt]=\"this\"\n [ptClass]=\"{\n circle: true,\n 'circle-checked': checked(),\n }\"\n>\n <span [ptInt]=\"this\" [ptClass]=\"'dot'\"></span>\n</span>\n<span [ptInt]=\"this\" [ptClass]=\"'label'\"><ng-content /></span>\n", dependencies: [{ kind: "directive", type: NgnPt, selector: "[ptInt]", inputs: ["ptInt", "ptClass", "ptDep"] }] });
136
+ }
137
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NgnRadio, decorators: [{
138
+ type: Component,
139
+ args: [{ selector: 'ngn-radio', imports: [NgnPt], hostDirectives: [NgnRovingItem], providers: [provideSelf(NgnRadio)], host: {
140
+ role: 'radio',
141
+ '[attr.aria-checked]': 'checked()',
142
+ '[attr.aria-disabled]': "effectiveDisabled() ? 'true' : null",
143
+ '[attr.aria-label]': 'label()',
144
+ }, template: "<span\n [ptInt]=\"this\"\n [ptClass]=\"{\n circle: true,\n 'circle-checked': checked(),\n }\"\n>\n <span [ptInt]=\"this\" [ptClass]=\"'dot'\"></span>\n</span>\n<span [ptInt]=\"this\" [ptClass]=\"'label'\"><ng-content /></span>\n" }]
145
+ }], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
146
+
147
+ /**
148
+ * Generated bundle index. Do not edit.
149
+ */
150
+
151
+ export { NGN_RADIO_GROUP, NgnRadio, NgnRadioGroup };
152
+ //# sourceMappingURL=ngneers-controls-radio.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngneers-controls-radio.mjs","sources":["../../src/radio/radio-group.token.ts","../../src/radio/radio-group.ts","../../src/radio/radio-group.html","../../src/radio/radio.ts","../../src/radio/radio.html","../../src/radio/ngneers-controls-radio.ts"],"sourcesContent":["import { InjectionToken, type Signal } from '@angular/core';\n\n/**\n * A single radio option registered with its enclosing group. The group keys\n * selection and keyboard coordination off these refs; `element` correlates a\n * roving-focus item back to its payload `value`.\n */\nexport interface NgnRadioRef<V> {\n readonly element: HTMLElement;\n /** The option payload this radio contributes to the group value. */\n readonly value: Signal<V>;\n /** Effective disabled state (own disabled OR the group being disabled). */\n readonly disabled: Signal<boolean>;\n}\n\n/**\n * The slice of the radio group that child `ngn-radio`s consume. Kept as a\n * token + interface (rather than the concrete class) so the child never imports\n * the group component — avoiding a circular dependency between the two files.\n */\nexport interface NgnRadioGroupApi<V> {\n /** The currently selected group value. */\n readonly value: Signal<V>;\n /** Whether the whole group is disabled. */\n readonly disabled: Signal<boolean>;\n /** Whether the group is read-only (navigable, but selection is frozen). */\n readonly readonly: Signal<boolean>;\n register(ref: NgnRadioRef<V>): void;\n unregister(ref: NgnRadioRef<V>): void;\n}\n\nexport const NGN_RADIO_GROUP = new InjectionToken<NgnRadioGroupApi<unknown>>('NGN_RADIO_GROUP');\n","import { Component, DestroyRef, effect, inject, signal } from '@angular/core';\nimport { provideSelf, ValueControlBase } from '@ngneers/controls/base';\nimport { NgnRovingGroup } from '@ngneers/controls/roving-focus';\nimport { radioGroupControlTemplate } from '@ngneers/controls-themes/templates/radio-group';\n\nimport { NGN_RADIO_GROUP, type NgnRadioGroupApi, type NgnRadioRef } from './radio-group.token';\n\n/**\n * A themed radio group. Owns the selected {@link value}; the individual\n * `ngn-radio` children projected inside are presentational and report their\n * payload up through {@link register}.\n *\n * Keyboard handling and roving tab order are delegated to `NgnRovingGroup`\n * (applied as a host directive). Selection follows focus: moving the roving\n * active item (arrows / Home / End / pointer) selects it, matching native\n * radio-group behavior.\n *\n * @category control\n */\n@Component({\n selector: 'ngn-radio-group',\n templateUrl: './radio-group.html',\n hostDirectives: [{ directive: NgnRovingGroup, inputs: ['orientation', 'rovingWrap'] }],\n providers: [provideSelf(NgnRadioGroup), { provide: NGN_RADIO_GROUP, useExisting: NgnRadioGroup }],\n host: {\n role: 'radiogroup',\n '[attr.aria-label]': 'label()',\n '[attr.aria-labelledby]': 'labelledBy()',\n '[attr.aria-orientation]': 'roving.orientation()',\n '[attr.aria-invalid]': \"invalid() ? 'true' : null\",\n '[attr.aria-disabled]': \"disabled() ? 'true' : null\",\n },\n})\nexport class NgnRadioGroup<V>\n extends ValueControlBase<'radioGroup', V>\n implements NgnRadioGroupApi<V>\n{\n protected readonly theme = this.injectThemeTemplate(radioGroupControlTemplate, {\n root: true,\n invalid: () => this.invalid(),\n });\n\n /** The roving-focus host directive that drives keyboard/tab coordination. */\n protected readonly roving = inject(NgnRovingGroup);\n\n private readonly _radios = signal<readonly NgnRadioRef<V>[]>([]);\n\n public register(ref: NgnRadioRef<V>): void {\n this._radios.update(list => (list.includes(ref) ? list : [...list, ref]));\n }\n\n public unregister(ref: NgnRadioRef<V>): void {\n this._radios.update(list => list.filter(r => r !== ref));\n }\n\n constructor() {\n super();\n\n // Selection follows focus: the roving group emits only on genuine\n // navigation/activation (never on mount or plain Tab-in), so wiring value\n // here gives native \"arrow selects\" behavior without spurious writes.\n const sub = this.roving.activeItemChange.subscribe(index => {\n if (this.readonly() || this.disabled()) {\n return;\n }\n const element = this.roving.items()[index]?.element;\n const radio = this._radios().find(r => r.element === element);\n if (!radio || radio.disabled()) {\n return;\n }\n this.value.set(radio.value());\n this.touched.set(true);\n });\n inject(DestroyRef).onDestroy(() => sub.unsubscribe());\n\n // Keep the roving tab stop on the selected radio so Tab-in lands on the\n // checked option (native behavior). Disabled radios are skipped so a\n // selected-but-disabled option never becomes the tab stop. `syncActiveIndex`\n // updates the tab stop silently — no emit, no focus move — so a programmatic\n // `value` change never yanks DOM focus into the group.\n effect(() => {\n const items = this.roving.items();\n if (!items.length) {\n return;\n }\n const radios = this._radios();\n const value = this.value();\n const index = items.findIndex(item => {\n const radio = radios.find(r => r.element === item.element);\n return radio ? !radio.disabled() && radio.value() === value : false;\n });\n if (index >= 0) {\n this.roving.syncActiveIndex(index);\n }\n });\n }\n}\n","<ng-content />\n","import {\n booleanAttribute,\n Component,\n computed,\n DestroyRef,\n effect,\n inject,\n input,\n} from '@angular/core';\nimport { NgnBase, NgnPt, provideSelf } from '@ngneers/controls/base';\nimport { NgnRovingItem } from '@ngneers/controls/roving-focus';\nimport { radioControlTemplate } from '@ngneers/controls-themes/templates/radio';\n\nimport { NGN_RADIO_GROUP } from './radio-group.token';\n\n/**\n * A single radio option. Must be projected inside an `ngn-radio-group`, which\n * owns the selected value — this control only contributes its {@link value}\n * payload and renders the themed dot. The label is authored via content\n * projection (`<ngn-radio [value]=\"…\">Label</ngn-radio>`) with an optional\n * {@link label} input fallback.\n *\n * @category control\n */\n@Component({\n selector: 'ngn-radio',\n templateUrl: './radio.html',\n imports: [NgnPt],\n hostDirectives: [NgnRovingItem],\n providers: [provideSelf(NgnRadio)],\n host: {\n role: 'radio',\n '[attr.aria-checked]': 'checked()',\n '[attr.aria-disabled]': \"effectiveDisabled() ? 'true' : null\",\n '[attr.aria-label]': 'label()',\n },\n})\nexport class NgnRadio<V> extends NgnBase<'radio'> {\n protected readonly theme = this.injectThemeTemplate(radioControlTemplate, {\n root: true,\n });\n\n /** The payload this radio selects into the enclosing group. */\n public readonly value = input.required<V>();\n /** Disables this individual option. */\n public readonly disabled = input(false, { transform: booleanAttribute });\n /** Optional accessible label; overrides projected content for the a11y name. */\n public readonly label = input<string | null>(null);\n\n private readonly _group = inject(NGN_RADIO_GROUP);\n private readonly _rovingItem = inject(NgnRovingItem);\n\n /** Whether this radio is the currently selected option in its group. */\n protected readonly checked = computed(() => this._group.value() === this.value());\n\n /** Disabled if this option or the whole group is disabled. */\n protected readonly effectiveDisabled = computed(() => this.disabled() || this._group.disabled());\n\n constructor() {\n super();\n\n // Feed the roving-focus item so keyboard nav / pointer activation skip a\n // disabled radio.\n effect(() => this._rovingItem.disabled.set(this.effectiveDisabled()));\n\n const ref = {\n element: this.element.nativeElement,\n value: this.value,\n disabled: this.effectiveDisabled,\n };\n this._group.register(ref);\n inject(DestroyRef).onDestroy(() => this._group.unregister(ref));\n }\n}\n","<span\n [ptInt]=\"this\"\n [ptClass]=\"{\n circle: true,\n 'circle-checked': checked(),\n }\"\n>\n <span [ptInt]=\"this\" [ptClass]=\"'dot'\"></span>\n</span>\n<span [ptInt]=\"this\" [ptClass]=\"'label'\"><ng-content /></span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}