ngwr 10.0.0 → 10.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 (238) hide show
  1. package/README.md +9 -8
  2. package/action-sheet/styles/_index.scss +6 -1
  3. package/alert/styles/_index.scss +7 -3
  4. package/badge/styles/_index.scss +1 -1
  5. package/badge/styles/_tag.scss +2 -2
  6. package/border-glow/styles/_index.scss +5 -0
  7. package/breadcrumbs/styles/_index.scss +1 -1
  8. package/button/styles/_index.scss +6 -6
  9. package/calendar/styles/_index.scss +9 -1
  10. package/circular-text/styles/_index.scss +6 -1
  11. package/density/styles/_index.scss +3 -1
  12. package/dialog/styles/_index.scss +1 -2
  13. package/drag-drop/styles/_index.scss +20 -7
  14. package/event-calendar/styles/_index.scss +284 -0
  15. package/falling-text/styles/_index.scss +5 -0
  16. package/fesm2022/ngwr-alert.mjs +8 -3
  17. package/fesm2022/ngwr-alert.mjs.map +1 -1
  18. package/fesm2022/ngwr-back-top.mjs +6 -4
  19. package/fesm2022/ngwr-back-top.mjs.map +1 -1
  20. package/fesm2022/ngwr-border-glow.mjs +12 -9
  21. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  22. package/fesm2022/ngwr-breadcrumbs.mjs +2 -2
  23. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  24. package/fesm2022/ngwr-calendar.mjs +5 -3
  25. package/fesm2022/ngwr-calendar.mjs.map +1 -1
  26. package/fesm2022/ngwr-card.mjs +2 -2
  27. package/fesm2022/ngwr-card.mjs.map +1 -1
  28. package/fesm2022/ngwr-carousel.mjs +17 -4
  29. package/fesm2022/ngwr-carousel.mjs.map +1 -1
  30. package/fesm2022/ngwr-cascader.mjs +31 -4
  31. package/fesm2022/ngwr-cascader.mjs.map +1 -1
  32. package/fesm2022/ngwr-checkbox.mjs +12 -3
  33. package/fesm2022/ngwr-checkbox.mjs.map +1 -1
  34. package/fesm2022/ngwr-circular-text.mjs +2 -2
  35. package/fesm2022/ngwr-circular-text.mjs.map +1 -1
  36. package/fesm2022/ngwr-command-palette.mjs +7 -3
  37. package/fesm2022/ngwr-command-palette.mjs.map +1 -1
  38. package/fesm2022/ngwr-counter.mjs +9 -1
  39. package/fesm2022/ngwr-counter.mjs.map +1 -1
  40. package/fesm2022/ngwr-date-picker.mjs +23 -6
  41. package/fesm2022/ngwr-date-picker.mjs.map +1 -1
  42. package/fesm2022/ngwr-descriptions.mjs +5 -4
  43. package/fesm2022/ngwr-descriptions.mjs.map +1 -1
  44. package/fesm2022/ngwr-drag-drop.mjs +2 -2
  45. package/fesm2022/ngwr-drag-drop.mjs.map +1 -1
  46. package/fesm2022/ngwr-dropdown.mjs +4 -0
  47. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  48. package/fesm2022/ngwr-event-calendar.mjs +723 -0
  49. package/fesm2022/ngwr-event-calendar.mjs.map +1 -0
  50. package/fesm2022/ngwr-falling-text.mjs +2 -2
  51. package/fesm2022/ngwr-falling-text.mjs.map +1 -1
  52. package/fesm2022/ngwr-file-upload.mjs +2 -2
  53. package/fesm2022/ngwr-file-upload.mjs.map +1 -1
  54. package/fesm2022/ngwr-form.mjs +258 -42
  55. package/fesm2022/ngwr-form.mjs.map +1 -1
  56. package/fesm2022/ngwr-fuzzy-text.mjs +15 -1
  57. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  58. package/fesm2022/ngwr-gauge.mjs +8 -3
  59. package/fesm2022/ngwr-gauge.mjs.map +1 -1
  60. package/fesm2022/ngwr-glitch-text.mjs +2 -2
  61. package/fesm2022/ngwr-glitch-text.mjs.map +1 -1
  62. package/fesm2022/ngwr-gradient-text.mjs +2 -2
  63. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  64. package/fesm2022/ngwr-i18n-en.mjs +73 -5
  65. package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
  66. package/fesm2022/ngwr-i18n-ru.mjs +73 -5
  67. package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
  68. package/fesm2022/ngwr-i18n.mjs +20 -2
  69. package/fesm2022/ngwr-i18n.mjs.map +1 -1
  70. package/fesm2022/ngwr-icon.mjs +5 -0
  71. package/fesm2022/ngwr-icon.mjs.map +1 -1
  72. package/fesm2022/ngwr-input-number.mjs +19 -3
  73. package/fesm2022/ngwr-input-number.mjs.map +1 -1
  74. package/fesm2022/ngwr-input.mjs +48 -6
  75. package/fesm2022/ngwr-input.mjs.map +1 -1
  76. package/fesm2022/ngwr-knob.mjs +8 -3
  77. package/fesm2022/ngwr-knob.mjs.map +1 -1
  78. package/fesm2022/ngwr-lightbox.mjs +32 -3
  79. package/fesm2022/ngwr-lightbox.mjs.map +1 -1
  80. package/fesm2022/ngwr-line-chart.mjs +3 -3
  81. package/fesm2022/ngwr-line-chart.mjs.map +1 -1
  82. package/fesm2022/ngwr-list.mjs +2 -2
  83. package/fesm2022/ngwr-list.mjs.map +1 -1
  84. package/fesm2022/ngwr-loading-bar.mjs +2 -2
  85. package/fesm2022/ngwr-loading-bar.mjs.map +1 -1
  86. package/fesm2022/ngwr-marquee.mjs +2 -2
  87. package/fesm2022/ngwr-marquee.mjs.map +1 -1
  88. package/fesm2022/ngwr-media.mjs +3 -0
  89. package/fesm2022/ngwr-media.mjs.map +1 -1
  90. package/fesm2022/ngwr-meter-group.mjs +14 -3
  91. package/fesm2022/ngwr-meter-group.mjs.map +1 -1
  92. package/fesm2022/ngwr-page-header.mjs +2 -2
  93. package/fesm2022/ngwr-page-header.mjs.map +1 -1
  94. package/fesm2022/ngwr-pagination.mjs +1 -1
  95. package/fesm2022/ngwr-pagination.mjs.map +1 -1
  96. package/fesm2022/ngwr-progress.mjs +8 -2
  97. package/fesm2022/ngwr-progress.mjs.map +1 -1
  98. package/fesm2022/ngwr-qr.mjs.map +1 -1
  99. package/fesm2022/ngwr-rating.mjs +6 -4
  100. package/fesm2022/ngwr-rating.mjs.map +1 -1
  101. package/fesm2022/ngwr-result.mjs +19 -12
  102. package/fesm2022/ngwr-result.mjs.map +1 -1
  103. package/fesm2022/ngwr-segmented.mjs +2 -2
  104. package/fesm2022/ngwr-segmented.mjs.map +1 -1
  105. package/fesm2022/ngwr-select.mjs +28 -8
  106. package/fesm2022/ngwr-select.mjs.map +1 -1
  107. package/fesm2022/ngwr-shiny-text.mjs +4 -6
  108. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  109. package/fesm2022/ngwr-speed-dial.mjs +11 -3
  110. package/fesm2022/ngwr-speed-dial.mjs.map +1 -1
  111. package/fesm2022/ngwr-spotlight-card.mjs +2 -2
  112. package/fesm2022/ngwr-spotlight-card.mjs.map +1 -1
  113. package/fesm2022/ngwr-squircle.mjs +1 -1
  114. package/fesm2022/ngwr-squircle.mjs.map +1 -1
  115. package/fesm2022/ngwr-star-border.mjs +2 -2
  116. package/fesm2022/ngwr-star-border.mjs.map +1 -1
  117. package/fesm2022/ngwr-switch.mjs +10 -3
  118. package/fesm2022/ngwr-switch.mjs.map +1 -1
  119. package/fesm2022/ngwr-table.mjs +233 -19
  120. package/fesm2022/ngwr-table.mjs.map +1 -1
  121. package/fesm2022/ngwr-tabs.mjs +21 -4
  122. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  123. package/fesm2022/ngwr-textarea.mjs +20 -4
  124. package/fesm2022/ngwr-textarea.mjs.map +1 -1
  125. package/fesm2022/ngwr-tilt-card.mjs +2 -2
  126. package/fesm2022/ngwr-tilt-card.mjs.map +1 -1
  127. package/fesm2022/ngwr-toolbar.mjs +2 -2
  128. package/fesm2022/ngwr-toolbar.mjs.map +1 -1
  129. package/fesm2022/ngwr-tour.mjs +264 -0
  130. package/fesm2022/ngwr-tour.mjs.map +1 -0
  131. package/fesm2022/ngwr-transfer.mjs +184 -0
  132. package/fesm2022/ngwr-transfer.mjs.map +1 -0
  133. package/fesm2022/ngwr-tree.mjs +23 -6
  134. package/fesm2022/ngwr-tree.mjs.map +1 -1
  135. package/fesm2022/ngwr-typewriter.mjs +2 -2
  136. package/fesm2022/ngwr-typewriter.mjs.map +1 -1
  137. package/fesm2022/ngwr-validators.mjs +118 -2
  138. package/fesm2022/ngwr-validators.mjs.map +1 -1
  139. package/fesm2022/ngwr-version.mjs +2 -2
  140. package/fesm2022/ngwr-version.mjs.map +1 -1
  141. package/fesm2022/ngwr-virtual-scroll.mjs +2 -2
  142. package/fesm2022/ngwr-virtual-scroll.mjs.map +1 -1
  143. package/fesm2022/ngwr-waves.mjs +2 -2
  144. package/fesm2022/ngwr-waves.mjs.map +1 -1
  145. package/form/styles/_index.scss +8 -4
  146. package/glitch-text/styles/_index.scss +5 -0
  147. package/gradient-text/styles/_index.scss +5 -0
  148. package/i18n/en.json +74 -6
  149. package/i18n/ru.json +74 -6
  150. package/icon/styles/_index.scss +5 -0
  151. package/keyboard/styles/_index.scss +5 -0
  152. package/llms-full.txt +123 -62
  153. package/llms.txt +29 -8
  154. package/loading-bar/styles/_index.scss +5 -0
  155. package/marquee/styles/_index.scss +7 -2
  156. package/overlay/styles/_index.scss +5 -0
  157. package/package.json +13 -1
  158. package/popover/styles/_index.scss +48 -12
  159. package/pull-to-refresh/styles/_index.scss +5 -0
  160. package/result/styles/_index.scss +3 -3
  161. package/schematics/icon-set/index.js +80 -34
  162. package/schematics/icon-set/schema.json +8 -3
  163. package/schematics/ng-add/index.js +5 -2
  164. package/schematics/page/templates.js +17 -21
  165. package/schematics/provider/index.js +31 -13
  166. package/schematics/provider/schema.json +40 -24
  167. package/schematics/use/index.js +5 -1
  168. package/schematics/use/schema.json +8 -3
  169. package/schematics/use/symbol-map.json +6 -177
  170. package/segmented/styles/_index.scss +1 -1
  171. package/select/styles/_index.scss +7 -3
  172. package/shiny-text/styles/_index.scss +5 -0
  173. package/sidebar/styles/_index.scss +3 -3
  174. package/speed-dial/styles/_index.scss +12 -1
  175. package/spotlight-card/styles/_index.scss +5 -0
  176. package/squircle/styles/_index.scss +5 -0
  177. package/star-border/styles/_index.scss +5 -0
  178. package/statistic/styles/_index.scss +2 -2
  179. package/stepper/styles/_index.scss +3 -3
  180. package/styles/_animations.scss +6 -0
  181. package/styles.scss +3 -0
  182. package/table/styles/_index.scss +100 -2
  183. package/tabs/styles/_index.scss +1 -1
  184. package/theme/styles/_colors.scss +65 -2
  185. package/theme/styles/_dark.scss +18 -6
  186. package/theme/styles/_focus.scss +2 -8
  187. package/tilt-card/styles/_index.scss +5 -0
  188. package/toast/styles/_index.scss +6 -3
  189. package/tour/styles/_index.scss +63 -0
  190. package/transfer/styles/_index.scss +105 -0
  191. package/types/ngwr-alert.d.ts +4 -1
  192. package/types/ngwr-avatar.d.ts +1 -1
  193. package/types/ngwr-back-top.d.ts +3 -2
  194. package/types/ngwr-badge.d.ts +1 -1
  195. package/types/ngwr-border-glow.d.ts +0 -1
  196. package/types/ngwr-carousel.d.ts +10 -1
  197. package/types/ngwr-cascader.d.ts +12 -1
  198. package/types/ngwr-checkbox.d.ts +9 -1
  199. package/types/ngwr-command-palette.d.ts +4 -1
  200. package/types/ngwr-date-picker.d.ts +9 -1
  201. package/types/ngwr-density.d.ts +1 -1
  202. package/types/ngwr-divider.d.ts +1 -1
  203. package/types/ngwr-event-calendar.d.ts +358 -0
  204. package/types/ngwr-form.d.ts +177 -20
  205. package/types/ngwr-fuzzy-text.d.ts +8 -0
  206. package/types/ngwr-gauge.d.ts +4 -1
  207. package/types/ngwr-i18n.d.ts +15 -0
  208. package/types/ngwr-input-number.d.ts +8 -1
  209. package/types/ngwr-input.d.ts +50 -20
  210. package/types/ngwr-knob.d.ts +4 -1
  211. package/types/ngwr-lightbox.d.ts +7 -1
  212. package/types/ngwr-line-chart.d.ts +1 -1
  213. package/types/ngwr-media.d.ts +1 -1
  214. package/types/ngwr-meter-group.d.ts +9 -1
  215. package/types/ngwr-page-header.d.ts +2 -2
  216. package/types/ngwr-pagination.d.ts +1 -1
  217. package/types/ngwr-progress.d.ts +4 -1
  218. package/types/ngwr-rating.d.ts +3 -2
  219. package/types/ngwr-result.d.ts +12 -6
  220. package/types/ngwr-segmented.d.ts +6 -0
  221. package/types/ngwr-select.d.ts +13 -7
  222. package/types/ngwr-shiny-text.d.ts +2 -4
  223. package/types/ngwr-speed-dial.d.ts +7 -1
  224. package/types/ngwr-squircle.d.ts +1 -1
  225. package/types/ngwr-switch.d.ts +7 -1
  226. package/types/ngwr-table.d.ts +126 -6
  227. package/types/ngwr-tabs.d.ts +1 -4
  228. package/types/ngwr-textarea.d.ts +8 -1
  229. package/types/ngwr-toolbar.d.ts +2 -2
  230. package/types/ngwr-tour.d.ts +132 -0
  231. package/types/ngwr-transfer.d.ts +118 -0
  232. package/types/ngwr-tree.d.ts +10 -2
  233. package/types/ngwr-validators.d.ts +62 -2
  234. package/types/ngwr-version.d.ts +2 -2
  235. package/typewriter/styles/_index.scss +5 -0
  236. package/typography/styles/_index.scss +5 -5
  237. package/virtual-scroll/styles/_index.scss +6 -1
  238. package/waves/styles/_index.scss +5 -0
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-icon.mjs","sources":["../../../projects/lib/icon/tokens/icon.token.ts","../../../projects/lib/icon/icon-registry.ts","../../../projects/lib/icon/icon.ts","../../../projects/lib/icon/utils/validate-icon.ts","../../../projects/lib/icon/providers/provide-wr-icons.ts","../../../projects/lib/icon/svg-icon.ts","../../../projects/lib/icon/ngwr-icon.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport type { WrIconDef } from '../interfaces';\n\n/**\n * Multi-provider token for registering icons with the icon registry.\n *\n * Use {@link provideWrIcons} instead of providing this token directly.\n *\n * @internal\n */\nexport const WR_ICONS = new InjectionToken<readonly WrIconDef[][]>('WR_ICONS');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Injectable, inject } from '@angular/core';\n\nimport type { WrIconDef } from './interfaces';\nimport { WR_ICONS } from './tokens';\n\n/**\n * One link in the icon-registry chain. {@link provideWrIcons} provides an\n * instance alongside its icons, so every injector level that registers icons\n * gets its own link whose parent is the next registering level above it.\n *\n * This exists because Angular does not merge `multi: true` providers across\n * injector levels — an element-level `provideWrIcons()` *replaces* the visible\n * `WR_ICONS` collection rather than adding to it. Reading only the closest\n * contribution silently hid every icon registered further up, which contradicts\n * the \"each call adds to the registry\" contract. Walking the chain restores it\n * for any number of levels.\n *\n * @internal\n */\n@Injectable()\nexport class WrIconRegistry {\n /** The next registering level up, if any. */\n private readonly parent = inject(WrIconRegistry, { skipSelf: true, optional: true });\n\n /** Icons registered at *this* level only. */\n private readonly own = inject(WR_ICONS, { self: true, optional: true }) ?? [];\n\n /**\n * Every icon visible from this level, nearest last so a local registration\n * wins over an identically named one further up.\n */\n resolve(): Map<string, WrIconDef> {\n const map = this.parent?.resolve() ?? new Map<string, WrIconDef>();\n for (const set of this.own) {\n for (const icon of set) map.set(icon.name, icon);\n }\n return map;\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ElementRef, ViewEncapsulation, computed, effect, inject, input, isDevMode } from '@angular/core';\n\nimport { WrIconRegistry } from './icon-registry';\nimport type { WrIconDef, WrIconName } from './interfaces';\n\n/**\n * Renders a registered SVG icon.\n *\n * Icons must be registered via {@link provideWrIcons} before use —\n * either at the application root or on any ancestor component.\n *\n * @example\n * ```html\n * <wr-icon name=\"home\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/icon\n */\n@Component({\n selector: 'wr-icon',\n template: '',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-icon',\n '[attr.data-icon]': 'name()',\n },\n})\nexport class WrIcon {\n readonly name = input.required<WrIconName>();\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /**\n * Every icon visible from this position, walked up the whole chain of\n * registering injector levels.\n *\n * Angular's `inject(WR_ICONS)` returns only the **closest** injector's\n * contribution — `multi` providers are not merged across levels — so a\n * component that registers its own icons used to shadow, not extend, what an\n * ancestor registered. {@link WrIconRegistry} is provided once per\n * registering level and links to its parent, so nesting any number of levels\n * now adds up, with the nearest registration winning a name collision.\n *\n * Optional: with no `provideWrIcons()` anywhere the map is simply empty and\n * every name reports as unregistered.\n */\n private readonly iconRegistry = inject(WrIconRegistry, { optional: true });\n\n private readonly registry = computed<ReadonlyMap<WrIconName, WrIconDef>>(\n () => (this.iconRegistry?.resolve() ?? new Map()) as ReadonlyMap<WrIconName, WrIconDef>\n );\n\n private readonly icon = computed(() => this.registry().get(this.name()));\n\n constructor() {\n effect(() => {\n const icon = this.icon();\n const name = this.name();\n\n if (!icon) {\n if (isDevMode()) {\n // Reported, never thrown. An exception here escapes into\n // `runEffectsInView`, which abandons the remaining effects of the\n // whole view — one unknown name would blank every `<wr-icon>` after\n // it while the console blamed only the first. Error level (not\n // `badgeLog`) so it survives a console filtered to errors.\n // eslint-disable-next-line no-console -- misconfiguration must be visible, but must not throw\n console.error(\n `[NGWR] No icon named \"${name}\" is registered. Did you forget to call provideWrIcons()? ` +\n `If the name IS registered, check the injector level: a component-level provideWrIcons() ` +\n `shadows icons registered on an ancestor component.`\n );\n }\n this.host.nativeElement.innerHTML = '';\n return;\n }\n\n this.host.nativeElement.innerHTML = icon.data;\n });\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrIconDef } from '../interfaces';\n\nconst VIEW_BOX_RE = /<svg\\b[^>]*\\bviewBox\\s*=/i;\nconst SVG_ROOT_RE = /<svg\\b/i;\n\n/**\n * Dev-mode sanity check for a registered icon.\n *\n * Warns about issues that prevent correct rendering — most importantly,\n * a missing `viewBox`, which causes the SVG not to scale to the icon\n * host's size.\n *\n * Production builds drop the call entirely via `isDevMode()` tree-shaking.\n *\n * @internal\n */\nexport function validateIcon(icon: WrIconDef): void {\n if (!SVG_ROOT_RE.test(icon.data)) {\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] Icon \"${icon.name}\" data does not contain an <svg> root element. ` +\n `Custom icons must be valid SVG markup.`\n );\n return;\n }\n\n if (!VIEW_BOX_RE.test(icon.data)) {\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] Icon \"${icon.name}\" has no viewBox attribute — it won't scale ` +\n `to the host size. Add viewBox=\"0 0 W H\" to the <svg> root.`\n );\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type Provider, isDevMode } from '@angular/core';\n\nimport { WrIconRegistry } from '../icon-registry';\nimport type { WrIconDef } from '../interfaces';\nimport { WR_ICONS } from '../tokens';\nimport { validateIcon } from '../utils';\n\n/**\n * Registers a set of icons for use by `<wr-icon>`.\n *\n * Can be called multiple times — each call adds to the registry.\n * Works at both the application root and at the component level,\n * so a feature module or a single component can bring its own icons\n * without polluting the global config.\n *\n * In dev mode, each icon is validated for common issues (missing\n * `viewBox`, malformed root). Validation is dropped from production\n * builds via `isDevMode()` tree-shaking.\n *\n * @example\n * ```ts\n * // App-level registration\n * import { home, user, cog, provideWrIcons } from 'ngwr/icon';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideWrIcons([home, user, cog]),\n * ],\n * };\n * ```\n *\n * @example\n * ```ts\n * // Component-level registration\n * import { logoGithub, logoNpm, provideWrIcons, WrIconDef } from 'ngwr/icon';\n *\n * @Component({\n * selector: 'ngwr-header',\n * imports: [WrIcon],\n * providers: [provideWrIcons([logoGithub, logoNpm])],\n * template: `<wr-icon name=\"logo-github\" />`,\n * })\n * export class HeaderComponent {}\n * ```\n */\nexport function provideWrIcons(icons: WrIconDef[]): Provider[] {\n if (isDevMode()) {\n for (const icon of icons) validateIcon(icon);\n }\n return [\n { provide: WR_ICONS, useValue: icons, multi: true },\n // A registry link per registering level. Angular does not merge `multi`\n // providers across injectors, so without this chain an element-level\n // registration would shadow everything registered above it instead of\n // adding to it.\n WrIconRegistry,\n ];\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrIconDef } from './interfaces';\n\n/**\n * Wrap a raw SVG string in the {@link WrIconDef} envelope. Use this when\n * importing icons from sources that ship full `<svg>` files — Tabler,\n * Phosphor, Heroicons, Iconoir, Radix, Bootstrap Icons, your designer.\n *\n * Pair with a bundler's raw-SVG import (Vite's `?raw`, Webpack's\n * `raw-loader`, esbuild's `--loader:.svg=text`) so the SVG file becomes\n * a string at build time.\n *\n * For sets with a non-SVG shape (Lucide's IconNode tuples, Feather's\n * inner-only SVG), use the dedicated adapter under\n * `ngwr/icon/adapters/<set>` instead.\n *\n * @example\n * ```ts\n * import { svgIcon, provideWrIcons } from 'ngwr/icon';\n * // Vite: the `?raw` suffix returns the file as a string.\n * import plusSvg from '@tabler/icons/icons/plus.svg?raw';\n * import phosphorPlusSvg from '@phosphor-icons/core/assets/regular/plus.svg?raw';\n *\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideWrIcons([\n * svgIcon('plus', plusSvg),\n * svgIcon('plus-phosphor', phosphorPlusSvg),\n * ]),\n * ],\n * });\n * ```\n */\nexport function svgIcon(name: string, svg: string): WrIconDef {\n return { name, data: svg };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-icon.mjs","sources":["../../../projects/lib/icon/tokens/icon.token.ts","../../../projects/lib/icon/icon-registry.ts","../../../projects/lib/icon/icon.ts","../../../projects/lib/icon/utils/validate-icon.ts","../../../projects/lib/icon/providers/provide-wr-icons.ts","../../../projects/lib/icon/svg-icon.ts","../../../projects/lib/icon/ngwr-icon.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { InjectionToken } from '@angular/core';\n\nimport type { WrIconDef } from '../interfaces';\n\n/**\n * Multi-provider token for registering icons with the icon registry.\n *\n * Use {@link provideWrIcons} instead of providing this token directly.\n *\n * @internal\n */\nexport const WR_ICONS = new InjectionToken<readonly WrIconDef[][]>('WR_ICONS');\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Injectable, inject } from '@angular/core';\n\nimport type { WrIconDef } from './interfaces';\nimport { WR_ICONS } from './tokens';\n\n/**\n * One link in the icon-registry chain. {@link provideWrIcons} provides an\n * instance alongside its icons, so every injector level that registers icons\n * gets its own link whose parent is the next registering level above it.\n *\n * This exists because Angular does not merge `multi: true` providers across\n * injector levels — an element-level `provideWrIcons()` *replaces* the visible\n * `WR_ICONS` collection rather than adding to it. Reading only the closest\n * contribution silently hid every icon registered further up, which contradicts\n * the \"each call adds to the registry\" contract. Walking the chain restores it\n * for any number of levels.\n *\n * @internal\n */\n@Injectable()\nexport class WrIconRegistry {\n /** The next registering level up, if any. */\n private readonly parent = inject(WrIconRegistry, { skipSelf: true, optional: true });\n\n /** Icons registered at *this* level only. */\n private readonly own = inject(WR_ICONS, { self: true, optional: true }) ?? [];\n\n /**\n * Every icon visible from this level, nearest last so a local registration\n * wins over an identically named one further up.\n */\n resolve(): Map<string, WrIconDef> {\n const map = this.parent?.resolve() ?? new Map<string, WrIconDef>();\n for (const set of this.own) {\n for (const icon of set) map.set(icon.name, icon);\n }\n return map;\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ElementRef, ViewEncapsulation, computed, effect, inject, input, isDevMode } from '@angular/core';\n\nimport { WrIconRegistry } from './icon-registry';\nimport type { WrIconDef, WrIconName } from './interfaces';\n\n/**\n * Renders a registered SVG icon.\n *\n * Icons must be registered via {@link provideWrIcons} before use —\n * either at the application root or on any ancestor component.\n *\n * @example\n * ```html\n * <wr-icon name=\"home\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/icon\n */\n@Component({\n selector: 'wr-icon',\n template: '',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-icon',\n '[attr.data-icon]': 'name()',\n },\n})\nexport class WrIcon {\n readonly name = input.required<WrIconName>();\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /**\n * Every icon visible from this position, walked up the whole chain of\n * registering injector levels.\n *\n * Angular's `inject(WR_ICONS)` returns only the **closest** injector's\n * contribution — `multi` providers are not merged across levels — so a\n * component that registers its own icons used to shadow, not extend, what an\n * ancestor registered. {@link WrIconRegistry} is provided once per\n * registering level and links to its parent, so nesting any number of levels\n * now adds up, with the nearest registration winning a name collision.\n *\n * Optional: with no `provideWrIcons()` anywhere the map is simply empty and\n * every name reports as unregistered.\n */\n private readonly iconRegistry = inject(WrIconRegistry, { optional: true });\n\n private readonly registry = computed<ReadonlyMap<WrIconName, WrIconDef>>(\n () => (this.iconRegistry?.resolve() ?? new Map()) as ReadonlyMap<WrIconName, WrIconDef>\n );\n\n private readonly icon = computed(() => this.registry().get(this.name()));\n\n constructor() {\n effect(() => {\n const icon = this.icon();\n const name = this.name();\n\n if (!icon) {\n if (isDevMode()) {\n // Reported, never thrown. An exception here escapes into\n // `runEffectsInView`, which abandons the remaining effects of the\n // whole view — one unknown name would blank every `<wr-icon>` after\n // it while the console blamed only the first. Error level (not\n // `badgeLog`) so it survives a console filtered to errors.\n // eslint-disable-next-line no-console -- misconfiguration must be visible, but must not throw\n console.error(\n `[NGWR] No icon named \"${name}\" is registered. Did you forget to call provideWrIcons()? ` +\n `If the name IS registered, check the injector level: a component-level provideWrIcons() ` +\n `shadows icons registered on an ancestor component.`\n );\n }\n this.host.nativeElement.innerHTML = '';\n return;\n }\n\n this.host.nativeElement.innerHTML = icon.data;\n\n // Every hand-written inline SVG in the library carries aria-hidden;\n // registered icons went in without it, so a decorative glyph could be\n // announced — usually as a bare \"graphic\" beside the label it decorates.\n // Consumers that need a name put it on the interactive host instead.\n this.host.nativeElement.querySelector('svg')?.setAttribute('aria-hidden', 'true');\n });\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrIconDef } from '../interfaces';\n\nconst VIEW_BOX_RE = /<svg\\b[^>]*\\bviewBox\\s*=/i;\nconst SVG_ROOT_RE = /<svg\\b/i;\n\n/**\n * Dev-mode sanity check for a registered icon.\n *\n * Warns about issues that prevent correct rendering — most importantly,\n * a missing `viewBox`, which causes the SVG not to scale to the icon\n * host's size.\n *\n * Production builds drop the call entirely via `isDevMode()` tree-shaking.\n *\n * @internal\n */\nexport function validateIcon(icon: WrIconDef): void {\n if (!SVG_ROOT_RE.test(icon.data)) {\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] Icon \"${icon.name}\" data does not contain an <svg> root element. ` +\n `Custom icons must be valid SVG markup.`\n );\n return;\n }\n\n if (!VIEW_BOX_RE.test(icon.data)) {\n // eslint-disable-next-line no-console -- dev-mode validation\n console.warn(\n `[NGWR] Icon \"${icon.name}\" has no viewBox attribute — it won't scale ` +\n `to the host size. Add viewBox=\"0 0 W H\" to the <svg> root.`\n );\n }\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { type Provider, isDevMode } from '@angular/core';\n\nimport { WrIconRegistry } from '../icon-registry';\nimport type { WrIconDef } from '../interfaces';\nimport { WR_ICONS } from '../tokens';\nimport { validateIcon } from '../utils';\n\n/**\n * Registers a set of icons for use by `<wr-icon>`.\n *\n * Can be called multiple times — each call adds to the registry.\n * Works at both the application root and at the component level,\n * so a feature module or a single component can bring its own icons\n * without polluting the global config.\n *\n * In dev mode, each icon is validated for common issues (missing\n * `viewBox`, malformed root). Validation is dropped from production\n * builds via `isDevMode()` tree-shaking.\n *\n * @example\n * ```ts\n * // App-level registration\n * import { home, user, cog, provideWrIcons } from 'ngwr/icon';\n *\n * export const appConfig: ApplicationConfig = {\n * providers: [\n * provideWrIcons([home, user, cog]),\n * ],\n * };\n * ```\n *\n * @example\n * ```ts\n * // Component-level registration\n * import { logoGithub, logoNpm, provideWrIcons, WrIconDef } from 'ngwr/icon';\n *\n * @Component({\n * selector: 'ngwr-header',\n * imports: [WrIcon],\n * providers: [provideWrIcons([logoGithub, logoNpm])],\n * template: `<wr-icon name=\"logo-github\" />`,\n * })\n * export class HeaderComponent {}\n * ```\n */\nexport function provideWrIcons(icons: WrIconDef[]): Provider[] {\n if (isDevMode()) {\n for (const icon of icons) validateIcon(icon);\n }\n return [\n { provide: WR_ICONS, useValue: icons, multi: true },\n // A registry link per registering level. Angular does not merge `multi`\n // providers across injectors, so without this chain an element-level\n // registration would shadow everything registered above it instead of\n // adding to it.\n WrIconRegistry,\n ];\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport type { WrIconDef } from './interfaces';\n\n/**\n * Wrap a raw SVG string in the {@link WrIconDef} envelope. Use this when\n * importing icons from sources that ship full `<svg>` files — Tabler,\n * Phosphor, Heroicons, Iconoir, Radix, Bootstrap Icons, your designer.\n *\n * Pair with a bundler's raw-SVG import (Vite's `?raw`, Webpack's\n * `raw-loader`, esbuild's `--loader:.svg=text`) so the SVG file becomes\n * a string at build time.\n *\n * For sets with a non-SVG shape (Lucide's IconNode tuples, Feather's\n * inner-only SVG), use the dedicated adapter under\n * `ngwr/icon/adapters/<set>` instead.\n *\n * @example\n * ```ts\n * import { svgIcon, provideWrIcons } from 'ngwr/icon';\n * // Vite: the `?raw` suffix returns the file as a string.\n * import plusSvg from '@tabler/icons/icons/plus.svg?raw';\n * import phosphorPlusSvg from '@phosphor-icons/core/assets/regular/plus.svg?raw';\n *\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideWrIcons([\n * svgIcon('plus', plusSvg),\n * svgIcon('plus-phosphor', phosphorPlusSvg),\n * ]),\n * ],\n * });\n * ```\n */\nexport function svgIcon(name: string, svg: string): WrIconDef {\n return { name, data: svg };\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -67,6 +67,22 @@ class WrInputNumber {
67
67
  /** Placeholder shown when the input is empty. */
68
68
  placeholder = input('', /* @ts-ignore */
69
69
  ...(ngDevMode ? [{ debugName: "placeholder" }] : /* istanbul ignore next */ []));
70
+ /**
71
+ * Accessible name for the field. Falls back to the placeholder — inside a
72
+ * `<wr-form-field>` the projected `wrInput` picks up the label's id and needs
73
+ * neither, but standalone the text field has no name at all.
74
+ */
75
+ ariaLabel = input(null, /* @ts-ignore */
76
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
77
+ resolvedAriaLabel = computed(() => {
78
+ // Not `??`: an empty placeholder is no name at all, so it must fall through.
79
+ const explicit = this.ariaLabel();
80
+ if (explicit)
81
+ return explicit;
82
+ const placeholder = this.placeholder();
83
+ return placeholder ? placeholder : null;
84
+ }, /* @ts-ignore */
85
+ ...(ngDevMode ? [{ debugName: "resolvedAriaLabel" }] : /* istanbul ignore next */ []));
70
86
  /** Disable interaction. @default false */
71
87
  disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
72
88
  /** Read-only — values cannot be changed (steppers + typing disabled). @default false */
@@ -207,12 +223,12 @@ class WrInputNumber {
207
223
  return formatter.format(v);
208
224
  }
209
225
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrInputNumber, deps: [], target: i0.ɵɵFactoryTarget.Component });
210
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrInputNumber, isStandalone: true, selector: "wr-input-number", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, decimals: { classPropertyName: "decimals", publicName: "decimals", isSignal: true, isRequired: false, transformFunction: null }, showSteppers: { classPropertyName: "showSteppers", publicName: "showSteppers", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<wr-input-group>\n @if (prefix(); as p) {\n <span wrInputPrefix>{{ p }}</span>\n }\n <input\n #input\n wrInput\n type=\"text\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n @if (suffix(); as s) {\n <span wrInputSuffix>{{ s }}</span>\n }\n @if (showSteppers()) {\n <div class=\"wr-input-number__steppers\" wrInputSuffix>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Increment\"\n [disabled]=\"!interactive() || atMax()\"\n (click)=\"stepBy(1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 5 L4 0 L8 5 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Decrement\"\n [disabled]=\"!interactive() || atMin()\"\n (click)=\"stepBy(-1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 0 L4 5 L8 0 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n </div>\n }\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputPrefix, selector: "[wrInputPrefix]" }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
226
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrInputNumber, isStandalone: true, selector: "wr-input-number", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, decimals: { classPropertyName: "decimals", publicName: "decimals", isSignal: true, isRequired: false, transformFunction: null }, showSteppers: { classPropertyName: "showSteppers", publicName: "showSteppers", isSignal: true, isRequired: false, transformFunction: null }, prefix: { classPropertyName: "prefix", publicName: "prefix", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<wr-input-group>\n @if (prefix(); as p) {\n <span wrInputPrefix>{{ p }}</span>\n }\n <input\n #input\n wrInput\n type=\"text\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n spellcheck=\"false\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n @if (suffix(); as s) {\n <span wrInputSuffix>{{ s }}</span>\n }\n @if (showSteppers()) {\n <div class=\"wr-input-number__steppers\" wrInputSuffix>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Increment\"\n [disabled]=\"!interactive() || atMax()\"\n (click)=\"stepBy(1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 5 L4 0 L8 5 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Decrement\"\n [disabled]=\"!interactive() || atMin()\"\n (click)=\"stepBy(-1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 0 L4 5 L8 0 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n </div>\n }\n</wr-input-group>\n", dependencies: [{ kind: "directive", type: WrInput, selector: "input[wrInput], textarea[wrInput]", inputs: ["wrSize", "rounded"] }, { kind: "component", type: WrInputGroup, selector: "wr-input-group", inputs: ["rounded"] }, { kind: "directive", type: WrInputPrefix, selector: "[wrInputPrefix]" }, { kind: "directive", type: WrInputSuffix, selector: "[wrInputSuffix]" }], encapsulation: i0.ViewEncapsulation.None });
211
227
  }
212
228
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrInputNumber, decorators: [{
213
229
  type: Component,
214
- args: [{ selector: 'wr-input-number', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputPrefix, WrInputSuffix], template: "<wr-input-group>\n @if (prefix(); as p) {\n <span wrInputPrefix>{{ p }}</span>\n }\n <input\n #input\n wrInput\n type=\"text\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n @if (suffix(); as s) {\n <span wrInputSuffix>{{ s }}</span>\n }\n @if (showSteppers()) {\n <div class=\"wr-input-number__steppers\" wrInputSuffix>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Increment\"\n [disabled]=\"!interactive() || atMax()\"\n (click)=\"stepBy(1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 5 L4 0 L8 5 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Decrement\"\n [disabled]=\"!interactive() || atMin()\"\n (click)=\"stepBy(-1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 0 L4 5 L8 0 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n </div>\n }\n</wr-input-group>\n" }]
215
- }], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], decimals: [{ type: i0.Input, args: [{ isSignal: true, alias: "decimals", required: false }] }], showSteppers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSteppers", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
230
+ args: [{ selector: 'wr-input-number', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, imports: [WrInput, WrInputGroup, WrInputPrefix, WrInputSuffix], template: "<wr-input-group>\n @if (prefix(); as p) {\n <span wrInputPrefix>{{ p }}</span>\n }\n <input\n #input\n wrInput\n type=\"text\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n spellcheck=\"false\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n @if (suffix(); as s) {\n <span wrInputSuffix>{{ s }}</span>\n }\n @if (showSteppers()) {\n <div class=\"wr-input-number__steppers\" wrInputSuffix>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Increment\"\n [disabled]=\"!interactive() || atMax()\"\n (click)=\"stepBy(1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 5 L4 0 L8 5 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Decrement\"\n [disabled]=\"!interactive() || atMin()\"\n (click)=\"stepBy(-1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 0 L4 5 L8 0 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n </div>\n }\n</wr-input-group>\n" }]
231
+ }], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], decimals: [{ type: i0.Input, args: [{ isSignal: true, alias: "decimals", required: false }] }], showSteppers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showSteppers", required: false }] }], prefix: [{ type: i0.Input, args: [{ isSignal: true, alias: "prefix", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
216
232
 
217
233
  /**
218
234
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-input-number.mjs","sources":["../../../projects/lib/input-number/input-number.ts","../../../projects/lib/input-number/input-number.html","../../../projects/lib/input-number/ngwr-input-number.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n LOCALE_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { WrInput, WrInputGroup, WrInputPrefix, WrInputSuffix } from 'ngwr/input';\nimport { clamp, round } from 'ngwr/utils';\n\n/** Round to `decimals` places, avoiding common float artefacts (`1.005 → 1.01`). */\n\n/** Resolve the locale's decimal + grouping separators from `Intl.NumberFormat`. */\nfunction resolveSeparators(locale: string): { decimal: string; group: string } {\n const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);\n const decimal = parts.find(p => p.type === 'decimal')?.value ?? '.';\n const group = parts.find(p => p.type === 'group')?.value ?? '';\n return { decimal, group };\n}\n\n/**\n * Numeric input with locale-aware formatting + ▲▼ stepper buttons.\n *\n * A signal-forms native control: it implements `FormValueControl<number | null>`,\n * so `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * Parses leniently while typing (allows partial input like `\"1.\"` or `\"-\"`),\n * re-formats with grouping + fixed decimals on blur.\n *\n * Locale comes from Angular's `LOCALE_ID` — input-number intentionally does\n * NOT depend on `ngwr/date-adapter` so it can be used in date-free apps.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-input-number [formField]=\"form.qty\" [min]=\"0\" [max]=\"100\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-input-number [(value)]=\"price\" [decimals]=\"2\" suffix=\"USD\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/input-number\n */\n@Component({\n selector: 'wr-input-number',\n templateUrl: './input-number.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n imports: [WrInput, WrInputGroup, WrInputPrefix, WrInputSuffix],\n})\nexport class WrInputNumber implements FormValueControl<number | null> {\n /** Minimum allowed value. @default -Infinity */\n readonly min = input<number | undefined>(Number.NEGATIVE_INFINITY, {\n transform: (v: unknown): number => coerceNumberProperty(v, Number.NEGATIVE_INFINITY),\n });\n\n /** Maximum allowed value. @default Infinity */\n readonly max = input<number | undefined>(Number.POSITIVE_INFINITY, {\n transform: (v: unknown): number => coerceNumberProperty(v, Number.POSITIVE_INFINITY),\n });\n\n private readonly minValue = computed(() => this.min() ?? Number.NEGATIVE_INFINITY);\n private readonly maxValue = computed(() => this.max() ?? Number.POSITIVE_INFINITY);\n\n /** Step used by stepper buttons + arrow keys. @default 1 */\n readonly step = input(1, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 1)) });\n\n /** Fixed number of decimals shown on blur. `null` keeps the entered precision. @default null */\n readonly decimals = input<number | null>(null);\n\n /** Render the ▲▼ stepper column. @default true */\n readonly showSteppers = input(true, { transform: coerceBooleanProperty });\n\n /** Optional prefix label (e.g. `\"$\"`). */\n readonly prefix = input<string>('');\n\n /** Optional suffix label (e.g. `\"kg\"`). */\n readonly suffix = input<string>('');\n\n /** Placeholder shown when the input is empty. */\n readonly placeholder = input<string>('');\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Read-only — values cannot be changed (steppers + typing disabled). @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Numeric value (`null` when empty). Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<number | null>(null);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n private readonly locale = inject(LOCALE_ID);\n private readonly separators = resolveSeparators(this.locale);\n\n /** Text currently in the input (may be partial / invalid mid-type). */\n protected readonly text = signal<string>('');\n\n /** Whether the input is focused. While true, the input handlers own `text`. */\n protected readonly focused = signal(false);\n\n protected readonly interactive = computed(() => !this.disabled() && !this.readonly());\n\n protected readonly atMin = computed(() => {\n const v = this.value();\n return v !== null && v <= this.minValue();\n });\n\n protected readonly atMax = computed(() => {\n const v = this.value();\n return v !== null && v >= this.maxValue();\n });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-input-number'];\n if (this.disabled()) parts.push('wr-input-number--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n // Keep the display `text` in sync with external writes to `value` (via\n // `[formField]` / `[(value)]`). While the user is editing, the input\n // handlers own `text`, so skip re-formatting to avoid clobbering partial\n // input (e.g. mid-typed grouping or a value that is still being clamped).\n effect(() => {\n const v = this.value();\n if (this.focused()) return;\n this.text.set(v === null || Number.isNaN(v) ? '' : this.format(this.constrain(v)));\n });\n }\n\n // Template handlers\n\n protected onInput(event: Event): void {\n const raw = (event.target as HTMLInputElement).value;\n this.text.set(raw);\n if (!raw.trim()) {\n this.value.set(null);\n return;\n }\n const parsed = this.parse(raw);\n if (parsed === null) return; // partial input — wait for more\n const next = this.constrain(parsed);\n this.value.set(next);\n }\n\n protected onFocus(): void {\n this.focused.set(true);\n }\n\n protected onBlur(): void {\n // Flipping `focused` false lets the sync effect re-format `text` from the\n // committed `value` (e.g. `\"1.\"` → `\"1\"`, or grouping the final number).\n this.focused.set(false);\n this.touch.emit();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (!this.interactive()) return;\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return;\n event.preventDefault();\n const direction = event.key === 'ArrowUp' ? 1 : -1;\n const multiplier = event.shiftKey ? 10 : 1;\n this.bump(direction * multiplier);\n }\n\n protected stepBy(direction: 1 | -1): void {\n if (!this.interactive()) return;\n this.bump(direction);\n }\n\n // Internals\n\n private bump(units: number): void {\n const stepSize = this.step() || 1;\n const base = this.value() ?? this.fallbackBase();\n const next = this.constrain(base + units * stepSize);\n this.value.set(next);\n this.text.set(this.format(next));\n }\n\n /** Choose a sensible starting point when bumping from `null`. */\n private fallbackBase(): number {\n if (Number.isFinite(this.minValue()) && this.minValue() > 0) return this.minValue();\n if (Number.isFinite(this.maxValue()) && this.maxValue() < 0) return this.maxValue();\n return 0;\n }\n\n private constrain(v: number): number {\n let next = clamp(v, this.minValue(), this.maxValue());\n const d = this.decimals();\n if (d !== null) next = round(next, d);\n return next;\n }\n\n /** Parse a locale-formatted string. Returns `null` for partial / not-yet-numeric input. */\n private parse(raw: string): number | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n // Strip group separators, normalise the decimal separator to `.`.\n let normalised = trimmed;\n if (this.separators.group) {\n normalised = normalised.split(this.separators.group).join('');\n }\n if (this.separators.decimal !== '.') {\n normalised = normalised.split(this.separators.decimal).join('.');\n }\n // Partial inputs we don't want to clobber while the user is still typing:\n // `-`, `-.`, `.`, `1.`, `-1.` etc.\n if (/^-?\\.?$/.test(normalised) || normalised.endsWith('.')) return null;\n const n = Number(normalised);\n return Number.isFinite(n) ? n : null;\n }\n\n /** Format a value using `Intl.NumberFormat` for the active locale. */\n private format(v: number): string {\n const d = this.decimals();\n const formatter = new Intl.NumberFormat(this.locale, {\n minimumFractionDigits: d ?? 0,\n maximumFractionDigits: d ?? 20,\n useGrouping: true,\n });\n return formatter.format(v);\n }\n}\n","<wr-input-group>\n @if (prefix(); as p) {\n <span wrInputPrefix>{{ p }}</span>\n }\n <input\n #input\n wrInput\n type=\"text\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n @if (suffix(); as s) {\n <span wrInputSuffix>{{ s }}</span>\n }\n @if (showSteppers()) {\n <div class=\"wr-input-number__steppers\" wrInputSuffix>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Increment\"\n [disabled]=\"!interactive() || atMax()\"\n (click)=\"stepBy(1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 5 L4 0 L8 5 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Decrement\"\n [disabled]=\"!interactive() || atMin()\"\n (click)=\"stepBy(-1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 0 L4 5 L8 0 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n </div>\n }\n</wr-input-group>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-input-number.mjs","sources":["../../../projects/lib/input-number/input-number.ts","../../../projects/lib/input-number/input-number.html","../../../projects/lib/input-number/ngwr-input-number.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n LOCALE_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n signal,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { WrInput, WrInputGroup, WrInputPrefix, WrInputSuffix } from 'ngwr/input';\nimport { clamp, round } from 'ngwr/utils';\n\n/** Round to `decimals` places, avoiding common float artefacts (`1.005 → 1.01`). */\n\n/** Resolve the locale's decimal + grouping separators from `Intl.NumberFormat`. */\nfunction resolveSeparators(locale: string): { decimal: string; group: string } {\n const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);\n const decimal = parts.find(p => p.type === 'decimal')?.value ?? '.';\n const group = parts.find(p => p.type === 'group')?.value ?? '';\n return { decimal, group };\n}\n\n/**\n * Numeric input with locale-aware formatting + ▲▼ stepper buttons.\n *\n * A signal-forms native control: it implements `FormValueControl<number | null>`,\n * so `[formField]` binds straight to its `value` model — no\n * `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * Parses leniently while typing (allows partial input like `\"1.\"` or `\"-\"`),\n * re-formats with grouping + fixed decimals on blur.\n *\n * Locale comes from Angular's `LOCALE_ID` — input-number intentionally does\n * NOT depend on `ngwr/date-adapter` so it can be used in date-free apps.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-input-number [formField]=\"form.qty\" [min]=\"0\" [max]=\"100\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-input-number [(value)]=\"price\" [decimals]=\"2\" suffix=\"USD\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/input-number\n */\n@Component({\n selector: 'wr-input-number',\n templateUrl: './input-number.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n imports: [WrInput, WrInputGroup, WrInputPrefix, WrInputSuffix],\n})\nexport class WrInputNumber implements FormValueControl<number | null> {\n /** Minimum allowed value. @default -Infinity */\n readonly min = input<number | undefined>(Number.NEGATIVE_INFINITY, {\n transform: (v: unknown): number => coerceNumberProperty(v, Number.NEGATIVE_INFINITY),\n });\n\n /** Maximum allowed value. @default Infinity */\n readonly max = input<number | undefined>(Number.POSITIVE_INFINITY, {\n transform: (v: unknown): number => coerceNumberProperty(v, Number.POSITIVE_INFINITY),\n });\n\n private readonly minValue = computed(() => this.min() ?? Number.NEGATIVE_INFINITY);\n private readonly maxValue = computed(() => this.max() ?? Number.POSITIVE_INFINITY);\n\n /** Step used by stepper buttons + arrow keys. @default 1 */\n readonly step = input(1, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 1)) });\n\n /** Fixed number of decimals shown on blur. `null` keeps the entered precision. @default null */\n readonly decimals = input<number | null>(null);\n\n /** Render the ▲▼ stepper column. @default true */\n readonly showSteppers = input(true, { transform: coerceBooleanProperty });\n\n /** Optional prefix label (e.g. `\"$\"`). */\n readonly prefix = input<string>('');\n\n /** Optional suffix label (e.g. `\"kg\"`). */\n readonly suffix = input<string>('');\n\n /** Placeholder shown when the input is empty. */\n readonly placeholder = input<string>('');\n\n /**\n * Accessible name for the field. Falls back to the placeholder — inside a\n * `<wr-form-field>` the projected `wrInput` picks up the label's id and needs\n * neither, but standalone the text field has no name at all.\n */\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly resolvedAriaLabel = computed(() => {\n // Not `??`: an empty placeholder is no name at all, so it must fall through.\n const explicit = this.ariaLabel();\n if (explicit) return explicit;\n const placeholder = this.placeholder();\n return placeholder ? placeholder : null;\n });\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Read-only — values cannot be changed (steppers + typing disabled). @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Numeric value (`null` when empty). Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<number | null>(null);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n private readonly locale = inject(LOCALE_ID);\n private readonly separators = resolveSeparators(this.locale);\n\n /** Text currently in the input (may be partial / invalid mid-type). */\n protected readonly text = signal<string>('');\n\n /** Whether the input is focused. While true, the input handlers own `text`. */\n protected readonly focused = signal(false);\n\n protected readonly interactive = computed(() => !this.disabled() && !this.readonly());\n\n protected readonly atMin = computed(() => {\n const v = this.value();\n return v !== null && v <= this.minValue();\n });\n\n protected readonly atMax = computed(() => {\n const v = this.value();\n return v !== null && v >= this.maxValue();\n });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-input-number'];\n if (this.disabled()) parts.push('wr-input-number--disabled');\n return parts.join(' ');\n });\n\n constructor() {\n // Keep the display `text` in sync with external writes to `value` (via\n // `[formField]` / `[(value)]`). While the user is editing, the input\n // handlers own `text`, so skip re-formatting to avoid clobbering partial\n // input (e.g. mid-typed grouping or a value that is still being clamped).\n effect(() => {\n const v = this.value();\n if (this.focused()) return;\n this.text.set(v === null || Number.isNaN(v) ? '' : this.format(this.constrain(v)));\n });\n }\n\n // Template handlers\n\n protected onInput(event: Event): void {\n const raw = (event.target as HTMLInputElement).value;\n this.text.set(raw);\n if (!raw.trim()) {\n this.value.set(null);\n return;\n }\n const parsed = this.parse(raw);\n if (parsed === null) return; // partial input — wait for more\n const next = this.constrain(parsed);\n this.value.set(next);\n }\n\n protected onFocus(): void {\n this.focused.set(true);\n }\n\n protected onBlur(): void {\n // Flipping `focused` false lets the sync effect re-format `text` from the\n // committed `value` (e.g. `\"1.\"` → `\"1\"`, or grouping the final number).\n this.focused.set(false);\n this.touch.emit();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (!this.interactive()) return;\n if (event.key !== 'ArrowUp' && event.key !== 'ArrowDown') return;\n event.preventDefault();\n const direction = event.key === 'ArrowUp' ? 1 : -1;\n const multiplier = event.shiftKey ? 10 : 1;\n this.bump(direction * multiplier);\n }\n\n protected stepBy(direction: 1 | -1): void {\n if (!this.interactive()) return;\n this.bump(direction);\n }\n\n // Internals\n\n private bump(units: number): void {\n const stepSize = this.step() || 1;\n const base = this.value() ?? this.fallbackBase();\n const next = this.constrain(base + units * stepSize);\n this.value.set(next);\n this.text.set(this.format(next));\n }\n\n /** Choose a sensible starting point when bumping from `null`. */\n private fallbackBase(): number {\n if (Number.isFinite(this.minValue()) && this.minValue() > 0) return this.minValue();\n if (Number.isFinite(this.maxValue()) && this.maxValue() < 0) return this.maxValue();\n return 0;\n }\n\n private constrain(v: number): number {\n let next = clamp(v, this.minValue(), this.maxValue());\n const d = this.decimals();\n if (d !== null) next = round(next, d);\n return next;\n }\n\n /** Parse a locale-formatted string. Returns `null` for partial / not-yet-numeric input. */\n private parse(raw: string): number | null {\n const trimmed = raw.trim();\n if (!trimmed) return null;\n // Strip group separators, normalise the decimal separator to `.`.\n let normalised = trimmed;\n if (this.separators.group) {\n normalised = normalised.split(this.separators.group).join('');\n }\n if (this.separators.decimal !== '.') {\n normalised = normalised.split(this.separators.decimal).join('.');\n }\n // Partial inputs we don't want to clobber while the user is still typing:\n // `-`, `-.`, `.`, `1.`, `-1.` etc.\n if (/^-?\\.?$/.test(normalised) || normalised.endsWith('.')) return null;\n const n = Number(normalised);\n return Number.isFinite(n) ? n : null;\n }\n\n /** Format a value using `Intl.NumberFormat` for the active locale. */\n private format(v: number): string {\n const d = this.decimals();\n const formatter = new Intl.NumberFormat(this.locale, {\n minimumFractionDigits: d ?? 0,\n maximumFractionDigits: d ?? 20,\n useGrouping: true,\n });\n return formatter.format(v);\n }\n}\n","<wr-input-group>\n @if (prefix(); as p) {\n <span wrInputPrefix>{{ p }}</span>\n }\n <input\n #input\n wrInput\n type=\"text\"\n inputmode=\"decimal\"\n autocomplete=\"off\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n spellcheck=\"false\"\n [value]=\"text()\"\n [placeholder]=\"placeholder()\"\n [disabled]=\"disabled()\"\n [readonly]=\"readonly()\"\n (input)=\"onInput($event)\"\n (focus)=\"onFocus()\"\n (blur)=\"onBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n @if (suffix(); as s) {\n <span wrInputSuffix>{{ s }}</span>\n }\n @if (showSteppers()) {\n <div class=\"wr-input-number__steppers\" wrInputSuffix>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Increment\"\n [disabled]=\"!interactive() || atMax()\"\n (click)=\"stepBy(1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 5 L4 0 L8 5 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n <button\n type=\"button\"\n class=\"wr-input-number__step\"\n tabindex=\"-1\"\n aria-label=\"Decrement\"\n [disabled]=\"!interactive() || atMin()\"\n (click)=\"stepBy(-1)\"\n >\n <svg width=\"10\" height=\"6\" viewBox=\"0 0 8 5\" aria-hidden=\"true\">\n <path d=\"M0 0 L4 5 L8 0 Z\" fill=\"currentColor\" />\n </svg>\n </button>\n </div>\n }\n</wr-input-group>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
2
  import * as i0 from '@angular/core';
3
- import { input, computed, Directive, ViewEncapsulation, Component, signal } from '@angular/core';
3
+ import { inject, ElementRef, computed, input, Directive, ViewEncapsulation, Component, signal } from '@angular/core';
4
+ import { WR_FORM_FIELD } from 'ngwr/form';
5
+ import { useI18nText } from 'ngwr/i18n';
4
6
 
5
7
  /**
6
8
  * @license
@@ -30,6 +32,33 @@ import { input, computed, Directive, ViewEncapsulation, Component, signal } from
30
32
  * @see https://ngwr.dev/reference/components/input
31
33
  */
32
34
  class WrInput {
35
+ host = inject(ElementRef);
36
+ field = inject(WR_FORM_FIELD, { optional: true });
37
+ /**
38
+ * Read once, at construction: a static `id=""` in the template is already on
39
+ * the element by the time a directive is instantiated, and it must win over
40
+ * the field's generated one.
41
+ */
42
+ ownId = this.host.nativeElement.getAttribute('id');
43
+ /**
44
+ * Adopts the surrounding `<wr-form-field>`'s `controlId`, so the label it
45
+ * already rendered actually points at this element. Without this the `for`
46
+ * referenced an id that existed nowhere and the input had no label at all.
47
+ */
48
+ resolvedId = computed(() => this.ownId ?? this.field?.controlId() ?? null, /* @ts-ignore */
49
+ ...(ngDevMode ? [{ debugName: "resolvedId" }] : /* istanbul ignore next */ []));
50
+ /**
51
+ * Announced state, taken from the surrounding `<wr-form-field>`.
52
+ *
53
+ * The field renders the message but cannot reach the projected control, so
54
+ * the control reads back: without this the error is visible on screen and
55
+ * invisible to a screen reader, which never learns the field is invalid or
56
+ * what the message says.
57
+ */
58
+ ariaInvalid = computed(() => (this.field?.describedBy() ? 'true' : null), /* @ts-ignore */
59
+ ...(ngDevMode ? [{ debugName: "ariaInvalid" }] : /* istanbul ignore next */ []));
60
+ describedBy = computed(() => this.field?.describedBy() ?? null, /* @ts-ignore */
61
+ ...(ngDevMode ? [{ debugName: "describedBy" }] : /* istanbul ignore next */ []));
33
62
  /**
34
63
  * Control size. Named `wrSize` (not `size`) so it never clashes with the
35
64
  * native `<input size>` attribute. @default 'md'
@@ -49,13 +78,18 @@ class WrInput {
49
78
  }, /* @ts-ignore */
50
79
  ...(ngDevMode ? [{ debugName: "classes" }] : /* istanbul ignore next */ []));
51
80
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
52
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.0", type: WrInput, isStandalone: true, selector: "input[wrInput], textarea[wrInput]", inputs: { wrSize: { classPropertyName: "wrSize", publicName: "wrSize", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()" } }, ngImport: i0 });
81
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.1.0", type: WrInput, isStandalone: true, selector: "input[wrInput], textarea[wrInput]", inputs: { wrSize: { classPropertyName: "wrSize", publicName: "wrSize", isSignal: true, isRequired: false, transformFunction: null }, rounded: { classPropertyName: "rounded", publicName: "rounded", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "classes()", "attr.id": "resolvedId()", "attr.aria-invalid": "ariaInvalid()", "attr.aria-describedby": "describedBy()" } }, ngImport: i0 });
53
82
  }
54
83
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrInput, decorators: [{
55
84
  type: Directive,
56
85
  args: [{
57
86
  selector: 'input[wrInput], textarea[wrInput]',
58
- host: { '[class]': 'classes()' },
87
+ host: {
88
+ '[class]': 'classes()',
89
+ '[attr.id]': 'resolvedId()',
90
+ '[attr.aria-invalid]': 'ariaInvalid()',
91
+ '[attr.aria-describedby]': 'describedBy()',
92
+ },
59
93
  }]
60
94
  }], propDecorators: { wrSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "wrSize", required: false }] }], rounded: [{ type: i0.Input, args: [{ isSignal: true, alias: "rounded", required: false }] }] } });
61
95
 
@@ -195,7 +229,15 @@ class WrPasswordToggle {
195
229
  ...(ngDevMode ? [{ debugName: "for" }] : /* istanbul ignore next */ []));
196
230
  revealed = signal(false, /* @ts-ignore */
197
231
  ...(ngDevMode ? [{ debugName: "revealed" }] : /* istanbul ignore next */ []));
198
- ariaLabel = computed(() => (this.revealed() ? 'Hide password' : 'Show password'), /* @ts-ignore */
232
+ /** Accessible name while the password is hidden. Falls back to `input.showPassword`. */
233
+ showLabel = input(null, /* @ts-ignore */
234
+ ...(ngDevMode ? [{ debugName: "showLabel" }] : /* istanbul ignore next */ []));
235
+ /** Accessible name while the password is revealed. Falls back to `input.hidePassword`. */
236
+ hideLabel = input(null, /* @ts-ignore */
237
+ ...(ngDevMode ? [{ debugName: "hideLabel" }] : /* istanbul ignore next */ []));
238
+ resolvedShowLabel = useI18nText(this.showLabel, 'input.showPassword', 'Show password');
239
+ resolvedHideLabel = useI18nText(this.hideLabel, 'input.hidePassword', 'Hide password');
240
+ ariaLabel = computed(() => this.revealed() ? this.resolvedHideLabel() : this.resolvedShowLabel(), /* @ts-ignore */
199
241
  ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
200
242
  toggle() {
201
243
  const input = this.for();
@@ -204,12 +246,12 @@ class WrPasswordToggle {
204
246
  this.revealed.set(next === 'text');
205
247
  }
206
248
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrPasswordToggle, deps: [], target: i0.ɵɵFactoryTarget.Component });
207
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrPasswordToggle, isStandalone: true, selector: "wr-password-toggle", inputs: { for: { classPropertyName: "for", publicName: "for", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"wr-input-group__toggle\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-pressed]=\"revealed()\"\n (click)=\"toggle()\"\n>\n @if (revealed()) {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n } @else {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n }\n</button>\n", encapsulation: i0.ViewEncapsulation.None });
249
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrPasswordToggle, isStandalone: true, selector: "wr-password-toggle", inputs: { for: { classPropertyName: "for", publicName: "for", isSignal: true, isRequired: true, transformFunction: null }, showLabel: { classPropertyName: "showLabel", publicName: "showLabel", isSignal: true, isRequired: false, transformFunction: null }, hideLabel: { classPropertyName: "hideLabel", publicName: "hideLabel", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: "<button\n type=\"button\"\n class=\"wr-input-group__toggle\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-pressed]=\"revealed()\"\n (click)=\"toggle()\"\n>\n @if (revealed()) {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n } @else {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n }\n</button>\n", encapsulation: i0.ViewEncapsulation.None });
208
250
  }
209
251
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrPasswordToggle, decorators: [{
210
252
  type: Component,
211
253
  args: [{ selector: 'wr-password-toggle', encapsulation: ViewEncapsulation.None, template: "<button\n type=\"button\"\n class=\"wr-input-group__toggle\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-pressed]=\"revealed()\"\n (click)=\"toggle()\"\n>\n @if (revealed()) {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n } @else {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n }\n</button>\n" }]
212
- }], propDecorators: { for: [{ type: i0.Input, args: [{ isSignal: true, alias: "for", required: true }] }] } });
254
+ }], propDecorators: { for: [{ type: i0.Input, args: [{ isSignal: true, alias: "for", required: true }] }], showLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "showLabel", required: false }] }], hideLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideLabel", required: false }] }] } });
213
255
 
214
256
  /**
215
257
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-input.mjs","sources":["../../../projects/lib/input/directives/wr-input.ts","../../../projects/lib/input/directives/wr-input-prefix.ts","../../../projects/lib/input/directives/wr-input-suffix.ts","../../../projects/lib/input/input-group.ts","../../../projects/lib/input/password-toggle.ts","../../../projects/lib/input/password-toggle.html","../../../projects/lib/input/ngwr-input.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Directive, computed, input } from '@angular/core';\n\nimport type { WrInputSize } from '../interfaces';\n\n/**\n * Applies NGWR input styling to a native `<input>` element.\n *\n * Because this is an attribute directive on the real `<input>` (not a wrapper\n * component), any other directive that targets `input` — `[(ngModel)]`,\n * `[formControl]`, validators, third-party libraries like `ngx-mask` — composes\n * naturally on the same element.\n *\n * @example\n * ```html\n * <input wrInput [(ngModel)]=\"name\" placeholder=\"Your name\" />\n *\n * <!-- Works with ngx-mask, validators, etc. -->\n * <input wrInput [(ngModel)]=\"phone\" mask=\"(000) 000-0000\" />\n * ```\n *\n * For prefix / suffix / password-toggle layouts, wrap the input in\n * `<wr-input-group>`.\n *\n * @see https://ngwr.dev/reference/components/input\n */\n@Directive({\n selector: 'input[wrInput], textarea[wrInput]',\n host: { '[class]': 'classes()' },\n})\nexport class WrInput {\n /**\n * Control size. Named `wrSize` (not `size`) so it never clashes with the\n * native `<input size>` attribute. @default 'md'\n */\n readonly wrSize = input<WrInputSize>('md');\n\n /** Pill-shaped corners. @default false */\n readonly rounded = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-input'];\n const size = this.wrSize();\n if (size !== 'md') parts.push(`wr-input--${size}`);\n if (this.rounded()) parts.push('wr-input--rounded');\n return parts.join(' ');\n });\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n/**\n * Marks an element as the **left** decoration inside `<wr-input-group>`.\n * Adds the `.wr-input-group__affix` class so the group's layout flexes it\n * to the input's left edge.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <span wrInputPrefix>$</span>\n * <input wrInput [(ngModel)]=\"amount\" type=\"number\" />\n * </wr-input-group>\n * ```\n */\n@Directive({\n selector: '[wrInputPrefix]',\n host: { class: 'wr-input-group__affix wr-input-group__affix--prefix' },\n})\nexport class WrInputPrefix {}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n/**\n * Marks an element as the **right** decoration inside `<wr-input-group>`.\n * Adds the `.wr-input-group__affix` class so the group's layout flexes it\n * to the input's right edge.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <input wrInput [(ngModel)]=\"amount\" type=\"number\" />\n * <span wrInputSuffix>USD</span>\n * </wr-input-group>\n * ```\n */\n@Directive({\n selector: '[wrInputSuffix]',\n host: { class: 'wr-input-group__affix wr-input-group__affix--suffix' },\n})\nexport class WrInputSuffix {}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\n/**\n * Container for `<input wrInput>` + `[wrInputPrefix]` / `[wrInputSuffix]` /\n * `<wr-password-toggle>` siblings. Renders the border and focus ring; the\n * inner native input drops its own border so it visually melts into the\n * group.\n *\n * Pure layout — no signals shared with the inner directive, focus styling is\n * driven entirely by `:focus-within` so any focusable child counts.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <span wrInputPrefix>$</span>\n * <input wrInput [(ngModel)]=\"amount\" type=\"number\" />\n * <span wrInputSuffix>USD</span>\n * </wr-input-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/input\n */\n@Component({\n selector: 'wr-input-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrInputGroup {\n /** Pill-shaped corners. @default false */\n readonly rounded = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-input-group'];\n if (this.rounded()) parts.push('wr-input-group--rounded');\n return parts.join(' ');\n });\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, computed, input, signal } from '@angular/core';\n\n/**\n * Self-contained eye-toggle button. Flips the linked `<input>`'s `type`\n * attribute between `password` and `text`. Drop it inside an\n * `<wr-input-group>` next to a password input.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <input wrInput type=\"password\" [(ngModel)]=\"pw\" #pwInput />\n * <wr-password-toggle [for]=\"pwInput\" />\n * </wr-input-group>\n * ```\n */\n@Component({\n selector: 'wr-password-toggle',\n templateUrl: './password-toggle.html',\n encapsulation: ViewEncapsulation.None,\n})\nexport class WrPasswordToggle {\n /** Reference to the linked password input. */\n readonly for = input.required<HTMLInputElement>();\n\n protected readonly revealed = signal(false);\n\n protected readonly ariaLabel = computed(() => (this.revealed() ? 'Hide password' : 'Show password'));\n\n protected toggle(): void {\n const input = this.for();\n const next = input.type === 'password' ? 'text' : 'password';\n input.type = next;\n this.revealed.set(next === 'text');\n }\n}\n","<button\n type=\"button\"\n class=\"wr-input-group__toggle\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-pressed]=\"revealed()\"\n (click)=\"toggle()\"\n>\n @if (revealed()) {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n } @else {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n }\n</button>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-input.mjs","sources":["../../../projects/lib/input/directives/wr-input.ts","../../../projects/lib/input/directives/wr-input-prefix.ts","../../../projects/lib/input/directives/wr-input-suffix.ts","../../../projects/lib/input/input-group.ts","../../../projects/lib/input/password-toggle.ts","../../../projects/lib/input/password-toggle.html","../../../projects/lib/input/ngwr-input.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Directive, ElementRef, computed, inject, input } from '@angular/core';\n\nimport { WR_FORM_FIELD } from 'ngwr/form';\n\nimport type { WrInputSize } from '../interfaces';\n\n/**\n * Applies NGWR input styling to a native `<input>` element.\n *\n * Because this is an attribute directive on the real `<input>` (not a wrapper\n * component), any other directive that targets `input` — `[(ngModel)]`,\n * `[formControl]`, validators, third-party libraries like `ngx-mask` — composes\n * naturally on the same element.\n *\n * @example\n * ```html\n * <input wrInput [(ngModel)]=\"name\" placeholder=\"Your name\" />\n *\n * <!-- Works with ngx-mask, validators, etc. -->\n * <input wrInput [(ngModel)]=\"phone\" mask=\"(000) 000-0000\" />\n * ```\n *\n * For prefix / suffix / password-toggle layouts, wrap the input in\n * `<wr-input-group>`.\n *\n * @see https://ngwr.dev/reference/components/input\n */\n@Directive({\n selector: 'input[wrInput], textarea[wrInput]',\n host: {\n '[class]': 'classes()',\n '[attr.id]': 'resolvedId()',\n '[attr.aria-invalid]': 'ariaInvalid()',\n '[attr.aria-describedby]': 'describedBy()',\n },\n})\nexport class WrInput {\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly field = inject(WR_FORM_FIELD, { optional: true });\n\n /**\n * Read once, at construction: a static `id=\"\"` in the template is already on\n * the element by the time a directive is instantiated, and it must win over\n * the field's generated one.\n */\n private readonly ownId = this.host.nativeElement.getAttribute('id');\n\n /**\n * Adopts the surrounding `<wr-form-field>`'s `controlId`, so the label it\n * already rendered actually points at this element. Without this the `for`\n * referenced an id that existed nowhere and the input had no label at all.\n */\n protected readonly resolvedId = computed(() => this.ownId ?? this.field?.controlId() ?? null);\n\n /**\n * Announced state, taken from the surrounding `<wr-form-field>`.\n *\n * The field renders the message but cannot reach the projected control, so\n * the control reads back: without this the error is visible on screen and\n * invisible to a screen reader, which never learns the field is invalid or\n * what the message says.\n */\n protected readonly ariaInvalid = computed(() => (this.field?.describedBy() ? 'true' : null));\n protected readonly describedBy = computed(() => this.field?.describedBy() ?? null);\n\n /**\n * Control size. Named `wrSize` (not `size`) so it never clashes with the\n * native `<input size>` attribute. @default 'md'\n */\n readonly wrSize = input<WrInputSize>('md');\n\n /** Pill-shaped corners. @default false */\n readonly rounded = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-input'];\n const size = this.wrSize();\n if (size !== 'md') parts.push(`wr-input--${size}`);\n if (this.rounded()) parts.push('wr-input--rounded');\n return parts.join(' ');\n });\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n/**\n * Marks an element as the **left** decoration inside `<wr-input-group>`.\n * Adds the `.wr-input-group__affix` class so the group's layout flexes it\n * to the input's left edge.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <span wrInputPrefix>$</span>\n * <input wrInput [(ngModel)]=\"amount\" type=\"number\" />\n * </wr-input-group>\n * ```\n */\n@Directive({\n selector: '[wrInputPrefix]',\n host: { class: 'wr-input-group__affix wr-input-group__affix--prefix' },\n})\nexport class WrInputPrefix {}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Directive } from '@angular/core';\n\n/**\n * Marks an element as the **right** decoration inside `<wr-input-group>`.\n * Adds the `.wr-input-group__affix` class so the group's layout flexes it\n * to the input's right edge.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <input wrInput [(ngModel)]=\"amount\" type=\"number\" />\n * <span wrInputSuffix>USD</span>\n * </wr-input-group>\n * ```\n */\n@Directive({\n selector: '[wrInputSuffix]',\n host: { class: 'wr-input-group__affix wr-input-group__affix--suffix' },\n})\nexport class WrInputSuffix {}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\n/**\n * Container for `<input wrInput>` + `[wrInputPrefix]` / `[wrInputSuffix]` /\n * `<wr-password-toggle>` siblings. Renders the border and focus ring; the\n * inner native input drops its own border so it visually melts into the\n * group.\n *\n * Pure layout — no signals shared with the inner directive, focus styling is\n * driven entirely by `:focus-within` so any focusable child counts.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <span wrInputPrefix>$</span>\n * <input wrInput [(ngModel)]=\"amount\" type=\"number\" />\n * <span wrInputSuffix>USD</span>\n * </wr-input-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/input\n */\n@Component({\n selector: 'wr-input-group',\n template: '<ng-content />',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrInputGroup {\n /** Pill-shaped corners. @default false */\n readonly rounded = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-input-group'];\n if (this.rounded()) parts.push('wr-input-group--rounded');\n return parts.join(' ');\n });\n}\n","/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { Component, ViewEncapsulation, computed, input, signal } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\n/**\n * Self-contained eye-toggle button. Flips the linked `<input>`'s `type`\n * attribute between `password` and `text`. Drop it inside an\n * `<wr-input-group>` next to a password input.\n *\n * @example\n * ```html\n * <wr-input-group>\n * <input wrInput type=\"password\" [(ngModel)]=\"pw\" #pwInput />\n * <wr-password-toggle [for]=\"pwInput\" />\n * </wr-input-group>\n * ```\n */\n@Component({\n selector: 'wr-password-toggle',\n templateUrl: './password-toggle.html',\n encapsulation: ViewEncapsulation.None,\n})\nexport class WrPasswordToggle {\n /** Reference to the linked password input. */\n readonly for = input.required<HTMLInputElement>();\n\n protected readonly revealed = signal(false);\n\n /** Accessible name while the password is hidden. Falls back to `input.showPassword`. */\n readonly showLabel = input<string | null>(null);\n\n /** Accessible name while the password is revealed. Falls back to `input.hidePassword`. */\n readonly hideLabel = input<string | null>(null);\n\n private readonly resolvedShowLabel = useI18nText(this.showLabel, 'input.showPassword', 'Show password');\n private readonly resolvedHideLabel = useI18nText(this.hideLabel, 'input.hidePassword', 'Hide password');\n\n protected readonly ariaLabel = computed(() =>\n this.revealed() ? this.resolvedHideLabel() : this.resolvedShowLabel()\n );\n\n protected toggle(): void {\n const input = this.for();\n const next = input.type === 'password' ? 'text' : 'password';\n input.type = next;\n this.revealed.set(next === 'text');\n }\n}\n","<button\n type=\"button\"\n class=\"wr-input-group__toggle\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-pressed]=\"revealed()\"\n (click)=\"toggle()\"\n>\n @if (revealed()) {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49\" />\n <path d=\"M14.084 14.158a3 3 0 0 1-4.242-4.242\" />\n <path d=\"M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143\" />\n <path d=\"m2 2 20 20\" />\n </svg>\n } @else {\n <svg\n class=\"wr-icon__svg\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n }\n</button>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { coerceNumberProperty, coerceBooleanProperty } from '@angular/cdk/coercion';
2
2
  import * as i0 from '@angular/core';
3
3
  import { input, computed, model, output, inject, ElementRef, effect, ViewEncapsulation, Component } from '@angular/core';
4
+ import { useI18nText } from 'ngwr/i18n';
4
5
  import { clamp } from 'ngwr/utils';
5
6
 
6
7
  /**
@@ -32,6 +33,10 @@ const ARC_SWEEP = ARC_END - ARC_START;
32
33
  * @see https://ngwr.dev/reference/components/knob
33
34
  */
34
35
  class WrKnob {
36
+ /** Accessible name — the role needs one. Falls back to `knob.label`. */
37
+ ariaLabel = input(null, /* @ts-ignore */
38
+ ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
39
+ resolvedAriaLabel = useI18nText(this.ariaLabel, 'knob.label', 'Value');
35
40
  /** Minimum allowed value. @default 0 */
36
41
  min = input(0, { ...(ngDevMode ? { debugName: "min" } : /* istanbul ignore next */ {}), transform: (v) => coerceNumberProperty(v, 0) });
37
42
  /** Maximum allowed value. @default 100 */
@@ -201,12 +206,12 @@ class WrKnob {
201
206
  return `M ${sx} ${sy} A ${r} ${r} 0 ${largeArc} 1 ${ex} ${ey}`;
202
207
  }
203
208
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrKnob, deps: [], target: i0.ɵɵFactoryTarget.Component });
204
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrKnob, isStandalone: true, selector: "wr-knob", inputs: { min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, trackColor: { classPropertyName: "trackColor", publicName: "trackColor", isSignal: true, isRequired: false, transformFunction: null }, valueColor: { classPropertyName: "valueColor", publicName: "valueColor", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div\n class=\"wr-knob__surface\"\n role=\"slider\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n <path\n class=\"wr-knob__track\"\n [attr.d]=\"trackPath()\"\n [attr.stroke]=\"trackColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <path\n class=\"wr-knob__value\"\n [attr.d]=\"valuePath()\"\n [attr.stroke]=\"valueColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <circle\n class=\"wr-knob__handle\"\n [attr.cx]=\"handlePos().x\"\n [attr.cy]=\"handlePos().y\"\n [attr.r]=\"strokeWidth() / 2\"\n [attr.fill]=\"valueColor()\"\n />\n </svg>\n @if (showValue()) {\n <div class=\"wr-knob__text\">\n {{ value() }}<span class=\"wr-knob__suffix\">{{ suffix() }}</span>\n </div>\n }\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
209
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: WrKnob, isStandalone: true, selector: "wr-knob", inputs: { ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, step: { classPropertyName: "step", publicName: "step", isSignal: true, isRequired: false, transformFunction: null }, size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, strokeWidth: { classPropertyName: "strokeWidth", publicName: "strokeWidth", isSignal: true, isRequired: false, transformFunction: null }, trackColor: { classPropertyName: "trackColor", publicName: "trackColor", isSignal: true, isRequired: false, transformFunction: null }, valueColor: { classPropertyName: "valueColor", publicName: "valueColor", isSignal: true, isRequired: false, transformFunction: null }, showValue: { classPropertyName: "showValue", publicName: "showValue", isSignal: true, isRequired: false, transformFunction: null }, suffix: { classPropertyName: "suffix", publicName: "suffix", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touch: "touch" }, host: { properties: { "class": "classes()" } }, ngImport: i0, template: "<div\n class=\"wr-knob__surface\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n <path\n class=\"wr-knob__track\"\n [attr.d]=\"trackPath()\"\n [attr.stroke]=\"trackColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <path\n class=\"wr-knob__value\"\n [attr.d]=\"valuePath()\"\n [attr.stroke]=\"valueColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <circle\n class=\"wr-knob__handle\"\n [attr.cx]=\"handlePos().x\"\n [attr.cy]=\"handlePos().y\"\n [attr.r]=\"strokeWidth() / 2\"\n [attr.fill]=\"valueColor()\"\n />\n </svg>\n @if (showValue()) {\n <div class=\"wr-knob__text\">\n {{ value() }}<span class=\"wr-knob__suffix\">{{ suffix() }}</span>\n </div>\n }\n</div>\n", encapsulation: i0.ViewEncapsulation.None });
205
210
  }
206
211
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: WrKnob, decorators: [{
207
212
  type: Component,
208
- args: [{ selector: 'wr-knob', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div\n class=\"wr-knob__surface\"\n role=\"slider\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n <path\n class=\"wr-knob__track\"\n [attr.d]=\"trackPath()\"\n [attr.stroke]=\"trackColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <path\n class=\"wr-knob__value\"\n [attr.d]=\"valuePath()\"\n [attr.stroke]=\"valueColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <circle\n class=\"wr-knob__handle\"\n [attr.cx]=\"handlePos().x\"\n [attr.cy]=\"handlePos().y\"\n [attr.r]=\"strokeWidth() / 2\"\n [attr.fill]=\"valueColor()\"\n />\n </svg>\n @if (showValue()) {\n <div class=\"wr-knob__text\">\n {{ value() }}<span class=\"wr-knob__suffix\">{{ suffix() }}</span>\n </div>\n }\n</div>\n" }]
209
- }], ctorParameters: () => [], propDecorators: { min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], trackColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackColor", required: false }] }], valueColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueColor", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
213
+ args: [{ selector: 'wr-knob', encapsulation: ViewEncapsulation.None, host: { '[class]': 'classes()' }, template: "<div\n class=\"wr-knob__surface\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n <path\n class=\"wr-knob__track\"\n [attr.d]=\"trackPath()\"\n [attr.stroke]=\"trackColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <path\n class=\"wr-knob__value\"\n [attr.d]=\"valuePath()\"\n [attr.stroke]=\"valueColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <circle\n class=\"wr-knob__handle\"\n [attr.cx]=\"handlePos().x\"\n [attr.cy]=\"handlePos().y\"\n [attr.r]=\"strokeWidth() / 2\"\n [attr.fill]=\"valueColor()\"\n />\n </svg>\n @if (showValue()) {\n <div class=\"wr-knob__text\">\n {{ value() }}<span class=\"wr-knob__suffix\">{{ suffix() }}</span>\n </div>\n }\n</div>\n" }]
214
+ }], ctorParameters: () => [], propDecorators: { ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], step: [{ type: i0.Input, args: [{ isSignal: true, alias: "step", required: false }] }], size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], strokeWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "strokeWidth", required: false }] }], trackColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "trackColor", required: false }] }], valueColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueColor", required: false }] }], showValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValue", required: false }] }], suffix: [{ type: i0.Input, args: [{ isSignal: true, alias: "suffix", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
210
215
 
211
216
  /**
212
217
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-knob.mjs","sources":["../../../projects/lib/knob/knob.ts","../../../projects/lib/knob/knob.html","../../../projects/lib/knob/ngwr-knob.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { clamp } from 'ngwr/utils';\n\nconst ARC_START = -135; // 7 o'clock\nconst ARC_END = 135; // 5 o'clock — 270° sweep total\nconst ARC_SWEEP = ARC_END - ARC_START;\n\n/**\n * Radial dial input. A signal-forms native control: it implements\n * `FormValueControl<number>`, so `[formField]` binds straight to its `value`\n * model — no `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * The value is clamped to `[min, max]`. Drag the indicator around the dial or\n * use ←→ / ↑↓ to step.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-knob [formField]=\"form.volume\" [min]=\"0\" [max]=\"100\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-knob [(value)]=\"vol\" suffix=\"%\" valueColor=\"var(--wr-color-success)\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/knob\n */\n@Component({\n selector: 'wr-knob',\n templateUrl: './knob.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrKnob implements FormValueControl<number> {\n /** Minimum allowed value. @default 0 */\n readonly min = input<number | undefined>(0, { transform: (v: unknown): number => coerceNumberProperty(v, 0) });\n\n /** Maximum allowed value. @default 100 */\n readonly max = input<number | undefined>(100, { transform: (v: unknown): number => coerceNumberProperty(v, 100) });\n\n private readonly minValue = computed(() => this.min() ?? 0);\n private readonly maxValue = computed(() => this.max() ?? 100);\n\n /** Step granularity. @default 1 */\n readonly step = input(1, { transform: (v: unknown): number => Math.max(0.0001, coerceNumberProperty(v, 1)) });\n\n /** Dial diameter in CSS pixels. @default 120 */\n readonly size = input(120, { transform: (v: unknown): number => Math.max(32, coerceNumberProperty(v, 120)) });\n\n /** Stroke width of the dial arc, in CSS pixels. @default 8 */\n readonly strokeWidth = input(8, {\n transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 8)),\n });\n\n /** Track (unfilled) color. @default rgba(--wr-color-light, 0.6) */\n readonly trackColor = input<string>('rgba(var(--wr-color-light-rgb), 0.6)');\n\n /** Filled-arc color. @default var(--wr-color-primary) */\n readonly valueColor = input<string>('var(--wr-color-primary)');\n\n /** Show the value text in the center. @default true */\n readonly showValue = input(true, { transform: coerceBooleanProperty });\n\n /** Optional suffix appended to the center text (e.g. `'%'`). */\n readonly suffix = input<string>('');\n\n /** Read-only — disables interaction but keeps the visual. @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<number>(0);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n private dragging = false;\n\n protected readonly interactive = computed(() => !this.disabled() && !this.readonly());\n\n protected readonly classes = computed(() => {\n const parts = ['wr-knob'];\n if (this.disabled()) parts.push('wr-knob--disabled');\n return parts.join(' ');\n });\n\n // Geometry — drawn into a 100×100 viewBox, scaled by `size`.\n protected readonly cx = 50;\n protected readonly cy = 50;\n protected readonly radius = computed(() => 50 - this.strokeWidth() / 2 - 0.5);\n\n /** Ratio of the filled arc — `0` at min, `1` at max. */\n protected readonly ratio = computed(() => {\n const range = this.maxValue() - this.minValue();\n if (range <= 0) return 0;\n return clamp((this.value() - this.minValue()) / range, 0, 1);\n });\n\n /** SVG path `d` for the background arc. */\n protected readonly trackPath = computed(() => this.arcPath(ARC_START, ARC_END));\n\n /** SVG path `d` for the filled arc. */\n protected readonly valuePath = computed(() => {\n const end = ARC_START + ARC_SWEEP * this.ratio();\n return this.arcPath(ARC_START, end);\n });\n\n /** Position of the handle dot — `{ x, y }` in viewBox units. */\n protected readonly handlePos = computed(() => {\n const angle = ARC_START + ARC_SWEEP * this.ratio();\n const rad = (angle * Math.PI) / 180;\n return {\n x: this.cx + this.radius() * Math.sin(rad),\n y: this.cy - this.radius() * Math.cos(rad),\n };\n });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n constructor() {\n // Keep the value within `[min, max]` even when written externally (via\n // `[formField]` / `[(value)]`). Interactive changes are already clamped in\n // `commit`, so this only normalizes out-of-range external writes.\n effect(() => {\n const clamped = clamp(this.value(), this.minValue(), this.maxValue());\n if (clamped !== this.value()) this.value.set(clamped);\n });\n }\n\n // Pointer / keyboard\n\n protected onPointerDown(event: PointerEvent): void {\n if (!this.interactive()) return;\n event.preventDefault();\n this.dragging = true;\n (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);\n this.updateFromPointer(event);\n }\n\n protected onPointerMove(event: PointerEvent): void {\n if (!this.dragging) return;\n this.updateFromPointer(event);\n }\n\n protected onPointerUp(event: PointerEvent): void {\n if (!this.dragging) return;\n this.dragging = false;\n (event.currentTarget as HTMLElement).releasePointerCapture(event.pointerId);\n this.touch.emit();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (!this.interactive()) return;\n const step = event.shiftKey ? this.step() * 10 : this.step();\n let next: number | null;\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowUp':\n next = this.value() + step;\n break;\n case 'ArrowLeft':\n case 'ArrowDown':\n next = this.value() - step;\n break;\n case 'Home':\n next = this.minValue();\n break;\n case 'End':\n next = this.maxValue();\n break;\n default:\n return;\n }\n event.preventDefault();\n this.commit(clamp(next, this.minValue(), this.maxValue()));\n }\n\n // Internals\n\n private updateFromPointer(event: PointerEvent): void {\n const rect = this.host.nativeElement.getBoundingClientRect();\n const dx = event.clientX - (rect.left + rect.width / 2);\n const dy = event.clientY - (rect.top + rect.height / 2);\n // Angle measured from 12 o'clock, clockwise.\n let angle = (Math.atan2(dx, -dy) * 180) / Math.PI;\n // Map [-180, 180] into the dial's arc range, clamping outside it.\n if (angle < ARC_START) angle = angle + 360 > ARC_END ? ARC_START : angle + 360;\n angle = clamp(angle, ARC_START, ARC_END);\n const ratio = (angle - ARC_START) / ARC_SWEEP;\n const range = this.maxValue() - this.minValue();\n const raw = this.minValue() + ratio * range;\n const stepped = Math.round(raw / this.step()) * this.step();\n this.commit(clamp(stepped, this.minValue(), this.maxValue()));\n }\n\n private commit(next: number): void {\n if (next === this.value()) return;\n this.value.set(next);\n }\n\n // Arc helper\n\n private arcPath(startDeg: number, endDeg: number): string {\n const r = this.radius();\n const s = (startDeg * Math.PI) / 180;\n const e = (endDeg * Math.PI) / 180;\n const sx = this.cx + r * Math.sin(s);\n const sy = this.cy - r * Math.cos(s);\n const ex = this.cx + r * Math.sin(e);\n const ey = this.cy - r * Math.cos(e);\n const largeArc = endDeg - startDeg > 180 ? 1 : 0;\n return `M ${sx} ${sy} A ${r} ${r} 0 ${largeArc} 1 ${ex} ${ey}`;\n }\n}\n","<div\n class=\"wr-knob__surface\"\n role=\"slider\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n <path\n class=\"wr-knob__track\"\n [attr.d]=\"trackPath()\"\n [attr.stroke]=\"trackColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <path\n class=\"wr-knob__value\"\n [attr.d]=\"valuePath()\"\n [attr.stroke]=\"valueColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <circle\n class=\"wr-knob__handle\"\n [attr.cx]=\"handlePos().x\"\n [attr.cy]=\"handlePos().y\"\n [attr.r]=\"strokeWidth() / 2\"\n [attr.fill]=\"valueColor()\"\n />\n </svg>\n @if (showValue()) {\n <div class=\"wr-knob__text\">\n {{ value() }}<span class=\"wr-knob__suffix\">{{ suffix() }}</span>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ngwr-knob.mjs","sources":["../../../projects/lib/knob/knob.ts","../../../projects/lib/knob/knob.html","../../../projects/lib/knob/ngwr-knob.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n ElementRef,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n model,\n output,\n} from '@angular/core';\nimport type { FormValueControl } from '@angular/forms/signals';\n\nimport { useI18nText } from 'ngwr/i18n';\nimport { clamp } from 'ngwr/utils';\n\nconst ARC_START = -135; // 7 o'clock\nconst ARC_END = 135; // 5 o'clock — 270° sweep total\nconst ARC_SWEEP = ARC_END - ARC_START;\n\n/**\n * Radial dial input. A signal-forms native control: it implements\n * `FormValueControl<number>`, so `[formField]` binds straight to its `value`\n * model — no `ControlValueAccessor` in between. `[(value)]` works standalone.\n *\n * The value is clamped to `[min, max]`. Drag the indicator around the dial or\n * use ←→ / ↑↓ to step.\n *\n * @example\n * ```html\n * <!-- signal forms -->\n * <wr-knob [formField]=\"form.volume\" [min]=\"0\" [max]=\"100\" />\n *\n * <!-- standalone two-way binding -->\n * <wr-knob [(value)]=\"vol\" suffix=\"%\" valueColor=\"var(--wr-color-success)\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/knob\n */\n@Component({\n selector: 'wr-knob',\n templateUrl: './knob.html',\n encapsulation: ViewEncapsulation.None,\n host: { '[class]': 'classes()' },\n})\nexport class WrKnob implements FormValueControl<number> {\n /** Accessible name — the role needs one. Falls back to `knob.label`. */\n readonly ariaLabel = input<string | null>(null);\n\n protected readonly resolvedAriaLabel = useI18nText(this.ariaLabel, 'knob.label', 'Value');\n\n /** Minimum allowed value. @default 0 */\n readonly min = input<number | undefined>(0, { transform: (v: unknown): number => coerceNumberProperty(v, 0) });\n\n /** Maximum allowed value. @default 100 */\n readonly max = input<number | undefined>(100, { transform: (v: unknown): number => coerceNumberProperty(v, 100) });\n\n private readonly minValue = computed(() => this.min() ?? 0);\n private readonly maxValue = computed(() => this.max() ?? 100);\n\n /** Step granularity. @default 1 */\n readonly step = input(1, { transform: (v: unknown): number => Math.max(0.0001, coerceNumberProperty(v, 1)) });\n\n /** Dial diameter in CSS pixels. @default 120 */\n readonly size = input(120, { transform: (v: unknown): number => Math.max(32, coerceNumberProperty(v, 120)) });\n\n /** Stroke width of the dial arc, in CSS pixels. @default 8 */\n readonly strokeWidth = input(8, {\n transform: (v: unknown): number => Math.max(1, coerceNumberProperty(v, 8)),\n });\n\n /** Track (unfilled) color. @default rgba(--wr-color-light, 0.6) */\n readonly trackColor = input<string>('rgba(var(--wr-color-light-rgb), 0.6)');\n\n /** Filled-arc color. @default var(--wr-color-primary) */\n readonly valueColor = input<string>('var(--wr-color-primary)');\n\n /** Show the value text in the center. @default true */\n readonly showValue = input(true, { transform: coerceBooleanProperty });\n\n /** Optional suffix appended to the center text (e.g. `'%'`). */\n readonly suffix = input<string>('');\n\n /** Read-only — disables interaction but keeps the visual. @default false */\n readonly readonly = input(false, { transform: coerceBooleanProperty });\n\n /** Disable interaction. @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n /** Bound by `[formField]`, or two-way via `[(value)]`. */\n readonly value = model<number>(0);\n\n /** Emitted on blur so a bound field can mark itself touched. */\n readonly touch = output<void>();\n\n private dragging = false;\n\n protected readonly interactive = computed(() => !this.disabled() && !this.readonly());\n\n protected readonly classes = computed(() => {\n const parts = ['wr-knob'];\n if (this.disabled()) parts.push('wr-knob--disabled');\n return parts.join(' ');\n });\n\n // Geometry — drawn into a 100×100 viewBox, scaled by `size`.\n protected readonly cx = 50;\n protected readonly cy = 50;\n protected readonly radius = computed(() => 50 - this.strokeWidth() / 2 - 0.5);\n\n /** Ratio of the filled arc — `0` at min, `1` at max. */\n protected readonly ratio = computed(() => {\n const range = this.maxValue() - this.minValue();\n if (range <= 0) return 0;\n return clamp((this.value() - this.minValue()) / range, 0, 1);\n });\n\n /** SVG path `d` for the background arc. */\n protected readonly trackPath = computed(() => this.arcPath(ARC_START, ARC_END));\n\n /** SVG path `d` for the filled arc. */\n protected readonly valuePath = computed(() => {\n const end = ARC_START + ARC_SWEEP * this.ratio();\n return this.arcPath(ARC_START, end);\n });\n\n /** Position of the handle dot — `{ x, y }` in viewBox units. */\n protected readonly handlePos = computed(() => {\n const angle = ARC_START + ARC_SWEEP * this.ratio();\n const rad = (angle * Math.PI) / 180;\n return {\n x: this.cx + this.radius() * Math.sin(rad),\n y: this.cy - this.radius() * Math.cos(rad),\n };\n });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n constructor() {\n // Keep the value within `[min, max]` even when written externally (via\n // `[formField]` / `[(value)]`). Interactive changes are already clamped in\n // `commit`, so this only normalizes out-of-range external writes.\n effect(() => {\n const clamped = clamp(this.value(), this.minValue(), this.maxValue());\n if (clamped !== this.value()) this.value.set(clamped);\n });\n }\n\n // Pointer / keyboard\n\n protected onPointerDown(event: PointerEvent): void {\n if (!this.interactive()) return;\n event.preventDefault();\n this.dragging = true;\n (event.currentTarget as HTMLElement).setPointerCapture(event.pointerId);\n this.updateFromPointer(event);\n }\n\n protected onPointerMove(event: PointerEvent): void {\n if (!this.dragging) return;\n this.updateFromPointer(event);\n }\n\n protected onPointerUp(event: PointerEvent): void {\n if (!this.dragging) return;\n this.dragging = false;\n (event.currentTarget as HTMLElement).releasePointerCapture(event.pointerId);\n this.touch.emit();\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n if (!this.interactive()) return;\n const step = event.shiftKey ? this.step() * 10 : this.step();\n let next: number | null;\n switch (event.key) {\n case 'ArrowRight':\n case 'ArrowUp':\n next = this.value() + step;\n break;\n case 'ArrowLeft':\n case 'ArrowDown':\n next = this.value() - step;\n break;\n case 'Home':\n next = this.minValue();\n break;\n case 'End':\n next = this.maxValue();\n break;\n default:\n return;\n }\n event.preventDefault();\n this.commit(clamp(next, this.minValue(), this.maxValue()));\n }\n\n // Internals\n\n private updateFromPointer(event: PointerEvent): void {\n const rect = this.host.nativeElement.getBoundingClientRect();\n const dx = event.clientX - (rect.left + rect.width / 2);\n const dy = event.clientY - (rect.top + rect.height / 2);\n // Angle measured from 12 o'clock, clockwise.\n let angle = (Math.atan2(dx, -dy) * 180) / Math.PI;\n // Map [-180, 180] into the dial's arc range, clamping outside it.\n if (angle < ARC_START) angle = angle + 360 > ARC_END ? ARC_START : angle + 360;\n angle = clamp(angle, ARC_START, ARC_END);\n const ratio = (angle - ARC_START) / ARC_SWEEP;\n const range = this.maxValue() - this.minValue();\n const raw = this.minValue() + ratio * range;\n const stepped = Math.round(raw / this.step()) * this.step();\n this.commit(clamp(stepped, this.minValue(), this.maxValue()));\n }\n\n private commit(next: number): void {\n if (next === this.value()) return;\n this.value.set(next);\n }\n\n // Arc helper\n\n private arcPath(startDeg: number, endDeg: number): string {\n const r = this.radius();\n const s = (startDeg * Math.PI) / 180;\n const e = (endDeg * Math.PI) / 180;\n const sx = this.cx + r * Math.sin(s);\n const sy = this.cy - r * Math.cos(s);\n const ex = this.cx + r * Math.sin(e);\n const ey = this.cy - r * Math.cos(e);\n const largeArc = endDeg - startDeg > 180 ? 1 : 0;\n return `M ${sx} ${sy} A ${r} ${r} 0 ${largeArc} 1 ${ex} ${ey}`;\n }\n}\n","<div\n class=\"wr-knob__surface\"\n role=\"slider\"\n [attr.aria-label]=\"resolvedAriaLabel()\"\n [attr.aria-valuemin]=\"min()\"\n [attr.aria-valuemax]=\"max()\"\n [attr.aria-valuenow]=\"value()\"\n [attr.aria-disabled]=\"disabled() || null\"\n [attr.tabindex]=\"interactive() ? 0 : -1\"\n [style.width.px]=\"size()\"\n [style.height.px]=\"size()\"\n (pointerdown)=\"onPointerDown($event)\"\n (pointermove)=\"onPointerMove($event)\"\n (pointerup)=\"onPointerUp($event)\"\n (pointercancel)=\"onPointerUp($event)\"\n (keydown)=\"onKeydown($event)\"\n>\n <svg viewBox=\"0 0 100 100\" aria-hidden=\"true\">\n <path\n class=\"wr-knob__track\"\n [attr.d]=\"trackPath()\"\n [attr.stroke]=\"trackColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <path\n class=\"wr-knob__value\"\n [attr.d]=\"valuePath()\"\n [attr.stroke]=\"valueColor()\"\n [attr.stroke-width]=\"strokeWidth()\"\n fill=\"none\"\n stroke-linecap=\"round\"\n />\n <circle\n class=\"wr-knob__handle\"\n [attr.cx]=\"handlePos().x\"\n [attr.cy]=\"handlePos().y\"\n [attr.r]=\"strokeWidth() / 2\"\n [attr.fill]=\"valueColor()\"\n />\n </svg>\n @if (showValue()) {\n <div class=\"wr-knob__text\">\n {{ value() }}<span class=\"wr-knob__suffix\">{{ suffix() }}</span>\n </div>\n }\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}