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.
- package/fesm2022/ngwr-border-glow.mjs +12 -3
- package/fesm2022/ngwr-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +14 -3
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-context-menu.mjs +6 -2
- package/fesm2022/ngwr-context-menu.mjs.map +1 -1
- package/fesm2022/ngwr-dialog.mjs +22 -16
- package/fesm2022/ngwr-dialog.mjs.map +1 -1
- package/fesm2022/ngwr-directives.mjs +5 -2
- package/fesm2022/ngwr-directives.mjs.map +1 -1
- package/fesm2022/ngwr-drawer.mjs +24 -18
- package/fesm2022/ngwr-drawer.mjs.map +1 -1
- package/fesm2022/ngwr-dropdown.mjs +6 -2
- package/fesm2022/ngwr-dropdown.mjs.map +1 -1
- package/fesm2022/ngwr-fuzzy-text.mjs +21 -4
- package/fesm2022/ngwr-fuzzy-text.mjs.map +1 -1
- package/fesm2022/ngwr-gradient-text.mjs +9 -2
- package/fesm2022/ngwr-gradient-text.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-feather.mjs +11 -0
- package/fesm2022/ngwr-icon-adapters-feather.mjs.map +1 -1
- package/fesm2022/ngwr-icon-adapters-lucide.mjs +22 -2
- package/fesm2022/ngwr-icon-adapters-lucide.mjs.map +1 -1
- package/fesm2022/ngwr-icon.mjs +474 -37
- package/fesm2022/ngwr-icon.mjs.map +1 -1
- package/fesm2022/ngwr-markdown.mjs +63 -11
- package/fesm2022/ngwr-markdown.mjs.map +1 -1
- package/fesm2022/ngwr-overlay.mjs +36 -7
- package/fesm2022/ngwr-overlay.mjs.map +1 -1
- package/fesm2022/ngwr-qr.mjs +38 -1
- package/fesm2022/ngwr-qr.mjs.map +1 -1
- package/fesm2022/ngwr-shiny-text.mjs +10 -3
- package/fesm2022/ngwr-shiny-text.mjs.map +1 -1
- package/fesm2022/ngwr-tabs.mjs +6 -2
- package/fesm2022/ngwr-tabs.mjs.map +1 -1
- package/fesm2022/ngwr-utils.mjs +107 -1
- package/fesm2022/ngwr-utils.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/llms-full.txt +1 -1
- package/package.json +3 -3
- package/types/ngwr-breadcrumbs.d.ts +1 -0
- package/types/ngwr-fuzzy-text.d.ts +5 -0
- package/types/ngwr-icon-adapters-feather.d.ts +11 -0
- package/types/ngwr-icon.d.ts +42 -1
- package/types/ngwr-shiny-text.d.ts +1 -0
- package/types/ngwr-utils.d.ts +47 -1
- package/types/ngwr-version.d.ts +1 -1
|
@@ -3,7 +3,7 @@ import { isPlatformBrowser } from '@angular/common';
|
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
4
|
import { input, inject, ElementRef, PLATFORM_ID, computed, effect, ViewEncapsulation, Component } from '@angular/core';
|
|
5
5
|
import { WrPlatform } from 'ngwr/platform';
|
|
6
|
-
import { numAttr } from 'ngwr/utils';
|
|
6
|
+
import { isSafeCssValue, numAttr } from 'ngwr/utils';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @license
|
|
@@ -48,7 +48,11 @@ function buildGlowVars(glowColor, intensity) {
|
|
|
48
48
|
}
|
|
49
49
|
function buildGradientVars(colors) {
|
|
50
50
|
const out = {};
|
|
51
|
-
|
|
51
|
+
// Each entry is INTERPOLATED into the `radial-gradient()` below, so a value
|
|
52
|
+
// that balances the parens around it escapes into a sibling layer and can add
|
|
53
|
+
// a `url()` the browser fetches. One unsafe entry discards the palette — the
|
|
54
|
+
// same all-or-nothing rule `wr-gradient-text` follows, for the same reason.
|
|
55
|
+
const palette = colors.length > 0 && colors.every(color => isSafeCssValue(color)) ? colors : DEFAULT_COLORS;
|
|
52
56
|
for (let i = 0; i < GRADIENT_VAR_NAMES.length; i++) {
|
|
53
57
|
const colour = palette[Math.min(GRADIENT_COLOR_INDEX[i], palette.length - 1)];
|
|
54
58
|
out[GRADIENT_VAR_NAMES[i]] = `radial-gradient(at ${GRADIENT_POSITIONS[i]}, ${colour} 0px, transparent 50%)`;
|
|
@@ -150,8 +154,13 @@ class WrBorderGlow {
|
|
|
150
154
|
Object.assign(vars, buildGradientVars(colors));
|
|
151
155
|
// Colour vars are written only when set — otherwise the stylesheet's
|
|
152
156
|
// per-theme defaults (light vs dark) take over.
|
|
157
|
+
// Composed, not passed through: `_rules.scss` reads this var inside a
|
|
158
|
+
// `linear-gradient()` and again in a `background` shorthand, where a `url()`
|
|
159
|
+
// is valid and fetches. An audit bound `url("…")` here and recorded the
|
|
160
|
+
// request. Validated like its `colors` sibling on this same component —
|
|
161
|
+
// leaving one of the two unchecked is two rules inside one component.
|
|
153
162
|
const bg = this.backgroundColor();
|
|
154
|
-
if (bg !== null)
|
|
163
|
+
if (bg !== null && isSafeCssValue(bg))
|
|
155
164
|
vars['--wr-border-glow-bg'] = bg;
|
|
156
165
|
const glow = this.glowColor();
|
|
157
166
|
if (glow !== null)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-border-glow.mjs","sources":["../../../projects/lib/border-glow/border-glow.ts","../../../projects/lib/border-glow/border-glow.html","../../../projects/lib/border-glow/ngwr-border-glow.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 * Port of the reactbits.dev BorderGlow effect — a cursor-tracked cone of\n * mesh-gradient light that follows the pointer along the card's perimeter,\n * with an outer halo and optional auto-sweep on mount.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport { Component, ElementRef, PLATFORM_ID, ViewEncapsulation, computed, effect, inject, input } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nconst RADIANS_TO_DEG = 180 / Math.PI;\n\ninterface ParsedHsl {\n readonly h: number;\n readonly s: number;\n readonly l: number;\n}\n\nfunction parseHsl(input: string): ParsedHsl {\n const match = /([\\d.]+)\\s*([\\d.]+)%?\\s*([\\d.]+)%?/.exec(input);\n if (!match) return { h: 40, s: 80, l: 80 };\n return { h: Number.parseFloat(match[1]), s: Number.parseFloat(match[2]), l: Number.parseFloat(match[3]) };\n}\n\nconst GLOW_OPACITY_STEPS = [100, 60, 50, 40, 30, 20, 10] as const;\nconst GLOW_VAR_SUFFIXES = ['', '-60', '-50', '-40', '-30', '-20', '-10'] as const;\n\nconst GRADIENT_POSITIONS = ['80% 55%', '69% 34%', '8% 6%', '41% 38%', '86% 85%', '82% 18%', '51% 4%'] as const;\nconst GRADIENT_VAR_NAMES = [\n '--wr-border-glow-gradient-one',\n '--wr-border-glow-gradient-two',\n '--wr-border-glow-gradient-three',\n '--wr-border-glow-gradient-four',\n '--wr-border-glow-gradient-five',\n '--wr-border-glow-gradient-six',\n '--wr-border-glow-gradient-seven',\n] as const;\nconst GRADIENT_COLOR_INDEX = [0, 1, 2, 0, 1, 2, 1] as const;\n\nconst DEFAULT_COLORS: readonly string[] = ['#c084fc', '#f472b6', '#38bdf8'];\n\nfunction buildGlowVars(glowColor: string, intensity: number): Record<string, string> {\n const { h, s, l } = parseHsl(glowColor);\n const base = `${h}deg ${s}% ${l}%`;\n const out: Record<string, string> = {};\n for (let i = 0; i < GLOW_OPACITY_STEPS.length; i++) {\n const alpha = Math.min(GLOW_OPACITY_STEPS[i] * intensity, 100);\n out[`--wr-border-glow-color${GLOW_VAR_SUFFIXES[i]}`] = `hsl(${base} / ${alpha}%)`;\n }\n return out;\n}\n\nfunction buildGradientVars(colors: readonly string[]): Record<string, string> {\n const out: Record<string, string> = {};\n const palette = colors.length > 0 ? colors : DEFAULT_COLORS;\n for (let i = 0; i < GRADIENT_VAR_NAMES.length; i++) {\n const colour = palette[Math.min(GRADIENT_COLOR_INDEX[i], palette.length - 1)];\n out[GRADIENT_VAR_NAMES[i]] = `radial-gradient(at ${GRADIENT_POSITIONS[i]}, ${colour} 0px, transparent 50%)`;\n }\n out['--wr-border-glow-gradient-base'] = `linear-gradient(${palette[0]} 0 100%)`;\n return out;\n}\n\ninterface AnimateOptions {\n readonly start?: number;\n readonly end?: number;\n readonly duration?: number;\n readonly delay?: number;\n readonly ease?: (t: number) => number;\n readonly onUpdate: (v: number) => void;\n readonly onEnd?: () => void;\n}\n\n/** Tiny rAF-driven tweener. Returns a cancel function so callers can clean up on destroy. */\nfunction animateValue(opts: AnimateOptions): () => void {\n const { start = 0, end = 100, duration = 1000, delay = 0, ease = (t: number): number => t, onUpdate, onEnd } = opts;\n let raf = 0;\n let cancelled = false;\n\n const startAt = performance.now() + delay;\n const tick = (): void => {\n if (cancelled) return;\n const elapsed = performance.now() - startAt;\n const t = Math.min(Math.max(elapsed / duration, 0), 1);\n onUpdate(start + (end - start) * ease(t));\n if (t < 1) raf = requestAnimationFrame(tick);\n else if (onEnd) onEnd();\n };\n\n const timer = setTimeout(() => {\n raf = requestAnimationFrame(tick);\n }, delay);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n cancelAnimationFrame(raf);\n };\n}\n\n/**\n * Cursor-tracked glowing border card. A cone of light follows the pointer\n * along the card's perimeter, brightening as the cursor approaches an edge.\n *\n * - Outer halo via stacked `box-shadow` on an inner `.edge-light` element.\n * - Inner \"soft bloom\" via `mix-blend-mode: soft-light` for content near the\n * edges (subtle; control via `[fillOpacity]`).\n * - Optional `[animated]` mode performs a one-shot sweep on mount, useful\n * for drawing attention to a freshly-rendered card.\n *\n * @example\n * ```html\n * <wr-border-glow [animated]=\"true\" [colors]=\"['#c084fc', '#f472b6', '#38bdf8']\">\n * <h3>Hover me</h3>\n * <p>The border lights up where the cursor is.</p>\n * </wr-border-glow>\n * ```\n *\n * @see https://www.reactbits.dev/components/border-glow (visual reference)\n */\n@Component({\n selector: 'wr-border-glow',\n templateUrl: './border-glow.html',\n styleUrl: './border-glow.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-border-glow',\n '(pointermove)': 'onPointerMove($event)',\n },\n})\nexport class WrBorderGlow {\n /** Card background fill. When unset, uses the theme surface token. */\n readonly backgroundColor = input<string | null>(null);\n\n /** Corner radius in pixels. @default 28 */\n readonly borderRadius = input(28, { transform: numAttr(28) });\n\n /** Halo extent in pixels — how far the outer glow reaches past the card edge. @default 40 */\n readonly glowRadius = input(40, { transform: numAttr(40) });\n\n /** Halo opacity multiplier (1 = full strength). @default 1 */\n readonly glowIntensity = input(1, { transform: numAttr(1) });\n\n /** Width of the lit cone as a percentage of the perimeter. @default 25 */\n readonly coneSpread = input(25, { transform: numAttr(25) });\n\n /** How sharply the halo fades as the cursor leaves the edge. Lower = wider falloff. @default 30 */\n readonly edgeSensitivity = input(30, { transform: numAttr(30) });\n\n /** Strength of the soft-light interior fill near edges. @default 0.5 */\n readonly fillOpacity = input(0.5, { transform: numAttr(0.5) });\n\n /**\n * Halo colour as `'H S L'` (HSL parts, no commas). When unset, the theme\n * decides: a deep amber on light surfaces, pale amber on dark. Note\n * `glowIntensity` only applies alongside an explicit `glowColor`.\n */\n readonly glowColor = input<string | null>(null);\n\n /**\n * Mesh-gradient palette for the colored border slice. When unset, the\n * theme decides: deep tones on light, pastels on dark.\n */\n readonly colors = input<readonly string[] | null>(null);\n\n /** Play a one-shot perimeter sweep on mount, then fade out. @default false */\n readonly animated = input(false, { transform: coerceBooleanProperty });\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n /** Inline CSS variable bag — recomputed when colour / radius / sensitivity inputs change. */\n protected readonly cssVars = computed<Record<string, string>>(() => {\n const vars: Record<string, string> = {\n '--wr-border-glow-radius': `${this.borderRadius()}px`,\n '--wr-border-glow-padding': `${this.glowRadius()}px`,\n '--wr-border-glow-cone-spread': String(this.coneSpread()),\n '--wr-border-glow-edge-sensitivity': String(this.edgeSensitivity()),\n '--wr-border-glow-fill-opacity': String(this.fillOpacity()),\n };\n const colors = this.colors();\n if (colors !== null) Object.assign(vars, buildGradientVars(colors));\n // Colour vars are written only when set — otherwise the stylesheet's\n // per-theme defaults (light vs dark) take over.\n const bg = this.backgroundColor();\n if (bg !== null) vars['--wr-border-glow-bg'] = bg;\n const glow = this.glowColor();\n if (glow !== null) Object.assign(vars, buildGlowVars(glow, this.glowIntensity()));\n return vars;\n });\n\n constructor() {\n // Apply the variable bag to the host on every input change. Bind in an\n // effect rather than `host: { '[style.--foo]': '...' }` so a single\n // `setProperty` loop handles the lot.\n effect(() => {\n const host = this.el.nativeElement;\n const vars = this.cssVars();\n for (const [k, v] of Object.entries(vars)) host.style.setProperty(k, v);\n });\n\n if (!this.isBrowser) return;\n\n // Auto-sweep on mount — fires once when `animated` is true.\n effect(onCleanup => {\n if (!this.animated()) return;\n onCleanup(this.runAutoSweep());\n });\n }\n\n /** Pointer-driven update of `--wr-border-glow-angle` + `--wr-border-glow-edge-proximity`. */\n protected onPointerMove(event: PointerEvent): void {\n const host = this.el.nativeElement;\n const rect = host.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const cx = rect.width / 2;\n const cy = rect.height / 2;\n\n const dx = x - cx;\n const dy = y - cy;\n\n // `edge-proximity`: 0 at centre, 1 at the perimeter (whichever axis hits first).\n let edge = 0;\n if (dx !== 0 || dy !== 0) {\n const kx = dx === 0 ? Infinity : cx / Math.abs(dx);\n const ky = dy === 0 ? Infinity : cy / Math.abs(dy);\n edge = Math.min(Math.max(1 / Math.min(kx, ky), 0), 1);\n }\n\n // `cursor-angle`: 0deg = top, increases clockwise.\n let angle = 0;\n if (dx !== 0 || dy !== 0) {\n angle = Math.atan2(dy, dx) * RADIANS_TO_DEG + 90;\n if (angle < 0) angle += 360;\n }\n\n host.style.setProperty('--wr-border-glow-edge-proximity', (edge * 100).toFixed(3));\n host.style.setProperty('--wr-border-glow-angle', `${angle.toFixed(3)}deg`);\n }\n\n /** One-shot perimeter sweep: in → around → out, mirroring the reactbits behaviour. */\n private runAutoSweep(): () => void {\n // Reduced motion: skip the decorative mount sweep. The pointer-driven\n // glow stays — it maps 1:1 to the cursor with no autonomous motion.\n if (this.platform.prefersReducedMotion()) return () => undefined;\n const host = this.el.nativeElement;\n const ANGLE_START = 110;\n const ANGLE_END = 465;\n host.classList.add('wr-border-glow--sweeping');\n host.style.setProperty('--wr-border-glow-angle', `${ANGLE_START}deg`);\n\n const easeOutCubic = (t: number): number => 1 - (1 - t) ** 3;\n const easeInCubic = (t: number): number => t * t * t;\n const lerpAngle = (v: number): string => `${(ANGLE_END - ANGLE_START) * (v / 100) + ANGLE_START}deg`;\n\n // 1. Ramp edge-proximity up to 100 quickly.\n const cancelA = animateValue({\n duration: 500,\n onUpdate: v => host.style.setProperty('--wr-border-glow-edge-proximity', `${v}`),\n });\n // 2. Sweep angle first half (ease-in).\n const cancelB = animateValue({\n duration: 1500,\n end: 50,\n ease: easeInCubic,\n onUpdate: v => host.style.setProperty('--wr-border-glow-angle', lerpAngle(v)),\n });\n // 3. Sweep angle second half (ease-out).\n const cancelC = animateValue({\n delay: 1500,\n duration: 2250,\n start: 50,\n end: 100,\n ease: easeOutCubic,\n onUpdate: v => host.style.setProperty('--wr-border-glow-angle', lerpAngle(v)),\n });\n // 4. Fade proximity back to 0.\n const cancelD = animateValue({\n delay: 2500,\n duration: 1500,\n start: 100,\n end: 0,\n ease: easeInCubic,\n onUpdate: v => host.style.setProperty('--wr-border-glow-edge-proximity', `${v}`),\n onEnd: () => host.classList.remove('wr-border-glow--sweeping'),\n });\n\n // Returned rather than registered on `destroyRef`: this method runs from an\n // effect, so registering there stacked one more teardown per re-run and none\n // of them fired until the component died. The caller ties it to the effect's\n // own cleanup instead.\n return () => {\n cancelA();\n cancelB();\n cancelC();\n cancelD();\n host.classList.remove('wr-border-glow--sweeping');\n };\n }\n}\n","<span class=\"wr-border-glow__edge\" aria-hidden=\"true\"></span>\n<div class=\"wr-border-glow__inner\">\n <ng-content />\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-border-glow.mjs","sources":["../../../projects/lib/border-glow/border-glow.ts","../../../projects/lib/border-glow/border-glow.html","../../../projects/lib/border-glow/ngwr-border-glow.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 * Port of the reactbits.dev BorderGlow effect — a cursor-tracked cone of\n * mesh-gradient light that follows the pointer along the card's perimeter,\n * with an outer halo and optional auto-sweep on mount.\n */\n\nimport { coerceBooleanProperty } from '@angular/cdk/coercion';\nimport { isPlatformBrowser } from '@angular/common';\nimport { Component, ElementRef, PLATFORM_ID, ViewEncapsulation, computed, effect, inject, input } from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { isSafeCssValue, numAttr } from 'ngwr/utils';\n\nconst RADIANS_TO_DEG = 180 / Math.PI;\n\ninterface ParsedHsl {\n readonly h: number;\n readonly s: number;\n readonly l: number;\n}\n\nfunction parseHsl(input: string): ParsedHsl {\n const match = /([\\d.]+)\\s*([\\d.]+)%?\\s*([\\d.]+)%?/.exec(input);\n if (!match) return { h: 40, s: 80, l: 80 };\n return { h: Number.parseFloat(match[1]), s: Number.parseFloat(match[2]), l: Number.parseFloat(match[3]) };\n}\n\nconst GLOW_OPACITY_STEPS = [100, 60, 50, 40, 30, 20, 10] as const;\nconst GLOW_VAR_SUFFIXES = ['', '-60', '-50', '-40', '-30', '-20', '-10'] as const;\n\nconst GRADIENT_POSITIONS = ['80% 55%', '69% 34%', '8% 6%', '41% 38%', '86% 85%', '82% 18%', '51% 4%'] as const;\nconst GRADIENT_VAR_NAMES = [\n '--wr-border-glow-gradient-one',\n '--wr-border-glow-gradient-two',\n '--wr-border-glow-gradient-three',\n '--wr-border-glow-gradient-four',\n '--wr-border-glow-gradient-five',\n '--wr-border-glow-gradient-six',\n '--wr-border-glow-gradient-seven',\n] as const;\nconst GRADIENT_COLOR_INDEX = [0, 1, 2, 0, 1, 2, 1] as const;\n\nconst DEFAULT_COLORS: readonly string[] = ['#c084fc', '#f472b6', '#38bdf8'];\n\nfunction buildGlowVars(glowColor: string, intensity: number): Record<string, string> {\n const { h, s, l } = parseHsl(glowColor);\n const base = `${h}deg ${s}% ${l}%`;\n const out: Record<string, string> = {};\n for (let i = 0; i < GLOW_OPACITY_STEPS.length; i++) {\n const alpha = Math.min(GLOW_OPACITY_STEPS[i] * intensity, 100);\n out[`--wr-border-glow-color${GLOW_VAR_SUFFIXES[i]}`] = `hsl(${base} / ${alpha}%)`;\n }\n return out;\n}\n\nfunction buildGradientVars(colors: readonly string[]): Record<string, string> {\n const out: Record<string, string> = {};\n // Each entry is INTERPOLATED into the `radial-gradient()` below, so a value\n // that balances the parens around it escapes into a sibling layer and can add\n // a `url()` the browser fetches. One unsafe entry discards the palette — the\n // same all-or-nothing rule `wr-gradient-text` follows, for the same reason.\n const palette = colors.length > 0 && colors.every(color => isSafeCssValue(color)) ? colors : DEFAULT_COLORS;\n for (let i = 0; i < GRADIENT_VAR_NAMES.length; i++) {\n const colour = palette[Math.min(GRADIENT_COLOR_INDEX[i], palette.length - 1)];\n out[GRADIENT_VAR_NAMES[i]] = `radial-gradient(at ${GRADIENT_POSITIONS[i]}, ${colour} 0px, transparent 50%)`;\n }\n out['--wr-border-glow-gradient-base'] = `linear-gradient(${palette[0]} 0 100%)`;\n return out;\n}\n\ninterface AnimateOptions {\n readonly start?: number;\n readonly end?: number;\n readonly duration?: number;\n readonly delay?: number;\n readonly ease?: (t: number) => number;\n readonly onUpdate: (v: number) => void;\n readonly onEnd?: () => void;\n}\n\n/** Tiny rAF-driven tweener. Returns a cancel function so callers can clean up on destroy. */\nfunction animateValue(opts: AnimateOptions): () => void {\n const { start = 0, end = 100, duration = 1000, delay = 0, ease = (t: number): number => t, onUpdate, onEnd } = opts;\n let raf = 0;\n let cancelled = false;\n\n const startAt = performance.now() + delay;\n const tick = (): void => {\n if (cancelled) return;\n const elapsed = performance.now() - startAt;\n const t = Math.min(Math.max(elapsed / duration, 0), 1);\n onUpdate(start + (end - start) * ease(t));\n if (t < 1) raf = requestAnimationFrame(tick);\n else if (onEnd) onEnd();\n };\n\n const timer = setTimeout(() => {\n raf = requestAnimationFrame(tick);\n }, delay);\n\n return () => {\n cancelled = true;\n clearTimeout(timer);\n cancelAnimationFrame(raf);\n };\n}\n\n/**\n * Cursor-tracked glowing border card. A cone of light follows the pointer\n * along the card's perimeter, brightening as the cursor approaches an edge.\n *\n * - Outer halo via stacked `box-shadow` on an inner `.edge-light` element.\n * - Inner \"soft bloom\" via `mix-blend-mode: soft-light` for content near the\n * edges (subtle; control via `[fillOpacity]`).\n * - Optional `[animated]` mode performs a one-shot sweep on mount, useful\n * for drawing attention to a freshly-rendered card.\n *\n * @example\n * ```html\n * <wr-border-glow [animated]=\"true\" [colors]=\"['#c084fc', '#f472b6', '#38bdf8']\">\n * <h3>Hover me</h3>\n * <p>The border lights up where the cursor is.</p>\n * </wr-border-glow>\n * ```\n *\n * @see https://www.reactbits.dev/components/border-glow (visual reference)\n */\n@Component({\n selector: 'wr-border-glow',\n templateUrl: './border-glow.html',\n styleUrl: './border-glow.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-border-glow',\n '(pointermove)': 'onPointerMove($event)',\n },\n})\nexport class WrBorderGlow {\n /** Card background fill. When unset, uses the theme surface token. */\n readonly backgroundColor = input<string | null>(null);\n\n /** Corner radius in pixels. @default 28 */\n readonly borderRadius = input(28, { transform: numAttr(28) });\n\n /** Halo extent in pixels — how far the outer glow reaches past the card edge. @default 40 */\n readonly glowRadius = input(40, { transform: numAttr(40) });\n\n /** Halo opacity multiplier (1 = full strength). @default 1 */\n readonly glowIntensity = input(1, { transform: numAttr(1) });\n\n /** Width of the lit cone as a percentage of the perimeter. @default 25 */\n readonly coneSpread = input(25, { transform: numAttr(25) });\n\n /** How sharply the halo fades as the cursor leaves the edge. Lower = wider falloff. @default 30 */\n readonly edgeSensitivity = input(30, { transform: numAttr(30) });\n\n /** Strength of the soft-light interior fill near edges. @default 0.5 */\n readonly fillOpacity = input(0.5, { transform: numAttr(0.5) });\n\n /**\n * Halo colour as `'H S L'` (HSL parts, no commas). When unset, the theme\n * decides: a deep amber on light surfaces, pale amber on dark. Note\n * `glowIntensity` only applies alongside an explicit `glowColor`.\n */\n readonly glowColor = input<string | null>(null);\n\n /**\n * Mesh-gradient palette for the colored border slice. When unset, the\n * theme decides: deep tones on light, pastels on dark.\n */\n readonly colors = input<readonly string[] | null>(null);\n\n /** Play a one-shot perimeter sweep on mount, then fade out. @default false */\n readonly animated = input(false, { transform: coerceBooleanProperty });\n\n private readonly el = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n /** Inline CSS variable bag — recomputed when colour / radius / sensitivity inputs change. */\n protected readonly cssVars = computed<Record<string, string>>(() => {\n const vars: Record<string, string> = {\n '--wr-border-glow-radius': `${this.borderRadius()}px`,\n '--wr-border-glow-padding': `${this.glowRadius()}px`,\n '--wr-border-glow-cone-spread': String(this.coneSpread()),\n '--wr-border-glow-edge-sensitivity': String(this.edgeSensitivity()),\n '--wr-border-glow-fill-opacity': String(this.fillOpacity()),\n };\n const colors = this.colors();\n if (colors !== null) Object.assign(vars, buildGradientVars(colors));\n // Colour vars are written only when set — otherwise the stylesheet's\n // per-theme defaults (light vs dark) take over.\n // Composed, not passed through: `_rules.scss` reads this var inside a\n // `linear-gradient()` and again in a `background` shorthand, where a `url()`\n // is valid and fetches. An audit bound `url(\"…\")` here and recorded the\n // request. Validated like its `colors` sibling on this same component —\n // leaving one of the two unchecked is two rules inside one component.\n const bg = this.backgroundColor();\n if (bg !== null && isSafeCssValue(bg)) vars['--wr-border-glow-bg'] = bg;\n const glow = this.glowColor();\n if (glow !== null) Object.assign(vars, buildGlowVars(glow, this.glowIntensity()));\n return vars;\n });\n\n constructor() {\n // Apply the variable bag to the host on every input change. Bind in an\n // effect rather than `host: { '[style.--foo]': '...' }` so a single\n // `setProperty` loop handles the lot.\n effect(() => {\n const host = this.el.nativeElement;\n const vars = this.cssVars();\n for (const [k, v] of Object.entries(vars)) host.style.setProperty(k, v);\n });\n\n if (!this.isBrowser) return;\n\n // Auto-sweep on mount — fires once when `animated` is true.\n effect(onCleanup => {\n if (!this.animated()) return;\n onCleanup(this.runAutoSweep());\n });\n }\n\n /** Pointer-driven update of `--wr-border-glow-angle` + `--wr-border-glow-edge-proximity`. */\n protected onPointerMove(event: PointerEvent): void {\n const host = this.el.nativeElement;\n const rect = host.getBoundingClientRect();\n const x = event.clientX - rect.left;\n const y = event.clientY - rect.top;\n const cx = rect.width / 2;\n const cy = rect.height / 2;\n\n const dx = x - cx;\n const dy = y - cy;\n\n // `edge-proximity`: 0 at centre, 1 at the perimeter (whichever axis hits first).\n let edge = 0;\n if (dx !== 0 || dy !== 0) {\n const kx = dx === 0 ? Infinity : cx / Math.abs(dx);\n const ky = dy === 0 ? Infinity : cy / Math.abs(dy);\n edge = Math.min(Math.max(1 / Math.min(kx, ky), 0), 1);\n }\n\n // `cursor-angle`: 0deg = top, increases clockwise.\n let angle = 0;\n if (dx !== 0 || dy !== 0) {\n angle = Math.atan2(dy, dx) * RADIANS_TO_DEG + 90;\n if (angle < 0) angle += 360;\n }\n\n host.style.setProperty('--wr-border-glow-edge-proximity', (edge * 100).toFixed(3));\n host.style.setProperty('--wr-border-glow-angle', `${angle.toFixed(3)}deg`);\n }\n\n /** One-shot perimeter sweep: in → around → out, mirroring the reactbits behaviour. */\n private runAutoSweep(): () => void {\n // Reduced motion: skip the decorative mount sweep. The pointer-driven\n // glow stays — it maps 1:1 to the cursor with no autonomous motion.\n if (this.platform.prefersReducedMotion()) return () => undefined;\n const host = this.el.nativeElement;\n const ANGLE_START = 110;\n const ANGLE_END = 465;\n host.classList.add('wr-border-glow--sweeping');\n host.style.setProperty('--wr-border-glow-angle', `${ANGLE_START}deg`);\n\n const easeOutCubic = (t: number): number => 1 - (1 - t) ** 3;\n const easeInCubic = (t: number): number => t * t * t;\n const lerpAngle = (v: number): string => `${(ANGLE_END - ANGLE_START) * (v / 100) + ANGLE_START}deg`;\n\n // 1. Ramp edge-proximity up to 100 quickly.\n const cancelA = animateValue({\n duration: 500,\n onUpdate: v => host.style.setProperty('--wr-border-glow-edge-proximity', `${v}`),\n });\n // 2. Sweep angle first half (ease-in).\n const cancelB = animateValue({\n duration: 1500,\n end: 50,\n ease: easeInCubic,\n onUpdate: v => host.style.setProperty('--wr-border-glow-angle', lerpAngle(v)),\n });\n // 3. Sweep angle second half (ease-out).\n const cancelC = animateValue({\n delay: 1500,\n duration: 2250,\n start: 50,\n end: 100,\n ease: easeOutCubic,\n onUpdate: v => host.style.setProperty('--wr-border-glow-angle', lerpAngle(v)),\n });\n // 4. Fade proximity back to 0.\n const cancelD = animateValue({\n delay: 2500,\n duration: 1500,\n start: 100,\n end: 0,\n ease: easeInCubic,\n onUpdate: v => host.style.setProperty('--wr-border-glow-edge-proximity', `${v}`),\n onEnd: () => host.classList.remove('wr-border-glow--sweeping'),\n });\n\n // Returned rather than registered on `destroyRef`: this method runs from an\n // effect, so registering there stacked one more teardown per re-run and none\n // of them fired until the component died. The caller ties it to the effect's\n // own cleanup instead.\n return () => {\n cancelA();\n cancelB();\n cancelC();\n cancelD();\n host.classList.remove('wr-border-glow--sweeping');\n };\n }\n}\n","<span class=\"wr-border-glow__edge\" aria-hidden=\"true\"></span>\n<div class=\"wr-border-glow__inner\">\n <ng-content />\n</div>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { input, ViewEncapsulation, Component
|
|
2
|
+
import { input, computed, ViewEncapsulation, Component } from '@angular/core';
|
|
3
3
|
import { useI18nText } from 'ngwr/i18n';
|
|
4
4
|
import { NgTemplateOutlet } from '@angular/common';
|
|
5
5
|
import { RouterLink } from '@angular/router';
|
|
@@ -11,6 +11,10 @@ import { WrIcon } from 'ngwr/icon';
|
|
|
11
11
|
* Use of this source code is governed by an MIT-style license that can be
|
|
12
12
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
13
13
|
*/
|
|
14
|
+
/** Escape a string for use inside a double-quoted CSS `<string>`. */
|
|
15
|
+
function cssString(value) {
|
|
16
|
+
return value.replace(/[\\"]/g, '\\$&').replace(/[\n\r\f]/g, char => `\\${char.codePointAt(0).toString(16)} `);
|
|
17
|
+
}
|
|
14
18
|
/**
|
|
15
19
|
* Breadcrumb navigation. Project `<wr-breadcrumbs-item>` children — each keeps
|
|
16
20
|
* its own element and takes `role="listitem"` inside the `<ol>` rather than
|
|
@@ -46,14 +50,21 @@ class WrBreadcrumbs {
|
|
|
46
50
|
// announced in Russian on the same page while this one stayed "Breadcrumbs", and
|
|
47
51
|
// the only escape was restating `[ariaLabel]` on every trail.
|
|
48
52
|
resolvedAriaLabel = useI18nText(this.ariaLabel, 'breadcrumbs.label', 'Breadcrumbs');
|
|
53
|
+
// The glyph is WRAPPED in quotes here and unwrapped by `content:` in the
|
|
54
|
+
// stylesheet, so an unescaped `"` inside it closes the library's own string
|
|
55
|
+
// and the rest of the value is parsed as CSS — `/" url("…") "` computes to
|
|
56
|
+
// `content: "/" url("…") ""`, an image the browser fetches. Escaping is the
|
|
57
|
+
// whole fix, and it is lossless: a separator that IS a quote still renders.
|
|
58
|
+
separatorValue = computed(() => `"${cssString(this.separator())}"`, /* @ts-ignore */
|
|
59
|
+
...(ngDevMode ? [{ debugName: "separatorValue" }] : /* istanbul ignore next */ []));
|
|
49
60
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrBreadcrumbs, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
50
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: WrBreadcrumbs, isStandalone: true, selector: "wr-breadcrumbs", inputs: { separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.--wr-breadcrumbs-separator": "
|
|
61
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.4", type: WrBreadcrumbs, isStandalone: true, selector: "wr-breadcrumbs", inputs: { separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "style.--wr-breadcrumbs-separator": "separatorValue()" }, classAttribute: "wr-breadcrumbs" }, ngImport: i0, template: "<nav class=\"wr-breadcrumbs__nav\" [attr.aria-label]=\"resolvedAriaLabel()\">\n <ol class=\"wr-breadcrumbs__list\">\n <ng-content />\n </ol>\n</nav>\n", styles: [".wr-tabs__tab:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:-2px}.wr-sidebar__entry:focus-visible,.wr-sidebar__group-toggle:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-sidebar__item:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:-2px}.wr-anchor__link:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-collapse__header:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:-2px}.wr-command-palette__option:focus-visible,.wr-command-palette__panel input:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-mention-panel__option:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-segmented__option:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-back-top:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-carousel__nav:focus-visible,.wr-carousel__dot:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-speed-dial__trigger:focus-visible,.wr-speed-dial__action:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-stepper__header:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-window__chrome-action:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-date-picker__trigger:focus-visible,.wr-time-picker__step:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-dropdown-item:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-alert__close:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-breadcrumbs{--wr-breadcrumbs-separator: \"/\";--wr-breadcrumbs-gap: .5rem;--wr-breadcrumbs-color: rgba(var(--wr-color-on-surface-rgb), .6);--wr-breadcrumbs-current-color: var(--wr-color-on-surface);--wr-breadcrumbs-link-color: var(--wr-color-primary-ink);--wr-breadcrumbs-separator-color: rgba(var(--wr-color-on-surface-rgb), .3);display:block;font-family:var(--wr-font-family-base);font-size:var(--wr-text-sm);color:var(--wr-breadcrumbs-color)}.wr-breadcrumbs__nav{display:block}.wr-breadcrumbs__list{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wr-breadcrumbs-gap);margin:0;padding:0;list-style:none}.wr-breadcrumbs__item{display:inline-flex;align-items:center;gap:var(--wr-breadcrumbs-gap)}.wr-breadcrumbs__item:not(:first-child):before{content:var(--wr-breadcrumbs-separator);color:var(--wr-breadcrumbs-separator-color);-webkit-user-select:none;user-select:none}.wr-breadcrumbs__link{display:inline-flex;align-items:center;gap:.375rem;color:var(--wr-breadcrumbs-link-color);text-decoration:none;border-radius:var(--wr-border-radius-sm);transition:color .15s ease}.wr-breadcrumbs__link:hover{text-decoration:underline}.wr-breadcrumbs__link:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:2px}.wr-breadcrumbs__current{display:inline-flex;align-items:center;gap:.375rem;color:var(--wr-breadcrumbs-current-color);font-weight:600}.wr-breadcrumbs__icon{--wr-icon-size: 1rem;flex:0 0 auto}\n"], encapsulation: i0.ViewEncapsulation.None });
|
|
51
62
|
}
|
|
52
63
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrBreadcrumbs, decorators: [{
|
|
53
64
|
type: Component,
|
|
54
65
|
args: [{ selector: 'wr-breadcrumbs', encapsulation: ViewEncapsulation.None, host: {
|
|
55
66
|
class: 'wr-breadcrumbs',
|
|
56
|
-
'[style.--wr-breadcrumbs-separator]':
|
|
67
|
+
'[style.--wr-breadcrumbs-separator]': 'separatorValue()',
|
|
57
68
|
}, template: "<nav class=\"wr-breadcrumbs__nav\" [attr.aria-label]=\"resolvedAriaLabel()\">\n <ol class=\"wr-breadcrumbs__list\">\n <ng-content />\n </ol>\n</nav>\n", styles: [".wr-tabs__tab:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:-2px}.wr-sidebar__entry:focus-visible,.wr-sidebar__group-toggle:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-sidebar__item:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:-2px}.wr-anchor__link:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-collapse__header:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:-2px}.wr-command-palette__option:focus-visible,.wr-command-palette__panel input:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-mention-panel__option:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-segmented__option:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-back-top:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-carousel__nav:focus-visible,.wr-carousel__dot:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-speed-dial__trigger:focus-visible,.wr-speed-dial__action:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-stepper__header:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-window__chrome-action:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-date-picker__trigger:focus-visible,.wr-time-picker__step:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-dropdown-item:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-alert__close:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo)}.wr-breadcrumbs{--wr-breadcrumbs-separator: \"/\";--wr-breadcrumbs-gap: .5rem;--wr-breadcrumbs-color: rgba(var(--wr-color-on-surface-rgb), .6);--wr-breadcrumbs-current-color: var(--wr-color-on-surface);--wr-breadcrumbs-link-color: var(--wr-color-primary-ink);--wr-breadcrumbs-separator-color: rgba(var(--wr-color-on-surface-rgb), .3);display:block;font-family:var(--wr-font-family-base);font-size:var(--wr-text-sm);color:var(--wr-breadcrumbs-color)}.wr-breadcrumbs__nav{display:block}.wr-breadcrumbs__list{display:flex;flex-wrap:wrap;align-items:center;gap:var(--wr-breadcrumbs-gap);margin:0;padding:0;list-style:none}.wr-breadcrumbs__item{display:inline-flex;align-items:center;gap:var(--wr-breadcrumbs-gap)}.wr-breadcrumbs__item:not(:first-child):before{content:var(--wr-breadcrumbs-separator);color:var(--wr-breadcrumbs-separator-color);-webkit-user-select:none;user-select:none}.wr-breadcrumbs__link{display:inline-flex;align-items:center;gap:.375rem;color:var(--wr-breadcrumbs-link-color);text-decoration:none;border-radius:var(--wr-border-radius-sm);transition:color .15s ease}.wr-breadcrumbs__link:hover{text-decoration:underline}.wr-breadcrumbs__link:focus-visible{outline:var(--wr-focus-ring-width) solid var(--wr-focus-ring-color);outline-offset:var(--wr-focus-ring-offset);box-shadow:0 0 0 var(--wr-focus-ring-offset) var(--wr-focus-ring-halo);outline-offset:2px}.wr-breadcrumbs__current{display:inline-flex;align-items:center;gap:.375rem;color:var(--wr-breadcrumbs-current-color);font-weight:600}.wr-breadcrumbs__icon{--wr-icon-size: 1rem;flex:0 0 auto}\n"] }]
|
|
58
69
|
}], propDecorators: { separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }] } });
|
|
59
70
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-breadcrumbs.mjs","sources":["../../../projects/lib/breadcrumbs/breadcrumbs.ts","../../../projects/lib/breadcrumbs/breadcrumbs.html","../../../projects/lib/breadcrumbs/breadcrumbs-item.ts","../../../projects/lib/breadcrumbs/breadcrumbs-item.html","../../../projects/lib/breadcrumbs/ngwr-breadcrumbs.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 { Component, ViewEncapsulation, input } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\n/**\n * Breadcrumb navigation. Project `<wr-breadcrumbs-item>` children — each keeps\n * its own element and takes `role=\"listitem\"` inside the `<ol>` rather than\n * rendering an `<li>`, separated by the configured glyph (default `/`). The\n * container exposes the `nav[aria-label]` landmark required by WCAG.\n *\n * @example\n * ```html\n * <wr-breadcrumbs>\n * <wr-breadcrumbs-item routerLink=\"/\">Home</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item routerLink=\"/docs\">Docs</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item>Current</wr-breadcrumbs-item>\n * </wr-breadcrumbs>\n *\n * <!-- Custom separator -->\n * <wr-breadcrumbs separator=\"›\">…</wr-breadcrumbs>\n * ```\n *\n * @see https://ngwr.dev/reference/components/breadcrumbs\n */\n@Component({\n selector: 'wr-breadcrumbs',\n templateUrl: './breadcrumbs.html',\n styleUrl: './breadcrumbs.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-breadcrumbs',\n '[style.--wr-breadcrumbs-separator]':
|
|
1
|
+
{"version":3,"file":"ngwr-breadcrumbs.mjs","sources":["../../../projects/lib/breadcrumbs/breadcrumbs.ts","../../../projects/lib/breadcrumbs/breadcrumbs.html","../../../projects/lib/breadcrumbs/breadcrumbs-item.ts","../../../projects/lib/breadcrumbs/breadcrumbs-item.html","../../../projects/lib/breadcrumbs/ngwr-breadcrumbs.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 { Component, ViewEncapsulation, computed, input } from '@angular/core';\n\nimport { useI18nText } from 'ngwr/i18n';\n\n/** Escape a string for use inside a double-quoted CSS `<string>`. */\nfunction cssString(value: string): string {\n return value.replace(/[\\\\\"]/g, '\\\\$&').replace(/[\\n\\r\\f]/g, char => `\\\\${char.codePointAt(0)!.toString(16)} `);\n}\n\n/**\n * Breadcrumb navigation. Project `<wr-breadcrumbs-item>` children — each keeps\n * its own element and takes `role=\"listitem\"` inside the `<ol>` rather than\n * rendering an `<li>`, separated by the configured glyph (default `/`). The\n * container exposes the `nav[aria-label]` landmark required by WCAG.\n *\n * @example\n * ```html\n * <wr-breadcrumbs>\n * <wr-breadcrumbs-item routerLink=\"/\">Home</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item routerLink=\"/docs\">Docs</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item>Current</wr-breadcrumbs-item>\n * </wr-breadcrumbs>\n *\n * <!-- Custom separator -->\n * <wr-breadcrumbs separator=\"›\">…</wr-breadcrumbs>\n * ```\n *\n * @see https://ngwr.dev/reference/components/breadcrumbs\n */\n@Component({\n selector: 'wr-breadcrumbs',\n templateUrl: './breadcrumbs.html',\n styleUrl: './breadcrumbs.scss',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-breadcrumbs',\n '[style.--wr-breadcrumbs-separator]': 'separatorValue()',\n },\n})\nexport class WrBreadcrumbs {\n /** Separator glyph between items. Any short string. @default '/' */\n readonly separator = input('/');\n\n /**\n * Accessible label for the `nav` landmark. Falls back to `breadcrumbs.label`,\n * then `'Breadcrumbs'`.\n */\n readonly ariaLabel = input<string | null>(null);\n\n // The English default used to live on the input itself, which made this the one\n // landmark in the library a catalog could not reach: `wr-anchor` and `wr-sidebar`\n // announced in Russian on the same page while this one stayed \"Breadcrumbs\", and\n // the only escape was restating `[ariaLabel]` on every trail.\n protected readonly resolvedAriaLabel = useI18nText(this.ariaLabel, 'breadcrumbs.label', 'Breadcrumbs');\n\n // The glyph is WRAPPED in quotes here and unwrapped by `content:` in the\n // stylesheet, so an unescaped `\"` inside it closes the library's own string\n // and the rest of the value is parsed as CSS — `/\" url(\"…\") \"` computes to\n // `content: \"/\" url(\"…\") \"\"`, an image the browser fetches. Escaping is the\n // whole fix, and it is lossless: a separator that IS a quote still renders.\n protected readonly separatorValue = computed(() => `\"${cssString(this.separator())}\"`);\n}\n","<nav class=\"wr-breadcrumbs__nav\" [attr.aria-label]=\"resolvedAriaLabel()\">\n <ol class=\"wr-breadcrumbs__list\">\n <ng-content />\n </ol>\n</nav>\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 { NgTemplateOutlet } from '@angular/common';\nimport { Component, ViewEncapsulation, computed, input } from '@angular/core';\nimport { RouterLink } from '@angular/router';\n\nimport { WrIcon, type WrIconName } from 'ngwr/icon';\n\n/**\n * One row inside `<wr-breadcrumbs>`. The host itself is the row — a\n * `<wr-breadcrumbs-item role=\"listitem\" class=\"wr-breadcrumbs__item\">`\n * inside the parent's `<ol>` — and it contains either a real\n * `<a class=\"wr-breadcrumbs__link\">` (when `[href]` or `[routerLink]` is\n * set) or, for the current crumb, a non-interactive\n * `<a class=\"wr-breadcrumbs__current\" role=\"text\" tabindex=\"-1\"\n * aria-current=\"page\">` (when neither is set — typically the last crumb).\n *\n * @example\n * ```html\n * <wr-breadcrumbs-item icon=\"home\" routerLink=\"/\">Home</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item href=\"https://ngwr.dev\">External</wr-breadcrumbs-item>\n * <wr-breadcrumbs-item>Current page</wr-breadcrumbs-item>\n * ```\n */\n@Component({\n selector: 'wr-breadcrumbs-item',\n templateUrl: './breadcrumbs-item.html',\n encapsulation: ViewEncapsulation.None,\n imports: [NgTemplateOutlet, RouterLink, WrIcon],\n host: { class: 'wr-breadcrumbs__item', role: 'listitem' },\n})\nexport class WrBreadcrumbsItem {\n /** Plain anchor href. Overridden by `routerLink` when both are set. */\n readonly href = input<string | null>(null);\n\n /** Angular router target. Anything `RouterLink` accepts (string or `any[]`). */\n readonly routerLink = input<string | readonly unknown[] | null>(null);\n\n /** Open external `href` in a new tab. Ignored when `routerLink` is set. @default false */\n readonly external = input(false);\n\n /** Optional leading icon rendered inline before the label. @default null */\n readonly icon = input<WrIconName | null>(null);\n\n protected readonly isLink = computed(() => this.href() != null || this.routerLink() != null);\n protected readonly isRouter = computed(() => this.routerLink() != null);\n\n protected readonly rootClass = computed(() => (this.isLink() ? 'wr-breadcrumbs__link' : 'wr-breadcrumbs__current'));\n}\n","<!--\n The label lives in a template rather than inside each branch below. A default\n `<ng-content />` written into two `@if` branches fills only ONE of them — the\n last in static order — and the other renders empty, with no template error and\n nothing in the console. This component has been broken exactly that way\n before; stamping one template from either branch keeps two anchors and one\n projection.\n-->\n<ng-template #label>\n @if (icon(); as i) {\n <wr-icon class=\"wr-breadcrumbs__icon\" [name]=\"i\" />\n }\n <ng-content />\n</ng-template>\n\n@if (isRouter()) {\n <!--\n Only ROUTER crumbs get `RouterLink`. Applied unconditionally it owns the\n anchor's `href` and writes null into it whenever `routerLink` is null —\n which silently turned every `href`-based crumb, a documented input, into\n text that navigates nowhere.\n -->\n <a [class]=\"rootClass()\" [routerLink]=\"routerLink()\">\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n} @else {\n <a\n [class]=\"rootClass()\"\n [attr.href]=\"href()\"\n [attr.aria-current]=\"isLink() ? null : 'page'\"\n [attr.role]=\"isLink() ? null : 'text'\"\n [attr.tabindex]=\"isLink() ? null : -1\"\n [attr.target]=\"external() ? '_blank' : null\"\n [attr.rel]=\"external() ? 'noreferrer noopener' : null\"\n >\n <ng-container [ngTemplateOutlet]=\"label\" />\n </a>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
@@ -1084,7 +1084,7 @@ class WrContextMenuPanel {
|
|
|
1084
1084
|
contentTpl = viewChild.required(TemplateRef, /* @ts-ignore */
|
|
1085
1085
|
...(ngDevMode ? [{ debugName: "contentTpl" }] : /* istanbul ignore next */ []));
|
|
1086
1086
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1087
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.4", type: WrContextMenuPanel, isStandalone: true, selector: "wr-context-menu", host: {
|
|
1087
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "22.1.4", type: WrContextMenuPanel, isStandalone: true, selector: "wr-context-menu", host: { properties: { "style.display": "'none'" } }, viewQueries: [{ propertyName: "contentTpl", first: true, predicate: TemplateRef, descendants: true, isSignal: true }], exportAs: ["wrContextMenu"], ngImport: i0, template: '<ng-template><div class="wr-context-menu" role="menu"><ng-content /></div></ng-template>', isInline: true, encapsulation: i0.ViewEncapsulation.None });
|
|
1088
1088
|
}
|
|
1089
1089
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImport: i0, type: WrContextMenuPanel, decorators: [{
|
|
1090
1090
|
type: Component,
|
|
@@ -1093,7 +1093,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.4", ngImpor
|
|
|
1093
1093
|
template: '<ng-template><div class="wr-context-menu" role="menu"><ng-content /></div></ng-template>',
|
|
1094
1094
|
exportAs: 'wrContextMenu',
|
|
1095
1095
|
encapsulation: ViewEncapsulation.None,
|
|
1096
|
-
|
|
1096
|
+
// A BOUND display rather than a static `style` attribute: Angular writes a
|
|
1097
|
+
// binding through `style.setProperty`, which no CSP governs, while a real
|
|
1098
|
+
// `style="…"` attribute is refused under `style-src 'self'` — and this host
|
|
1099
|
+
// would then lay out an empty box in the middle of the content.
|
|
1100
|
+
host: { '[style.display]': "'none'" },
|
|
1097
1101
|
}]
|
|
1098
1102
|
}], propDecorators: { contentTpl: [{ type: i0.ViewChild, args: [i0.forwardRef(() => TemplateRef), { isSignal: true }] }] } });
|
|
1099
1103
|
|