ngwr 13.0.0 → 13.0.1

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 (47) hide show
  1. package/fesm2022/ngwr-border-glow.mjs +12 -3
  2. package/fesm2022/ngwr-border-glow.mjs.map +1 -1
  3. package/fesm2022/ngwr-breadcrumbs.mjs +14 -3
  4. package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
  5. package/fesm2022/ngwr-context-menu.mjs +6 -2
  6. package/fesm2022/ngwr-context-menu.mjs.map +1 -1
  7. package/fesm2022/ngwr-dialog.mjs +22 -16
  8. package/fesm2022/ngwr-dialog.mjs.map +1 -1
  9. package/fesm2022/ngwr-directives.mjs +5 -2
  10. package/fesm2022/ngwr-directives.mjs.map +1 -1
  11. package/fesm2022/ngwr-drawer.mjs +24 -18
  12. package/fesm2022/ngwr-drawer.mjs.map +1 -1
  13. package/fesm2022/ngwr-dropdown.mjs +6 -2
  14. package/fesm2022/ngwr-dropdown.mjs.map +1 -1
  15. package/fesm2022/ngwr-fuzzy-text.mjs +21 -4
  16. package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
  17. package/fesm2022/ngwr-gradient-text.mjs +9 -2
  18. package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
  19. package/fesm2022/ngwr-icon-adapters-feather.mjs +11 -0
  20. package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
  21. package/fesm2022/ngwr-icon-adapters-lucide.mjs +22 -2
  22. package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
  23. package/fesm2022/ngwr-icon.mjs +474 -37
  24. package/fesm2022/ngwr-icon.mjs.map +1 -1
  25. package/fesm2022/ngwr-markdown.mjs +63 -11
  26. package/fesm2022/ngwr-markdown.mjs.map +1 -1
  27. package/fesm2022/ngwr-overlay.mjs +36 -7
  28. package/fesm2022/ngwr-overlay.mjs.map +1 -1
  29. package/fesm2022/ngwr-qr.mjs +38 -1
  30. package/fesm2022/ngwr-qr.mjs.map +1 -1
  31. package/fesm2022/ngwr-shiny-text.mjs +10 -3
  32. package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
  33. package/fesm2022/ngwr-tabs.mjs +6 -2
  34. package/fesm2022/ngwr-tabs.mjs.map +1 -1
  35. package/fesm2022/ngwr-utils.mjs +107 -1
  36. package/fesm2022/ngwr-utils.mjs.map +1 -1
  37. package/fesm2022/ngwr-version.mjs +1 -1
  38. package/fesm2022/ngwr-version.mjs.map +1 -1
  39. package/llms-full.txt +1 -1
  40. package/package.json +3 -3
  41. package/types/ngwr-breadcrumbs.d.ts +1 -0
  42. package/types/ngwr-fuzzy-text.d.ts +5 -0
  43. package/types/ngwr-icon-adapters-feather.d.ts +11 -0
  44. package/types/ngwr-icon.d.ts +42 -1
  45. package/types/ngwr-shiny-text.d.ts +1 -0
  46. package/types/ngwr-utils.d.ts +47 -1
  47. package/types/ngwr-version.d.ts +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-dropdown.mjs","sources":["../../../projects/lib/dropdown/interfaces/dropdown-position.ts","../../../projects/lib/dropdown/dropdown.ts","../../../projects/lib/dropdown/dropdown-menu.ts","../../../projects/lib/dropdown/dropdown-item.ts","../../../projects/lib/dropdown/dropdown-item.html","../../../projects/lib/dropdown/ngwr-dropdown.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 type { ConnectedPosition } from '@angular/cdk/overlay';\n\n/**\n * Where the dropdown menu opens, relative to the trigger.\n */\nexport type WrDropdownPosition =\n 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'right';\n\n/**\n * Maps friendly names to CDK ConnectedPosition fallback lists.\n *\n * @internal\n */\nexport const WR_DROPDOWN_POSITIONS: Record<WrDropdownPosition, ConnectedPosition[]> = {\n top: [{ originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom' }],\n 'top-start': [{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' }],\n 'top-end': [{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom' }],\n bottom: [{ originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top' }],\n 'bottom-start': [{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' }],\n 'bottom-end': [{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top' }],\n left: [{ originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center' }],\n right: [{ originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center' }],\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 BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n DestroyRef,\n Directive,\n ElementRef,\n ViewContainerRef,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { WR_OVERLAY, WR_RESPONSIVE_OVERLAYS, WrOutsideClick, wrPresentAsSheet } from 'ngwr/overlay';\n\nimport type { WrDropdownMenu } from './dropdown-menu';\nimport { WR_DROPDOWN_POSITIONS, type WrDropdownPosition, type WrDropdownTrigger } from './interfaces';\n\n/**\n * Attach to any element to open a `<wr-dropdown-menu>` as a CDK overlay.\n *\n * @example\n * ```html\n * <button [wrDropdown]=\"menu\" position=\"bottom-start\" trigger=\"click\">\n * Actions\n * </button>\n *\n * <wr-dropdown-menu #menu>\n * <wr-dropdown-item icon=\"copy\" (click)=\"copy()\">Copy</wr-dropdown-item>\n * <wr-dropdown-item icon=\"trash\" (click)=\"remove()\">Delete</wr-dropdown-item>\n * </wr-dropdown-menu>\n * ```\n *\n * @see https://ngwr.dev/reference/components/dropdown\n */\nlet triggerUid = 0;\n\n@Directive({\n selector: '[wrDropdown]',\n host: {\n class: 'wr-dropdown-trigger',\n '[attr.id]': 'triggerId',\n '[attr.aria-haspopup]': '\"menu\"',\n '[attr.aria-expanded]': 'isOpen()',\n '[attr.aria-controls]': 'isOpen() ? menu().menuId() : null',\n '(click)': 'onClick($event)',\n '(keydown)': 'onKeydown($event)',\n '(mouseenter)': 'onMouseEnter()',\n '(mouseleave)': 'onMouseLeave($event)',\n },\n})\nexport class WrDropdown {\n /** Menu to open. Pass a `<wr-dropdown-menu>` template reference. */\n readonly menu = input.required<WrDropdownMenu>({ alias: 'wrDropdown' });\n\n /** How the menu opens. @default 'click' */\n readonly trigger = input<WrDropdownTrigger>('click');\n\n /** Where the menu anchors relative to the trigger. @default 'bottom-start' */\n readonly position = input<WrDropdownPosition>('bottom-start');\n\n /**\n * Present the menu as a full-width bottom-sheet on small viewports instead\n * of an anchored panel. `undefined` follows the app-wide\n * `provideWrResponsiveOverlays()` setting; `true`/`false` overrides it.\n * @default undefined\n */\n readonly responsive = input<boolean | undefined, BooleanInput>(undefined, {\n transform: (v: BooleanInput): boolean | undefined => (v == null ? undefined : coerceBooleanProperty(v)),\n });\n\n /** Fires after the menu opens. */\n readonly opened = output<void>();\n\n /** Fires after the menu closes. */\n readonly closed = output<void>();\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly outsideClick = inject(WrOutsideClick);\n private readonly responsiveConfig = inject(WR_RESPONSIVE_OVERLAYS);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n\n /** @internal Public so host bindings can read it. */\n readonly isOpen = signal(false);\n\n /**\n * Id the menu names itself after. The trigger is the CONSUMER's own element, so\n * an `id` they already put there wins: overwriting it broke `<label for>`,\n * `document.getElementById` and any `aria-labelledby` aimed at that button from\n * elsewhere in their app. The generated one is only a fallback so the menu has\n * something to reference.\n */\n // `.id` rather than `getAttribute`: it is always a string, and an empty one is no\n // id at all, so it falls through to the generated fallback.\n protected readonly triggerId = this.host.nativeElement.id || `wr-dropdown-trigger-${++triggerUid}`;\n\n private overlayRef: OverlayRef | null = null;\n\n constructor() {\n // The host view carrying `[wrDropdown]` can be destroyed while the menu is\n // open — a route change, or an `@if` around the trigger. The overlay lives\n // in the CDK container, not in that view, so nothing removes it unless we do.\n this.destroyRef.onDestroy(() => this.closeOverlay());\n\n effect(() => {\n if (this.isOpen()) {\n this.openOverlay();\n } else {\n this.closeOverlay();\n }\n });\n }\n\n /** Open the menu. */\n open(): void {\n this.isOpen.set(true);\n }\n\n /** Close the menu. */\n close(): void {\n this.isOpen.set(false);\n }\n\n /** Toggle the menu. */\n toggle(): void {\n this.isOpen.update(v => !v);\n }\n\n // Host listeners\n\n /** @internal */\n /**\n * Whether the pointer, rather than the keyboard, opened the current menu.\n *\n * A hover-opened menu must not take focus — the APG shows a menu on hover and\n * leaves the caret where it was — while a keyboard-opened one must. The\n * trigger MODE cannot answer that on its own: a `trigger=\"hover\"` menu is\n * still openable with Enter, and that open should focus the first item.\n */\n private openedByPointer = false;\n\n protected onClick(event: MouseEvent): void {\n if (this.trigger() !== 'click') return;\n event.stopPropagation();\n this.openedByPointer = false;\n this.toggle();\n }\n\n /** @internal */\n protected onMouseEnter(): void {\n if (this.trigger() !== 'hover') return;\n // A POINTER opened this, so the menu must not take the keyboard with it —\n // see `openedByPointer`.\n this.openedByPointer = true;\n this.isOpen.set(true);\n }\n\n /** @internal */\n protected onMouseLeave(event: MouseEvent): void {\n if (this.trigger() !== 'hover') return;\n const related = event.relatedTarget as Node | null;\n if (related && this.overlayRef?.overlayElement.contains(related)) return;\n this.isOpen.set(false);\n }\n\n // Overlay management\n\n private openOverlay(): void {\n if (this.overlayRef) return;\n\n // On small viewports (when opted in) detach from the trigger and present\n // the menu as a full-width slide-up sheet pinned to the bottom edge.\n const asSheet = wrPresentAsSheet(this.responsive(), this.responsiveConfig);\n\n const positionStrategy = asSheet\n ? this.overlay.position().global().centerHorizontally().bottom('0')\n : this.overlay\n .position()\n .flexibleConnectedTo(this.host)\n .withPositions(WR_DROPDOWN_POSITIONS[this.position()])\n .withPush(true);\n\n this.overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: asSheet ? this.scrollStrategies.block() : this.scrollStrategies.reposition(),\n width: asSheet ? '100%' : undefined,\n hasBackdrop: asSheet,\n backdropClass: asSheet ? 'wr-overlay-backdrop' : undefined,\n panelClass: asSheet\n ? ['wr-dropdown-overlay', 'wr-overlay-sheet']\n : ['wr-dropdown-overlay', `wr-dropdown-overlay--${this.position()}`],\n });\n\n if (asSheet) {\n this.overlayRef\n .backdropClick()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this.isOpen.set(false));\n }\n\n // Wire trigger id into menu so it can render aria-labelledby.\n this.menu().triggerId.set(this.triggerId);\n\n const portal = new TemplatePortal(this.menu().contentTpl(), this.vcr);\n this.overlayRef.attach(portal);\n\n // Focus the first menu item after the menu renders — unless a POINTER\n // opened it. This used to be unconditional, so merely sweeping the cursor\n // over a `trigger=\"hover\"` menu yanked the caret out of whatever the user\n // was typing; the APG's own rule is that hover shows a menu and does not\n // move focus into it. A keyboard open (Enter / Space / ArrowDown) still\n // focuses the first item, on a hover trigger too.\n if (!this.openedByPointer) queueMicrotask(() => this.focusItemAt(0));\n\n this.outsideClick\n .outsidePointerEvents(this.overlayRef)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (this.host.nativeElement.contains(event.target as Node)) return;\n this.isOpen.set(false);\n });\n\n this.overlayRef\n .keydownEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n this.handleMenuKeydown(event);\n });\n\n if (this.trigger() === 'hover') {\n this.overlayRef.overlayElement.addEventListener('mouseleave', this.onOverlayMouseLeave);\n }\n\n this.opened.emit();\n }\n\n private closeOverlay(): void {\n if (!this.overlayRef) return;\n if (this.trigger() === 'hover') {\n this.overlayRef.overlayElement.removeEventListener('mouseleave', this.onOverlayMouseLeave);\n }\n // Take the focus back before the pane goes, or it lands on `<body>` and the\n // next Tab starts from the top of the document. Only when focus is actually\n // inside the menu: closing a menu nobody was in must not steal the caret\n // from wherever the user has since moved.\n const active = document.activeElement;\n const focusWasInside = active instanceof Node && this.overlayRef.overlayElement.contains(active);\n this.overlayRef.dispose();\n this.overlayRef = null;\n if (focusWasInside) this.host.nativeElement.focus();\n this.closed.emit();\n }\n\n // Keyboard handling\n\n /** @internal Trigger keydown — ArrowDown/Up/Enter/Space open the menu. */\n protected onKeydown(event: KeyboardEvent): void {\n if (this.isOpen()) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n // Opened from the keyboard — including on a `hover` trigger, which stays\n // keyboard-operable — so the first item SHOULD take focus.\n this.openedByPointer = false;\n this.open();\n }\n }\n\n private handleMenuKeydown(event: KeyboardEvent): void {\n const items = this.getItems();\n if (items.length === 0 && event.key !== 'Escape' && event.key !== 'Tab') return;\n const current = document.activeElement as HTMLElement | null;\n const idx = current ? items.indexOf(current) : -1;\n\n // CDK's keyboard dispatcher feeds this overlay EVERY document keydown, not\n // just the ones typed into it — and a `trigger=\"hover\"` menu is open with\n // the caret deliberately left wherever the user was (see `openedByPointer`).\n // So ownership is checked here rather than assumed: without it, ArrowDown /\n // ArrowUp / Home / End pressed in an unrelated field were `preventDefault`ed\n // and yanked focus into the menu. The trigger counts as ours — a hover menu\n // that the user has tabbed back to should still open to the keyboard.\n const typedIn = event.target;\n const ours =\n typedIn instanceof Node &&\n (this.host.nativeElement.contains(typedIn) || (this.overlayRef?.overlayElement.contains(typedIn) ?? false));\n // Escape (and Tab) still close from anywhere — routing to the topmost\n // overlay regardless of focus is the dispatcher's whole job. Escape just\n // must not drag the caret onto the trigger from a field the user is in.\n if (!ours && event.key !== 'Escape' && event.key !== 'Tab') return;\n\n switch (event.key) {\n case 'Escape':\n event.preventDefault();\n this.isOpen.set(false);\n if (ours) this.host.nativeElement.focus();\n break;\n case 'Tab':\n // Let focus leave naturally; close the menu.\n this.isOpen.set(false);\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.focusItemAt(idx < items.length - 1 ? idx + 1 : 0);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.focusItemAt(idx > 0 ? idx - 1 : items.length - 1);\n break;\n case 'Home':\n event.preventDefault();\n this.focusItemAt(0);\n break;\n case 'End':\n event.preventDefault();\n this.focusItemAt(items.length - 1);\n break;\n default:\n break;\n }\n }\n\n private getItems(): readonly HTMLElement[] {\n if (!this.overlayRef) return [];\n return Array.from(\n this.overlayRef.overlayElement.querySelectorAll<HTMLElement>('.wr-dropdown-item:not(.wr-dropdown-item--disabled)')\n );\n }\n\n private focusItemAt(index: number): void {\n const items = this.getItems();\n if (items.length === 0) return;\n const clamped = ((index % items.length) + items.length) % items.length;\n items[clamped]?.focus();\n }\n\n private readonly onOverlayMouseLeave = (event: MouseEvent): void => {\n const related = event.relatedTarget as Node | null;\n if (related && this.host.nativeElement.contains(related)) return;\n this.isOpen.set(false);\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, TemplateRef, ViewEncapsulation, signal, viewChild } from '@angular/core';\n\nlet uid = 0;\n\n/**\n * Holds the menu content rendered when a {@link WrDropdown} opens.\n *\n * The component itself doesn't render anywhere — the directive grabs its\n * internal `<ng-template>` and portals it into an overlay.\n *\n * @example\n * ```html\n * <button [wrDropdown]=\"menu\">Actions</button>\n * <wr-dropdown-menu #menu>\n * <wr-dropdown-item icon=\"copy\">Copy</wr-dropdown-item>\n * <wr-dropdown-item icon=\"trash\">Delete</wr-dropdown-item>\n * </wr-dropdown-menu>\n * ```\n *\n * @see https://ngwr.dev/reference/components/dropdown\n */\n@Component({\n selector: 'wr-dropdown-menu',\n template:\n '<ng-template><div class=\"wr-dropdown-menu\" role=\"menu\" [attr.id]=\"menuId()\" [attr.aria-labelledby]=\"triggerId() || null\"><ng-content /></div></ng-template>',\n exportAs: 'wrDropdownMenu',\n encapsulation: ViewEncapsulation.None,\n host: { style: 'display:none' },\n})\nexport class WrDropdownMenu {\n /** The internal template the directive portals into the overlay. @internal */\n readonly contentTpl = viewChild.required(TemplateRef);\n\n /** Stable id used on the menu element and referenced from the trigger's `aria-controls`. */\n readonly menuId = signal(`wr-dropdown-menu-${++uid}`);\n\n /** Trigger element id, set by the directive for `aria-labelledby` wiring. */\n readonly triggerId = signal<string | null>(null);\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ElementRef, ViewEncapsulation, computed, inject, input } from '@angular/core';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\n\n/**\n * Single row inside a `<wr-dropdown-menu>`.\n *\n * @example\n * ```html\n * <wr-dropdown-item icon=\"copy\" (click)=\"copy()\">Copy</wr-dropdown-item>\n * <wr-dropdown-item icon=\"trash\" disabled>Delete</wr-dropdown-item>\n * ```\n */\n@Component({\n selector: 'wr-dropdown-item',\n templateUrl: './dropdown-item.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n role: 'menuitem',\n '[class]': 'classes()',\n '[attr.tabindex]': '-1',\n '[attr.aria-disabled]': 'disabled() ? true : null',\n '(keydown.enter)': 'activate($event)',\n '(keydown.space)': 'activate($event)',\n },\n imports: [WrIcon],\n})\nexport class WrDropdownItem {\n /** Optional leading icon name. @default null */\n readonly icon = input<WrIconName | null>(null);\n\n /** Disable interaction (suppresses pointer + keyboard). @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-dropdown-item'];\n if (this.disabled()) parts.push('wr-dropdown-item--disabled');\n return parts.join(' ');\n });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /** @internal Keyboard activation — fires the same click consumers bind to. */\n protected activate(event: Event): void {\n if (this.disabled()) return;\n event.preventDefault();\n this.host.nativeElement.click();\n }\n}\n","@if (icon(); as name) {\n <wr-icon class=\"wr-dropdown-item__icon\" [name]=\"name\" />\n}\n<span class=\"wr-dropdown-item__label\">\n <ng-content />\n</span>\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-dropdown.mjs","sources":["../../../projects/lib/dropdown/interfaces/dropdown-position.ts","../../../projects/lib/dropdown/dropdown.ts","../../../projects/lib/dropdown/dropdown-menu.ts","../../../projects/lib/dropdown/dropdown-item.ts","../../../projects/lib/dropdown/dropdown-item.html","../../../projects/lib/dropdown/ngwr-dropdown.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 type { ConnectedPosition } from '@angular/cdk/overlay';\n\n/**\n * Where the dropdown menu opens, relative to the trigger.\n */\nexport type WrDropdownPosition =\n 'top' | 'top-start' | 'top-end' | 'bottom' | 'bottom-start' | 'bottom-end' | 'left' | 'right';\n\n/**\n * Maps friendly names to CDK ConnectedPosition fallback lists.\n *\n * @internal\n */\nexport const WR_DROPDOWN_POSITIONS: Record<WrDropdownPosition, ConnectedPosition[]> = {\n top: [{ originX: 'center', originY: 'top', overlayX: 'center', overlayY: 'bottom' }],\n 'top-start': [{ originX: 'start', originY: 'top', overlayX: 'start', overlayY: 'bottom' }],\n 'top-end': [{ originX: 'end', originY: 'top', overlayX: 'end', overlayY: 'bottom' }],\n bottom: [{ originX: 'center', originY: 'bottom', overlayX: 'center', overlayY: 'top' }],\n 'bottom-start': [{ originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top' }],\n 'bottom-end': [{ originX: 'end', originY: 'bottom', overlayX: 'end', overlayY: 'top' }],\n left: [{ originX: 'start', originY: 'center', overlayX: 'end', overlayY: 'center' }],\n right: [{ originX: 'end', originY: 'center', overlayX: 'start', overlayY: 'center' }],\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 BooleanInput, coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { type OverlayRef, ScrollStrategyOptions } from '@angular/cdk/overlay';\nimport { TemplatePortal } from '@angular/cdk/portal';\nimport {\n DestroyRef,\n Directive,\n ElementRef,\n ViewContainerRef,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { WR_OVERLAY, WR_RESPONSIVE_OVERLAYS, WrOutsideClick, wrPresentAsSheet } from 'ngwr/overlay';\n\nimport type { WrDropdownMenu } from './dropdown-menu';\nimport { WR_DROPDOWN_POSITIONS, type WrDropdownPosition, type WrDropdownTrigger } from './interfaces';\n\n/**\n * Attach to any element to open a `<wr-dropdown-menu>` as a CDK overlay.\n *\n * @example\n * ```html\n * <button [wrDropdown]=\"menu\" position=\"bottom-start\" trigger=\"click\">\n * Actions\n * </button>\n *\n * <wr-dropdown-menu #menu>\n * <wr-dropdown-item icon=\"copy\" (click)=\"copy()\">Copy</wr-dropdown-item>\n * <wr-dropdown-item icon=\"trash\" (click)=\"remove()\">Delete</wr-dropdown-item>\n * </wr-dropdown-menu>\n * ```\n *\n * @see https://ngwr.dev/reference/components/dropdown\n */\nlet triggerUid = 0;\n\n@Directive({\n selector: '[wrDropdown]',\n host: {\n class: 'wr-dropdown-trigger',\n '[attr.id]': 'triggerId',\n '[attr.aria-haspopup]': '\"menu\"',\n '[attr.aria-expanded]': 'isOpen()',\n '[attr.aria-controls]': 'isOpen() ? menu().menuId() : null',\n '(click)': 'onClick($event)',\n '(keydown)': 'onKeydown($event)',\n '(mouseenter)': 'onMouseEnter()',\n '(mouseleave)': 'onMouseLeave($event)',\n },\n})\nexport class WrDropdown {\n /** Menu to open. Pass a `<wr-dropdown-menu>` template reference. */\n readonly menu = input.required<WrDropdownMenu>({ alias: 'wrDropdown' });\n\n /** How the menu opens. @default 'click' */\n readonly trigger = input<WrDropdownTrigger>('click');\n\n /** Where the menu anchors relative to the trigger. @default 'bottom-start' */\n readonly position = input<WrDropdownPosition>('bottom-start');\n\n /**\n * Present the menu as a full-width bottom-sheet on small viewports instead\n * of an anchored panel. `undefined` follows the app-wide\n * `provideWrResponsiveOverlays()` setting; `true`/`false` overrides it.\n * @default undefined\n */\n readonly responsive = input<boolean | undefined, BooleanInput>(undefined, {\n transform: (v: BooleanInput): boolean | undefined => (v == null ? undefined : coerceBooleanProperty(v)),\n });\n\n /** Fires after the menu opens. */\n readonly opened = output<void>();\n\n /** Fires after the menu closes. */\n readonly closed = output<void>();\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly overlay = inject(WR_OVERLAY);\n private readonly outsideClick = inject(WrOutsideClick);\n private readonly responsiveConfig = inject(WR_RESPONSIVE_OVERLAYS);\n private readonly vcr = inject(ViewContainerRef);\n private readonly scrollStrategies = inject(ScrollStrategyOptions);\n private readonly destroyRef = inject(DestroyRef);\n\n /** @internal Public so host bindings can read it. */\n readonly isOpen = signal(false);\n\n /**\n * Id the menu names itself after. The trigger is the CONSUMER's own element, so\n * an `id` they already put there wins: overwriting it broke `<label for>`,\n * `document.getElementById` and any `aria-labelledby` aimed at that button from\n * elsewhere in their app. The generated one is only a fallback so the menu has\n * something to reference.\n */\n // `.id` rather than `getAttribute`: it is always a string, and an empty one is no\n // id at all, so it falls through to the generated fallback.\n protected readonly triggerId = this.host.nativeElement.id || `wr-dropdown-trigger-${++triggerUid}`;\n\n private overlayRef: OverlayRef | null = null;\n\n constructor() {\n // The host view carrying `[wrDropdown]` can be destroyed while the menu is\n // open — a route change, or an `@if` around the trigger. The overlay lives\n // in the CDK container, not in that view, so nothing removes it unless we do.\n this.destroyRef.onDestroy(() => this.closeOverlay());\n\n effect(() => {\n if (this.isOpen()) {\n this.openOverlay();\n } else {\n this.closeOverlay();\n }\n });\n }\n\n /** Open the menu. */\n open(): void {\n this.isOpen.set(true);\n }\n\n /** Close the menu. */\n close(): void {\n this.isOpen.set(false);\n }\n\n /** Toggle the menu. */\n toggle(): void {\n this.isOpen.update(v => !v);\n }\n\n // Host listeners\n\n /** @internal */\n /**\n * Whether the pointer, rather than the keyboard, opened the current menu.\n *\n * A hover-opened menu must not take focus — the APG shows a menu on hover and\n * leaves the caret where it was — while a keyboard-opened one must. The\n * trigger MODE cannot answer that on its own: a `trigger=\"hover\"` menu is\n * still openable with Enter, and that open should focus the first item.\n */\n private openedByPointer = false;\n\n protected onClick(event: MouseEvent): void {\n if (this.trigger() !== 'click') return;\n event.stopPropagation();\n this.openedByPointer = false;\n this.toggle();\n }\n\n /** @internal */\n protected onMouseEnter(): void {\n if (this.trigger() !== 'hover') return;\n // A POINTER opened this, so the menu must not take the keyboard with it —\n // see `openedByPointer`.\n this.openedByPointer = true;\n this.isOpen.set(true);\n }\n\n /** @internal */\n protected onMouseLeave(event: MouseEvent): void {\n if (this.trigger() !== 'hover') return;\n const related = event.relatedTarget as Node | null;\n if (related && this.overlayRef?.overlayElement.contains(related)) return;\n this.isOpen.set(false);\n }\n\n // Overlay management\n\n private openOverlay(): void {\n if (this.overlayRef) return;\n\n // On small viewports (when opted in) detach from the trigger and present\n // the menu as a full-width slide-up sheet pinned to the bottom edge.\n const asSheet = wrPresentAsSheet(this.responsive(), this.responsiveConfig);\n\n const positionStrategy = asSheet\n ? this.overlay.position().global().centerHorizontally().bottom('0')\n : this.overlay\n .position()\n .flexibleConnectedTo(this.host)\n .withPositions(WR_DROPDOWN_POSITIONS[this.position()])\n .withPush(true);\n\n this.overlayRef = this.overlay.create({\n positionStrategy,\n scrollStrategy: asSheet ? this.scrollStrategies.block() : this.scrollStrategies.reposition(),\n width: asSheet ? '100%' : undefined,\n hasBackdrop: asSheet,\n backdropClass: asSheet ? 'wr-overlay-backdrop' : undefined,\n panelClass: asSheet\n ? ['wr-dropdown-overlay', 'wr-overlay-sheet']\n : ['wr-dropdown-overlay', `wr-dropdown-overlay--${this.position()}`],\n });\n\n if (asSheet) {\n this.overlayRef\n .backdropClick()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this.isOpen.set(false));\n }\n\n // Wire trigger id into menu so it can render aria-labelledby.\n this.menu().triggerId.set(this.triggerId);\n\n const portal = new TemplatePortal(this.menu().contentTpl(), this.vcr);\n this.overlayRef.attach(portal);\n\n // Focus the first menu item after the menu renders — unless a POINTER\n // opened it. This used to be unconditional, so merely sweeping the cursor\n // over a `trigger=\"hover\"` menu yanked the caret out of whatever the user\n // was typing; the APG's own rule is that hover shows a menu and does not\n // move focus into it. A keyboard open (Enter / Space / ArrowDown) still\n // focuses the first item, on a hover trigger too.\n if (!this.openedByPointer) queueMicrotask(() => this.focusItemAt(0));\n\n this.outsideClick\n .outsidePointerEvents(this.overlayRef)\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n if (this.host.nativeElement.contains(event.target as Node)) return;\n this.isOpen.set(false);\n });\n\n this.overlayRef\n .keydownEvents()\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(event => {\n this.handleMenuKeydown(event);\n });\n\n if (this.trigger() === 'hover') {\n this.overlayRef.overlayElement.addEventListener('mouseleave', this.onOverlayMouseLeave);\n }\n\n this.opened.emit();\n }\n\n private closeOverlay(): void {\n if (!this.overlayRef) return;\n if (this.trigger() === 'hover') {\n this.overlayRef.overlayElement.removeEventListener('mouseleave', this.onOverlayMouseLeave);\n }\n // Take the focus back before the pane goes, or it lands on `<body>` and the\n // next Tab starts from the top of the document. Only when focus is actually\n // inside the menu: closing a menu nobody was in must not steal the caret\n // from wherever the user has since moved.\n const active = document.activeElement;\n const focusWasInside = active instanceof Node && this.overlayRef.overlayElement.contains(active);\n this.overlayRef.dispose();\n this.overlayRef = null;\n if (focusWasInside) this.host.nativeElement.focus();\n this.closed.emit();\n }\n\n // Keyboard handling\n\n /** @internal Trigger keydown — ArrowDown/Up/Enter/Space open the menu. */\n protected onKeydown(event: KeyboardEvent): void {\n if (this.isOpen()) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n // Opened from the keyboard — including on a `hover` trigger, which stays\n // keyboard-operable — so the first item SHOULD take focus.\n this.openedByPointer = false;\n this.open();\n }\n }\n\n private handleMenuKeydown(event: KeyboardEvent): void {\n const items = this.getItems();\n if (items.length === 0 && event.key !== 'Escape' && event.key !== 'Tab') return;\n const current = document.activeElement as HTMLElement | null;\n const idx = current ? items.indexOf(current) : -1;\n\n // CDK's keyboard dispatcher feeds this overlay EVERY document keydown, not\n // just the ones typed into it — and a `trigger=\"hover\"` menu is open with\n // the caret deliberately left wherever the user was (see `openedByPointer`).\n // So ownership is checked here rather than assumed: without it, ArrowDown /\n // ArrowUp / Home / End pressed in an unrelated field were `preventDefault`ed\n // and yanked focus into the menu. The trigger counts as ours — a hover menu\n // that the user has tabbed back to should still open to the keyboard.\n const typedIn = event.target;\n const ours =\n typedIn instanceof Node &&\n (this.host.nativeElement.contains(typedIn) || (this.overlayRef?.overlayElement.contains(typedIn) ?? false));\n // Escape (and Tab) still close from anywhere — routing to the topmost\n // overlay regardless of focus is the dispatcher's whole job. Escape just\n // must not drag the caret onto the trigger from a field the user is in.\n if (!ours && event.key !== 'Escape' && event.key !== 'Tab') return;\n\n switch (event.key) {\n case 'Escape':\n event.preventDefault();\n this.isOpen.set(false);\n if (ours) this.host.nativeElement.focus();\n break;\n case 'Tab':\n // Let focus leave naturally; close the menu.\n this.isOpen.set(false);\n break;\n case 'ArrowDown':\n event.preventDefault();\n this.focusItemAt(idx < items.length - 1 ? idx + 1 : 0);\n break;\n case 'ArrowUp':\n event.preventDefault();\n this.focusItemAt(idx > 0 ? idx - 1 : items.length - 1);\n break;\n case 'Home':\n event.preventDefault();\n this.focusItemAt(0);\n break;\n case 'End':\n event.preventDefault();\n this.focusItemAt(items.length - 1);\n break;\n default:\n break;\n }\n }\n\n private getItems(): readonly HTMLElement[] {\n if (!this.overlayRef) return [];\n return Array.from(\n this.overlayRef.overlayElement.querySelectorAll<HTMLElement>('.wr-dropdown-item:not(.wr-dropdown-item--disabled)')\n );\n }\n\n private focusItemAt(index: number): void {\n const items = this.getItems();\n if (items.length === 0) return;\n const clamped = ((index % items.length) + items.length) % items.length;\n items[clamped]?.focus();\n }\n\n private readonly onOverlayMouseLeave = (event: MouseEvent): void => {\n const related = event.relatedTarget as Node | null;\n if (related && this.host.nativeElement.contains(related)) return;\n this.isOpen.set(false);\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, TemplateRef, ViewEncapsulation, signal, viewChild } from '@angular/core';\n\nlet uid = 0;\n\n/**\n * Holds the menu content rendered when a {@link WrDropdown} opens.\n *\n * The component itself doesn't render anywhere — the directive grabs its\n * internal `<ng-template>` and portals it into an overlay.\n *\n * @example\n * ```html\n * <button [wrDropdown]=\"menu\">Actions</button>\n * <wr-dropdown-menu #menu>\n * <wr-dropdown-item icon=\"copy\">Copy</wr-dropdown-item>\n * <wr-dropdown-item icon=\"trash\">Delete</wr-dropdown-item>\n * </wr-dropdown-menu>\n * ```\n *\n * @see https://ngwr.dev/reference/components/dropdown\n */\n@Component({\n selector: 'wr-dropdown-menu',\n template:\n '<ng-template><div class=\"wr-dropdown-menu\" role=\"menu\" [attr.id]=\"menuId()\" [attr.aria-labelledby]=\"triggerId() || null\"><ng-content /></div></ng-template>',\n exportAs: 'wrDropdownMenu',\n encapsulation: ViewEncapsulation.None,\n // A BOUND display rather than a static `style` attribute: Angular writes a\n // binding through `style.setProperty`, which no CSP governs, while a real\n // `style=\"…\"` attribute is refused under `style-src 'self'` — and this host\n // would then lay out an empty box in the middle of the content.\n host: { '[style.display]': \"'none'\" },\n})\nexport class WrDropdownMenu {\n /** The internal template the directive portals into the overlay. @internal */\n readonly contentTpl = viewChild.required(TemplateRef);\n\n /** Stable id used on the menu element and referenced from the trigger's `aria-controls`. */\n readonly menuId = signal(`wr-dropdown-menu-${++uid}`);\n\n /** Trigger element id, set by the directive for `aria-labelledby` wiring. */\n readonly triggerId = signal<string | null>(null);\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 { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ElementRef, ViewEncapsulation, computed, inject, input } from '@angular/core';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\n\n/**\n * Single row inside a `<wr-dropdown-menu>`.\n *\n * @example\n * ```html\n * <wr-dropdown-item icon=\"copy\" (click)=\"copy()\">Copy</wr-dropdown-item>\n * <wr-dropdown-item icon=\"trash\" disabled>Delete</wr-dropdown-item>\n * ```\n */\n@Component({\n selector: 'wr-dropdown-item',\n templateUrl: './dropdown-item.html',\n encapsulation: ViewEncapsulation.None,\n host: {\n role: 'menuitem',\n '[class]': 'classes()',\n '[attr.tabindex]': '-1',\n '[attr.aria-disabled]': 'disabled() ? true : null',\n '(keydown.enter)': 'activate($event)',\n '(keydown.space)': 'activate($event)',\n },\n imports: [WrIcon],\n})\nexport class WrDropdownItem {\n /** Optional leading icon name. @default null */\n readonly icon = input<WrIconName | null>(null);\n\n /** Disable interaction (suppresses pointer + keyboard). @default false */\n readonly disabled = input(false, { transform: coerceBooleanProperty });\n\n protected readonly classes = computed(() => {\n const parts = ['wr-dropdown-item'];\n if (this.disabled()) parts.push('wr-dropdown-item--disabled');\n return parts.join(' ');\n });\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n\n /** @internal Keyboard activation — fires the same click consumers bind to. */\n protected activate(event: Event): void {\n if (this.disabled()) return;\n event.preventDefault();\n this.host.nativeElement.click();\n }\n}\n","@if (icon(); as name) {\n <wr-icon class=\"wr-dropdown-item__icon\" [name]=\"name\" />\n}\n<span class=\"wr-dropdown-item__label\">\n <ng-content />\n</span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -39,6 +39,18 @@ import { numAttr } from 'ngwr/utils';
39
39
  * @see https://www.reactbits.dev/text-animations/fuzzy-text
40
40
  */
41
41
  class WrFuzzyText {
42
+ /**
43
+ * Visual-hiding declarations for the screen-reader copy of the text. A stable
44
+ * object literal, so the binding is written once rather than on every pass.
45
+ */
46
+ srOnly = {
47
+ position: 'absolute',
48
+ width: '1px',
49
+ height: '1px',
50
+ overflow: 'hidden',
51
+ 'clip-path': 'inset(50%)',
52
+ 'white-space': 'nowrap',
53
+ };
42
54
  /** Text to render. */
43
55
  text = input.required(/* @ts-ignore */
44
56
  ...(ngDevMode ? [{ debugName: "text" }] : /* istanbul ignore next */ []));
@@ -379,7 +391,7 @@ class WrFuzzyText {
379
391
  };
380
392
  }
381
393
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrFuzzyText, deps: [], target: i0.ɵɵFactoryTarget.Component });
382
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.4", type: WrFuzzyText, isStandalone: true, selector: "wr-fuzzy-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null }, fontWeight: { classPropertyName: "fontWeight", publicName: "fontWeight", isSignal: true, isRequired: false, transformFunction: null }, fontFamily: { classPropertyName: "fontFamily", publicName: "fontFamily", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, gradient: { classPropertyName: "gradient", publicName: "gradient", isSignal: true, isRequired: false, transformFunction: null }, enableHover: { classPropertyName: "enableHover", publicName: "enableHover", isSignal: true, isRequired: false, transformFunction: null }, baseIntensity: { classPropertyName: "baseIntensity", publicName: "baseIntensity", isSignal: true, isRequired: false, transformFunction: null }, hoverIntensity: { classPropertyName: "hoverIntensity", publicName: "hoverIntensity", isSignal: true, isRequired: false, transformFunction: null }, fuzzRange: { classPropertyName: "fuzzRange", publicName: "fuzzRange", isSignal: true, isRequired: false, transformFunction: null }, fps: { classPropertyName: "fps", publicName: "fps", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, transitionDuration: { classPropertyName: "transitionDuration", publicName: "transitionDuration", isSignal: true, isRequired: false, transformFunction: null }, clickEffect: { classPropertyName: "clickEffect", publicName: "clickEffect", isSignal: true, isRequired: false, transformFunction: null }, glitchMode: { classPropertyName: "glitchMode", publicName: "glitchMode", isSignal: true, isRequired: false, transformFunction: null }, glitchInterval: { classPropertyName: "glitchInterval", publicName: "glitchInterval", isSignal: true, isRequired: false, transformFunction: null }, glitchDuration: { classPropertyName: "glitchDuration", publicName: "glitchDuration", isSignal: true, isRequired: false, transformFunction: null }, letterSpacing: { classPropertyName: "letterSpacing", publicName: "letterSpacing", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "color: var(--wr-color-dark)", classAttribute: "wr-fuzzy-text" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0, template: "<span class=\"wr-fuzzy-text__sr-only\" style=\"position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap\">{{ text() }}</span><canvas #canvas aria-hidden=\"true\"></canvas>", isInline: true, encapsulation: i0.ViewEncapsulation.None });
394
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.4", type: WrFuzzyText, isStandalone: true, selector: "wr-fuzzy-text", inputs: { text: { classPropertyName: "text", publicName: "text", isSignal: true, isRequired: true, transformFunction: null }, fontSize: { classPropertyName: "fontSize", publicName: "fontSize", isSignal: true, isRequired: false, transformFunction: null }, fontWeight: { classPropertyName: "fontWeight", publicName: "fontWeight", isSignal: true, isRequired: false, transformFunction: null }, fontFamily: { classPropertyName: "fontFamily", publicName: "fontFamily", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, gradient: { classPropertyName: "gradient", publicName: "gradient", isSignal: true, isRequired: false, transformFunction: null }, enableHover: { classPropertyName: "enableHover", publicName: "enableHover", isSignal: true, isRequired: false, transformFunction: null }, baseIntensity: { classPropertyName: "baseIntensity", publicName: "baseIntensity", isSignal: true, isRequired: false, transformFunction: null }, hoverIntensity: { classPropertyName: "hoverIntensity", publicName: "hoverIntensity", isSignal: true, isRequired: false, transformFunction: null }, fuzzRange: { classPropertyName: "fuzzRange", publicName: "fuzzRange", isSignal: true, isRequired: false, transformFunction: null }, fps: { classPropertyName: "fps", publicName: "fps", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, transitionDuration: { classPropertyName: "transitionDuration", publicName: "transitionDuration", isSignal: true, isRequired: false, transformFunction: null }, clickEffect: { classPropertyName: "clickEffect", publicName: "clickEffect", isSignal: true, isRequired: false, transformFunction: null }, glitchMode: { classPropertyName: "glitchMode", publicName: "glitchMode", isSignal: true, isRequired: false, transformFunction: null }, glitchInterval: { classPropertyName: "glitchInterval", publicName: "glitchInterval", isSignal: true, isRequired: false, transformFunction: null }, glitchDuration: { classPropertyName: "glitchDuration", publicName: "glitchDuration", isSignal: true, isRequired: false, transformFunction: null }, letterSpacing: { classPropertyName: "letterSpacing", publicName: "letterSpacing", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.color": "'var(--wr-color-dark)'" }, classAttribute: "wr-fuzzy-text" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["canvas"], descendants: true, isSignal: true }], ngImport: i0, template: "<span class=\"wr-fuzzy-text__sr-only\" [style]=\"srOnly\">{{ text() }}</span><canvas #canvas aria-hidden=\"true\"></canvas>", isInline: true, encapsulation: i0.ViewEncapsulation.None });
383
395
  }
384
396
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrFuzzyText, decorators: [{
385
397
  type: Component,
@@ -390,11 +402,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
390
402
  // and `wr-decrypt-text` carry. Hidden inline rather than through a class: this
391
403
  // entry point ships no stylesheet, and a consumer who imported none would
392
404
  // otherwise see the text twice.
393
- template: '<span class="wr-fuzzy-text__sr-only" style="position:absolute;width:1px;height:1px;overflow:hidden;' +
394
- 'clip-path:inset(50%);white-space:nowrap">{{ text() }}</span>' +
405
+ //
406
+ // BOUND, not a static `style="…"` attribute. A real attribute is refused under
407
+ // `style-src 'self'`, and what is lost there is not a colour: the span drops
408
+ // every visual-hiding declaration and the word renders on screen beside the
409
+ // canvas that already draws it. A binding goes through `style.setProperty`,
410
+ // which is CSSOM and outside CSP's reach.
411
+ template: '<span class="wr-fuzzy-text__sr-only" [style]="srOnly">{{ text() }}</span>' +
395
412
  '<canvas #canvas aria-hidden="true"></canvas>',
396
413
  encapsulation: ViewEncapsulation.None,
397
- host: { class: 'wr-fuzzy-text', style: 'color: var(--wr-color-dark)' },
414
+ host: { class: 'wr-fuzzy-text', '[style.color]': "'var(--wr-color-dark)'" },
398
415
  }]
399
416
  }], ctorParameters: () => [], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }], fontSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "fontSize", required: false }] }], fontWeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "fontWeight", required: false }] }], fontFamily: [{ type: i0.Input, args: [{ isSignal: true, alias: "fontFamily", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], gradient: [{ type: i0.Input, args: [{ isSignal: true, alias: "gradient", required: false }] }], enableHover: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableHover", required: false }] }], baseIntensity: [{ type: i0.Input, args: [{ isSignal: true, alias: "baseIntensity", required: false }] }], hoverIntensity: [{ type: i0.Input, args: [{ isSignal: true, alias: "hoverIntensity", required: false }] }], fuzzRange: [{ type: i0.Input, args: [{ isSignal: true, alias: "fuzzRange", required: false }] }], fps: [{ type: i0.Input, args: [{ isSignal: true, alias: "fps", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], transitionDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "transitionDuration", required: false }] }], clickEffect: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickEffect", required: false }] }], glitchMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "glitchMode", required: false }] }], glitchInterval: [{ type: i0.Input, args: [{ isSignal: true, alias: "glitchInterval", required: false }] }], glitchDuration: [{ type: i0.Input, args: [{ isSignal: true, alias: "glitchDuration", required: false }] }], letterSpacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "letterSpacing", required: false }] }], canvasRef: [{ type: i0.ViewChild, args: ['canvas', { isSignal: true }] }] } });
400
417
 
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-fuzzy-text.mjs","sources":["../../../projects/lib/fuzzy-text/fuzzy-text.ts","../../../projects/lib/fuzzy-text/ngwr-fuzzy-text.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 * Angular adaptation of the FuzzyText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/fuzzy-text\n *\n * Renders text to an offscreen 2D canvas, then redraws it onto the\n * visible canvas one row (or column) at a time with random horizontal /\n * vertical offsets. Intensity reacts to hover / click / glitch state.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport type { ElementRef } from '@angular/core';\nimport {\n Component,\n DestroyRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n effect,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrFuzzyTextDirection } from './interfaces';\n\n/**\n * Canvas-rendered \"fuzzy\" text — each row/column of glyphs is offset by\n * a random amount per frame, giving the text a TV-static or motion-blur\n * appearance. Intensity ramps up on hover, click, and during periodic\n * glitch bursts (configurable).\n *\n * @example\n * ```html\n * <wr-fuzzy-text text=\"404\" />\n * <wr-fuzzy-text\n * text=\"HELLO\"\n * color=\"#0ea5e9\"\n * [fuzzRange]=\"50\"\n * [hoverIntensity]=\"0.8\"\n * [glitchMode]=\"true\"\n * />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/fuzzy-text\n */\n@Component({\n selector: 'wr-fuzzy-text',\n // The text is drawn into the canvas as PIXELS, so without the first span there is\n // nothing for a screen reader to read at all — the same layer `wr-rotating-text`\n // and `wr-decrypt-text` carry. Hidden inline rather than through a class: this\n // entry point ships no stylesheet, and a consumer who imported none would\n // otherwise see the text twice.\n template:\n '<span class=\"wr-fuzzy-text__sr-only\" style=\"position:absolute;width:1px;height:1px;overflow:hidden;' +\n 'clip-path:inset(50%);white-space:nowrap\">{{ text() }}</span>' +\n '<canvas #canvas aria-hidden=\"true\"></canvas>',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-fuzzy-text', style: 'color: var(--wr-color-dark)' },\n})\nexport class WrFuzzyText {\n /** Text to render. */\n readonly text = input.required<string>();\n\n /** Font size as CSS length (`'4rem'`, `'72px'`, …) or px number. @default 'clamp(2rem, 10vw, 10rem)' */\n readonly fontSize = input<string | number>('clamp(2rem, 10vw, 10rem)');\n\n /** Font weight. @default 900 */\n readonly fontWeight = input<number | string>(900);\n\n /** Font family. `'inherit'` reads the canvas's computed style. @default 'inherit' */\n readonly fontFamily = input('inherit');\n\n /** Text colour. `'inherit'` reads the canvas's computed style. Ignored if `[gradient]` is set. @default 'inherit' */\n readonly color = input('inherit');\n\n /** Optional horizontal gradient stops. */\n readonly gradient = input<readonly string[] | null>(null);\n\n /** Enable hover / touch reactivity. @default true */\n readonly enableHover = input(true, { transform: coerceBooleanProperty });\n\n /** Base intensity (0..1) when idle. @default 0.18 */\n readonly baseIntensity = input(0.18, { transform: numAttr(0.18) });\n\n /** Intensity (0..1) while the pointer hovers the text. @default 0.5 */\n readonly hoverIntensity = input(0.5, { transform: numAttr(0.5) });\n\n /** Max pixel displacement per row/column at intensity 1. @default 30 */\n readonly fuzzRange = input(30, { transform: numAttr(30) });\n\n /** Frame rate cap. @default 60 */\n readonly fps = input(60, { transform: numAttr(60) });\n\n /** Fuzz direction. @default 'horizontal' */\n readonly direction = input<WrFuzzyTextDirection>('horizontal');\n\n /** Ms to ease intensity toward target. `0` snaps. @default 0 */\n readonly transitionDuration = input(0, { transform: numAttr(0) });\n\n /** Spike to full intensity briefly on click. @default false */\n readonly clickEffect = input(false, { transform: coerceBooleanProperty });\n\n /** Periodic \"glitch\" bursts at full intensity. @default false */\n readonly glitchMode = input(false, { transform: coerceBooleanProperty });\n\n /** Ms between glitch bursts. @default 2000 */\n readonly glitchInterval = input(2000, { transform: numAttr(2000) });\n\n /** Ms a glitch burst lasts. @default 200 */\n readonly glitchDuration = input(200, { transform: numAttr(200) });\n\n /** Extra pixels between glyphs. @default 0 */\n readonly letterSpacing = input(0, { transform: numAttr(0) });\n\n private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private teardown: (() => void) | undefined;\n\n /**\n * `init()` suspends on font loading, so the component can be destroyed while\n * it is awaiting. At that moment `teardown` is still undefined, so the\n * destroy hook has nothing to call — and everything the rest of `init()`\n * starts (the rAF loop, the glitch timers, canvas listeners) would run for\n * the life of the page. This flag lets the continuation bail out.\n */\n private destroyed = false;\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => {\n void this.init();\n });\n\n // Re-init whenever any input that affects the offscreen rendering changes.\n effect(() => {\n this.text();\n this.fontSize();\n this.fontWeight();\n this.fontFamily();\n this.color();\n this.gradient();\n this.letterSpacing();\n this.direction();\n this.fuzzRange();\n this.fps();\n this.glitchMode();\n this.glitchInterval();\n this.glitchDuration();\n // Skip if we haven't booted yet.\n if (!this.teardown) return;\n this.teardown();\n this.teardown = undefined;\n queueMicrotask(() => {\n void this.init();\n });\n });\n\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.teardown?.();\n });\n }\n\n // Init / loop\n\n private async init(): Promise<void> {\n const canvas = this.canvasRef().nativeElement;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const fontFamily =\n this.fontFamily() === 'inherit' ? window.getComputedStyle(canvas).fontFamily || 'sans-serif' : this.fontFamily();\n const color = this.color() === 'inherit' ? window.getComputedStyle(canvas).color || '#fff' : this.color();\n const fontSize = this.fontSize();\n const fontSizeStr = typeof fontSize === 'number' ? `${fontSize}px` : fontSize;\n const fontWeight = this.fontWeight();\n const fontString = `${fontWeight} ${fontSizeStr} ${fontFamily}`;\n\n try {\n await document.fonts.load(fontString);\n } catch {\n await document.fonts.ready;\n }\n\n // Destroyed while the fonts were loading — nothing below may start.\n if (this.destroyed) return;\n\n // Numeric font size for buffer maths.\n let numericFontSize: number;\n if (typeof fontSize === 'number') {\n numericFontSize = fontSize;\n } else {\n const tmp = document.createElement('span');\n tmp.style.fontSize = fontSize;\n document.body.appendChild(tmp);\n numericFontSize = Number.parseFloat(window.getComputedStyle(tmp).fontSize);\n document.body.removeChild(tmp);\n }\n\n const text = this.text();\n const letterSpacing = this.letterSpacing();\n const fuzzRange = this.fuzzRange();\n const direction = this.direction();\n\n // Offscreen canvas with the laid-out text.\n const offscreen = document.createElement('canvas');\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) return;\n offCtx.font = fontString;\n offCtx.textBaseline = 'alphabetic';\n\n let totalWidth = 0;\n if (letterSpacing !== 0) {\n for (const ch of text) totalWidth += offCtx.measureText(ch).width + letterSpacing;\n totalWidth -= letterSpacing;\n } else {\n totalWidth = offCtx.measureText(text).width;\n }\n const m = offCtx.measureText(text);\n const actualLeft = m.actualBoundingBoxLeft ?? 0;\n const actualRight = letterSpacing !== 0 ? totalWidth : (m.actualBoundingBoxRight ?? m.width);\n const actualAscent = m.actualBoundingBoxAscent ?? numericFontSize;\n const actualDescent = m.actualBoundingBoxDescent ?? numericFontSize * 0.2;\n const textBoundingWidth = Math.ceil(letterSpacing !== 0 ? totalWidth : actualLeft + actualRight);\n const tightHeight = Math.ceil(actualAscent + actualDescent);\n\n const extraWidthBuffer = 10;\n const offscreenWidth = textBoundingWidth + extraWidthBuffer;\n offscreen.width = offscreenWidth;\n offscreen.height = tightHeight;\n const xOffset = extraWidthBuffer / 2;\n\n offCtx.font = fontString;\n offCtx.textBaseline = 'alphabetic';\n\n const gradient = this.gradient();\n if (gradient && gradient.length >= 2) {\n const g = offCtx.createLinearGradient(0, 0, offscreenWidth, 0);\n gradient.forEach((c, i) => g.addColorStop(i / (gradient.length - 1), c));\n offCtx.fillStyle = g;\n } else {\n offCtx.fillStyle = color;\n }\n\n if (letterSpacing !== 0) {\n let xPos = xOffset;\n for (const ch of text) {\n offCtx.fillText(ch, xPos, actualAscent);\n xPos += offCtx.measureText(ch).width + letterSpacing;\n }\n } else {\n offCtx.fillText(text, xOffset - actualLeft, actualAscent);\n }\n\n // Size the visible canvas, leaving room for the max horizontal fuzz.\n const horizontalMargin = fuzzRange + 20;\n const verticalMargin = 0;\n canvas.width = offscreenWidth + horizontalMargin * 2;\n canvas.height = tightHeight + verticalMargin * 2;\n ctx.translate(horizontalMargin, verticalMargin);\n\n const interactiveLeft = horizontalMargin + xOffset;\n const interactiveTop = verticalMargin;\n const interactiveRight = interactiveLeft + textBoundingWidth;\n const interactiveBottom = interactiveTop + tightHeight;\n\n // Reduced motion: paint the text once, clean — no fuzz loop, no\n // glitch bursts, no pointer reactivity. Teardown must still be set\n // so the re-init effect keeps redrawing on input changes.\n if (this.platform.prefersReducedMotion()) {\n ctx.drawImage(offscreen, 0, 0);\n this.teardown = (): void => undefined;\n return;\n }\n\n let isHovering = false;\n let isClicking = false;\n let isGlitching = false;\n let currentIntensity = this.baseIntensity();\n let targetIntensity = currentIntensity;\n let lastFrame = 0;\n const frameDuration = 1000 / this.fps();\n\n let rafId = 0;\n let glitchOnTimer: ReturnType<typeof setTimeout> | undefined;\n let glitchOffTimer: ReturnType<typeof setTimeout> | undefined;\n let clickTimer: ReturnType<typeof setTimeout> | undefined;\n\n const startGlitchLoop = (): void => {\n if (!this.glitchMode()) return;\n glitchOnTimer = setTimeout(() => {\n isGlitching = true;\n glitchOffTimer = setTimeout(() => {\n isGlitching = false;\n startGlitchLoop();\n }, this.glitchDuration());\n }, this.glitchInterval());\n };\n if (this.glitchMode()) startGlitchLoop();\n\n const run = (ts: number): void => {\n if (ts - lastFrame < frameDuration) {\n rafId = requestAnimationFrame(run);\n return;\n }\n lastFrame = ts;\n\n ctx.clearRect(\n -fuzzRange - 20,\n -fuzzRange - 10,\n offscreenWidth + 2 * (fuzzRange + 20),\n tightHeight + 2 * (fuzzRange + 10)\n );\n\n if (isClicking) targetIntensity = 1;\n else if (isGlitching) targetIntensity = 1;\n else if (isHovering) targetIntensity = this.hoverIntensity();\n else targetIntensity = this.baseIntensity();\n\n const td = this.transitionDuration();\n if (td > 0) {\n const step = 1 / (td / frameDuration);\n if (currentIntensity < targetIntensity) currentIntensity = Math.min(currentIntensity + step, targetIntensity);\n else if (currentIntensity > targetIntensity)\n currentIntensity = Math.max(currentIntensity - step, targetIntensity);\n } else {\n currentIntensity = targetIntensity;\n }\n\n if (direction === 'horizontal') {\n for (let j = 0; j < tightHeight; j++) {\n const dx = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange);\n ctx.drawImage(offscreen, 0, j, offscreenWidth, 1, dx, j, offscreenWidth, 1);\n }\n } else if (direction === 'vertical') {\n for (let i = 0; i < offscreenWidth; i++) {\n const dy = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange);\n ctx.drawImage(offscreen, i, 0, 1, tightHeight, i, dy, 1, tightHeight);\n }\n } else {\n // both: horizontal pass then vertical pass on the result\n for (let j = 0; j < tightHeight; j++) {\n const dx = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange);\n ctx.drawImage(offscreen, 0, j, offscreenWidth, 1, dx, j, offscreenWidth, 1);\n }\n const w = offscreenWidth + fuzzRange;\n const h = tightHeight + fuzzRange;\n const data = ctx.getImageData(0, 0, w, h);\n ctx.clearRect(\n -fuzzRange - 20,\n -fuzzRange - 10,\n offscreenWidth + 2 * (fuzzRange + 20),\n tightHeight + 2 * (fuzzRange + 10)\n );\n ctx.putImageData(data, 0, 0);\n for (let i = 0; i < w; i++) {\n const dy = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange * 0.5);\n const col = ctx.getImageData(i, 0, 1, h);\n ctx.clearRect(i, -fuzzRange, 1, tightHeight + 2 * fuzzRange);\n ctx.putImageData(col, i, dy);\n }\n }\n\n rafId = requestAnimationFrame(run);\n };\n rafId = requestAnimationFrame(run);\n\n const isInsideText = (x: number, y: number): boolean =>\n x >= interactiveLeft && x <= interactiveRight && y >= interactiveTop && y <= interactiveBottom;\n\n const onMouseMove = (e: MouseEvent): void => {\n if (!this.enableHover()) return;\n const rect = canvas.getBoundingClientRect();\n isHovering = isInsideText(e.clientX - rect.left, e.clientY - rect.top);\n };\n const onMouseLeave = (): void => {\n isHovering = false;\n };\n const onTouchMove = (e: TouchEvent): void => {\n if (!this.enableHover()) return;\n e.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const t = e.touches[0];\n isHovering = isInsideText(t.clientX - rect.left, t.clientY - rect.top);\n };\n const onTouchEnd = (): void => {\n isHovering = false;\n };\n const onClick = (): void => {\n if (!this.clickEffect()) return;\n isClicking = true;\n clearTimeout(clickTimer);\n clickTimer = setTimeout(() => {\n isClicking = false;\n }, 150);\n };\n\n // Attached unconditionally, and gated inside the three handlers that can SET a\n // reactive state instead. `enableHover` and `clickEffect` are not in the re-init\n // effect's dependency list, so an attach conditional on them read the value at\n // boot and never again: a `[clickEffect]` bound to a signal that starts `false` —\n // the default, so the ordinary case — stayed dead after it flipped true. Adding\n // them to that list would restart the rAF loop and the glitch timers just to\n // toggle a listener, which is visible; the guards are not. `onTouchMove` calls\n // `preventDefault()` only past its own guard, so a hover-disabled instance still\n // swallows nothing.\n //\n // `onMouseLeave` / `onTouchEnd` stay ungated deliberately: they only ever CLEAR\n // toward the idle state, and gating them would strand `isHovering` on for good\n // when hover is switched off mid-hover.\n canvas.addEventListener('mousemove', onMouseMove);\n canvas.addEventListener('mouseleave', onMouseLeave);\n canvas.addEventListener('touchmove', onTouchMove, { passive: false });\n canvas.addEventListener('touchend', onTouchEnd);\n canvas.addEventListener('click', onClick);\n\n this.teardown = (): void => {\n cancelAnimationFrame(rafId);\n clearTimeout(glitchOnTimer);\n clearTimeout(glitchOffTimer);\n clearTimeout(clickTimer);\n canvas.removeEventListener('mousemove', onMouseMove);\n canvas.removeEventListener('mouseleave', onMouseLeave);\n canvas.removeEventListener('touchmove', onTouchMove);\n canvas.removeEventListener('touchend', onTouchEnd);\n canvas.removeEventListener('click', onClick);\n };\n }\n}\n\nexport type { WrFuzzyTextDirection } from './interfaces';\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-fuzzy-text.mjs","sources":["../../../projects/lib/fuzzy-text/fuzzy-text.ts","../../../projects/lib/fuzzy-text/ngwr-fuzzy-text.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 * Angular adaptation of the FuzzyText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/fuzzy-text\n *\n * Renders text to an offscreen 2D canvas, then redraws it onto the\n * visible canvas one row (or column) at a time with random horizontal /\n * vertical offsets. Intensity reacts to hover / click / glitch state.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport type { ElementRef } from '@angular/core';\nimport {\n Component,\n DestroyRef,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n effect,\n inject,\n input,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrFuzzyTextDirection } from './interfaces';\n\n/**\n * Canvas-rendered \"fuzzy\" text — each row/column of glyphs is offset by\n * a random amount per frame, giving the text a TV-static or motion-blur\n * appearance. Intensity ramps up on hover, click, and during periodic\n * glitch bursts (configurable).\n *\n * @example\n * ```html\n * <wr-fuzzy-text text=\"404\" />\n * <wr-fuzzy-text\n * text=\"HELLO\"\n * color=\"#0ea5e9\"\n * [fuzzRange]=\"50\"\n * [hoverIntensity]=\"0.8\"\n * [glitchMode]=\"true\"\n * />\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/fuzzy-text\n */\n@Component({\n selector: 'wr-fuzzy-text',\n // The text is drawn into the canvas as PIXELS, so without the first span there is\n // nothing for a screen reader to read at all — the same layer `wr-rotating-text`\n // and `wr-decrypt-text` carry. Hidden inline rather than through a class: this\n // entry point ships no stylesheet, and a consumer who imported none would\n // otherwise see the text twice.\n //\n // BOUND, not a static `style=\"…\"` attribute. A real attribute is refused under\n // `style-src 'self'`, and what is lost there is not a colour: the span drops\n // every visual-hiding declaration and the word renders on screen beside the\n // canvas that already draws it. A binding goes through `style.setProperty`,\n // which is CSSOM and outside CSP's reach.\n template:\n '<span class=\"wr-fuzzy-text__sr-only\" [style]=\"srOnly\">{{ text() }}</span>' +\n '<canvas #canvas aria-hidden=\"true\"></canvas>',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-fuzzy-text', '[style.color]': \"'var(--wr-color-dark)'\" },\n})\nexport class WrFuzzyText {\n /**\n * Visual-hiding declarations for the screen-reader copy of the text. A stable\n * object literal, so the binding is written once rather than on every pass.\n */\n protected readonly srOnly: Readonly<Record<string, string>> = {\n position: 'absolute',\n width: '1px',\n height: '1px',\n overflow: 'hidden',\n 'clip-path': 'inset(50%)',\n 'white-space': 'nowrap',\n };\n\n /** Text to render. */\n readonly text = input.required<string>();\n\n /** Font size as CSS length (`'4rem'`, `'72px'`, …) or px number. @default 'clamp(2rem, 10vw, 10rem)' */\n readonly fontSize = input<string | number>('clamp(2rem, 10vw, 10rem)');\n\n /** Font weight. @default 900 */\n readonly fontWeight = input<number | string>(900);\n\n /** Font family. `'inherit'` reads the canvas's computed style. @default 'inherit' */\n readonly fontFamily = input('inherit');\n\n /** Text colour. `'inherit'` reads the canvas's computed style. Ignored if `[gradient]` is set. @default 'inherit' */\n readonly color = input('inherit');\n\n /** Optional horizontal gradient stops. */\n readonly gradient = input<readonly string[] | null>(null);\n\n /** Enable hover / touch reactivity. @default true */\n readonly enableHover = input(true, { transform: coerceBooleanProperty });\n\n /** Base intensity (0..1) when idle. @default 0.18 */\n readonly baseIntensity = input(0.18, { transform: numAttr(0.18) });\n\n /** Intensity (0..1) while the pointer hovers the text. @default 0.5 */\n readonly hoverIntensity = input(0.5, { transform: numAttr(0.5) });\n\n /** Max pixel displacement per row/column at intensity 1. @default 30 */\n readonly fuzzRange = input(30, { transform: numAttr(30) });\n\n /** Frame rate cap. @default 60 */\n readonly fps = input(60, { transform: numAttr(60) });\n\n /** Fuzz direction. @default 'horizontal' */\n readonly direction = input<WrFuzzyTextDirection>('horizontal');\n\n /** Ms to ease intensity toward target. `0` snaps. @default 0 */\n readonly transitionDuration = input(0, { transform: numAttr(0) });\n\n /** Spike to full intensity briefly on click. @default false */\n readonly clickEffect = input(false, { transform: coerceBooleanProperty });\n\n /** Periodic \"glitch\" bursts at full intensity. @default false */\n readonly glitchMode = input(false, { transform: coerceBooleanProperty });\n\n /** Ms between glitch bursts. @default 2000 */\n readonly glitchInterval = input(2000, { transform: numAttr(2000) });\n\n /** Ms a glitch burst lasts. @default 200 */\n readonly glitchDuration = input(200, { transform: numAttr(200) });\n\n /** Extra pixels between glyphs. @default 0 */\n readonly letterSpacing = input(0, { transform: numAttr(0) });\n\n private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n private readonly platform = inject(WrPlatform);\n\n private teardown: (() => void) | undefined;\n\n /**\n * `init()` suspends on font loading, so the component can be destroyed while\n * it is awaiting. At that moment `teardown` is still undefined, so the\n * destroy hook has nothing to call — and everything the rest of `init()`\n * starts (the rAF loop, the glitch timers, canvas listeners) would run for\n * the life of the page. This flag lets the continuation bail out.\n */\n private destroyed = false;\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => {\n void this.init();\n });\n\n // Re-init whenever any input that affects the offscreen rendering changes.\n effect(() => {\n this.text();\n this.fontSize();\n this.fontWeight();\n this.fontFamily();\n this.color();\n this.gradient();\n this.letterSpacing();\n this.direction();\n this.fuzzRange();\n this.fps();\n this.glitchMode();\n this.glitchInterval();\n this.glitchDuration();\n // Skip if we haven't booted yet.\n if (!this.teardown) return;\n this.teardown();\n this.teardown = undefined;\n queueMicrotask(() => {\n void this.init();\n });\n });\n\n this.destroyRef.onDestroy(() => {\n this.destroyed = true;\n this.teardown?.();\n });\n }\n\n // Init / loop\n\n private async init(): Promise<void> {\n const canvas = this.canvasRef().nativeElement;\n const ctx = canvas.getContext('2d');\n if (!ctx) return;\n\n const fontFamily =\n this.fontFamily() === 'inherit' ? window.getComputedStyle(canvas).fontFamily || 'sans-serif' : this.fontFamily();\n const color = this.color() === 'inherit' ? window.getComputedStyle(canvas).color || '#fff' : this.color();\n const fontSize = this.fontSize();\n const fontSizeStr = typeof fontSize === 'number' ? `${fontSize}px` : fontSize;\n const fontWeight = this.fontWeight();\n const fontString = `${fontWeight} ${fontSizeStr} ${fontFamily}`;\n\n try {\n await document.fonts.load(fontString);\n } catch {\n await document.fonts.ready;\n }\n\n // Destroyed while the fonts were loading — nothing below may start.\n if (this.destroyed) return;\n\n // Numeric font size for buffer maths.\n let numericFontSize: number;\n if (typeof fontSize === 'number') {\n numericFontSize = fontSize;\n } else {\n const tmp = document.createElement('span');\n tmp.style.fontSize = fontSize;\n document.body.appendChild(tmp);\n numericFontSize = Number.parseFloat(window.getComputedStyle(tmp).fontSize);\n document.body.removeChild(tmp);\n }\n\n const text = this.text();\n const letterSpacing = this.letterSpacing();\n const fuzzRange = this.fuzzRange();\n const direction = this.direction();\n\n // Offscreen canvas with the laid-out text.\n const offscreen = document.createElement('canvas');\n const offCtx = offscreen.getContext('2d');\n if (!offCtx) return;\n offCtx.font = fontString;\n offCtx.textBaseline = 'alphabetic';\n\n let totalWidth = 0;\n if (letterSpacing !== 0) {\n for (const ch of text) totalWidth += offCtx.measureText(ch).width + letterSpacing;\n totalWidth -= letterSpacing;\n } else {\n totalWidth = offCtx.measureText(text).width;\n }\n const m = offCtx.measureText(text);\n const actualLeft = m.actualBoundingBoxLeft ?? 0;\n const actualRight = letterSpacing !== 0 ? totalWidth : (m.actualBoundingBoxRight ?? m.width);\n const actualAscent = m.actualBoundingBoxAscent ?? numericFontSize;\n const actualDescent = m.actualBoundingBoxDescent ?? numericFontSize * 0.2;\n const textBoundingWidth = Math.ceil(letterSpacing !== 0 ? totalWidth : actualLeft + actualRight);\n const tightHeight = Math.ceil(actualAscent + actualDescent);\n\n const extraWidthBuffer = 10;\n const offscreenWidth = textBoundingWidth + extraWidthBuffer;\n offscreen.width = offscreenWidth;\n offscreen.height = tightHeight;\n const xOffset = extraWidthBuffer / 2;\n\n offCtx.font = fontString;\n offCtx.textBaseline = 'alphabetic';\n\n const gradient = this.gradient();\n if (gradient && gradient.length >= 2) {\n const g = offCtx.createLinearGradient(0, 0, offscreenWidth, 0);\n gradient.forEach((c, i) => g.addColorStop(i / (gradient.length - 1), c));\n offCtx.fillStyle = g;\n } else {\n offCtx.fillStyle = color;\n }\n\n if (letterSpacing !== 0) {\n let xPos = xOffset;\n for (const ch of text) {\n offCtx.fillText(ch, xPos, actualAscent);\n xPos += offCtx.measureText(ch).width + letterSpacing;\n }\n } else {\n offCtx.fillText(text, xOffset - actualLeft, actualAscent);\n }\n\n // Size the visible canvas, leaving room for the max horizontal fuzz.\n const horizontalMargin = fuzzRange + 20;\n const verticalMargin = 0;\n canvas.width = offscreenWidth + horizontalMargin * 2;\n canvas.height = tightHeight + verticalMargin * 2;\n ctx.translate(horizontalMargin, verticalMargin);\n\n const interactiveLeft = horizontalMargin + xOffset;\n const interactiveTop = verticalMargin;\n const interactiveRight = interactiveLeft + textBoundingWidth;\n const interactiveBottom = interactiveTop + tightHeight;\n\n // Reduced motion: paint the text once, clean — no fuzz loop, no\n // glitch bursts, no pointer reactivity. Teardown must still be set\n // so the re-init effect keeps redrawing on input changes.\n if (this.platform.prefersReducedMotion()) {\n ctx.drawImage(offscreen, 0, 0);\n this.teardown = (): void => undefined;\n return;\n }\n\n let isHovering = false;\n let isClicking = false;\n let isGlitching = false;\n let currentIntensity = this.baseIntensity();\n let targetIntensity = currentIntensity;\n let lastFrame = 0;\n const frameDuration = 1000 / this.fps();\n\n let rafId = 0;\n let glitchOnTimer: ReturnType<typeof setTimeout> | undefined;\n let glitchOffTimer: ReturnType<typeof setTimeout> | undefined;\n let clickTimer: ReturnType<typeof setTimeout> | undefined;\n\n const startGlitchLoop = (): void => {\n if (!this.glitchMode()) return;\n glitchOnTimer = setTimeout(() => {\n isGlitching = true;\n glitchOffTimer = setTimeout(() => {\n isGlitching = false;\n startGlitchLoop();\n }, this.glitchDuration());\n }, this.glitchInterval());\n };\n if (this.glitchMode()) startGlitchLoop();\n\n const run = (ts: number): void => {\n if (ts - lastFrame < frameDuration) {\n rafId = requestAnimationFrame(run);\n return;\n }\n lastFrame = ts;\n\n ctx.clearRect(\n -fuzzRange - 20,\n -fuzzRange - 10,\n offscreenWidth + 2 * (fuzzRange + 20),\n tightHeight + 2 * (fuzzRange + 10)\n );\n\n if (isClicking) targetIntensity = 1;\n else if (isGlitching) targetIntensity = 1;\n else if (isHovering) targetIntensity = this.hoverIntensity();\n else targetIntensity = this.baseIntensity();\n\n const td = this.transitionDuration();\n if (td > 0) {\n const step = 1 / (td / frameDuration);\n if (currentIntensity < targetIntensity) currentIntensity = Math.min(currentIntensity + step, targetIntensity);\n else if (currentIntensity > targetIntensity)\n currentIntensity = Math.max(currentIntensity - step, targetIntensity);\n } else {\n currentIntensity = targetIntensity;\n }\n\n if (direction === 'horizontal') {\n for (let j = 0; j < tightHeight; j++) {\n const dx = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange);\n ctx.drawImage(offscreen, 0, j, offscreenWidth, 1, dx, j, offscreenWidth, 1);\n }\n } else if (direction === 'vertical') {\n for (let i = 0; i < offscreenWidth; i++) {\n const dy = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange);\n ctx.drawImage(offscreen, i, 0, 1, tightHeight, i, dy, 1, tightHeight);\n }\n } else {\n // both: horizontal pass then vertical pass on the result\n for (let j = 0; j < tightHeight; j++) {\n const dx = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange);\n ctx.drawImage(offscreen, 0, j, offscreenWidth, 1, dx, j, offscreenWidth, 1);\n }\n const w = offscreenWidth + fuzzRange;\n const h = tightHeight + fuzzRange;\n const data = ctx.getImageData(0, 0, w, h);\n ctx.clearRect(\n -fuzzRange - 20,\n -fuzzRange - 10,\n offscreenWidth + 2 * (fuzzRange + 20),\n tightHeight + 2 * (fuzzRange + 10)\n );\n ctx.putImageData(data, 0, 0);\n for (let i = 0; i < w; i++) {\n const dy = Math.floor(currentIntensity * (Math.random() - 0.5) * fuzzRange * 0.5);\n const col = ctx.getImageData(i, 0, 1, h);\n ctx.clearRect(i, -fuzzRange, 1, tightHeight + 2 * fuzzRange);\n ctx.putImageData(col, i, dy);\n }\n }\n\n rafId = requestAnimationFrame(run);\n };\n rafId = requestAnimationFrame(run);\n\n const isInsideText = (x: number, y: number): boolean =>\n x >= interactiveLeft && x <= interactiveRight && y >= interactiveTop && y <= interactiveBottom;\n\n const onMouseMove = (e: MouseEvent): void => {\n if (!this.enableHover()) return;\n const rect = canvas.getBoundingClientRect();\n isHovering = isInsideText(e.clientX - rect.left, e.clientY - rect.top);\n };\n const onMouseLeave = (): void => {\n isHovering = false;\n };\n const onTouchMove = (e: TouchEvent): void => {\n if (!this.enableHover()) return;\n e.preventDefault();\n const rect = canvas.getBoundingClientRect();\n const t = e.touches[0];\n isHovering = isInsideText(t.clientX - rect.left, t.clientY - rect.top);\n };\n const onTouchEnd = (): void => {\n isHovering = false;\n };\n const onClick = (): void => {\n if (!this.clickEffect()) return;\n isClicking = true;\n clearTimeout(clickTimer);\n clickTimer = setTimeout(() => {\n isClicking = false;\n }, 150);\n };\n\n // Attached unconditionally, and gated inside the three handlers that can SET a\n // reactive state instead. `enableHover` and `clickEffect` are not in the re-init\n // effect's dependency list, so an attach conditional on them read the value at\n // boot and never again: a `[clickEffect]` bound to a signal that starts `false` —\n // the default, so the ordinary case — stayed dead after it flipped true. Adding\n // them to that list would restart the rAF loop and the glitch timers just to\n // toggle a listener, which is visible; the guards are not. `onTouchMove` calls\n // `preventDefault()` only past its own guard, so a hover-disabled instance still\n // swallows nothing.\n //\n // `onMouseLeave` / `onTouchEnd` stay ungated deliberately: they only ever CLEAR\n // toward the idle state, and gating them would strand `isHovering` on for good\n // when hover is switched off mid-hover.\n canvas.addEventListener('mousemove', onMouseMove);\n canvas.addEventListener('mouseleave', onMouseLeave);\n canvas.addEventListener('touchmove', onTouchMove, { passive: false });\n canvas.addEventListener('touchend', onTouchEnd);\n canvas.addEventListener('click', onClick);\n\n this.teardown = (): void => {\n cancelAnimationFrame(rafId);\n clearTimeout(glitchOnTimer);\n clearTimeout(glitchOffTimer);\n clearTimeout(clickTimer);\n canvas.removeEventListener('mousemove', onMouseMove);\n canvas.removeEventListener('mouseleave', onMouseLeave);\n canvas.removeEventListener('touchmove', onTouchMove);\n canvas.removeEventListener('touchend', onTouchEnd);\n canvas.removeEventListener('click', onClick);\n };\n }\n}\n\nexport type { WrFuzzyTextDirection } from './interfaces';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { coerceBooleanProperty } from '@angular/cdk/coercion';
2
2
  import * as i0 from '@angular/core';
3
3
  import { input, computed, ViewEncapsulation, Component } from '@angular/core';
4
- import { numAttr } from 'ngwr/utils';
4
+ import { numAttr, isSafeCssValue } from 'ngwr/utils';
5
5
 
6
6
  /**
7
7
  * @license
@@ -53,7 +53,14 @@ class WrGradientText {
53
53
  /** Bounce back-and-forth instead of restarting. @default true */
54
54
  yoyo = input(true, { ...(ngDevMode ? { debugName: "yoyo" } : /* istanbul ignore next */ {}), transform: coerceBooleanProperty });
55
55
  gradient = computed(() => {
56
- const cols = this.colors().length > 0 ? this.colors() : DEFAULT_COLORS;
56
+ // The stops are JOINED into the gradient below and published as
57
+ // `--wr-gradient-text-image`, which the stylesheet substitutes into
58
+ // `background-image`. An entry that closes the library's own paren escapes
59
+ // into a sibling background layer, so one unsafe stop discards the palette
60
+ // rather than being repaired in place — a half-validated gradient is worse
61
+ // to look at than the default one.
62
+ const raw = this.colors();
63
+ const cols = raw.length > 0 && raw.every(color => isSafeCssValue(color)) ? raw : DEFAULT_COLORS;
57
64
  // Duplicate the first colour at the end for seamless looping.
58
65
  const stops = [...cols, cols[0]].join(', ');
59
66
  const angle = this.directionAngle();
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-gradient-text.mjs","sources":["../../../projects/lib/gradient-text/gradient-text.ts","../../../projects/lib/gradient-text/gradient-text.html","../../../projects/lib/gradient-text/ngwr-gradient-text.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 * Angular adaptation of the GradientText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/gradient-text\n *\n * The reactbits version uses `motion/react` to drive `background-position`\n * via rAF. This port is pure CSS — same effect via keyframes on\n * `background-position`, parameterised by inputs.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrGradientTextDirection } from './interfaces';\n\nconst DEFAULT_COLORS: readonly string[] = ['#5227FF', '#FF9FFC', '#B497CF'];\n\n/**\n * Animated multi-stop gradient text. The gradient slides across the text\n * via `background-clip: text`. Optional `[showBorder]` wraps the text in\n * a dark pill with the same animated gradient as a border ring.\n *\n * @example\n * ```html\n * <wr-gradient-text>Hello, ngwr!</wr-gradient-text>\n * <wr-gradient-text\n * [colors]=\"['#5227FF', '#FF9FFC', '#B497CF']\"\n * direction=\"diagonal\"\n * [animationSpeed]=\"6\"\n * [showBorder]=\"true\"\n * >\n * Premium feature\n * </wr-gradient-text>\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/gradient-text\n */\n@Component({\n selector: 'wr-gradient-text',\n templateUrl: './gradient-text.html',\n styleUrl: './gradient-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-gradient-text',\n '[class.wr-gradient-text--border]': 'showBorder()',\n '[class.wr-gradient-text--pause-on-hover]': 'pauseOnHover()',\n '[class.wr-gradient-text--yoyo]': 'yoyo()',\n '[class.wr-gradient-text--vertical]': \"direction() === 'vertical'\",\n '[class.wr-gradient-text--diagonal]': \"direction() === 'diagonal'\",\n '[style.--wr-gradient-text-image]': 'gradient()',\n '[style.--wr-gradient-text-size]': 'size()',\n '[style.--wr-gradient-text-duration]': \"animationSpeed() + 's'\",\n },\n})\nexport class WrGradientText {\n /** Gradient stops. @default ['#5227FF', '#FF9FFC', '#B497CF'] */\n readonly colors = input<readonly string[]>(DEFAULT_COLORS);\n\n /** Seconds per full sweep (or per half if `[yoyo]` is on). @default 8 */\n readonly animationSpeed = input(8, { transform: numAttr(8) });\n\n /** Wrap the text in a dark pill with the gradient as a border. @default false */\n readonly showBorder = input(false, { transform: coerceBooleanProperty });\n\n /** Gradient slide direction. @default 'horizontal' */\n readonly direction = input<WrGradientTextDirection>('horizontal');\n\n /** Pause the animation while hovered. @default false */\n readonly pauseOnHover = input(false, { transform: coerceBooleanProperty });\n\n /** Bounce back-and-forth instead of restarting. @default true */\n readonly yoyo = input(true, { transform: coerceBooleanProperty });\n\n protected readonly gradient = computed(() => {\n const cols = this.colors().length > 0 ? this.colors() : DEFAULT_COLORS;\n // Duplicate the first colour at the end for seamless looping.\n const stops = [...cols, cols[0]].join(', ');\n const angle = this.directionAngle();\n return `linear-gradient(${angle}, ${stops})`;\n });\n\n protected readonly size = computed(() => {\n switch (this.direction()) {\n case 'vertical':\n return '100% 300%';\n case 'diagonal':\n return '300% 300%';\n case 'horizontal':\n default:\n return '300% 100%';\n }\n });\n\n private directionAngle(): string {\n switch (this.direction()) {\n case 'vertical':\n return 'to bottom';\n case 'diagonal':\n return 'to bottom right';\n case 'horizontal':\n default:\n return 'to right';\n }\n }\n}\n\nexport type { WrGradientTextDirection } from './interfaces';\n","@if (showBorder()) {\n <span class=\"wr-gradient-text__border\" aria-hidden=\"true\"></span>\n}\n<span class=\"wr-gradient-text__text\">\n <ng-content />\n</span>\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-gradient-text.mjs","sources":["../../../projects/lib/gradient-text/gradient-text.ts","../../../projects/lib/gradient-text/gradient-text.html","../../../projects/lib/gradient-text/ngwr-gradient-text.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 * Angular adaptation of the GradientText effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/text-animations/gradient-text\n *\n * The reactbits version uses `motion/react` to drive `background-position`\n * via rAF. This port is pure CSS — same effect via keyframes on\n * `background-position`, parameterised by inputs.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\nimport { isSafeCssValue, numAttr } from 'ngwr/utils';\n\nimport type { WrGradientTextDirection } from './interfaces';\n\nconst DEFAULT_COLORS: readonly string[] = ['#5227FF', '#FF9FFC', '#B497CF'];\n\n/**\n * Animated multi-stop gradient text. The gradient slides across the text\n * via `background-clip: text`. Optional `[showBorder]` wraps the text in\n * a dark pill with the same animated gradient as a border ring.\n *\n * @example\n * ```html\n * <wr-gradient-text>Hello, ngwr!</wr-gradient-text>\n * <wr-gradient-text\n * [colors]=\"['#5227FF', '#FF9FFC', '#B497CF']\"\n * direction=\"diagonal\"\n * [animationSpeed]=\"6\"\n * [showBorder]=\"true\"\n * >\n * Premium feature\n * </wr-gradient-text>\n * ```\n *\n * @see https://www.reactbits.dev/text-animations/gradient-text\n */\n@Component({\n selector: 'wr-gradient-text',\n templateUrl: './gradient-text.html',\n styleUrl: './gradient-text.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-gradient-text',\n '[class.wr-gradient-text--border]': 'showBorder()',\n '[class.wr-gradient-text--pause-on-hover]': 'pauseOnHover()',\n '[class.wr-gradient-text--yoyo]': 'yoyo()',\n '[class.wr-gradient-text--vertical]': \"direction() === 'vertical'\",\n '[class.wr-gradient-text--diagonal]': \"direction() === 'diagonal'\",\n '[style.--wr-gradient-text-image]': 'gradient()',\n '[style.--wr-gradient-text-size]': 'size()',\n '[style.--wr-gradient-text-duration]': \"animationSpeed() + 's'\",\n },\n})\nexport class WrGradientText {\n /** Gradient stops. @default ['#5227FF', '#FF9FFC', '#B497CF'] */\n readonly colors = input<readonly string[]>(DEFAULT_COLORS);\n\n /** Seconds per full sweep (or per half if `[yoyo]` is on). @default 8 */\n readonly animationSpeed = input(8, { transform: numAttr(8) });\n\n /** Wrap the text in a dark pill with the gradient as a border. @default false */\n readonly showBorder = input(false, { transform: coerceBooleanProperty });\n\n /** Gradient slide direction. @default 'horizontal' */\n readonly direction = input<WrGradientTextDirection>('horizontal');\n\n /** Pause the animation while hovered. @default false */\n readonly pauseOnHover = input(false, { transform: coerceBooleanProperty });\n\n /** Bounce back-and-forth instead of restarting. @default true */\n readonly yoyo = input(true, { transform: coerceBooleanProperty });\n\n protected readonly gradient = computed(() => {\n // The stops are JOINED into the gradient below and published as\n // `--wr-gradient-text-image`, which the stylesheet substitutes into\n // `background-image`. An entry that closes the library's own paren escapes\n // into a sibling background layer, so one unsafe stop discards the palette\n // rather than being repaired in place — a half-validated gradient is worse\n // to look at than the default one.\n const raw = this.colors();\n const cols = raw.length > 0 && raw.every(color => isSafeCssValue(color)) ? raw : DEFAULT_COLORS;\n // Duplicate the first colour at the end for seamless looping.\n const stops = [...cols, cols[0]].join(', ');\n const angle = this.directionAngle();\n return `linear-gradient(${angle}, ${stops})`;\n });\n\n protected readonly size = computed(() => {\n switch (this.direction()) {\n case 'vertical':\n return '100% 300%';\n case 'diagonal':\n return '300% 300%';\n case 'horizontal':\n default:\n return '300% 100%';\n }\n });\n\n private directionAngle(): string {\n switch (this.direction()) {\n case 'vertical':\n return 'to bottom';\n case 'diagonal':\n return 'to bottom right';\n case 'horizontal':\n default:\n return 'to right';\n }\n }\n}\n\nexport type { WrGradientTextDirection } from './interfaces';\n","@if (showBorder()) {\n <span class=\"wr-gradient-text__border\" aria-hidden=\"true\"></span>\n}\n<span class=\"wr-gradient-text__text\">\n <ng-content />\n</span>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
@@ -34,6 +34,17 @@ const SVG_ATTRS = [
34
34
  *
35
35
  * provideWrIcons([feather('plus', featherIcons.plus)]);
36
36
  * ```
37
+ *
38
+ * `innerSvg` is **markup**, not text — that is the shape upstream ships and the
39
+ * reason this adapter exists — so it is interpolated into the envelope
40
+ * verbatim. There is no escaping to add here: escaped markup is not markup.
41
+ * A `</svg>` in that input therefore closes the envelope early, and everything
42
+ * after it is a sibling of the icon rather than a child. Nothing executes
43
+ * regardless, because `<wr-icon>` never assigns the result to `innerHTML` — it
44
+ * rebuilds the first `<svg>` root from an allowlist and drops the rest. Feed
45
+ * this a map fetched at runtime and the sanitizer is what stands between it and
46
+ * the app's origin; feed it the `icons.json` from your own node_modules and
47
+ * neither matters.
37
48
  */
38
49
  function feather(name, innerSvg) {
39
50
  return { name, data: `<svg ${SVG_ATTRS}>${innerSvg}</svg>` };
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-icon-adapters-feather.mjs","sources":["../../../projects/lib/icon/adapters/feather/adapter.ts","../../../projects/lib/icon/adapters/feather/public-api.ts","../../../projects/lib/icon/adapters/feather/ngwr-icon-adapters-feather.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 type { WrIconDef } from 'ngwr/icon';\n\n/**\n * Default SVG attributes Feather applies to every icon. Kept identical\n * to what `feather.replace()` emits in the browser so visual parity\n * with upstream is preserved.\n */\nconst SVG_ATTRS = [\n 'xmlns=\"http://www.w3.org/2000/svg\"',\n 'width=\"24\"',\n 'height=\"24\"',\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 'class=\"wr-icon__svg feather\"',\n].join(' ');\n\n/**\n * Wrap a single Feather icon (inner SVG markup) in a {@link WrIconDef}\n * envelope. Pair with the upstream `icons.json` map.\n *\n * @example\n * ```ts\n * import { feather } from 'ngwr/icon/adapters/feather';\n * // feather-icons ships an inner-SVG-only map under dist/icons.json:\n * // { \"plus\": \"<line .../><line .../>\", \"trash\": \"...\", ... }\n * import featherIcons from 'feather-icons/dist/icons.json';\n *\n * provideWrIcons([feather('plus', featherIcons.plus)]);\n * ```\n */\nfunction feather(name: string, innerSvg: string): WrIconDef {\n return { name, data: `<svg ${SVG_ATTRS}>${innerSvg}</svg>` };\n}\n\n/**\n * Bulk variant — pass a `{ alias: innerSvg }` object. Aliases (the\n * keys) become the registry names so you can use shorter or\n * project-specific names.\n *\n * @example\n * ```ts\n * import { featherIcons } from 'ngwr/icon/adapters/feather';\n * import featherSource from 'feather-icons/dist/icons.json';\n *\n * provideWrIcons(featherIcons({\n * plus: featherSource.plus,\n * trash: featherSource.trash,\n * x: featherSource.x,\n * }));\n * ```\n */\nfunction featherIcons(icons: Record<string, string>): WrIconDef[] {\n return Object.entries(icons).map(([name, innerSvg]) => feather(name, innerSvg));\n}\n\nexport { feather, featherIcons };\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\nexport { feather, featherIcons } from './adapter';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;;AAKG;AAIH;;;;AAIG;AACH,MAAM,SAAS,GAAG;IAChB,oCAAoC;IACpC,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,aAAa;IACb,uBAAuB;IACvB,kBAAkB;IAClB,wBAAwB;IACxB,yBAAyB;IACzB,8BAA8B;AAC/B,CAAA,CAAC,IAAI,CAAC,GAAG,CAAC;AAEX;;;;;;;;;;;;;AAaG;AACH,SAAS,OAAO,CAAC,IAAY,EAAE,QAAgB,EAAA;IAC7C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA,KAAA,EAAQ,SAAS,CAAA,CAAA,EAAI,QAAQ,CAAA,MAAA,CAAQ,EAAE;AAC9D;AAEA;;;;;;;;;;;;;;;;AAgBG;AACH,SAAS,YAAY,CAAC,KAA6B,EAAA;IACjD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACjF;;AChEA;;;;;AAKG;;ACLH;;AAEG;;;;"}
1
+ {"version":3,"file":"ngwr-icon-adapters-feather.mjs","sources":["../../../projects/lib/icon/adapters/feather/adapter.ts","../../../projects/lib/icon/adapters/feather/public-api.ts","../../../projects/lib/icon/adapters/feather/ngwr-icon-adapters-feather.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 type { WrIconDef } from 'ngwr/icon';\n\n/**\n * Default SVG attributes Feather applies to every icon. Kept identical\n * to what `feather.replace()` emits in the browser so visual parity\n * with upstream is preserved.\n */\nconst SVG_ATTRS = [\n 'xmlns=\"http://www.w3.org/2000/svg\"',\n 'width=\"24\"',\n 'height=\"24\"',\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 'class=\"wr-icon__svg feather\"',\n].join(' ');\n\n/**\n * Wrap a single Feather icon (inner SVG markup) in a {@link WrIconDef}\n * envelope. Pair with the upstream `icons.json` map.\n *\n * @example\n * ```ts\n * import { feather } from 'ngwr/icon/adapters/feather';\n * // feather-icons ships an inner-SVG-only map under dist/icons.json:\n * // { \"plus\": \"<line .../><line .../>\", \"trash\": \"...\", ... }\n * import featherIcons from 'feather-icons/dist/icons.json';\n *\n * provideWrIcons([feather('plus', featherIcons.plus)]);\n * ```\n *\n * `innerSvg` is **markup**, not text — that is the shape upstream ships and the\n * reason this adapter exists — so it is interpolated into the envelope\n * verbatim. There is no escaping to add here: escaped markup is not markup.\n * A `</svg>` in that input therefore closes the envelope early, and everything\n * after it is a sibling of the icon rather than a child. Nothing executes\n * regardless, because `<wr-icon>` never assigns the result to `innerHTML` — it\n * rebuilds the first `<svg>` root from an allowlist and drops the rest. Feed\n * this a map fetched at runtime and the sanitizer is what stands between it and\n * the app's origin; feed it the `icons.json` from your own node_modules and\n * neither matters.\n */\nfunction feather(name: string, innerSvg: string): WrIconDef {\n return { name, data: `<svg ${SVG_ATTRS}>${innerSvg}</svg>` };\n}\n\n/**\n * Bulk variant — pass a `{ alias: innerSvg }` object. Aliases (the\n * keys) become the registry names so you can use shorter or\n * project-specific names.\n *\n * @example\n * ```ts\n * import { featherIcons } from 'ngwr/icon/adapters/feather';\n * import featherSource from 'feather-icons/dist/icons.json';\n *\n * provideWrIcons(featherIcons({\n * plus: featherSource.plus,\n * trash: featherSource.trash,\n * x: featherSource.x,\n * }));\n * ```\n */\nfunction featherIcons(icons: Record<string, string>): WrIconDef[] {\n return Object.entries(icons).map(([name, innerSvg]) => feather(name, innerSvg));\n}\n\nexport { feather, featherIcons };\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\nexport { feather, featherIcons } from './adapter';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;;AAKG;AAIH;;;;AAIG;AACH,MAAM,SAAS,GAAG;IAChB,oCAAoC;IACpC,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,aAAa;IACb,uBAAuB;IACvB,kBAAkB;IAClB,wBAAwB;IACxB,yBAAyB;IACzB,8BAA8B;AAC/B,CAAA,CAAC,IAAI,CAAC,GAAG,CAAC;AAEX;;;;;;;;;;;;;;;;;;;;;;;;AAwBG;AACH,SAAS,OAAO,CAAC,IAAY,EAAE,QAAgB,EAAA;IAC7C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA,KAAA,EAAQ,SAAS,CAAA,CAAA,EAAI,QAAQ,CAAA,MAAA,CAAQ,EAAE;AAC9D;AAEA;;;;;;;;;;;;;;;;AAgBG;AACH,SAAS,YAAY,CAAC,KAA6B,EAAA;IACjD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,QAAQ,CAAC,KAAK,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AACjF;;AC3EA;;;;;AAKG;;ACLH;;AAEG;;;;"}
@@ -64,10 +64,30 @@ function lucide(name, children) {
64
64
  function lucideIcons(icons) {
65
65
  return Object.entries(icons).map(([name, node]) => lucide(name, node));
66
66
  }
67
+ /**
68
+ * A tag or attribute name that can only ever be a name.
69
+ *
70
+ * `renderChild` builds markup by concatenation, so a name carrying a quote, a
71
+ * space or an `=` does not become a strangely-named attribute — it closes the
72
+ * one being written and opens whatever comes next, which is how
73
+ * `{ 'href': 'x" onerror="…' }`'s sibling, a hostile KEY, injects a handler
74
+ * through an API whose signature says `Record<string, string | number>`.
75
+ * Escaping cannot help a name: `onerror` is a perfectly valid name and the only
76
+ * honest serialisation of it is `onerror="…"`. So names are constrained and
77
+ * values are escaped, and it is {@link sanitizeIcon} at the render sink that
78
+ * refuses `onerror` itself.
79
+ */
80
+ const NAME_RE = /^[A-Za-z_][\w.:-]*$/;
81
+ /** The four characters that can leave an attribute value or a tag body. */
82
+ function escapeAttribute(value) {
83
+ return String(value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
84
+ }
67
85
  function renderChild([tag, attrs]) {
86
+ if (!NAME_RE.test(tag))
87
+ return '';
68
88
  const rendered = Object.entries(attrs)
69
- .filter((entry) => entry[1] !== undefined)
70
- .map(([key, value]) => `${key}="${value}"`)
89
+ .filter((entry) => entry[1] !== undefined && NAME_RE.test(entry[0]))
90
+ .map(([key, value]) => `${key}="${escapeAttribute(value)}"`)
71
91
  .join(' ');
72
92
  return `<${tag} ${rendered}/>`;
73
93
  }
@@ -1 +1 @@
1
- {"version":3,"file":"ngwr-icon-adapters-lucide.mjs","sources":["../../../projects/lib/icon/adapters/lucide/adapter.ts","../../../projects/lib/icon/adapters/lucide/public-api.ts","../../../projects/lib/icon/adapters/lucide/ngwr-icon-adapters-lucide.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 type { WrIconDef } from 'ngwr/icon';\n\n/**\n * Shape of a `lucide` icon export — an array of `[tag, attrs]` tuples\n * representing the inner SVG children. The outer `<svg>` wrapper is\n * added by the adapter when converting to a {@link WrIconDef}.\n */\ntype LucideIconNode = readonly (readonly [string, Record<string, string | number | undefined>])[];\n\n/**\n * Default SVG attributes Lucide applies to every icon. Kept identical\n * to what the `lucide` package's `createElement` would emit so visual\n * parity with upstream is preserved.\n */\nconst SVG_ATTRS = [\n 'xmlns=\"http://www.w3.org/2000/svg\"',\n 'width=\"24\"',\n 'height=\"24\"',\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 'class=\"wr-icon__svg lucide\"',\n].join(' ');\n\n/**\n * Wrap a single Lucide icon in the {@link WrIconDef} envelope. Use this\n * when you need fine-grained control over the registered name, or when\n * the bulk {@link lucideIcons} helper isn't a good fit.\n *\n * @example\n * ```ts\n * import { Plus } from 'lucide';\n * import { lucide } from 'ngwr/icon/adapters/lucide';\n *\n * provideWrIcons([lucide('plus', Plus)]);\n * ```\n */\nfunction lucide(name: string, children: LucideIconNode): WrIconDef {\n const inner = children.map(renderChild).join('');\n return { name, data: `<svg ${SVG_ATTRS}>${inner}</svg>` };\n}\n\n/**\n * Wrap a bag of Lucide icons in one shot. Keys become the registered\n * names **verbatim** — exactly what you pass to `<wr-icon name>` — matching\n * the singular `lucide()` helper and the other adapters. Kebab-case by\n * convention, so quote multi-word keys (`'chevron-down'`). Values are the\n * upstream IconNode tuples.\n *\n * Tree-shaking: every `Plus`, `Trash`, … import lives in *your* file\n * — ngwr ships only this wrapper, not the icon data. Unused icons in\n * `lucide` itself get dropped by the bundler.\n *\n * @example\n * ```ts\n * import { Plus, Trash, ChevronDown } from 'lucide';\n * import { lucideIcons } from 'ngwr/icon/adapters/lucide';\n *\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideWrIcons(lucideIcons({ plus: Plus, trash: Trash, 'chevron-down': ChevronDown })),\n * ],\n * });\n * ```\n */\nfunction lucideIcons(icons: Record<string, LucideIconNode>): WrIconDef[] {\n return Object.entries(icons).map(([name, node]) => lucide(name, node));\n}\n\nfunction renderChild([tag, attrs]: readonly [string, Record<string, string | number | undefined>]): string {\n const rendered = Object.entries(attrs)\n .filter((entry): entry is [string, string | number] => entry[1] !== undefined)\n .map(([key, value]) => `${key}=\"${value}\"`)\n .join(' ');\n return `<${tag} ${rendered}/>`;\n}\n\nexport { lucide, lucideIcons, type LucideIconNode };\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\nexport { lucide, lucideIcons, type LucideIconNode } from './adapter';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;;AAKG;AAWH;;;;AAIG;AACH,MAAM,SAAS,GAAG;IAChB,oCAAoC;IACpC,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,aAAa;IACb,uBAAuB;IACvB,kBAAkB;IAClB,wBAAwB;IACxB,yBAAyB;IACzB,6BAA6B;AAC9B,CAAA,CAAC,IAAI,CAAC,GAAG,CAAC;AAEX;;;;;;;;;;;;AAYG;AACH,SAAS,MAAM,CAAC,IAAY,EAAE,QAAwB,EAAA;AACpD,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAChD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA,KAAA,EAAQ,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,MAAA,CAAQ,EAAE;AAC3D;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH,SAAS,WAAW,CAAC,KAAqC,EAAA;IACxD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACxE;AAEA,SAAS,WAAW,CAAC,CAAC,GAAG,EAAE,KAAK,CAAiE,EAAA;AAC/F,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK;AAClC,SAAA,MAAM,CAAC,CAAC,KAAK,KAAyC,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS;AAC5E,SAAA,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAA,EAAG,GAAG,CAAA,EAAA,EAAK,KAAK,GAAG;SACzC,IAAI,CAAC,GAAG,CAAC;AACZ,IAAA,OAAO,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,EAAI,QAAQ,IAAI;AAChC;;ACrFA;;;;;AAKG;;ACLH;;AAEG;;;;"}
1
+ {"version":3,"file":"ngwr-icon-adapters-lucide.mjs","sources":["../../../projects/lib/icon/adapters/lucide/adapter.ts","../../../projects/lib/icon/adapters/lucide/public-api.ts","../../../projects/lib/icon/adapters/lucide/ngwr-icon-adapters-lucide.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 type { WrIconDef } from 'ngwr/icon';\n\n/**\n * Shape of a `lucide` icon export — an array of `[tag, attrs]` tuples\n * representing the inner SVG children. The outer `<svg>` wrapper is\n * added by the adapter when converting to a {@link WrIconDef}.\n */\ntype LucideIconNode = readonly (readonly [string, Record<string, string | number | undefined>])[];\n\n/**\n * Default SVG attributes Lucide applies to every icon. Kept identical\n * to what the `lucide` package's `createElement` would emit so visual\n * parity with upstream is preserved.\n */\nconst SVG_ATTRS = [\n 'xmlns=\"http://www.w3.org/2000/svg\"',\n 'width=\"24\"',\n 'height=\"24\"',\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 'class=\"wr-icon__svg lucide\"',\n].join(' ');\n\n/**\n * Wrap a single Lucide icon in the {@link WrIconDef} envelope. Use this\n * when you need fine-grained control over the registered name, or when\n * the bulk {@link lucideIcons} helper isn't a good fit.\n *\n * @example\n * ```ts\n * import { Plus } from 'lucide';\n * import { lucide } from 'ngwr/icon/adapters/lucide';\n *\n * provideWrIcons([lucide('plus', Plus)]);\n * ```\n */\nfunction lucide(name: string, children: LucideIconNode): WrIconDef {\n const inner = children.map(renderChild).join('');\n return { name, data: `<svg ${SVG_ATTRS}>${inner}</svg>` };\n}\n\n/**\n * Wrap a bag of Lucide icons in one shot. Keys become the registered\n * names **verbatim** — exactly what you pass to `<wr-icon name>` — matching\n * the singular `lucide()` helper and the other adapters. Kebab-case by\n * convention, so quote multi-word keys (`'chevron-down'`). Values are the\n * upstream IconNode tuples.\n *\n * Tree-shaking: every `Plus`, `Trash`, … import lives in *your* file\n * — ngwr ships only this wrapper, not the icon data. Unused icons in\n * `lucide` itself get dropped by the bundler.\n *\n * @example\n * ```ts\n * import { Plus, Trash, ChevronDown } from 'lucide';\n * import { lucideIcons } from 'ngwr/icon/adapters/lucide';\n *\n * bootstrapApplication(AppComponent, {\n * providers: [\n * provideWrIcons(lucideIcons({ plus: Plus, trash: Trash, 'chevron-down': ChevronDown })),\n * ],\n * });\n * ```\n */\nfunction lucideIcons(icons: Record<string, LucideIconNode>): WrIconDef[] {\n return Object.entries(icons).map(([name, node]) => lucide(name, node));\n}\n\n/**\n * A tag or attribute name that can only ever be a name.\n *\n * `renderChild` builds markup by concatenation, so a name carrying a quote, a\n * space or an `=` does not become a strangely-named attribute — it closes the\n * one being written and opens whatever comes next, which is how\n * `{ 'href': 'x\" onerror=\"…' }`'s sibling, a hostile KEY, injects a handler\n * through an API whose signature says `Record<string, string | number>`.\n * Escaping cannot help a name: `onerror` is a perfectly valid name and the only\n * honest serialisation of it is `onerror=\"…\"`. So names are constrained and\n * values are escaped, and it is {@link sanitizeIcon} at the render sink that\n * refuses `onerror` itself.\n */\nconst NAME_RE = /^[A-Za-z_][\\w.:-]*$/;\n\n/** The four characters that can leave an attribute value or a tag body. */\nfunction escapeAttribute(value: string | number): string {\n return String(value).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n}\n\nfunction renderChild([tag, attrs]: readonly [string, Record<string, string | number | undefined>]): string {\n if (!NAME_RE.test(tag)) return '';\n\n const rendered = Object.entries(attrs)\n .filter((entry): entry is [string, string | number] => entry[1] !== undefined && NAME_RE.test(entry[0]))\n .map(([key, value]) => `${key}=\"${escapeAttribute(value)}\"`)\n .join(' ');\n return `<${tag} ${rendered}/>`;\n}\n\nexport { lucide, lucideIcons, type LucideIconNode };\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\nexport { lucide, lucideIcons, type LucideIconNode } from './adapter';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"AAAA;;;;;AAKG;AAWH;;;;AAIG;AACH,MAAM,SAAS,GAAG;IAChB,oCAAoC;IACpC,YAAY;IACZ,aAAa;IACb,qBAAqB;IACrB,aAAa;IACb,uBAAuB;IACvB,kBAAkB;IAClB,wBAAwB;IACxB,yBAAyB;IACzB,6BAA6B;AAC9B,CAAA,CAAC,IAAI,CAAC,GAAG,CAAC;AAEX;;;;;;;;;;;;AAYG;AACH,SAAS,MAAM,CAAC,IAAY,EAAE,QAAwB,EAAA;AACpD,IAAA,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;IAChD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAA,KAAA,EAAQ,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,MAAA,CAAQ,EAAE;AAC3D;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH,SAAS,WAAW,CAAC,KAAqC,EAAA;IACxD,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACxE;AAEA;;;;;;;;;;;;AAYG;AACH,MAAM,OAAO,GAAG,qBAAqB;AAErC;AACA,SAAS,eAAe,CAAC,KAAsB,EAAA;AAC7C,IAAA,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;AACjH;AAEA,SAAS,WAAW,CAAC,CAAC,GAAG,EAAE,KAAK,CAAiE,EAAA;AAC/F,IAAA,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;AAAE,QAAA,OAAO,EAAE;AAEjC,IAAA,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK;SAClC,MAAM,CAAC,CAAC,KAAK,KAAyC,KAAK,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACtG,SAAA,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAA,EAAG,GAAG,CAAA,EAAA,EAAK,eAAe,CAAC,KAAK,CAAC,GAAG;SAC1D,IAAI,CAAC,GAAG,CAAC;AACZ,IAAA,OAAO,CAAA,CAAA,EAAI,GAAG,CAAA,CAAA,EAAI,QAAQ,IAAI;AAChC;;AC3GA;;;;;AAKG;;ACLH;;AAEG;;;;"}