ngwr 15.2.0 → 15.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/alert/styles/_index.scss +13 -5
- package/fesm2022/ngwr-alert.mjs +2 -2
- package/fesm2022/ngwr-alert.mjs.map +1 -1
- package/fesm2022/ngwr-breadcrumbs.mjs +18 -2
- package/fesm2022/ngwr-breadcrumbs.mjs.map +1 -1
- package/fesm2022/ngwr-hotkey.mjs +23 -1
- package/fesm2022/ngwr-hotkey.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ar.mjs +2 -0
- package/fesm2022/ngwr-i18n-ar.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-cs.mjs +2 -0
- package/fesm2022/ngwr-i18n-cs.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-de.mjs +2 -0
- package/fesm2022/ngwr-i18n-de.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-en.mjs +2 -0
- package/fesm2022/ngwr-i18n-en.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-es.mjs +2 -0
- package/fesm2022/ngwr-i18n-es.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-fr.mjs +2 -0
- package/fesm2022/ngwr-i18n-fr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-he.mjs +2 -0
- package/fesm2022/ngwr-i18n-he.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-hi.mjs +2 -0
- package/fesm2022/ngwr-i18n-hi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-id.mjs +2 -0
- package/fesm2022/ngwr-i18n-id.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-it.mjs +2 -0
- package/fesm2022/ngwr-i18n-it.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ja.mjs +2 -0
- package/fesm2022/ngwr-i18n-ja.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ko.mjs +2 -0
- package/fesm2022/ngwr-i18n-ko.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-nl.mjs +2 -0
- package/fesm2022/ngwr-i18n-nl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pl.mjs +2 -0
- package/fesm2022/ngwr-i18n-pl.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-pt.mjs +2 -0
- package/fesm2022/ngwr-i18n-pt.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-ru.mjs +2 -0
- package/fesm2022/ngwr-i18n-ru.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-sv.mjs +2 -0
- package/fesm2022/ngwr-i18n-sv.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-tr.mjs +2 -0
- package/fesm2022/ngwr-i18n-tr.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-uk.mjs +2 -0
- package/fesm2022/ngwr-i18n-uk.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-vi.mjs +2 -0
- package/fesm2022/ngwr-i18n-vi.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh-tw.mjs +2 -0
- package/fesm2022/ngwr-i18n-zh-tw.mjs.map +1 -1
- package/fesm2022/ngwr-i18n-zh.mjs +2 -0
- package/fesm2022/ngwr-i18n-zh.mjs.map +1 -1
- package/fesm2022/ngwr-pagination.mjs +3 -0
- package/fesm2022/ngwr-pagination.mjs.map +1 -1
- package/fesm2022/ngwr-pipes.mjs +5 -2
- package/fesm2022/ngwr-pipes.mjs.map +1 -1
- package/fesm2022/ngwr-schema-form.mjs +3 -0
- package/fesm2022/ngwr-schema-form.mjs.map +1 -1
- package/fesm2022/ngwr-select-testing.mjs +16 -0
- package/fesm2022/ngwr-select-testing.mjs.map +1 -1
- package/fesm2022/ngwr-select.mjs +218 -38
- package/fesm2022/ngwr-select.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +9 -5
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/i18n/ar.json +2 -0
- package/i18n/cs.json +2 -0
- package/i18n/de.json +2 -0
- package/i18n/en.json +2 -0
- package/i18n/es.json +2 -0
- package/i18n/fr.json +2 -0
- package/i18n/he.json +2 -0
- package/i18n/hi.json +2 -0
- package/i18n/id.json +2 -0
- package/i18n/it.json +2 -0
- package/i18n/ja.json +2 -0
- package/i18n/ko.json +2 -0
- package/i18n/nl.json +2 -0
- package/i18n/pl.json +2 -0
- package/i18n/pt.json +2 -0
- package/i18n/ru.json +2 -0
- package/i18n/sv.json +2 -0
- package/i18n/tr.json +2 -0
- package/i18n/uk.json +2 -0
- package/i18n/vi.json +2 -0
- package/i18n/zh-TW.json +2 -0
- package/i18n/zh.json +2 -0
- package/llms-full.txt +3 -3
- package/package.json +1 -1
- package/schematics/use/symbol-map.json +1 -0
- package/select/styles/_index.scss +23 -1
- package/skills/ngwr/references/catalog.md +1 -1
- package/types/ngwr-alert.d.ts +3 -1
- package/types/ngwr-breadcrumbs.d.ts +15 -0
- package/types/ngwr-hotkey.d.ts +14 -2
- package/types/ngwr-select-testing.d.ts +9 -0
- package/types/ngwr-select.d.ts +133 -2
- package/types/ngwr-sidebar.d.ts +1 -1
- package/types/ngwr-version.d.ts +1 -1
|
@@ -12,6 +12,7 @@ import { WrCountUp } from "ngwr/counter";
|
|
|
12
12
|
* Use of this source code is governed by an MIT-style license that can be
|
|
13
13
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
14
14
|
*/
|
|
15
|
+
const PLAIN_DECIMAL = /^[+-]?(?:\d+\.?\d*|\.\d+)$/;
|
|
15
16
|
var WrStatistic = class WrStatistic {
|
|
16
17
|
platform = inject(WrPlatform);
|
|
17
18
|
locale = inject(LOCALE_ID);
|
|
@@ -37,7 +38,7 @@ var WrStatistic = class WrStatistic {
|
|
|
37
38
|
const n = typeof raw === "number" ? raw : coerceNumberProperty(raw, NaN);
|
|
38
39
|
return Number.isFinite(n) ? n : null;
|
|
39
40
|
}, ...ngDevMode ? [{ debugName: "numericValue" }] : /* istanbul ignore next */ []);
|
|
40
|
-
animated = computed(() => this.platform.isBrowser && this.animate() && !this.platform.prefersReducedMotion() && this.numericValue() !== null, ...ngDevMode ? [{ debugName: "animated" }] : /* istanbul ignore next */ []);
|
|
41
|
+
animated = computed(() => this.platform.isBrowser && this.animate() && !this.platform.prefersReducedMotion() && typeof this.value() === "number" && this.numericValue() !== null, ...ngDevMode ? [{ debugName: "animated" }] : /* istanbul ignore next */ []);
|
|
41
42
|
animateFrom = signal(0, ...ngDevMode ? [{ debugName: "animateFrom" }] : /* istanbul ignore next */ []);
|
|
42
43
|
lastNumeric = signal(0, ...ngDevMode ? [{ debugName: "lastNumeric" }] : /* istanbul ignore next */ []);
|
|
43
44
|
constructor() {
|
|
@@ -52,10 +53,13 @@ var WrStatistic = class WrStatistic {
|
|
|
52
53
|
}
|
|
53
54
|
displayValue = computed(() => {
|
|
54
55
|
const n = this.numericValue();
|
|
55
|
-
if (n !== null)
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
if (n !== null) {
|
|
57
|
+
const raw = typeof this.value() === "string" ? String(this.value()).trim() : "";
|
|
58
|
+
return new Intl.NumberFormat(this.locale, {
|
|
59
|
+
minimumFractionDigits: this.precision(),
|
|
60
|
+
maximumFractionDigits: this.precision()
|
|
61
|
+
}).format(PLAIN_DECIMAL.test(raw) ? raw : n);
|
|
62
|
+
}
|
|
59
63
|
const raw = this.value();
|
|
60
64
|
return raw === null || raw === void 0 || raw === "" ? "—" : String(raw);
|
|
61
65
|
}, ...ngDevMode ? [{ debugName: "displayValue" }] : /* istanbul ignore next */ []);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-statistic.mjs","names":[],"sources":["../../../projects/lib/statistic/statistic.ts","../../../projects/lib/statistic/statistic.html","../../../projects/lib/statistic/statistic-countdown.ts","../../../projects/lib/statistic/statistic-countdown.html","../../../projects/lib/statistic/statistic-group.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n LOCALE_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\n\nimport { WrCountUp } from 'ngwr/counter';\nimport { useI18nFormatter, useI18nText } from 'ngwr/i18n';\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\n/**\n * KPI card — label + big number + optional prefix/suffix + delta. Pair\n * with `<wr-statistic-group>` for a responsive dashboard grid.\n *\n * When `value` is numeric the number counts up (eased) from its previous\n * value to the new one on every change — see `animate`. String values and\n * `prefers-reduced-motion` render instantly.\n *\n * @example\n * ```html\n * <wr-statistic label=\"Active users\" [value]=\"12345\" suffix=\"users\" />\n * <wr-statistic label=\"Revenue\" [value]=\"9512\" prefix=\"$\" [delta]=\"12.4\" />\n * <wr-statistic label=\"Churn\" [value]=\"1.8\" suffix=\"%\" [precision]=\"1\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/statistic\n */\n@Component({\n selector: 'wr-statistic',\n templateUrl: './statistic.html',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-statistic' },\n imports: [WrCountUp],\n})\nexport class WrStatistic {\n private readonly platform = inject(WrPlatform);\n private readonly locale = inject(LOCALE_ID);\n\n /**\n * The caption above the figure — what the number counts. Keep it short; the\n * value is the thing being read, and this names it.\n */\n readonly label = input<string>('');\n\n /** The number (or string) to display in the main slot. */\n readonly value = input<number | string | null>(null);\n\n /** Prefix glyph / symbol (e.g. `'$'`). */\n readonly prefix = input<string>('');\n\n /** Suffix glyph / unit (e.g. `'%'`, `'kg'`). */\n readonly suffix = input<string>('');\n\n /** Fixed number of decimals applied to numeric values. @default 0 */\n readonly precision = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n\n /**\n * Count up to a new numeric `value` instead of swapping instantly. Always\n * off for string values or under `prefers-reduced-motion`. @default true\n */\n readonly animate = input(true, { transform: coerceBooleanProperty });\n\n /** Count-up duration (ms). @default 700 */\n readonly duration = input(700, { transform: numAttr(700) });\n\n /**\n * The current value coerced to a finite number, or `null` when `value` is\n * a non-numeric string / empty / nullish (rendered as-is).\n */\n protected readonly numericValue = computed<number | null>(() => {\n const raw = this.value();\n if (raw === null || raw === '') return null;\n const n = typeof raw === 'number' ? raw : coerceNumberProperty(raw, Number.NaN);\n return Number.isFinite(n) ? n : null;\n });\n\n /** Whether the value should count up (browser, numeric, opted-in, motion allowed). */\n protected readonly animated = computed<boolean>(\n () =>\n this.platform.isBrowser && this.animate() && !this.platform.prefersReducedMotion() && this.numericValue() !== null\n );\n\n /** Animation start — the previously-rendered numeric value (0 on first paint). */\n protected readonly animateFrom = signal(0);\n\n /** Bookkeeping: the last numeric value seen, fed back as the next `from`. */\n private readonly lastNumeric = signal(0);\n\n constructor() {\n // Whenever the numeric value changes, snapshot the prior value as the\n // count-up start, then remember the new one for the next transition.\n effect(() => {\n const next = this.numericValue();\n if (next === null) return;\n untracked(() => {\n this.animateFrom.set(this.lastNumeric());\n this.lastNumeric.set(next);\n });\n });\n }\n\n /**\n * Static (non-animated) display string. Numeric values honour `precision`\n * and locale grouping so they match the count-up output; everything else\n * renders verbatim with an em-dash fallback.\n */\n protected readonly displayValue = computed<string>(() => {\n const n = this.numericValue();\n if (n !== null) {\n return new Intl.NumberFormat(this.locale, {\n minimumFractionDigits: this.precision(),\n maximumFractionDigits: this.precision(),\n }).format(n);\n }\n // `numericValue` above already reads `''` as \"no value\"; rendering it\n // verbatim put an empty card on screen instead of the placeholder.\n const raw = this.value();\n return raw === null || raw === undefined || raw === '' ? '—' : String(raw);\n });\n\n /**\n * Optional delta vs previous period — shown as `+x.x%` (or `-x.x%`).\n * Use `deltaSuffix` to change the trailing unit.\n */\n readonly delta = input<number | null>(null, {\n transform: (v: unknown): number | null => {\n if (v === null || v === undefined || v === '') return null;\n const n = coerceNumberProperty(v, Number.NaN);\n return Number.isFinite(n) ? n : null;\n },\n });\n\n // The default moved from the literal `'%'` to `null` so the catalog gets a\n // say. `%` is a string the LIBRARY owns and no locale could reach: a locale\n // that writes it differently — or writes it as a word — had nowhere to put\n // that but a per-instance binding on every `<wr-statistic>` on the page. A\n // bound value still wins, exactly as before, which is what makes this safe.\n /** Unit appended to the delta value. Falls back to `statistic.deltaSuffix`, then `'%'`. */\n readonly deltaSuffix = input<string | null>(null);\n\n protected readonly hasDelta = computed(() => this.delta() !== null);\n\n protected readonly deltaDirection = computed<'up' | 'down' | 'flat'>(() => {\n const d = this.delta();\n if (d === null || d === 0) return 'flat';\n return d > 0 ? 'up' : 'down';\n });\n\n protected readonly resolvedDeltaSuffix = useI18nText(this.deltaSuffix, 'statistic.deltaSuffix', '%');\n\n /** `{{value}}{{suffix}}` — the join, so a locale owns the space before the unit. */\n private readonly deltaFormat = useI18nFormatter('statistic.delta', '{{value}}{{suffix}}');\n\n /**\n * The delta chip, e.g. `+12.4%`.\n *\n * It was `` `${sign}${d}${suffix}` ``, printed one line under a value that\n * goes through `Intl.NumberFormat` — so the two disagreed inside one\n * component: ar-SA showed `١٬٢٣٤٬٥٦٧٫٨٩` above a Latin `12.4%`, and de-DE\n * `1.234.567,89` above `+12.4%`. The sign comes from `signDisplay`, which also\n * fixes the RTL half of it: `+` written by hand is a neutral character that\n * the BiDi algorithm moves to the other end of the number.\n *\n * The digit count is taken from the number rather than from `precision()`,\n * which describes the VALUE and not the delta — so what renders is the same\n * digits as before, in the locale's own numerals. One exception, and it is an\n * improvement rather than a regression: a magnitude JavaScript prints in\n * exponent notation (`1e-7`, `1e+21`) used to reach the DOM that way and is\n * now formatted as a number.\n */\n protected readonly deltaText = computed(() => {\n const d = this.delta();\n if (d === null) return '';\n const decimals = Math.min(20, (String(Math.abs(d)).split('.')[1] ?? '').length);\n const value = new Intl.NumberFormat(this.locale, {\n signDisplay: 'exceptZero',\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(d);\n return this.deltaFormat({ value, suffix: this.resolvedDeltaSuffix() });\n });\n}\n","@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n @if (prefix()) {\n <span class=\"wr-statistic__prefix\">{{ prefix() }}</span>\n }\n @if (animated()) {\n <wr-count-up\n class=\"wr-statistic__number\"\n [from]=\"animateFrom()\"\n [to]=\"numericValue() ?? 0\"\n [decimals]=\"precision()\"\n [duration]=\"duration()\"\n />\n } @else {\n <span class=\"wr-statistic__number\">{{ displayValue() }}</span>\n }\n @if (suffix()) {\n <span class=\"wr-statistic__suffix\">{{ suffix() }}</span>\n }\n</div>\n@if (hasDelta()) {\n <div [class]=\"`wr-statistic__delta wr-statistic__delta--${deltaDirection()}`\">\n @if (deltaDirection() === 'up') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 1 L9 8 L1 8 Z\" fill=\"currentColor\" />\n </svg>\n } @else if (deltaDirection() === 'down') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 9 L9 2 L1 2 Z\" fill=\"currentColor\" />\n </svg>\n }\n <span>{{ deltaText() }}</span>\n </div>\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 { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n PLATFORM_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n\nimport { numAttr } from 'ngwr/utils';\n\n// Helpers\n\nfunction toMs(value: Date | string | number): number {\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'number') return value;\n return new Date(value).getTime();\n}\n\nfunction pad(n: number, width: number): string {\n return String(n).padStart(width, '0');\n}\n\n/**\n * The format's tokens, longest first inside the alternation so `DD` beats `D`,\n * `HH` beats `H`, `mm` beats `m` and `SSS` beats `ss` beats `s`. Matched in one pass\n * so the output is never re-scanned: a sequential `.replace()` chain turned\n * `D days HH:mm:ss` into `1 day42 11:59:42`, its last `/s/g` step re-matching the\n * literal `s` inside `days`.\n */\nconst TOKEN = /(?<![A-Za-z])(?:SSS|DD|HH|mm|ss|D|H|m|s)(?![A-Za-z])/g;\n\n/** Each unit's length, largest first, keyed by its token's letter. */\nconst UNITS = [\n ['D', 86_400_000],\n ['H', 3_600_000],\n ['m', 60_000],\n ['s', 1000],\n ['S', 1],\n] as const;\n\n/**\n * A unit the format does not show is carried into the next larger one it does:\n * `HH:mm:ss` with three days left reads `73:00:00`. Every unit was taken modulo\n * the next one whatever the format held, so the default format dropped whole days\n * and showed `00:59:59` for three days and an hour.\n */\nfunction formatRemaining(ms: number, fmt: string): string {\n const shown = new Set((fmt.match(TOKEN) ?? []).map(token => token[0]));\n const value: Record<string, number> = {};\n let rest = ms;\n for (const [unit, size] of UNITS) {\n if (!shown.has(unit)) continue;\n value[unit] = Math.floor(rest / size);\n rest -= value[unit] * size;\n }\n return fmt.replace(TOKEN, token => {\n const n = value[token[0]];\n return token === 'SSS' ? pad(n, 3) : token.length === 2 ? pad(n, 2) : String(n);\n });\n}\n\n/**\n * Live-counting variant of `<wr-statistic>` that targets a future date\n * and ticks down to zero. The format string uses Day/Hour/Minute/Second\n * tokens (`D`, `H`, `m`, `s`, double for zero-padded, plus `SSS` for\n * milliseconds).\n *\n * @example\n * ```html\n * <wr-statistic-countdown\n * label=\"Launch in\"\n * [target]=\"launchDate\"\n * format=\"D days HH:mm:ss\"\n * (countdownEnd)=\"onLive()\"\n * />\n * ```\n *\n * @see https://ngwr.dev/reference/components/statistic\n */\n@Component({\n selector: 'wr-statistic-countdown',\n templateUrl: './statistic-countdown.html',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-statistic' },\n})\nexport class WrStatisticCountdown {\n /** Target date / timestamp the countdown is running down to. */\n readonly target = input.required<Date | string | number>();\n\n /** Label rendered above the value. */\n readonly label = input<string>('');\n\n /**\n * Format string. Tokens: `D`/`DD` (days), `H`/`HH` (hours),\n * `m`/`mm` (minutes), `s`/`ss` (seconds), `SSS` (milliseconds).\n * Double-letter forms zero-pad to width 2. A unit the format leaves out is\n * carried into the next larger one it shows, so `HH:mm:ss` reads `73:00:00`\n * with three days and an hour left. @default 'HH:mm:ss'\n */\n readonly format = input<string>('HH:mm:ss');\n\n /** Optional text shown once the countdown reaches zero. */\n readonly endText = input<string | null>(null);\n\n /**\n * Tick interval in ms. Drop to ~16 for `SSS` (millisecond display). Floored\n * at one frame — `0` (or an unparseable value) asked `setInterval` to run as\n * fast as the browser would allow, which is a busy loop, not a countdown.\n * @default 1000\n */\n readonly tickMs = input(1000, { transform: (v: unknown): number => Math.max(16, numAttr(1000)(v)) });\n\n /** Fires once when the countdown crosses zero. */\n readonly countdownEnd = output<void>();\n\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private readonly targetMs = computed(() => toMs(this.target()));\n\n /**\n * Milliseconds left, or `null` when `target` does not parse to a date at all.\n * `new Date('nope').getTime()` is `NaN`, and `NaN` propagated all the way to\n * the screen as `NaN:NaN:NaN` — and, worse, `tick` compared it to `0` and so\n * never fired `countdownEnd`, while a guard that only clamped the text would\n * have fired it immediately for a target that was never reached.\n */\n private remainingMs(): number | null {\n const target = this.targetMs();\n return Number.isFinite(target) ? Math.max(0, target - Date.now()) : null;\n }\n\n /** Remaining milliseconds (live signal). */\n protected readonly remaining = signal(0);\n protected readonly finished = signal(false);\n\n protected readonly display = computed(() => {\n if (this.finished() && this.endText() != null) return this.endText()!;\n return formatRemaining(this.remaining(), this.format());\n });\n\n constructor() {\n // Seed once synchronously so SSR / first paint shows a sane value.\n effect(() => {\n const ms = this.remainingMs();\n this.remaining.set(ms ?? 0);\n this.finished.set(ms === 0);\n });\n\n if (!this.isBrowser) return;\n\n // The interval is REBUILT when `tickMs` changes, which is what makes the\n // input bindable rather than an authoring-time constant. Read once from\n // inside `afterNextRender` it was a plain, untracked read, so\n // `[tickMs]=\"precise() ? 16 : 1000\"` kept whatever period the first frame\n // saw and nothing looked wrong — the countdown still counted. Same shape\n // `wr-rotating-text` uses for its own rotation period; the `onCleanup` is\n // what keeps a period change from leaving the old interval running beside\n // the new one.\n effect(onCleanup => {\n const handle = setInterval(() => this.tick(), this.tickMs());\n onCleanup(() => clearInterval(handle));\n });\n }\n\n private tick(): void {\n const ms = this.remainingMs();\n if (ms === null) return;\n this.remaining.set(ms);\n if (ms === 0 && !this.finished()) {\n this.finished.set(true);\n this.countdownEnd.emit();\n }\n }\n}\n","@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n <span class=\"wr-statistic__number\">{{ display() }}</span>\n</div>\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 { coerceNumberProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, input } from '@angular/core';\n\n/**\n * Dashboard grid for `<wr-statistic>` cards. The column count follows the\n * group's OWN width — an intrinsic container-query grid sized by its box, not\n * a viewport media query — so it reflows correctly inside any column, card, or\n * split pane. Columns are never narrower than `min`; `columns` optionally caps\n * how many ever sit side by side on a wide container.\n *\n * @example\n * ```html\n * <wr-statistic-group [columns]=\"4\" min=\"11rem\">\n * <wr-statistic label=\"Active users\" [value]=\"12345\" />\n * <wr-statistic label=\"Revenue\" [value]=\"9512\" prefix=\"$\" [delta]=\"12.4\" />\n * <wr-statistic label=\"Churn\" [value]=\"1.8\" suffix=\"%\" [delta]=\"-0.4\" />\n * <wr-statistic label=\"Sessions\" [value]=\"48210\" />\n * </wr-statistic-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/statistic\n */\n@Component({\n selector: 'wr-statistic-group',\n template: '<div class=\"wr-statistic-group__grid\"><ng-content /></div>',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-statistic-group',\n '[style.--wr-statistic-group-min]': 'min()',\n '[style.--wr-statistic-group-columns]': 'columns() || null',\n },\n})\nexport class WrStatisticGroup {\n /**\n * Minimum width of each column before the grid reflows to fewer columns.\n * Any CSS length — smaller packs more cards per row. @default '12rem'\n */\n readonly min = input<string>('12rem');\n\n /**\n * Cap on how many columns ever sit side by side on a wide container. `0`\n * (default) leaves it uncapped — fit as many `min`-wide columns as the\n * width allows. @default 0\n */\n readonly columns = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-statistic.mjs","names":[],"sources":["../../../projects/lib/statistic/statistic.ts","../../../projects/lib/statistic/statistic.html","../../../projects/lib/statistic/statistic-countdown.ts","../../../projects/lib/statistic/statistic-countdown.html","../../../projects/lib/statistic/statistic-group.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n */\n\nimport { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';\nimport {\n Component,\n LOCALE_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n signal,\n untracked,\n} from '@angular/core';\n\nimport { WrCountUp } from 'ngwr/counter';\nimport { useI18nFormatter, useI18nText } from 'ngwr/i18n';\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\n/** Digits with one optional point and a sign: the form `Intl` reads exactly. */\nconst PLAIN_DECIMAL = /^[+-]?(?:\\d+\\.?\\d*|\\.\\d+)$/;\n\n/**\n * KPI card — label + big number + optional prefix/suffix + delta. Pair\n * with `<wr-statistic-group>` for a responsive dashboard grid.\n *\n * When `value` is numeric the number counts up (eased) from its previous\n * value to the new one on every change — see `animate`. String values and\n * `prefers-reduced-motion` render instantly.\n *\n * @example\n * ```html\n * <wr-statistic label=\"Active users\" [value]=\"12345\" suffix=\"users\" />\n * <wr-statistic label=\"Revenue\" [value]=\"9512\" prefix=\"$\" [delta]=\"12.4\" />\n * <wr-statistic label=\"Churn\" [value]=\"1.8\" suffix=\"%\" [precision]=\"1\" />\n * ```\n *\n * @see https://ngwr.dev/reference/components/statistic\n */\n@Component({\n selector: 'wr-statistic',\n templateUrl: './statistic.html',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-statistic' },\n imports: [WrCountUp],\n})\nexport class WrStatistic {\n private readonly platform = inject(WrPlatform);\n private readonly locale = inject(LOCALE_ID);\n\n /**\n * The caption above the figure — what the number counts. Keep it short; the\n * value is the thing being read, and this names it.\n */\n readonly label = input<string>('');\n\n /** The number (or string) to display in the main slot. */\n readonly value = input<number | string | null>(null);\n\n /** Prefix glyph / symbol (e.g. `'$'`). */\n readonly prefix = input<string>('');\n\n /** Suffix glyph / unit (e.g. `'%'`, `'kg'`). */\n readonly suffix = input<string>('');\n\n /** Fixed number of decimals applied to numeric values. @default 0 */\n readonly precision = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n\n /**\n * Count up to a new numeric `value` instead of swapping instantly. Always\n * off for string values or under `prefers-reduced-motion`. @default true\n */\n readonly animate = input(true, { transform: coerceBooleanProperty });\n\n /** Count-up duration (ms). @default 700 */\n readonly duration = input(700, { transform: numAttr(700) });\n\n /**\n * The current value coerced to a finite number, or `null` when `value` is\n * a non-numeric string / empty / nullish (rendered as-is).\n */\n protected readonly numericValue = computed<number | null>(() => {\n const raw = this.value();\n if (raw === null || raw === '') return null;\n const n = typeof raw === 'number' ? raw : coerceNumberProperty(raw, Number.NaN);\n return Number.isFinite(n) ? n : null;\n });\n\n /** Whether the value should count up (browser, numeric, opted-in, motion allowed). */\n protected readonly animated = computed<boolean>(\n () =>\n this.platform.isBrowser &&\n this.animate() &&\n !this.platform.prefersReducedMotion() &&\n typeof this.value() === 'number' &&\n this.numericValue() !== null\n );\n\n /** Animation start — the previously-rendered numeric value (0 on first paint). */\n protected readonly animateFrom = signal(0);\n\n /** Bookkeeping: the last numeric value seen, fed back as the next `from`. */\n private readonly lastNumeric = signal(0);\n\n constructor() {\n // Whenever the numeric value changes, snapshot the prior value as the\n // count-up start, then remember the new one for the next transition.\n effect(() => {\n const next = this.numericValue();\n if (next === null) return;\n untracked(() => {\n this.animateFrom.set(this.lastNumeric());\n this.lastNumeric.set(next);\n });\n });\n }\n\n /**\n * Static (non-animated) display string. Numeric values honour `precision`\n * and locale grouping so they match the count-up output; everything else\n * renders verbatim with an em-dash fallback.\n */\n protected readonly displayValue = computed<string>(() => {\n const n = this.numericValue();\n if (n !== null) {\n // A plain decimal string is formatted as it is, the way `wrNumber` does it,\n // so a long amount keeps every digit. `format()` has taken a string since\n // ES2023, though the ES2022 lib types it as a number only.\n const raw = typeof this.value() === 'string' ? String(this.value()).trim() : '';\n return new Intl.NumberFormat(this.locale, {\n minimumFractionDigits: this.precision(),\n maximumFractionDigits: this.precision(),\n }).format(PLAIN_DECIMAL.test(raw) ? (raw as unknown as number) : n);\n }\n // `numericValue` above already reads `''` as \"no value\"; rendering it\n // verbatim put an empty card on screen instead of the placeholder.\n const raw = this.value();\n return raw === null || raw === undefined || raw === '' ? '—' : String(raw);\n });\n\n /**\n * Optional delta vs previous period — shown as `+x.x%` (or `-x.x%`).\n * Use `deltaSuffix` to change the trailing unit.\n */\n readonly delta = input<number | null>(null, {\n transform: (v: unknown): number | null => {\n if (v === null || v === undefined || v === '') return null;\n const n = coerceNumberProperty(v, Number.NaN);\n return Number.isFinite(n) ? n : null;\n },\n });\n\n // The default moved from the literal `'%'` to `null` so the catalog gets a\n // say. `%` is a string the LIBRARY owns and no locale could reach: a locale\n // that writes it differently — or writes it as a word — had nowhere to put\n // that but a per-instance binding on every `<wr-statistic>` on the page. A\n // bound value still wins, exactly as before, which is what makes this safe.\n /** Unit appended to the delta value. Falls back to `statistic.deltaSuffix`, then `'%'`. */\n readonly deltaSuffix = input<string | null>(null);\n\n protected readonly hasDelta = computed(() => this.delta() !== null);\n\n protected readonly deltaDirection = computed<'up' | 'down' | 'flat'>(() => {\n const d = this.delta();\n if (d === null || d === 0) return 'flat';\n return d > 0 ? 'up' : 'down';\n });\n\n protected readonly resolvedDeltaSuffix = useI18nText(this.deltaSuffix, 'statistic.deltaSuffix', '%');\n\n /** `{{value}}{{suffix}}` — the join, so a locale owns the space before the unit. */\n private readonly deltaFormat = useI18nFormatter('statistic.delta', '{{value}}{{suffix}}');\n\n /**\n * The delta chip, e.g. `+12.4%`.\n *\n * It was `` `${sign}${d}${suffix}` ``, printed one line under a value that\n * goes through `Intl.NumberFormat` — so the two disagreed inside one\n * component: ar-SA showed `١٬٢٣٤٬٥٦٧٫٨٩` above a Latin `12.4%`, and de-DE\n * `1.234.567,89` above `+12.4%`. The sign comes from `signDisplay`, which also\n * fixes the RTL half of it: `+` written by hand is a neutral character that\n * the BiDi algorithm moves to the other end of the number.\n *\n * The digit count is taken from the number rather than from `precision()`,\n * which describes the VALUE and not the delta — so what renders is the same\n * digits as before, in the locale's own numerals. One exception, and it is an\n * improvement rather than a regression: a magnitude JavaScript prints in\n * exponent notation (`1e-7`, `1e+21`) used to reach the DOM that way and is\n * now formatted as a number.\n */\n protected readonly deltaText = computed(() => {\n const d = this.delta();\n if (d === null) return '';\n const decimals = Math.min(20, (String(Math.abs(d)).split('.')[1] ?? '').length);\n const value = new Intl.NumberFormat(this.locale, {\n signDisplay: 'exceptZero',\n minimumFractionDigits: decimals,\n maximumFractionDigits: decimals,\n }).format(d);\n return this.deltaFormat({ value, suffix: this.resolvedDeltaSuffix() });\n });\n}\n","@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n @if (prefix()) {\n <span class=\"wr-statistic__prefix\">{{ prefix() }}</span>\n }\n @if (animated()) {\n <wr-count-up\n class=\"wr-statistic__number\"\n [from]=\"animateFrom()\"\n [to]=\"numericValue() ?? 0\"\n [decimals]=\"precision()\"\n [duration]=\"duration()\"\n />\n } @else {\n <span class=\"wr-statistic__number\">{{ displayValue() }}</span>\n }\n @if (suffix()) {\n <span class=\"wr-statistic__suffix\">{{ suffix() }}</span>\n }\n</div>\n@if (hasDelta()) {\n <div [class]=\"`wr-statistic__delta wr-statistic__delta--${deltaDirection()}`\">\n @if (deltaDirection() === 'up') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 1 L9 8 L1 8 Z\" fill=\"currentColor\" />\n </svg>\n } @else if (deltaDirection() === 'down') {\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 10 10\" aria-hidden=\"true\">\n <path d=\"M5 9 L9 2 L1 2 Z\" fill=\"currentColor\" />\n </svg>\n }\n <span>{{ deltaText() }}</span>\n </div>\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 { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n PLATFORM_ID,\n ViewEncapsulation,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n} from '@angular/core';\n\nimport { numAttr } from 'ngwr/utils';\n\n// Helpers\n\nfunction toMs(value: Date | string | number): number {\n if (value instanceof Date) return value.getTime();\n if (typeof value === 'number') return value;\n return new Date(value).getTime();\n}\n\nfunction pad(n: number, width: number): string {\n return String(n).padStart(width, '0');\n}\n\n/**\n * The format's tokens, longest first inside the alternation so `DD` beats `D`,\n * `HH` beats `H`, `mm` beats `m` and `SSS` beats `ss` beats `s`. Matched in one pass\n * so the output is never re-scanned: a sequential `.replace()` chain turned\n * `D days HH:mm:ss` into `1 day42 11:59:42`, its last `/s/g` step re-matching the\n * literal `s` inside `days`.\n */\nconst TOKEN = /(?<![A-Za-z])(?:SSS|DD|HH|mm|ss|D|H|m|s)(?![A-Za-z])/g;\n\n/** Each unit's length, largest first, keyed by its token's letter. */\nconst UNITS = [\n ['D', 86_400_000],\n ['H', 3_600_000],\n ['m', 60_000],\n ['s', 1000],\n ['S', 1],\n] as const;\n\n/**\n * A unit the format does not show is carried into the next larger one it does:\n * `HH:mm:ss` with three days left reads `73:00:00`. Every unit was taken modulo\n * the next one whatever the format held, so the default format dropped whole days\n * and showed `00:59:59` for three days and an hour.\n */\nfunction formatRemaining(ms: number, fmt: string): string {\n const shown = new Set((fmt.match(TOKEN) ?? []).map(token => token[0]));\n const value: Record<string, number> = {};\n let rest = ms;\n for (const [unit, size] of UNITS) {\n if (!shown.has(unit)) continue;\n value[unit] = Math.floor(rest / size);\n rest -= value[unit] * size;\n }\n return fmt.replace(TOKEN, token => {\n const n = value[token[0]];\n return token === 'SSS' ? pad(n, 3) : token.length === 2 ? pad(n, 2) : String(n);\n });\n}\n\n/**\n * Live-counting variant of `<wr-statistic>` that targets a future date\n * and ticks down to zero. The format string uses Day/Hour/Minute/Second\n * tokens (`D`, `H`, `m`, `s`, double for zero-padded, plus `SSS` for\n * milliseconds).\n *\n * @example\n * ```html\n * <wr-statistic-countdown\n * label=\"Launch in\"\n * [target]=\"launchDate\"\n * format=\"D days HH:mm:ss\"\n * (countdownEnd)=\"onLive()\"\n * />\n * ```\n *\n * @see https://ngwr.dev/reference/components/statistic\n */\n@Component({\n selector: 'wr-statistic-countdown',\n templateUrl: './statistic-countdown.html',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-statistic' },\n})\nexport class WrStatisticCountdown {\n /** Target date / timestamp the countdown is running down to. */\n readonly target = input.required<Date | string | number>();\n\n /** Label rendered above the value. */\n readonly label = input<string>('');\n\n /**\n * Format string. Tokens: `D`/`DD` (days), `H`/`HH` (hours),\n * `m`/`mm` (minutes), `s`/`ss` (seconds), `SSS` (milliseconds).\n * Double-letter forms zero-pad to width 2. A unit the format leaves out is\n * carried into the next larger one it shows, so `HH:mm:ss` reads `73:00:00`\n * with three days and an hour left. @default 'HH:mm:ss'\n */\n readonly format = input<string>('HH:mm:ss');\n\n /** Optional text shown once the countdown reaches zero. */\n readonly endText = input<string | null>(null);\n\n /**\n * Tick interval in ms. Drop to ~16 for `SSS` (millisecond display). Floored\n * at one frame — `0` (or an unparseable value) asked `setInterval` to run as\n * fast as the browser would allow, which is a busy loop, not a countdown.\n * @default 1000\n */\n readonly tickMs = input(1000, { transform: (v: unknown): number => Math.max(16, numAttr(1000)(v)) });\n\n /** Fires once when the countdown crosses zero. */\n readonly countdownEnd = output<void>();\n\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private readonly targetMs = computed(() => toMs(this.target()));\n\n /**\n * Milliseconds left, or `null` when `target` does not parse to a date at all.\n * `new Date('nope').getTime()` is `NaN`, and `NaN` propagated all the way to\n * the screen as `NaN:NaN:NaN` — and, worse, `tick` compared it to `0` and so\n * never fired `countdownEnd`, while a guard that only clamped the text would\n * have fired it immediately for a target that was never reached.\n */\n private remainingMs(): number | null {\n const target = this.targetMs();\n return Number.isFinite(target) ? Math.max(0, target - Date.now()) : null;\n }\n\n /** Remaining milliseconds (live signal). */\n protected readonly remaining = signal(0);\n protected readonly finished = signal(false);\n\n protected readonly display = computed(() => {\n if (this.finished() && this.endText() != null) return this.endText()!;\n return formatRemaining(this.remaining(), this.format());\n });\n\n constructor() {\n // Seed once synchronously so SSR / first paint shows a sane value.\n effect(() => {\n const ms = this.remainingMs();\n this.remaining.set(ms ?? 0);\n this.finished.set(ms === 0);\n });\n\n if (!this.isBrowser) return;\n\n // The interval is REBUILT when `tickMs` changes, which is what makes the\n // input bindable rather than an authoring-time constant. Read once from\n // inside `afterNextRender` it was a plain, untracked read, so\n // `[tickMs]=\"precise() ? 16 : 1000\"` kept whatever period the first frame\n // saw and nothing looked wrong — the countdown still counted. Same shape\n // `wr-rotating-text` uses for its own rotation period; the `onCleanup` is\n // what keeps a period change from leaving the old interval running beside\n // the new one.\n effect(onCleanup => {\n const handle = setInterval(() => this.tick(), this.tickMs());\n onCleanup(() => clearInterval(handle));\n });\n }\n\n private tick(): void {\n const ms = this.remainingMs();\n if (ms === null) return;\n this.remaining.set(ms);\n if (ms === 0 && !this.finished()) {\n this.finished.set(true);\n this.countdownEnd.emit();\n }\n }\n}\n","@if (label()) {\n <div class=\"wr-statistic__label\">{{ label() }}</div>\n}\n<div class=\"wr-statistic__value\">\n <span class=\"wr-statistic__number\">{{ display() }}</span>\n</div>\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 { coerceNumberProperty } from '@angular/cdk/coercion';\nimport { Component, ViewEncapsulation, input } from '@angular/core';\n\n/**\n * Dashboard grid for `<wr-statistic>` cards. The column count follows the\n * group's OWN width — an intrinsic container-query grid sized by its box, not\n * a viewport media query — so it reflows correctly inside any column, card, or\n * split pane. Columns are never narrower than `min`; `columns` optionally caps\n * how many ever sit side by side on a wide container.\n *\n * @example\n * ```html\n * <wr-statistic-group [columns]=\"4\" min=\"11rem\">\n * <wr-statistic label=\"Active users\" [value]=\"12345\" />\n * <wr-statistic label=\"Revenue\" [value]=\"9512\" prefix=\"$\" [delta]=\"12.4\" />\n * <wr-statistic label=\"Churn\" [value]=\"1.8\" suffix=\"%\" [delta]=\"-0.4\" />\n * <wr-statistic label=\"Sessions\" [value]=\"48210\" />\n * </wr-statistic-group>\n * ```\n *\n * @see https://ngwr.dev/reference/components/statistic\n */\n@Component({\n selector: 'wr-statistic-group',\n template: '<div class=\"wr-statistic-group__grid\"><ng-content /></div>',\n encapsulation: ViewEncapsulation.None,\n host: {\n class: 'wr-statistic-group',\n '[style.--wr-statistic-group-min]': 'min()',\n '[style.--wr-statistic-group-columns]': 'columns() || null',\n },\n})\nexport class WrStatisticGroup {\n /**\n * Minimum width of each column before the grid reflows to fewer columns.\n * Any CSS length — smaller packs more cards per row. @default '12rem'\n */\n readonly min = input<string>('12rem');\n\n /**\n * Cap on how many columns ever sit side by side on a wide container. `0`\n * (default) leaves it uncapped — fit as many `min`-wide columns as the\n * width allows. @default 0\n */\n readonly columns = input(0, { transform: (v: unknown): number => Math.max(0, coerceNumberProperty(v, 0)) });\n}\n"],"mappings":"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"}
|
|
@@ -5,7 +5,7 @@ import { InjectionToken } from "@angular/core";
|
|
|
5
5
|
* Use of this source code is governed by an MIT-style license that can be
|
|
6
6
|
* found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE
|
|
7
7
|
*/
|
|
8
|
-
const NGWR_VERSION = "15.
|
|
8
|
+
const NGWR_VERSION = "15.3.0";
|
|
9
9
|
/**
|
|
10
10
|
* @license
|
|
11
11
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-version.mjs","names":[],"sources":["../../../projects/lib/version/version.ts","../../../projects/lib/version/version.token.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\n/**\n * The ngwr library version string, kept in sync with\n * `projects/lib/package.json` by `scripts/release/prepare.ts`.\n *\n * Prefer this over reading `package.json` at runtime — that requires a JSON\n * import or `require`, neither of which tree-shakes well in Angular builds.\n *\n * Distinct from `Version` exported by `@angular/core`, which reports the\n * loaded Angular runtime version (e.g. `'22.0.0'`), not ngwr's.\n */\nexport const NGWR_VERSION = '15.
|
|
1
|
+
{"version":3,"file":"ngwr-version.mjs","names":[],"sources":["../../../projects/lib/version/version.ts","../../../projects/lib/version/version.token.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\n/**\n * The ngwr library version string, kept in sync with\n * `projects/lib/package.json` by `scripts/release/prepare.ts`.\n *\n * Prefer this over reading `package.json` at runtime — that requires a JSON\n * import or `require`, neither of which tree-shakes well in Angular builds.\n *\n * Distinct from `Version` exported by `@angular/core`, which reports the\n * loaded Angular runtime version (e.g. `'22.0.0'`), not ngwr's.\n */\nexport const NGWR_VERSION = '15.3.0';\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 { InjectionToken } from '@angular/core';\n\nimport { NGWR_VERSION } from './version';\n\n/**\n * Injection token holding the ngwr library version string.\n *\n * Default factory returns {@link NGWR_VERSION}. Override it in tests or in\n * apps that want to surface a custom build identifier.\n *\n * @example\n * ```ts\n * @Component({...})\n * export class FooterComponent {\n * readonly version = inject(NGWR_VERSION_TOKEN);\n * }\n * ```\n */\nexport const NGWR_VERSION_TOKEN = new InjectionToken<string>('NGWR_VERSION_TOKEN', {\n providedIn: 'root',\n factory: () => NGWR_VERSION,\n});\n"],"mappings":";;;;;;;AAiBA,MAAa,eAAe;;;;;;;ACQ5B,MAAa,qBAAqB,IAAI,eAAuB,sBAAsB;CACjF,YAAY;CACZ,eAAe;AAChB,CAAA"}
|
package/i18n/ar.json
CHANGED
package/i18n/cs.json
CHANGED
package/i18n/de.json
CHANGED
|
@@ -100,6 +100,8 @@
|
|
|
100
100
|
"removeItem": "{{label}} entfernen",
|
|
101
101
|
"noResults": "Keine Ergebnisse",
|
|
102
102
|
"loading": "Wird geladen…",
|
|
103
|
+
"loadError": "Ergebnisse konnten nicht geladen werden",
|
|
104
|
+
"retry": "Erneut versuchen",
|
|
103
105
|
"more": "+{{count}} weitere"
|
|
104
106
|
},
|
|
105
107
|
"tree": {
|
package/i18n/en.json
CHANGED
package/i18n/es.json
CHANGED
package/i18n/fr.json
CHANGED
package/i18n/he.json
CHANGED
package/i18n/hi.json
CHANGED
package/i18n/id.json
CHANGED
package/i18n/it.json
CHANGED
package/i18n/ja.json
CHANGED
package/i18n/ko.json
CHANGED
package/i18n/nl.json
CHANGED
package/i18n/pl.json
CHANGED
package/i18n/pt.json
CHANGED
package/i18n/ru.json
CHANGED
package/i18n/sv.json
CHANGED
package/i18n/tr.json
CHANGED
package/i18n/uk.json
CHANGED
package/i18n/vi.json
CHANGED
package/i18n/zh-TW.json
CHANGED
package/i18n/zh.json
CHANGED
package/llms-full.txt
CHANGED
|
@@ -788,7 +788,7 @@
|
|
|
788
788
|
- selector: `[wrHotkey]`
|
|
789
789
|
- exports: WrHotkey, WrHotkeyBinding, parseHotkeySpec, matchesHotkey, WrParsedHotkey, WrHotkeyHandle, WrHotkeyOptions, WrHotkeySpec
|
|
790
790
|
- keywords: service, keyboard
|
|
791
|
-
- Register keyboard shortcuts like `mod+k`, where `mod` is ⌘ on macOS and Ctrl elsewhere.
|
|
791
|
+
- Register keyboard shortcuts like `mod+k`, where `mod` is ⌘ on macOS and Ctrl elsewhere. A letter shortcut also fires on a non-Latin layout.
|
|
792
792
|
|
|
793
793
|
## ngwr/i18n
|
|
794
794
|
- import: `import { WrI18n } from 'ngwr/i18n'`
|
|
@@ -1136,8 +1136,8 @@
|
|
|
1136
1136
|
|
|
1137
1137
|
## ngwr/select
|
|
1138
1138
|
- import: `import { WrSelect } from 'ngwr/select'`
|
|
1139
|
-
- selector: `wr-option-group`, `ng-template[wrOptionLeading]`, `wr-option`, `wr-select`
|
|
1140
|
-
- exports: WrSelect, WrOption, WrOptionGroup, WrOptionLeading, WR_SELECT, WrOptionLeadingContext, WrOptionLeadingPlacement, WrSelectMode, WrSelectSearchLoader, WrSelectTagValidator, WrSelectSize, WrSelectContext
|
|
1139
|
+
- selector: `ng-template[wrSelectLoadError]`, `wr-option-group`, `ng-template[wrOptionLeading]`, `wr-option`, `wr-select`
|
|
1140
|
+
- exports: WrSelect, WrOption, WrOptionGroup, WrOptionLeading, WrSelectLoadError, WR_SELECT, WrOptionLeadingContext, WrOptionLeadingPlacement, WrSelectMode, WrSelectSearchLoader, WrSelectTagValidator, WrSelectSize, WrSelectContext, WrSelectLoadErrorContext
|
|
1141
1141
|
- keywords: overlay
|
|
1142
1142
|
- Pick one or several values from a list, with search and free-text tags.
|
|
1143
1143
|
|
package/package.json
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
@use '../../theme/styles' as theme;
|
|
2
2
|
|
|
3
|
+
// Styles for the entry points this component's own markup renders: the retry on
|
|
4
|
+
// a failed load wears `.wr-btn`, and its loader is a `wr-spinner`.
|
|
5
|
+
@use '../../button/styles' as button-styles;
|
|
6
|
+
@use '../../spinner/styles' as spinner-styles; // WrSpinner
|
|
7
|
+
|
|
3
8
|
.wr-select {
|
|
4
9
|
--wr-select-color: var(--wr-color-on-surface);
|
|
5
10
|
--wr-select-bg: var(--wr-color-surface);
|
|
@@ -441,6 +446,8 @@
|
|
|
441
446
|
// Shared by the loading and the empty row — one padding for the panel's
|
|
442
447
|
// status text, whichever of the two is rendered.
|
|
443
448
|
--wr-select-panel-message-padding: var(--wr-space-md);
|
|
449
|
+
--wr-select-panel-retry-gap: var(--wr-space-sm);
|
|
450
|
+
--wr-select-panel-retry-active-bg: var(--wr-color-hover);
|
|
444
451
|
// Option sizing — default md. --sm/--lg are set from the trigger size because
|
|
445
452
|
// the panel is portaled into an overlay and can't inherit the host size class.
|
|
446
453
|
--wr-option-font-size: var(--wr-control-font-size-md);
|
|
@@ -494,12 +501,27 @@
|
|
|
494
501
|
}
|
|
495
502
|
|
|
496
503
|
&__loading,
|
|
497
|
-
&__empty
|
|
504
|
+
&__empty,
|
|
505
|
+
&__error {
|
|
498
506
|
padding: var(--wr-select-panel-message-padding);
|
|
499
507
|
color: var(--wr-color-on-surface-muted);
|
|
500
508
|
font-size: var(--wr-option-font-size);
|
|
501
509
|
text-align: center;
|
|
502
510
|
}
|
|
511
|
+
|
|
512
|
+
// A button on a line of its own, under the message.
|
|
513
|
+
&__retry {
|
|
514
|
+
display: flex;
|
|
515
|
+
width: fit-content;
|
|
516
|
+
margin-block-start: var(--wr-select-panel-retry-gap);
|
|
517
|
+
margin-inline: auto;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
// Focus stays in the field, so the button the field names as active takes the
|
|
521
|
+
// tint an active option takes, rather than a ring that would never go away.
|
|
522
|
+
&__error--active &__retry {
|
|
523
|
+
--wr-btn-bg: var(--wr-select-panel-retry-active-bg);
|
|
524
|
+
}
|
|
503
525
|
}
|
|
504
526
|
|
|
505
527
|
.wr-option {
|
|
@@ -209,7 +209,7 @@ root barrel for components: the root `ngwr` exports only `provideWr()`.
|
|
|
209
209
|
| `ngwr/scroll` | `import { WrScroll } from 'ngwr/scroll'` | — |
|
|
210
210
|
| `ngwr/segmented` | `import { WrSegmented } from 'ngwr/segmented'` | `wr-segmented` |
|
|
211
211
|
| `ngwr/segmented/testing` | `import { WrSegmentedHarness } from 'ngwr/segmented/testing'` | — |
|
|
212
|
-
| `ngwr/select` | `import { WrSelect } from 'ngwr/select'` | `wr-option-group` `ng-template[wrOptionLeading]` `wr-option` `wr-select` |
|
|
212
|
+
| `ngwr/select` | `import { WrSelect } from 'ngwr/select'` | `ng-template[wrSelectLoadError]` `wr-option-group` `ng-template[wrOptionLeading]` `wr-option` `wr-select` |
|
|
213
213
|
| `ngwr/select/testing` | `import { WrOptionHarness } from 'ngwr/select/testing'` | — |
|
|
214
214
|
| `ngwr/sidebar` | `import { WrSidebar } from 'ngwr/sidebar'` | `wr-sidebar` |
|
|
215
215
|
| `ngwr/skeleton` | `import { WrSkeleton } from 'ngwr/skeleton'` | `wr-skeleton` |
|
package/types/ngwr-alert.d.ts
CHANGED
|
@@ -11,11 +11,13 @@ import * as i0 from "@angular/core";
|
|
|
11
11
|
type WrAlertType = 'info' | 'success' | 'warning' | 'danger' | 'neutral' | 'offline';
|
|
12
12
|
/**
|
|
13
13
|
* Inline status banner. Use for feedback messages — saved/failed/notice etc.
|
|
14
|
+
* Content placed inside renders below the message, in `.wr-alert__content`.
|
|
14
15
|
*
|
|
15
16
|
* @example
|
|
16
17
|
* ```html
|
|
17
18
|
* <wr-alert title="Saved" message="Your changes are live." type="success" />
|
|
18
19
|
* <wr-alert title="Failed" type="danger" closable (closed)="onClose()" />
|
|
20
|
+
* <wr-alert title="Sync failed" type="danger">Request <code>8f2c41</code> timed out.</wr-alert>
|
|
19
21
|
* ```
|
|
20
22
|
*
|
|
21
23
|
* @see https://ngwr.dev/reference/components/alert
|
|
@@ -123,6 +125,6 @@ export declare class WrAlert {
|
|
|
123
125
|
};
|
|
124
126
|
}, {
|
|
125
127
|
"closed": "closed";
|
|
126
|
-
}, never,
|
|
128
|
+
}, never, ["*"], true, never>;
|
|
127
129
|
}
|
|
128
130
|
export type { WrAlertType };
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
+
import { Params } from "@angular/router";
|
|
2
3
|
/**
|
|
3
4
|
* Breadcrumb navigation. Project `<wr-breadcrumbs-item>` children — each keeps
|
|
4
5
|
* its own element and takes `role="listitem"` inside the `<ol>` rather than
|
|
@@ -55,6 +56,7 @@ export declare class WrBreadcrumbs {
|
|
|
55
56
|
* @example
|
|
56
57
|
* ```html
|
|
57
58
|
* <wr-breadcrumbs-item icon="home" routerLink="/">Home</wr-breadcrumbs-item>
|
|
59
|
+
* <wr-breadcrumbs-item routerLink="/debts" [queryParams]="{ date: day }">Debts</wr-breadcrumbs-item>
|
|
58
60
|
* <wr-breadcrumbs-item href="https://ngwr.dev">External</wr-breadcrumbs-item>
|
|
59
61
|
* <wr-breadcrumbs-item>Current page</wr-breadcrumbs-item>
|
|
60
62
|
* ```
|
|
@@ -64,6 +66,14 @@ export declare class WrBreadcrumbsItem {
|
|
|
64
66
|
readonly href: import("@angular/core").InputSignal<string | null>;
|
|
65
67
|
/** Angular router target. Anything `RouterLink` accepts (string or `any[]`). */
|
|
66
68
|
readonly routerLink: import("@angular/core").InputSignal<string | readonly unknown[] | null>;
|
|
69
|
+
/**
|
|
70
|
+
* Query parameters for a `routerLink` crumb, the way `RouterLink` takes them.
|
|
71
|
+
* A `?` written into `routerLink` is part of the path, and the router escapes
|
|
72
|
+
* it: `/debts?date=1` became `/debts%3Fdate%3D1`. Ignored without `routerLink`.
|
|
73
|
+
*
|
|
74
|
+
* @default null
|
|
75
|
+
*/
|
|
76
|
+
readonly queryParams: import("@angular/core").InputSignal<Params | null>;
|
|
67
77
|
/** Open external `href` in a new tab. Ignored when `routerLink` is set. @default false */
|
|
68
78
|
readonly external: import("@angular/core").InputSignal<boolean>;
|
|
69
79
|
/** Optional leading icon rendered inline before the label. @default null */
|
|
@@ -83,6 +93,11 @@ export declare class WrBreadcrumbsItem {
|
|
|
83
93
|
"required": false;
|
|
84
94
|
"isSignal": true;
|
|
85
95
|
};
|
|
96
|
+
"queryParams": {
|
|
97
|
+
"alias": "queryParams";
|
|
98
|
+
"required": false;
|
|
99
|
+
"isSignal": true;
|
|
100
|
+
};
|
|
86
101
|
"external": {
|
|
87
102
|
"alias": "external";
|
|
88
103
|
"required": false;
|
package/types/ngwr-hotkey.d.ts
CHANGED
|
@@ -43,7 +43,8 @@ interface WrHotkeyOptions {
|
|
|
43
43
|
/**
|
|
44
44
|
* Global keybinding registry.
|
|
45
45
|
*
|
|
46
|
-
* Bindings are keyed off `KeyboardEvent.key` + modifier state
|
|
46
|
+
* Bindings are keyed off `KeyboardEvent.key` + modifier state, and a letter
|
|
47
|
+
* shortcut also fires on a non-Latin layout, by the physical key. Multiple
|
|
47
48
|
* handlers per chord fire in priority order; a handler that calls
|
|
48
49
|
* `event.preventDefault()` stops lower-priority bindings on that key.
|
|
49
50
|
*
|
|
@@ -153,6 +154,17 @@ interface WrParsedHotkey {
|
|
|
153
154
|
* @param isMac - when true, `mod` resolves to `meta` (Cmd); otherwise `ctrl`
|
|
154
155
|
*/
|
|
155
156
|
declare function parseHotkeySpec(spec: WrHotkeySpec, isMac?: boolean): WrParsedHotkey;
|
|
156
|
-
/**
|
|
157
|
+
/**
|
|
158
|
+
* Does `event` satisfy the parsed hotkey?
|
|
159
|
+
*
|
|
160
|
+
* The typed character decides, and the physical key only stands in when that
|
|
161
|
+
* character is a letter of a non-Latin script. On a Russian layout the key
|
|
162
|
+
* labelled K types `л`, so `mod+k` used to be dead for anyone who had not
|
|
163
|
+
* switched to English; the same goes for Greek, Hebrew or Arabic. A Latin
|
|
164
|
+
* layout never falls back, not even on a letter outside ASCII: on Dvorak the key
|
|
165
|
+
* labelled K types `t`, and Turkish `ı` or German `ß` are keys of their own.
|
|
166
|
+
* Nor does a chord holding Alt, since macOS Option and Windows AltGr type a
|
|
167
|
+
* symbol on purpose, `€` on AltGr+E among them.
|
|
168
|
+
*/
|
|
157
169
|
declare function matchesHotkey(event: KeyboardEvent, parsed: WrParsedHotkey): boolean;
|
|
158
170
|
export { type WrHotkeyHandle, type WrHotkeyOptions, type WrHotkeySpec, type WrParsedHotkey, matchesHotkey, parseHotkeySpec };
|