@bitforgehq/ui 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/CHANGELOG.md +482 -0
  2. package/README.md +17 -11
  3. package/ai/MANIFEST.index.json +288 -0
  4. package/ai/MANIFEST.json +8716 -3926
  5. package/ai/REFERENCE.index.json +413 -0
  6. package/ai/REFERENCE.json +4710 -2047
  7. package/ai/UI_GUIDE.md +185 -57
  8. package/ai/components/back-button.md +42 -2
  9. package/ai/components/badge.md +17 -7
  10. package/ai/components/bar-chart.md +188 -0
  11. package/ai/components/breadcrumb-item.md +121 -0
  12. package/ai/components/breadcrumb.md +277 -0
  13. package/ai/components/button.md +82 -15
  14. package/ai/components/calendar.md +300 -0
  15. package/ai/components/card.md +63 -2
  16. package/ai/components/chart-card.md +283 -0
  17. package/ai/components/combobox.md +411 -0
  18. package/ai/components/date-input.md +396 -0
  19. package/ai/components/datetime-input.md +215 -0
  20. package/ai/components/description-item.md +111 -0
  21. package/ai/components/description-list.md +160 -0
  22. package/ai/components/donut-chart.md +169 -0
  23. package/ai/components/header.md +67 -2
  24. package/ai/components/icon-button.md +74 -16
  25. package/ai/components/icon.md +63 -7
  26. package/ai/components/line-chart.md +234 -0
  27. package/ai/components/list.md +70 -6
  28. package/ai/components/menu.md +5 -0
  29. package/ai/components/multi-combobox.md +257 -0
  30. package/ai/components/nav-group.md +178 -0
  31. package/ai/components/nav-item.md +210 -0
  32. package/ai/components/page-header.md +237 -0
  33. package/ai/components/pagination.md +173 -0
  34. package/ai/components/popover.md +250 -0
  35. package/ai/components/side-panel.md +391 -0
  36. package/ai/components/sidebar.md +363 -0
  37. package/ai/components/skeleton.md +215 -0
  38. package/ai/components/sparkline.md +188 -0
  39. package/ai/components/stat.md +233 -0
  40. package/ai/components/tab-group.md +226 -0
  41. package/ai/components/tab-panel.md +163 -0
  42. package/ai/components/table.md +568 -0
  43. package/ai/components/tabs.md +42 -2
  44. package/ai/components/theme-menu-button.md +182 -0
  45. package/ai/components/theme-switch.md +170 -0
  46. package/ai/components/time-input.md +240 -0
  47. package/ai/components/toolbar.md +289 -0
  48. package/ai/components/tooltip.md +230 -0
  49. package/ai/components/top-nav.md +159 -0
  50. package/ai/reference/bf-badge-appearance.md +36 -0
  51. package/ai/reference/bf-badge-variant.md +1 -1
  52. package/ai/reference/bf-bar-chart-orientation.md +27 -0
  53. package/ai/reference/bf-button-appearance.md +36 -0
  54. package/ai/reference/bf-button-variant.md +1 -1
  55. package/ai/reference/bf-calendar-disabled-date.md +23 -0
  56. package/ai/reference/bf-calendar-harness.md +51 -0
  57. package/ai/reference/bf-calendar-weekday.md +31 -0
  58. package/ai/reference/bf-chart-card-heading-level.md +26 -0
  59. package/ai/reference/bf-chart-curve.md +28 -0
  60. package/ai/reference/bf-chart-harness.md +51 -0
  61. package/ai/reference/bf-chart-legend-position.md +30 -0
  62. package/ai/reference/bf-chart-series.md +23 -0
  63. package/ai/reference/bf-chart-value-format.md +23 -0
  64. package/ai/reference/bf-color-scheme-service.md +30 -0
  65. package/ai/reference/bf-color-scheme.md +31 -0
  66. package/ai/reference/bf-combobox-filter.md +27 -0
  67. package/ai/reference/bf-combobox-harness.md +89 -0
  68. package/ai/reference/bf-combobox-option.md +33 -0
  69. package/ai/reference/bf-compare-with.md +2 -0
  70. package/ai/reference/bf-date-input-harness.md +67 -0
  71. package/ai/reference/bf-date-input-picker.md +27 -0
  72. package/ai/reference/bf-date-time-input-harness.md +76 -0
  73. package/ai/reference/bf-date-time-input-picker.md +27 -0
  74. package/ai/reference/bf-description-list-layout.md +26 -0
  75. package/ai/reference/bf-donut-slice.md +22 -0
  76. package/ai/reference/bf-labels.md +67 -20
  77. package/ai/reference/bf-menu-button-variant.md +1 -0
  78. package/ai/reference/bf-menu-placement.md +1 -0
  79. package/ai/reference/bf-overlay-options.md +28 -27
  80. package/ai/reference/bf-overlay-placement.md +34 -0
  81. package/ai/reference/bf-overlay-position.md +1 -1
  82. package/ai/reference/bf-overlay-service.md +5 -3
  83. package/ai/reference/bf-page-header-heading-level.md +26 -0
  84. package/ai/reference/bf-pagination-harness.md +61 -0
  85. package/ai/reference/bf-platform-service.md +17 -15
  86. package/ai/reference/bf-popover-harness.md +42 -0
  87. package/ai/reference/bf-popover-placement.md +28 -0
  88. package/ai/reference/bf-popover-trigger-directive.md +56 -0
  89. package/ai/reference/bf-side-panel-config.md +35 -0
  90. package/ai/reference/bf-side-panel-harness.md +34 -0
  91. package/ai/reference/bf-side-panel-ref.md +44 -0
  92. package/ai/reference/bf-side-panel-service.md +43 -0
  93. package/ai/reference/bf-side-panel-template-context.md +32 -0
  94. package/ai/reference/bf-side-panel-width.md +28 -0
  95. package/ai/reference/bf-size.md +12 -0
  96. package/ai/reference/bf-skeleton-shape.md +28 -0
  97. package/ai/reference/bf-stat-trend-intent.md +27 -0
  98. package/ai/reference/bf-stat-trend.md +27 -0
  99. package/ai/reference/bf-stat-variant.md +26 -0
  100. package/ai/reference/bf-tab-group-harness.md +44 -0
  101. package/ai/reference/bf-table-align.md +26 -0
  102. package/ai/reference/bf-table-cell-context.md +24 -0
  103. package/ai/reference/bf-table-cell-directive.md +22 -0
  104. package/ai/reference/bf-table-column.md +28 -0
  105. package/ai/reference/bf-table-harness.md +77 -0
  106. package/ai/reference/bf-table-row-key.md +21 -0
  107. package/ai/reference/bf-table-sort-direction.md +26 -0
  108. package/ai/reference/bf-table-sort.md +27 -0
  109. package/ai/reference/bf-theme.md +5 -4
  110. package/ai/reference/bf-time-input-harness.md +67 -0
  111. package/ai/reference/bf-time-input-hour-cycle.md +27 -0
  112. package/ai/reference/bf-time-input-picker.md +27 -0
  113. package/ai/reference/bf-tooltip-directive.md +43 -0
  114. package/ai/reference/bf-tooltip-harness.md +43 -0
  115. package/ai/reference/bf-tooltip-placement.md +28 -0
  116. package/ai/reference/bf_color_scheme_storage.md +20 -0
  117. package/ai/reference/bf_side_panel_data.md +17 -0
  118. package/ai/reference/bf_theme_storage.md +3 -1
  119. package/ai/reference/provide-bf-color-scheme.md +20 -0
  120. package/ai/reference/provide-bf-labels.md +12 -4
  121. package/ai/reference/slide-in-from-end.md +24 -0
  122. package/ai/reference/slide-out-to-end.md +24 -0
  123. package/fesm2022/bitforgehq-ui-charts.mjs +3045 -0
  124. package/fesm2022/bitforgehq-ui-charts.mjs.map +1 -0
  125. package/fesm2022/bitforgehq-ui-icons.mjs +107 -3
  126. package/fesm2022/bitforgehq-ui-icons.mjs.map +1 -1
  127. package/fesm2022/bitforgehq-ui-mobile.mjs +14 -59
  128. package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -1
  129. package/fesm2022/bitforgehq-ui-overlay.mjs +6436 -33
  130. package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
  131. package/fesm2022/bitforgehq-ui-testing.mjs +618 -1
  132. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
  133. package/fesm2022/bitforgehq-ui.mjs +5092 -153
  134. package/fesm2022/bitforgehq-ui.mjs.map +1 -1
  135. package/llms-full.txt +25177 -14398
  136. package/llms.txt +95 -1
  137. package/package.json +7 -3
  138. package/theme.css +101 -0
  139. package/types/bitforgehq-ui-charts.d.ts +967 -0
  140. package/types/bitforgehq-ui-icons.d.ts +13 -1
  141. package/types/bitforgehq-ui-mobile.d.ts +25 -18
  142. package/types/bitforgehq-ui-overlay.d.ts +1844 -7
  143. package/types/bitforgehq-ui-testing.d.ts +748 -1
  144. package/types/bitforgehq-ui.d.ts +2136 -44
@@ -0,0 +1,3045 @@
1
+ import * as i0 from "@angular/core";
2
+ import { Component, DOCUMENT, DestroyRef, ElementRef, InjectionToken, afterNextRender, booleanAttribute, computed, inject, input, numberAttribute, output, signal, viewChild } from "@angular/core";
3
+ import { BF_LABELS, BfSkeletonComponent, ɵuniqueId } from "@bitforgehq/ui";
4
+ import { NgTemplateOutlet } from "@angular/common";
5
+ const CHAR_PX = 7;
6
+ function textWidth(text) {
7
+ return text.length * CHAR_PX;
8
+ }
9
+ function labelEvery(labels, room, slot) {
10
+ const widest = Math.max(0, ...labels.map(textWidth)) + 12;
11
+ if (labels.length === 0 || room <= 0 || slot <= 0) return 1;
12
+ return Math.max(1, Math.ceil(widest / slot));
13
+ }
14
+ function finiteValues(series, indexes) {
15
+ return indexes.flatMap((i) => (series[i]?.values ?? []).filter((v) => v !== null && Number.isFinite(v)));
16
+ }
17
+ function mirror(x, width, rtl) {
18
+ return rtl ? width - x : x;
19
+ }
20
+ function clamp(value, lo, hi) {
21
+ return Math.min(hi, Math.max(lo, value));
22
+ }
23
+ const BF_CHART_CARD = new InjectionToken("BF_CHART_CARD");
24
+ function documentLocale(document) {
25
+ const lang = document.documentElement.lang;
26
+ if (!lang) return;
27
+ try {
28
+ return Intl.NumberFormat.supportedLocalesOf(lang).length > 0 ? lang : void 0;
29
+ } catch {
30
+ return;
31
+ }
32
+ }
33
+ function defaultValueFormat(document) {
34
+ const format = new Intl.NumberFormat(documentLocale(document));
35
+ return (value) => format.format(value);
36
+ }
37
+ function percentFormat(document) {
38
+ const format = new Intl.NumberFormat(documentLocale(document), {
39
+ style: "percent",
40
+ maximumFractionDigits: 0
41
+ });
42
+ return (share) => format.format(share);
43
+ }
44
+ function formatOrDash(value, format) {
45
+ return value === null || value === void 0 || !Number.isFinite(value) ? "–" : format(value);
46
+ }
47
+ const SWATCH_BASE = "size-2.5 shrink-0 rounded-full forced-colors:border forced-colors:border-[CanvasText]";
48
+ const SWATCH_HIDDEN = `${SWATCH_BASE} border-[1.5px] border-text-subtle bg-transparent`;
49
+ function chartSwatchClasses(swatch, hidden) {
50
+ return hidden ? SWATCH_HIDDEN : `${SWATCH_BASE} ${swatch}`;
51
+ }
52
+ const HOST$1 = "pointer-events-none absolute z-10 flex w-max min-w-32 max-w-60 flex-col gap-1 rounded-tile border border-border bg-surface px-3 py-2 text-caption text-text shadow-floating";
53
+ var BfChartTooltipComponent = class BfChartTooltipComponent {
54
+ tip = input.required(...ngDevMode ? [{ debugName: "tip" }] : /* istanbul ignore next */ []);
55
+ plotWidth = input(0, ...ngDevMode ? [{ debugName: "plotWidth" }] : /* istanbul ignore next */ []);
56
+ hostClasses = HOST$1;
57
+ shift = computed(() => {
58
+ const width = this.plotWidth();
59
+ return `translate(${width > 0 && this.tip().x > width / 2 ? "calc(-100% - 12px)" : "12px"}, -50%)`;
60
+ }, ...ngDevMode ? [{ debugName: "shift" }] : /* istanbul ignore next */ []);
61
+ swatch(swatch) {
62
+ return chartSwatchClasses(swatch, false);
63
+ }
64
+ static ɵfac = i0.ɵɵngDeclareFactory({
65
+ minVersion: "12.0.0",
66
+ version: "22.1.7",
67
+ ngImport: i0,
68
+ type: BfChartTooltipComponent,
69
+ deps: [],
70
+ target: i0.ɵɵFactoryTarget.Component
71
+ });
72
+ static ɵcmp = i0.ɵɵngDeclareComponent({
73
+ minVersion: "17.0.0",
74
+ version: "22.1.7",
75
+ type: BfChartTooltipComponent,
76
+ isStandalone: true,
77
+ selector: "bf-chart-tooltip",
78
+ inputs: {
79
+ tip: {
80
+ classPropertyName: "tip",
81
+ publicName: "tip",
82
+ isSignal: true,
83
+ isRequired: true,
84
+ transformFunction: null
85
+ },
86
+ plotWidth: {
87
+ classPropertyName: "plotWidth",
88
+ publicName: "plotWidth",
89
+ isSignal: true,
90
+ isRequired: false,
91
+ transformFunction: null
92
+ }
93
+ },
94
+ host: {
95
+ attributes: { "aria-hidden": "true" },
96
+ properties: {
97
+ "class": "hostClasses",
98
+ "style.left.px": "tip().x",
99
+ "style.top.px": "tip().y",
100
+ "style.transform": "shift()"
101
+ }
102
+ },
103
+ ngImport: i0,
104
+ template: `
105
+ @if (tip().title) {
106
+ <span class="font-bold">{{ tip().title }}</span>
107
+ }
108
+ @for (row of tip().rows; track $index) {
109
+ <span class="flex items-center gap-2">
110
+ <span [class]="swatch(row.swatch)"></span>
111
+ <span class="text-text-secondary min-w-0 flex-1 truncate">{{ row.name }}</span>
112
+ <span class="font-bold tabular-nums">{{ row.value }}</span>
113
+ </span>
114
+ }
115
+ `,
116
+ isInline: true
117
+ });
118
+ };
119
+ i0.ɵɵngDeclareClassMetadata({
120
+ minVersion: "12.0.0",
121
+ version: "22.1.7",
122
+ ngImport: i0,
123
+ type: BfChartTooltipComponent,
124
+ decorators: [{
125
+ type: Component,
126
+ args: [{
127
+ selector: "bf-chart-tooltip",
128
+ host: {
129
+ "aria-hidden": "true",
130
+ "[class]": "hostClasses",
131
+ "[style.left.px]": "tip().x",
132
+ "[style.top.px]": "tip().y",
133
+ "[style.transform]": "shift()"
134
+ },
135
+ template: `
136
+ @if (tip().title) {
137
+ <span class="font-bold">{{ tip().title }}</span>
138
+ }
139
+ @for (row of tip().rows; track $index) {
140
+ <span class="flex items-center gap-2">
141
+ <span [class]="swatch(row.swatch)"></span>
142
+ <span class="text-text-secondary min-w-0 flex-1 truncate">{{ row.name }}</span>
143
+ <span class="font-bold tabular-nums">{{ row.value }}</span>
144
+ </span>
145
+ }
146
+ `
147
+ }]
148
+ }],
149
+ propDecorators: {
150
+ tip: [{
151
+ type: i0.Input,
152
+ args: [{
153
+ isSignal: true,
154
+ alias: "tip",
155
+ required: true
156
+ }]
157
+ }],
158
+ plotWidth: [{
159
+ type: i0.Input,
160
+ args: [{
161
+ isSignal: true,
162
+ alias: "plotWidth",
163
+ required: false
164
+ }]
165
+ }]
166
+ }
167
+ });
168
+ const LEGEND = "flex flex-wrap items-center gap-x-1 gap-y-1";
169
+ const LEGEND_BUTTON = "inline-flex min-h-6 cursor-pointer items-center gap-2 rounded-control px-2 text-caption text-text-secondary transition-colors duration-150 select-none hover:bg-surface-muted active:bg-surface-pressed focus-visible:outline-hidden focus-visible:ring-4 focus-visible:ring-ring aria-[pressed=false]:text-text-muted aria-[pressed=false]:line-through pointer-coarse:min-h-hit";
170
+ const PLOT = "relative block h-(--bf-chart-height) rounded-tile touch-pan-y focus-visible:outline-hidden focus-visible:ring-4 focus-visible:ring-ring";
171
+ const DATA_BUTTON = "inline-flex min-h-6 cursor-pointer items-center rounded-control px-2 text-label-xs font-bold text-primary-text transition-colors duration-150 hover:bg-primary-soft hover:text-primary-strong active:bg-primary-soft-pressed focus-visible:outline-hidden focus-visible:ring-4 focus-visible:ring-ring pointer-coarse:min-h-hit";
172
+ const TABLE = "w-full border-collapse text-start";
173
+ const TH_HEAD = "h-8 border-b border-border px-3 text-start align-middle text-label-xs font-bold text-text-muted";
174
+ const TH_ROW = "h-10 border-b border-divider px-3 text-start align-middle text-label-sm font-bold text-text";
175
+ const TD = "h-10 border-b border-divider px-3 text-end align-middle text-label-sm font-medium text-text tabular-nums";
176
+ const TH_VALUE = `${TH_HEAD} text-end`;
177
+ var BfChartFrameComponent = class BfChartFrameComponent {
178
+ label = input.required(...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
179
+ height = input.required({
180
+ ...ngDevMode ? { debugName: "height" } : /* istanbul ignore next */ {},
181
+ transform: numberAttribute
182
+ });
183
+ legend = input([], ...ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []);
184
+ legendPosition = input("bottom", ...ngDevMode ? [{ debugName: "legendPosition" }] : /* istanbul ignore next */ []);
185
+ tooltip = input(null, ...ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []);
186
+ announcement = input("", ...ngDevMode ? [{ debugName: "announcement" }] : /* istanbul ignore next */ []);
187
+ table = input({
188
+ head: [],
189
+ rows: []
190
+ }, ...ngDevMode ? [{ debugName: "table" }] : /* istanbul ignore next */ []);
191
+ dataToggle = input(true, {
192
+ ...ngDevMode ? { debugName: "dataToggle" } : /* istanbul ignore next */ {},
193
+ transform: booleanAttribute
194
+ });
195
+ vertical = input(false, {
196
+ ...ngDevMode ? { debugName: "vertical" } : /* istanbul ignore next */ {},
197
+ transform: booleanAttribute
198
+ });
199
+ legendToggled = output();
200
+ pointed = output();
201
+ left = output();
202
+ stepped = output();
203
+ focusChanged = output();
204
+ labels = inject(BF_LABELS);
205
+ tableId = ɵuniqueId("bf-chart-data");
206
+ showData = signal(false, ...ngDevMode ? [{ debugName: "showData" }] : /* istanbul ignore next */ []);
207
+ plot = viewChild.required("plot", ...ngDevMode ? [{ debugName: "plot" }] : /* istanbul ignore next */ []);
208
+ plotElement = computed(() => this.plot().nativeElement, ...ngDevMode ? [{ debugName: "plotElement" }] : /* istanbul ignore next */ []);
209
+ plotWidth() {
210
+ return this.plot().nativeElement.clientWidth;
211
+ }
212
+ plotClasses = PLOT;
213
+ legendClasses = LEGEND;
214
+ legendButtonClasses = LEGEND_BUTTON;
215
+ dataButtonClasses = DATA_BUTTON;
216
+ tableClasses = TABLE;
217
+ thHeadClasses = TH_HEAD;
218
+ thValueClasses = TH_VALUE;
219
+ thRowClasses = TH_ROW;
220
+ tdClasses = TD;
221
+ swatchClasses(swatch, hidden) {
222
+ return chartSwatchClasses(swatch, hidden);
223
+ }
224
+ onKeydown(event) {
225
+ const rtl = this.plot().nativeElement.closest("[dir]")?.getAttribute("dir") === "rtl";
226
+ const forward = rtl ? "ArrowLeft" : "ArrowRight";
227
+ const back = rtl ? "ArrowRight" : "ArrowLeft";
228
+ let step = null;
229
+ if (event.key === forward || this.vertical() && event.key === "ArrowDown") step = "next";
230
+ else if (event.key === back || this.vertical() && event.key === "ArrowUp") step = "previous";
231
+ else if (event.key === "Home") step = "first";
232
+ else if (event.key === "End") step = "last";
233
+ else if (event.key === "Escape") step = "clear";
234
+ if (step) {
235
+ event.preventDefault();
236
+ this.stepped.emit(step);
237
+ }
238
+ }
239
+ onPointer(event) {
240
+ const box = this.plot().nativeElement.getBoundingClientRect();
241
+ this.pointed.emit({
242
+ x: event.clientX - box.left,
243
+ y: event.clientY - box.top
244
+ });
245
+ }
246
+ static ɵfac = i0.ɵɵngDeclareFactory({
247
+ minVersion: "12.0.0",
248
+ version: "22.1.7",
249
+ ngImport: i0,
250
+ type: BfChartFrameComponent,
251
+ deps: [],
252
+ target: i0.ɵɵFactoryTarget.Component
253
+ });
254
+ static ɵcmp = i0.ɵɵngDeclareComponent({
255
+ minVersion: "17.0.0",
256
+ version: "22.1.7",
257
+ type: BfChartFrameComponent,
258
+ isStandalone: true,
259
+ selector: "bf-chart-frame",
260
+ inputs: {
261
+ label: {
262
+ classPropertyName: "label",
263
+ publicName: "label",
264
+ isSignal: true,
265
+ isRequired: true,
266
+ transformFunction: null
267
+ },
268
+ height: {
269
+ classPropertyName: "height",
270
+ publicName: "height",
271
+ isSignal: true,
272
+ isRequired: true,
273
+ transformFunction: null
274
+ },
275
+ legend: {
276
+ classPropertyName: "legend",
277
+ publicName: "legend",
278
+ isSignal: true,
279
+ isRequired: false,
280
+ transformFunction: null
281
+ },
282
+ legendPosition: {
283
+ classPropertyName: "legendPosition",
284
+ publicName: "legendPosition",
285
+ isSignal: true,
286
+ isRequired: false,
287
+ transformFunction: null
288
+ },
289
+ tooltip: {
290
+ classPropertyName: "tooltip",
291
+ publicName: "tooltip",
292
+ isSignal: true,
293
+ isRequired: false,
294
+ transformFunction: null
295
+ },
296
+ announcement: {
297
+ classPropertyName: "announcement",
298
+ publicName: "announcement",
299
+ isSignal: true,
300
+ isRequired: false,
301
+ transformFunction: null
302
+ },
303
+ table: {
304
+ classPropertyName: "table",
305
+ publicName: "table",
306
+ isSignal: true,
307
+ isRequired: false,
308
+ transformFunction: null
309
+ },
310
+ dataToggle: {
311
+ classPropertyName: "dataToggle",
312
+ publicName: "dataToggle",
313
+ isSignal: true,
314
+ isRequired: false,
315
+ transformFunction: null
316
+ },
317
+ vertical: {
318
+ classPropertyName: "vertical",
319
+ publicName: "vertical",
320
+ isSignal: true,
321
+ isRequired: false,
322
+ transformFunction: null
323
+ }
324
+ },
325
+ outputs: {
326
+ legendToggled: "legendToggled",
327
+ pointed: "pointed",
328
+ left: "left",
329
+ stepped: "stepped",
330
+ focusChanged: "focusChanged"
331
+ },
332
+ host: {
333
+ properties: { "style.--bf-chart-height.px": "height()" },
334
+ classAttribute: "block"
335
+ },
336
+ viewQueries: [{
337
+ propertyName: "plot",
338
+ first: true,
339
+ predicate: ["plot"],
340
+ descendants: true,
341
+ isSignal: true
342
+ }],
343
+ ngImport: i0,
344
+ template: `
345
+ <figure class="m-0 flex flex-col gap-2" [attr.aria-label]="label()">
346
+ @if (legendPosition() === 'top') {
347
+ <ng-container *ngTemplateOutlet="legendTpl" />
348
+ }
349
+ <div
350
+ #plot
351
+ data-bf-chart-plot
352
+ role="group"
353
+ tabindex="0"
354
+ [attr.aria-label]="labels.chartValues"
355
+ [class]="plotClasses"
356
+ (keydown)="onKeydown($event)"
357
+ (pointermove)="onPointer($event)"
358
+ (pointerdown)="onPointer($event)"
359
+ (pointerleave)="left.emit()"
360
+ (focus)="focusChanged.emit(true)"
361
+ (blur)="focusChanged.emit(false)"
362
+ >
363
+ <ng-content />
364
+ @if (tooltip(); as tip) {
365
+ <bf-chart-tooltip data-bf-chart-tooltip [tip]="tip" [plotWidth]="plotWidth()" />
366
+ }
367
+ </div>
368
+ @if (legendPosition() === 'bottom') {
369
+ <ng-container *ngTemplateOutlet="legendTpl" />
370
+ }
371
+ <div class="sr-only" aria-live="polite" data-bf-chart-live>{{ announcement() }}</div>
372
+ @if (dataToggle()) {
373
+ <div class="flex justify-end">
374
+ <button
375
+ type="button"
376
+ data-bf-chart-data-toggle
377
+ [class]="dataButtonClasses"
378
+ [attr.aria-expanded]="showData() ? 'true' : 'false'"
379
+ [attr.aria-controls]="tableId"
380
+ (click)="showData.set(!showData())"
381
+ >
382
+ {{ showData() ? labels.chartHideData : labels.chartShowData }}
383
+ </button>
384
+ </div>
385
+ }
386
+ <div [id]="tableId" [hidden]="!showData()" class="overflow-x-auto">
387
+ @if (showData()) {
388
+ <table data-bf-chart-table [class]="tableClasses">
389
+ <caption class="sr-only">
390
+ {{
391
+ label()
392
+ }}
393
+ </caption>
394
+ <thead>
395
+ <tr>
396
+ @for (cell of table().head; track $index; let first = $first) {
397
+ <th scope="col" [class]="first ? thHeadClasses : thValueClasses">{{ cell }}</th>
398
+ }
399
+ </tr>
400
+ </thead>
401
+ <tbody>
402
+ @for (row of table().rows; track $index) {
403
+ <tr>
404
+ @for (cell of row; track $index; let first = $first) {
405
+ @if (first) {
406
+ <th scope="row" [class]="thRowClasses">{{ cell }}</th>
407
+ } @else {
408
+ <td [class]="tdClasses">{{ cell }}</td>
409
+ }
410
+ }
411
+ </tr>
412
+ }
413
+ </tbody>
414
+ </table>
415
+ }
416
+ </div>
417
+ </figure>
418
+
419
+ <ng-template #legendTpl>
420
+ @if (legend().length > 0) {
421
+ <div
422
+ role="group"
423
+ data-bf-chart-legend
424
+ [attr.aria-label]="labels.chartLegend"
425
+ [class]="legendClasses"
426
+ >
427
+ @for (item of legend(); track $index; let i = $index) {
428
+ <button
429
+ type="button"
430
+ [class]="legendButtonClasses"
431
+ [attr.aria-pressed]="item.hidden ? 'false' : 'true'"
432
+ (click)="legendToggled.emit(i)"
433
+ >
434
+ <span [class]="swatchClasses(item.swatch, item.hidden)"></span>
435
+ {{ item.name }}
436
+ </button>
437
+ }
438
+ </div>
439
+ }
440
+ </ng-template>
441
+ `,
442
+ isInline: true,
443
+ dependencies: [{
444
+ kind: "directive",
445
+ type: NgTemplateOutlet,
446
+ selector: "[ngTemplateOutlet]",
447
+ inputs: [
448
+ "ngTemplateOutletContext",
449
+ "ngTemplateOutlet",
450
+ "ngTemplateOutletInjector"
451
+ ]
452
+ }, {
453
+ kind: "component",
454
+ type: BfChartTooltipComponent,
455
+ selector: "bf-chart-tooltip",
456
+ inputs: ["tip", "plotWidth"]
457
+ }]
458
+ });
459
+ };
460
+ i0.ɵɵngDeclareClassMetadata({
461
+ minVersion: "12.0.0",
462
+ version: "22.1.7",
463
+ ngImport: i0,
464
+ type: BfChartFrameComponent,
465
+ decorators: [{
466
+ type: Component,
467
+ args: [{
468
+ selector: "bf-chart-frame",
469
+ imports: [NgTemplateOutlet, BfChartTooltipComponent],
470
+ host: {
471
+ class: "block",
472
+ "[style.--bf-chart-height.px]": "height()"
473
+ },
474
+ template: `
475
+ <figure class="m-0 flex flex-col gap-2" [attr.aria-label]="label()">
476
+ @if (legendPosition() === 'top') {
477
+ <ng-container *ngTemplateOutlet="legendTpl" />
478
+ }
479
+ <div
480
+ #plot
481
+ data-bf-chart-plot
482
+ role="group"
483
+ tabindex="0"
484
+ [attr.aria-label]="labels.chartValues"
485
+ [class]="plotClasses"
486
+ (keydown)="onKeydown($event)"
487
+ (pointermove)="onPointer($event)"
488
+ (pointerdown)="onPointer($event)"
489
+ (pointerleave)="left.emit()"
490
+ (focus)="focusChanged.emit(true)"
491
+ (blur)="focusChanged.emit(false)"
492
+ >
493
+ <ng-content />
494
+ @if (tooltip(); as tip) {
495
+ <bf-chart-tooltip data-bf-chart-tooltip [tip]="tip" [plotWidth]="plotWidth()" />
496
+ }
497
+ </div>
498
+ @if (legendPosition() === 'bottom') {
499
+ <ng-container *ngTemplateOutlet="legendTpl" />
500
+ }
501
+ <div class="sr-only" aria-live="polite" data-bf-chart-live>{{ announcement() }}</div>
502
+ @if (dataToggle()) {
503
+ <div class="flex justify-end">
504
+ <button
505
+ type="button"
506
+ data-bf-chart-data-toggle
507
+ [class]="dataButtonClasses"
508
+ [attr.aria-expanded]="showData() ? 'true' : 'false'"
509
+ [attr.aria-controls]="tableId"
510
+ (click)="showData.set(!showData())"
511
+ >
512
+ {{ showData() ? labels.chartHideData : labels.chartShowData }}
513
+ </button>
514
+ </div>
515
+ }
516
+ <div [id]="tableId" [hidden]="!showData()" class="overflow-x-auto">
517
+ @if (showData()) {
518
+ <table data-bf-chart-table [class]="tableClasses">
519
+ <caption class="sr-only">
520
+ {{
521
+ label()
522
+ }}
523
+ </caption>
524
+ <thead>
525
+ <tr>
526
+ @for (cell of table().head; track $index; let first = $first) {
527
+ <th scope="col" [class]="first ? thHeadClasses : thValueClasses">{{ cell }}</th>
528
+ }
529
+ </tr>
530
+ </thead>
531
+ <tbody>
532
+ @for (row of table().rows; track $index) {
533
+ <tr>
534
+ @for (cell of row; track $index; let first = $first) {
535
+ @if (first) {
536
+ <th scope="row" [class]="thRowClasses">{{ cell }}</th>
537
+ } @else {
538
+ <td [class]="tdClasses">{{ cell }}</td>
539
+ }
540
+ }
541
+ </tr>
542
+ }
543
+ </tbody>
544
+ </table>
545
+ }
546
+ </div>
547
+ </figure>
548
+
549
+ <ng-template #legendTpl>
550
+ @if (legend().length > 0) {
551
+ <div
552
+ role="group"
553
+ data-bf-chart-legend
554
+ [attr.aria-label]="labels.chartLegend"
555
+ [class]="legendClasses"
556
+ >
557
+ @for (item of legend(); track $index; let i = $index) {
558
+ <button
559
+ type="button"
560
+ [class]="legendButtonClasses"
561
+ [attr.aria-pressed]="item.hidden ? 'false' : 'true'"
562
+ (click)="legendToggled.emit(i)"
563
+ >
564
+ <span [class]="swatchClasses(item.swatch, item.hidden)"></span>
565
+ {{ item.name }}
566
+ </button>
567
+ }
568
+ </div>
569
+ }
570
+ </ng-template>
571
+ `
572
+ }]
573
+ }],
574
+ propDecorators: {
575
+ label: [{
576
+ type: i0.Input,
577
+ args: [{
578
+ isSignal: true,
579
+ alias: "label",
580
+ required: true
581
+ }]
582
+ }],
583
+ height: [{
584
+ type: i0.Input,
585
+ args: [{
586
+ isSignal: true,
587
+ alias: "height",
588
+ required: true
589
+ }]
590
+ }],
591
+ legend: [{
592
+ type: i0.Input,
593
+ args: [{
594
+ isSignal: true,
595
+ alias: "legend",
596
+ required: false
597
+ }]
598
+ }],
599
+ legendPosition: [{
600
+ type: i0.Input,
601
+ args: [{
602
+ isSignal: true,
603
+ alias: "legendPosition",
604
+ required: false
605
+ }]
606
+ }],
607
+ tooltip: [{
608
+ type: i0.Input,
609
+ args: [{
610
+ isSignal: true,
611
+ alias: "tooltip",
612
+ required: false
613
+ }]
614
+ }],
615
+ announcement: [{
616
+ type: i0.Input,
617
+ args: [{
618
+ isSignal: true,
619
+ alias: "announcement",
620
+ required: false
621
+ }]
622
+ }],
623
+ table: [{
624
+ type: i0.Input,
625
+ args: [{
626
+ isSignal: true,
627
+ alias: "table",
628
+ required: false
629
+ }]
630
+ }],
631
+ dataToggle: [{
632
+ type: i0.Input,
633
+ args: [{
634
+ isSignal: true,
635
+ alias: "dataToggle",
636
+ required: false
637
+ }]
638
+ }],
639
+ vertical: [{
640
+ type: i0.Input,
641
+ args: [{
642
+ isSignal: true,
643
+ alias: "vertical",
644
+ required: false
645
+ }]
646
+ }],
647
+ legendToggled: [{
648
+ type: i0.Output,
649
+ args: ["legendToggled"]
650
+ }],
651
+ pointed: [{
652
+ type: i0.Output,
653
+ args: ["pointed"]
654
+ }],
655
+ left: [{
656
+ type: i0.Output,
657
+ args: ["left"]
658
+ }],
659
+ stepped: [{
660
+ type: i0.Output,
661
+ args: ["stepped"]
662
+ }],
663
+ focusChanged: [{
664
+ type: i0.Output,
665
+ args: ["focusChanged"]
666
+ }],
667
+ plot: [{
668
+ type: i0.ViewChild,
669
+ args: ["plot", { isSignal: true }]
670
+ }]
671
+ }
672
+ });
673
+ var ChartInteraction = class {
674
+ hiddenSet = signal(/* @__PURE__ */ new Set(), ...ngDevMode ? [{ debugName: "hiddenSet" }] : /* istanbul ignore next */ []);
675
+ activeIndex = signal(null, ...ngDevMode ? [{ debugName: "activeIndex" }] : /* istanbul ignore next */ []);
676
+ spoken = signal("", ...ngDevMode ? [{ debugName: "spoken" }] : /* istanbul ignore next */ []);
677
+ hidden = this.hiddenSet.asReadonly();
678
+ active = this.activeIndex.asReadonly();
679
+ announcement = this.spoken.asReadonly();
680
+ hasActive = computed(() => this.activeIndex() !== null, ...ngDevMode ? [{ debugName: "hasActive" }] : /* istanbul ignore next */ []);
681
+ isHidden(index) {
682
+ return this.hiddenSet().has(index);
683
+ }
684
+ toggle(index) {
685
+ const next = new Set(this.hiddenSet());
686
+ if (!next.delete(index)) next.add(index);
687
+ this.hiddenSet.set(next);
688
+ }
689
+ point(index) {
690
+ this.activeIndex.set(index);
691
+ }
692
+ step(step, targets, describe) {
693
+ if (step === "clear" || targets.length === 0) {
694
+ this.activeIndex.set(null);
695
+ return;
696
+ }
697
+ const at = this.activeIndex();
698
+ const position = at === null ? -1 : targets.indexOf(at);
699
+ let next;
700
+ if (step === "first" || step === "next" && position === -1) next = 0;
701
+ else if (step === "last" || step === "previous" && position === -1) next = targets.length - 1;
702
+ else if (step === "next") next = Math.min(targets.length - 1, position + 1);
703
+ else next = Math.max(0, position - 1);
704
+ const index = targets[next] ?? null;
705
+ this.activeIndex.set(index);
706
+ if (index !== null) this.spoken.set(describe(index));
707
+ }
708
+ };
709
+ function px(value) {
710
+ return Math.round(value * 100) / 100 || 0;
711
+ }
712
+ function segments(points) {
713
+ const runs = [];
714
+ let run = [];
715
+ for (const point of points) if (point) run.push(point);
716
+ else if (run.length > 0) {
717
+ runs.push(run);
718
+ run = [];
719
+ }
720
+ if (run.length > 0) runs.push(run);
721
+ return runs;
722
+ }
723
+ const sign = (n) => n < 0 ? -1 : 1;
724
+ function innerTangent(a, b, c) {
725
+ const h0 = b.x - a.x;
726
+ const h1 = c.x - b.x;
727
+ const s0 = h0 === 0 ? 0 : (b.y - a.y) / h0;
728
+ const s1 = h1 === 0 ? 0 : (c.y - b.y) / h1;
729
+ const p = h0 + h1 === 0 ? 0 : (s0 * h1 + s1 * h0) / (h0 + h1);
730
+ return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), .5 * Math.abs(p)) || 0;
731
+ }
732
+ function endTangent(a, b, t) {
733
+ const h = b.x - a.x;
734
+ return h === 0 ? t : (3 * (b.y - a.y) / h - t) / 2;
735
+ }
736
+ function runCommands(run, curve) {
737
+ if (curve === "linear" || run.length < 3) return run.slice(1).map((p) => `L${px(p.x)},${px(p.y)}`);
738
+ const n = run.length;
739
+ const tangents = new Array(n).fill(0);
740
+ for (let i = 1; i < n - 1; i++) tangents[i] = innerTangent(run[i - 1], run[i], run[i + 1]);
741
+ tangents[0] = endTangent(run[0], run[1], tangents[1]);
742
+ tangents[n - 1] = endTangent(run[n - 2], run[n - 1], tangents[n - 2]);
743
+ const commands = [];
744
+ for (let i = 1; i < n; i++) {
745
+ const a = run[i - 1];
746
+ const b = run[i];
747
+ const dx = (b.x - a.x) / 3;
748
+ const ta = tangents[i - 1];
749
+ const tb = tangents[i];
750
+ commands.push(`C${px(a.x + dx)},${px(a.y + dx * ta)} ${px(b.x - dx)},${px(b.y - dx * tb)} ${px(b.x)},${px(b.y)}`);
751
+ }
752
+ return commands;
753
+ }
754
+ function linePath(points, curve) {
755
+ return segments(points).map((run) => {
756
+ const first = run[0];
757
+ return [`M${px(first.x)},${px(first.y)}`, ...runCommands(run, curve)].join("");
758
+ }).join("");
759
+ }
760
+ function areaPath(points, curve, baseline) {
761
+ return segments(points).map((run) => {
762
+ const first = run[0];
763
+ const last = run[run.length - 1];
764
+ return [
765
+ `M${px(first.x)},${px(baseline)}`,
766
+ `L${px(first.x)},${px(first.y)}`,
767
+ ...runCommands(run, curve),
768
+ `L${px(last.x)},${px(baseline)}Z`
769
+ ].join("");
770
+ }).join("");
771
+ }
772
+ function niceStep(span, count) {
773
+ const raw = span / Math.max(1, count);
774
+ if (!Number.isFinite(raw) || raw <= 0) return 1;
775
+ const magnitude = 10 ** Math.floor(Math.log10(raw));
776
+ const normalized = raw / magnitude;
777
+ return (normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10) * magnitude;
778
+ }
779
+ function clean(value, step) {
780
+ const decimals = Math.max(0, -Math.floor(Math.log10(step)));
781
+ return Number(value.toFixed(Math.min(20, decimals))) || 0;
782
+ }
783
+ function niceTicks(min, max, count = 5) {
784
+ let lo = Math.min(min, max);
785
+ let hi = Math.max(min, max);
786
+ if (!Number.isFinite(lo) || !Number.isFinite(hi)) {
787
+ lo = 0;
788
+ hi = 1;
789
+ } else if (lo === hi) {
790
+ const pad = lo === 0 ? 1 : Math.abs(lo) * .1;
791
+ lo = lo === 0 ? 0 : lo - pad;
792
+ hi += pad;
793
+ }
794
+ const step = niceStep(hi - lo, count);
795
+ const start = Math.floor(lo / step + 1e-9);
796
+ const end = Math.ceil(hi / step - 1e-9);
797
+ const ticks = [];
798
+ for (let k = start; k <= end; k++) ticks.push(clean(k * step, step));
799
+ return {
800
+ min: clean(start * step, step),
801
+ max: clean(end * step, step),
802
+ step,
803
+ ticks
804
+ };
805
+ }
806
+ function observeWidth(target, fallback) {
807
+ const width = signal(fallback, ...ngDevMode ? [{ debugName: "width" }] : /* istanbul ignore next */ []);
808
+ const rtl = signal(false, ...ngDevMode ? [{ debugName: "rtl" }] : /* istanbul ignore next */ []);
809
+ const view = inject(DOCUMENT).defaultView;
810
+ let observer = null;
811
+ const measure = () => {
812
+ const element = target();
813
+ if (!element) return;
814
+ const measured = Math.round(element.clientWidth);
815
+ if (measured > 0) width.set(measured);
816
+ rtl.set(element.closest("[dir]")?.getAttribute("dir") === "rtl");
817
+ };
818
+ afterNextRender(() => {
819
+ measure();
820
+ const element = target();
821
+ if (element && view && typeof view.ResizeObserver === "function") {
822
+ observer = new view.ResizeObserver(measure);
823
+ observer.observe(element);
824
+ }
825
+ });
826
+ inject(DestroyRef).onDestroy(() => observer?.disconnect());
827
+ return {
828
+ width: width.asReadonly(),
829
+ rtl: rtl.asReadonly()
830
+ };
831
+ }
832
+ const STROKE = [
833
+ "stroke-chart-1",
834
+ "stroke-chart-2",
835
+ "stroke-chart-3",
836
+ "stroke-chart-4",
837
+ "stroke-chart-5",
838
+ "stroke-chart-6",
839
+ "stroke-chart-7",
840
+ "stroke-chart-8"
841
+ ];
842
+ const FILL = [
843
+ "fill-chart-1",
844
+ "fill-chart-2",
845
+ "fill-chart-3",
846
+ "fill-chart-4",
847
+ "fill-chart-5",
848
+ "fill-chart-6",
849
+ "fill-chart-7",
850
+ "fill-chart-8"
851
+ ];
852
+ const AREA$2 = [
853
+ "fill-chart-1/16",
854
+ "fill-chart-2/16",
855
+ "fill-chart-3/16",
856
+ "fill-chart-4/16",
857
+ "fill-chart-5/16",
858
+ "fill-chart-6/16",
859
+ "fill-chart-7/16",
860
+ "fill-chart-8/16"
861
+ ];
862
+ const SWATCH = [
863
+ "bg-chart-1",
864
+ "bg-chart-2",
865
+ "bg-chart-3",
866
+ "bg-chart-4",
867
+ "bg-chart-5",
868
+ "bg-chart-6",
869
+ "bg-chart-7",
870
+ "bg-chart-8"
871
+ ];
872
+ function slot(index) {
873
+ return (index % STROKE.length + STROKE.length) % STROKE.length;
874
+ }
875
+ function seriesStroke(index) {
876
+ return STROKE[slot(index)];
877
+ }
878
+ function seriesFill(index) {
879
+ return FILL[slot(index)];
880
+ }
881
+ function seriesArea(index) {
882
+ return AREA$2[slot(index)];
883
+ }
884
+ function seriesSwatch(index) {
885
+ return SWATCH[slot(index)];
886
+ }
887
+ function seriesLegend(series, interaction) {
888
+ return series.length < 2 ? [] : series.map((s, i) => ({
889
+ name: s.name,
890
+ swatch: seriesSwatch(i),
891
+ hidden: interaction.isHidden(i)
892
+ }));
893
+ }
894
+ function visibleSeries(series, interaction) {
895
+ return series.map((_, i) => i).filter((i) => !interaction.isHidden(i));
896
+ }
897
+ function seriesTable(series, categories, labels, format) {
898
+ return {
899
+ head: [labels.chartCategory, ...series.map((s) => s.name)],
900
+ rows: categories.map((category, j) => [category, ...series.map((s) => formatOrDash(s.values[j], format))])
901
+ };
902
+ }
903
+ function seriesTooltipRows(series, visible, at, format) {
904
+ return visible.map((index) => ({
905
+ name: series[index]?.name ?? "",
906
+ value: formatOrDash(series[index]?.values[at], format),
907
+ swatch: seriesSwatch(index)
908
+ }));
909
+ }
910
+ function describeCategory(series, categories, visible, at, format) {
911
+ const values = seriesTooltipRows(series, visible, at, format).map((row) => `${row.name} ${row.value}`).join(", ");
912
+ return `${categories[at] ?? ""}: ${values}`;
913
+ }
914
+ function valueAt(series, index, at) {
915
+ const v = series[index]?.values[at];
916
+ return v === null || v === void 0 || !Number.isFinite(v) ? null : v;
917
+ }
918
+ const FALLBACK_WIDTH$3 = 600;
919
+ const TOP$1 = 8;
920
+ const BOTTOM$1 = 24;
921
+ const END$1 = 8;
922
+ const LINE$1 = "fill-none [stroke-dasharray:1] animate-chart-draw motion-reduce:animate-none";
923
+ const AREA$1 = "stroke-none animate-chart-fade motion-reduce:animate-none";
924
+ const AXIS_TEXT$1 = "fill-text-muted text-micro";
925
+ const MARKER = "fill-surface";
926
+ var BfLineChartComponent = class BfLineChartComponent {
927
+ series = input.required(...ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []);
928
+ categories = input.required(...ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []);
929
+ label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
930
+ height = input(240, {
931
+ ...ngDevMode ? { debugName: "height" } : /* istanbul ignore next */ {},
932
+ transform: numberAttribute
933
+ });
934
+ area = input(false, {
935
+ ...ngDevMode ? { debugName: "area" } : /* istanbul ignore next */ {},
936
+ transform: booleanAttribute
937
+ });
938
+ curve = input("linear", ...ngDevMode ? [{ debugName: "curve" }] : /* istanbul ignore next */ []);
939
+ valueFormat = input(void 0, ...ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []);
940
+ legend = input(void 0, ...ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []);
941
+ interaction = new ChartInteraction();
942
+ labels = inject(BF_LABELS);
943
+ card = inject(BF_CHART_CARD, { optional: true });
944
+ document = inject(DOCUMENT);
945
+ frame = viewChild.required(BfChartFrameComponent, ...ngDevMode ? [{ debugName: "frame" }] : /* istanbul ignore next */ []);
946
+ box = observeWidth(() => this.frame().plotElement(), FALLBACK_WIDTH$3);
947
+ axisTextClasses = AXIS_TEXT$1;
948
+ name = computed(() => this.label() || (this.card?.title() ?? "") || this.labels.chart, ...ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []);
949
+ legendPosition = computed(() => this.legend() ?? this.card?.legend() ?? "bottom", ...ngDevMode ? [{ debugName: "legendPosition" }] : /* istanbul ignore next */ []);
950
+ format = computed(() => this.valueFormat() ?? defaultValueFormat(this.document), ...ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []);
951
+ generations = computed(() => [{
952
+ series: this.series(),
953
+ categories: this.categories()
954
+ }], ...ngDevMode ? [{ debugName: "generations" }] : /* istanbul ignore next */ []);
955
+ viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []);
956
+ visible = computed(() => visibleSeries(this.series(), this.interaction), ...ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []);
957
+ geometry = computed(() => {
958
+ const width = this.box.width();
959
+ const height = this.height();
960
+ const rtl = this.box.rtl();
961
+ const categories = this.categories();
962
+ const format = this.format();
963
+ const series = this.series();
964
+ const visible = this.visible();
965
+ const values = finiteValues(series, visible);
966
+ const lo = Math.min(...values, ...this.area() ? [0] : []);
967
+ const hi = Math.max(...values, ...this.area() ? [0] : []);
968
+ const plotHeight = Math.max(1, height - TOP$1 - BOTTOM$1);
969
+ const scale = niceTicks(lo, hi, Math.max(2, Math.floor(plotHeight / 48)));
970
+ const tickTexts = scale.ticks.map(format);
971
+ const start = Math.max(...tickTexts.map(textWidth)) + 12;
972
+ const plotWidth = Math.max(1, width - start - END$1);
973
+ const n = categories.length;
974
+ const xAt = (i) => mirror(n > 1 ? start + i * plotWidth / (n - 1) : start + plotWidth / 2, width, rtl);
975
+ const yAt = (v) => TOP$1 + (1 - (v - scale.min) / (scale.max - scale.min || 1)) * plotHeight;
976
+ const baseline = TOP$1 + plotHeight;
977
+ const valueBase = yAt(clamp(0, scale.min, scale.max));
978
+ const ticks = scale.ticks.map((value, i) => ({
979
+ key: value,
980
+ text: tickTexts[i] ?? "",
981
+ x: px(mirror(start - 8, width, rtl)),
982
+ y: px(yAt(value)),
983
+ anchor: rtl ? "start" : "end"
984
+ }));
985
+ const every = labelEvery(categories, plotWidth, n > 1 ? plotWidth / (n - 1) : plotWidth);
986
+ const categoryLabels = categories.flatMap((text, i) => {
987
+ if (i % every !== 0) return [];
988
+ const edge = n === 1 ? "middle" : i === 0 ? "first" : i === n - 1 ? "last" : "middle";
989
+ const anchor = edge === "middle" ? "middle" : edge === "first" !== rtl ? "start" : "end";
990
+ return [{
991
+ key: i,
992
+ text,
993
+ x: px(xAt(i)),
994
+ y: baseline + 18,
995
+ anchor
996
+ }];
997
+ });
998
+ const marks = visible.map((index) => {
999
+ const points = categories.map((_, j) => {
1000
+ const v = valueAt(series, index, j);
1001
+ return v === null ? null : {
1002
+ x: xAt(j),
1003
+ y: yAt(v)
1004
+ };
1005
+ });
1006
+ return {
1007
+ index,
1008
+ line: linePath(points, this.curve()),
1009
+ area: areaPath(points, this.curve(), valueBase),
1010
+ dots: segments(points).filter((run) => run.length === 1).map(([p]) => ({
1011
+ x: px(p.x),
1012
+ y: px(p.y)
1013
+ }))
1014
+ };
1015
+ });
1016
+ const [left, right] = rtl ? [END$1, width - start] : [start, width - END$1];
1017
+ return {
1018
+ width,
1019
+ top: TOP$1,
1020
+ baseline,
1021
+ left,
1022
+ right,
1023
+ ticks,
1024
+ categoryLabels,
1025
+ marks,
1026
+ xAt,
1027
+ yAt
1028
+ };
1029
+ }, ...ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []);
1030
+ legendItems = computed(() => seriesLegend(this.series(), this.interaction), ...ngDevMode ? [{ debugName: "legendItems" }] : /* istanbul ignore next */ []);
1031
+ active = computed(() => {
1032
+ const at = this.interaction.active();
1033
+ return at !== null && at < this.categories().length ? at : null;
1034
+ }, ...ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []);
1035
+ crosshairX = computed(() => {
1036
+ const at = this.active();
1037
+ return at === null ? null : px(this.geometry().xAt(at));
1038
+ }, ...ngDevMode ? [{ debugName: "crosshairX" }] : /* istanbul ignore next */ []);
1039
+ markers = computed(() => {
1040
+ const at = this.active();
1041
+ if (at === null) return [];
1042
+ const { xAt, yAt } = this.geometry();
1043
+ return this.visible().flatMap((index) => {
1044
+ const v = valueAt(this.series(), index, at);
1045
+ return v === null ? [] : [{
1046
+ index,
1047
+ x: px(xAt(at)),
1048
+ y: px(yAt(v))
1049
+ }];
1050
+ });
1051
+ }, ...ngDevMode ? [{ debugName: "markers" }] : /* istanbul ignore next */ []);
1052
+ tooltip = computed(() => {
1053
+ const at = this.active();
1054
+ if (at === null) return null;
1055
+ const { xAt, top, baseline } = this.geometry();
1056
+ const ys = this.markers().map((m) => m.y);
1057
+ const y = ys.length > 0 ? Math.min(...ys) : (top + baseline) / 2;
1058
+ return {
1059
+ title: this.categories()[at] ?? "",
1060
+ rows: seriesTooltipRows(this.series(), this.visible(), at, this.format()),
1061
+ x: px(xAt(at)),
1062
+ y: px(clamp(y, top + 24, baseline - 24))
1063
+ };
1064
+ }, ...ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []);
1065
+ table = computed(() => seriesTable(this.series(), this.categories(), this.labels, this.format()), ...ngDevMode ? [{ debugName: "table" }] : /* istanbul ignore next */ []);
1066
+ lineClasses(index) {
1067
+ return `${LINE$1} ${seriesStroke(index)}`;
1068
+ }
1069
+ areaClasses(index) {
1070
+ return `${AREA$1} ${seriesArea(index)}`;
1071
+ }
1072
+ dotClasses(index) {
1073
+ return `${seriesFill(index)} animate-chart-fade motion-reduce:animate-none`;
1074
+ }
1075
+ markerClasses(index) {
1076
+ return `${MARKER} ${seriesStroke(index)}`;
1077
+ }
1078
+ onPointed(pointer) {
1079
+ const n = this.categories().length;
1080
+ if (n === 0) return;
1081
+ const { xAt } = this.geometry();
1082
+ let best = 0;
1083
+ for (let i = 1; i < n; i++) if (Math.abs(xAt(i) - pointer.x) < Math.abs(xAt(best) - pointer.x)) best = i;
1084
+ this.interaction.point(best);
1085
+ }
1086
+ onStep(step) {
1087
+ const targets = this.categories().map((_, i) => i);
1088
+ this.interaction.step(step, targets, (i) => describeCategory(this.series(), this.categories(), this.visible(), i, this.format()));
1089
+ }
1090
+ onFocus(focused) {
1091
+ if (!focused) this.interaction.point(null);
1092
+ else if (this.interaction.active() === null) this.onStep("first");
1093
+ }
1094
+ static ɵfac = i0.ɵɵngDeclareFactory({
1095
+ minVersion: "12.0.0",
1096
+ version: "22.1.7",
1097
+ ngImport: i0,
1098
+ type: BfLineChartComponent,
1099
+ deps: [],
1100
+ target: i0.ɵɵFactoryTarget.Component
1101
+ });
1102
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1103
+ minVersion: "17.0.0",
1104
+ version: "22.1.7",
1105
+ type: BfLineChartComponent,
1106
+ isStandalone: true,
1107
+ selector: "bf-line-chart",
1108
+ inputs: {
1109
+ series: {
1110
+ classPropertyName: "series",
1111
+ publicName: "series",
1112
+ isSignal: true,
1113
+ isRequired: true,
1114
+ transformFunction: null
1115
+ },
1116
+ categories: {
1117
+ classPropertyName: "categories",
1118
+ publicName: "categories",
1119
+ isSignal: true,
1120
+ isRequired: true,
1121
+ transformFunction: null
1122
+ },
1123
+ label: {
1124
+ classPropertyName: "label",
1125
+ publicName: "label",
1126
+ isSignal: true,
1127
+ isRequired: false,
1128
+ transformFunction: null
1129
+ },
1130
+ height: {
1131
+ classPropertyName: "height",
1132
+ publicName: "height",
1133
+ isSignal: true,
1134
+ isRequired: false,
1135
+ transformFunction: null
1136
+ },
1137
+ area: {
1138
+ classPropertyName: "area",
1139
+ publicName: "area",
1140
+ isSignal: true,
1141
+ isRequired: false,
1142
+ transformFunction: null
1143
+ },
1144
+ curve: {
1145
+ classPropertyName: "curve",
1146
+ publicName: "curve",
1147
+ isSignal: true,
1148
+ isRequired: false,
1149
+ transformFunction: null
1150
+ },
1151
+ valueFormat: {
1152
+ classPropertyName: "valueFormat",
1153
+ publicName: "valueFormat",
1154
+ isSignal: true,
1155
+ isRequired: false,
1156
+ transformFunction: null
1157
+ },
1158
+ legend: {
1159
+ classPropertyName: "legend",
1160
+ publicName: "legend",
1161
+ isSignal: true,
1162
+ isRequired: false,
1163
+ transformFunction: null
1164
+ }
1165
+ },
1166
+ host: { classAttribute: "block w-full min-w-0" },
1167
+ viewQueries: [{
1168
+ propertyName: "frame",
1169
+ first: true,
1170
+ predicate: BfChartFrameComponent,
1171
+ descendants: true,
1172
+ isSignal: true
1173
+ }],
1174
+ ngImport: i0,
1175
+ template: `
1176
+ <bf-chart-frame
1177
+ [label]="name()"
1178
+ [height]="height()"
1179
+ [legend]="legendItems()"
1180
+ [legendPosition]="legendPosition()"
1181
+ [tooltip]="tooltip()"
1182
+ [announcement]="interaction.announcement()"
1183
+ [table]="table()"
1184
+ (legendToggled)="interaction.toggle($event)"
1185
+ (pointed)="onPointed($event)"
1186
+ (left)="interaction.point(null)"
1187
+ (stepped)="onStep($event)"
1188
+ (focusChanged)="onFocus($event)"
1189
+ >
1190
+ <svg
1191
+ aria-hidden="true"
1192
+ focusable="false"
1193
+ direction="ltr"
1194
+ class="block w-full overflow-visible"
1195
+ [attr.height]="height()"
1196
+ [attr.viewBox]="viewBox()"
1197
+ >
1198
+ @let g = geometry();
1199
+ @for (tick of g.ticks; track tick.key) {
1200
+ <line
1201
+ data-bf-chart-grid
1202
+ class="stroke-chart-grid"
1203
+ stroke-width="1"
1204
+ [attr.x1]="g.left"
1205
+ [attr.x2]="g.right"
1206
+ [attr.y1]="tick.y"
1207
+ [attr.y2]="tick.y"
1208
+ />
1209
+ <text
1210
+ dominant-baseline="middle"
1211
+ [class]="axisTextClasses"
1212
+ [attr.x]="tick.x"
1213
+ [attr.y]="tick.y"
1214
+ [attr.text-anchor]="tick.anchor"
1215
+ >
1216
+ {{ tick.text }}
1217
+ </text>
1218
+ }
1219
+ <line
1220
+ data-bf-chart-axis
1221
+ class="stroke-chart-axis"
1222
+ stroke-width="1"
1223
+ [attr.x1]="g.left"
1224
+ [attr.x2]="g.right"
1225
+ [attr.y1]="g.baseline"
1226
+ [attr.y2]="g.baseline"
1227
+ />
1228
+ @for (label of g.categoryLabels; track label.key) {
1229
+ <text
1230
+ data-bf-chart-category
1231
+ [class]="axisTextClasses"
1232
+ [attr.x]="label.x"
1233
+ [attr.y]="label.y"
1234
+ [attr.text-anchor]="label.anchor"
1235
+ >
1236
+ {{ label.text }}
1237
+ </text>
1238
+ }
1239
+ @let x = crosshairX();
1240
+ @if (x !== null) {
1241
+ <line
1242
+ data-bf-chart-crosshair
1243
+ class="stroke-chart-axis"
1244
+ stroke-width="1"
1245
+ stroke-dasharray="3 3"
1246
+ [attr.x1]="x"
1247
+ [attr.x2]="x"
1248
+ [attr.y1]="g.top"
1249
+ [attr.y2]="g.baseline"
1250
+ />
1251
+ }
1252
+ <!-- Re-created on every data change, so the enter motion replays. -->
1253
+ @for (generation of generations(); track generation) {
1254
+ <g>
1255
+ @for (mark of g.marks; track mark.index) {
1256
+ @if (area()) {
1257
+ <path data-bf-chart-area [attr.d]="mark.area" [class]="areaClasses(mark.index)" />
1258
+ }
1259
+ <path
1260
+ data-bf-chart-line
1261
+ pathLength="1"
1262
+ stroke-width="2"
1263
+ stroke-linejoin="round"
1264
+ stroke-linecap="round"
1265
+ [attr.d]="mark.line"
1266
+ [class]="lineClasses(mark.index)"
1267
+ />
1268
+ @for (dot of mark.dots; track $index) {
1269
+ <circle
1270
+ r="2.5"
1271
+ [attr.cx]="dot.x"
1272
+ [attr.cy]="dot.y"
1273
+ [class]="dotClasses(mark.index)"
1274
+ />
1275
+ }
1276
+ }
1277
+ </g>
1278
+ }
1279
+ @for (marker of markers(); track marker.index) {
1280
+ <circle
1281
+ data-bf-chart-marker
1282
+ r="4"
1283
+ stroke-width="2"
1284
+ [attr.cx]="marker.x"
1285
+ [attr.cy]="marker.y"
1286
+ [class]="markerClasses(marker.index)"
1287
+ />
1288
+ }
1289
+ </svg>
1290
+ </bf-chart-frame>
1291
+ `,
1292
+ isInline: true,
1293
+ dependencies: [{
1294
+ kind: "component",
1295
+ type: BfChartFrameComponent,
1296
+ selector: "bf-chart-frame",
1297
+ inputs: [
1298
+ "label",
1299
+ "height",
1300
+ "legend",
1301
+ "legendPosition",
1302
+ "tooltip",
1303
+ "announcement",
1304
+ "table",
1305
+ "dataToggle",
1306
+ "vertical"
1307
+ ],
1308
+ outputs: [
1309
+ "legendToggled",
1310
+ "pointed",
1311
+ "left",
1312
+ "stepped",
1313
+ "focusChanged"
1314
+ ]
1315
+ }]
1316
+ });
1317
+ };
1318
+ i0.ɵɵngDeclareClassMetadata({
1319
+ minVersion: "12.0.0",
1320
+ version: "22.1.7",
1321
+ ngImport: i0,
1322
+ type: BfLineChartComponent,
1323
+ decorators: [{
1324
+ type: Component,
1325
+ args: [{
1326
+ selector: "bf-line-chart",
1327
+ imports: [BfChartFrameComponent],
1328
+ host: { class: "block w-full min-w-0" },
1329
+ template: `
1330
+ <bf-chart-frame
1331
+ [label]="name()"
1332
+ [height]="height()"
1333
+ [legend]="legendItems()"
1334
+ [legendPosition]="legendPosition()"
1335
+ [tooltip]="tooltip()"
1336
+ [announcement]="interaction.announcement()"
1337
+ [table]="table()"
1338
+ (legendToggled)="interaction.toggle($event)"
1339
+ (pointed)="onPointed($event)"
1340
+ (left)="interaction.point(null)"
1341
+ (stepped)="onStep($event)"
1342
+ (focusChanged)="onFocus($event)"
1343
+ >
1344
+ <svg
1345
+ aria-hidden="true"
1346
+ focusable="false"
1347
+ direction="ltr"
1348
+ class="block w-full overflow-visible"
1349
+ [attr.height]="height()"
1350
+ [attr.viewBox]="viewBox()"
1351
+ >
1352
+ @let g = geometry();
1353
+ @for (tick of g.ticks; track tick.key) {
1354
+ <line
1355
+ data-bf-chart-grid
1356
+ class="stroke-chart-grid"
1357
+ stroke-width="1"
1358
+ [attr.x1]="g.left"
1359
+ [attr.x2]="g.right"
1360
+ [attr.y1]="tick.y"
1361
+ [attr.y2]="tick.y"
1362
+ />
1363
+ <text
1364
+ dominant-baseline="middle"
1365
+ [class]="axisTextClasses"
1366
+ [attr.x]="tick.x"
1367
+ [attr.y]="tick.y"
1368
+ [attr.text-anchor]="tick.anchor"
1369
+ >
1370
+ {{ tick.text }}
1371
+ </text>
1372
+ }
1373
+ <line
1374
+ data-bf-chart-axis
1375
+ class="stroke-chart-axis"
1376
+ stroke-width="1"
1377
+ [attr.x1]="g.left"
1378
+ [attr.x2]="g.right"
1379
+ [attr.y1]="g.baseline"
1380
+ [attr.y2]="g.baseline"
1381
+ />
1382
+ @for (label of g.categoryLabels; track label.key) {
1383
+ <text
1384
+ data-bf-chart-category
1385
+ [class]="axisTextClasses"
1386
+ [attr.x]="label.x"
1387
+ [attr.y]="label.y"
1388
+ [attr.text-anchor]="label.anchor"
1389
+ >
1390
+ {{ label.text }}
1391
+ </text>
1392
+ }
1393
+ @let x = crosshairX();
1394
+ @if (x !== null) {
1395
+ <line
1396
+ data-bf-chart-crosshair
1397
+ class="stroke-chart-axis"
1398
+ stroke-width="1"
1399
+ stroke-dasharray="3 3"
1400
+ [attr.x1]="x"
1401
+ [attr.x2]="x"
1402
+ [attr.y1]="g.top"
1403
+ [attr.y2]="g.baseline"
1404
+ />
1405
+ }
1406
+ <!-- Re-created on every data change, so the enter motion replays. -->
1407
+ @for (generation of generations(); track generation) {
1408
+ <g>
1409
+ @for (mark of g.marks; track mark.index) {
1410
+ @if (area()) {
1411
+ <path data-bf-chart-area [attr.d]="mark.area" [class]="areaClasses(mark.index)" />
1412
+ }
1413
+ <path
1414
+ data-bf-chart-line
1415
+ pathLength="1"
1416
+ stroke-width="2"
1417
+ stroke-linejoin="round"
1418
+ stroke-linecap="round"
1419
+ [attr.d]="mark.line"
1420
+ [class]="lineClasses(mark.index)"
1421
+ />
1422
+ @for (dot of mark.dots; track $index) {
1423
+ <circle
1424
+ r="2.5"
1425
+ [attr.cx]="dot.x"
1426
+ [attr.cy]="dot.y"
1427
+ [class]="dotClasses(mark.index)"
1428
+ />
1429
+ }
1430
+ }
1431
+ </g>
1432
+ }
1433
+ @for (marker of markers(); track marker.index) {
1434
+ <circle
1435
+ data-bf-chart-marker
1436
+ r="4"
1437
+ stroke-width="2"
1438
+ [attr.cx]="marker.x"
1439
+ [attr.cy]="marker.y"
1440
+ [class]="markerClasses(marker.index)"
1441
+ />
1442
+ }
1443
+ </svg>
1444
+ </bf-chart-frame>
1445
+ `
1446
+ }]
1447
+ }],
1448
+ propDecorators: {
1449
+ series: [{
1450
+ type: i0.Input,
1451
+ args: [{
1452
+ isSignal: true,
1453
+ alias: "series",
1454
+ required: true
1455
+ }]
1456
+ }],
1457
+ categories: [{
1458
+ type: i0.Input,
1459
+ args: [{
1460
+ isSignal: true,
1461
+ alias: "categories",
1462
+ required: true
1463
+ }]
1464
+ }],
1465
+ label: [{
1466
+ type: i0.Input,
1467
+ args: [{
1468
+ isSignal: true,
1469
+ alias: "label",
1470
+ required: false
1471
+ }]
1472
+ }],
1473
+ height: [{
1474
+ type: i0.Input,
1475
+ args: [{
1476
+ isSignal: true,
1477
+ alias: "height",
1478
+ required: false
1479
+ }]
1480
+ }],
1481
+ area: [{
1482
+ type: i0.Input,
1483
+ args: [{
1484
+ isSignal: true,
1485
+ alias: "area",
1486
+ required: false
1487
+ }]
1488
+ }],
1489
+ curve: [{
1490
+ type: i0.Input,
1491
+ args: [{
1492
+ isSignal: true,
1493
+ alias: "curve",
1494
+ required: false
1495
+ }]
1496
+ }],
1497
+ valueFormat: [{
1498
+ type: i0.Input,
1499
+ args: [{
1500
+ isSignal: true,
1501
+ alias: "valueFormat",
1502
+ required: false
1503
+ }]
1504
+ }],
1505
+ legend: [{
1506
+ type: i0.Input,
1507
+ args: [{
1508
+ isSignal: true,
1509
+ alias: "legend",
1510
+ required: false
1511
+ }]
1512
+ }],
1513
+ frame: [{
1514
+ type: i0.ViewChild,
1515
+ args: [i0.forwardRef(() => BfChartFrameComponent), { isSignal: true }]
1516
+ }]
1517
+ }
1518
+ });
1519
+ const FALLBACK_WIDTH$2 = 600;
1520
+ const TOP = 8;
1521
+ const BOTTOM = 24;
1522
+ const END = 12;
1523
+ const BAND_FILL = .72;
1524
+ const BAR_MAX = 40;
1525
+ const GAP = 2;
1526
+ const SEGMENT_GAP = 2;
1527
+ const BAR = "transform-fill motion-reduce:animate-none";
1528
+ const GROW = {
1529
+ up: "origin-bottom animate-chart-grow-y",
1530
+ down: "origin-top animate-chart-grow-y",
1531
+ left: "origin-[0%_50%] animate-chart-grow-x",
1532
+ right: "origin-[100%_50%] animate-chart-grow-x"
1533
+ };
1534
+ const AXIS_TEXT = "fill-text-muted text-micro";
1535
+ var BfBarChartComponent = class BfBarChartComponent {
1536
+ series = input.required(...ngDevMode ? [{ debugName: "series" }] : /* istanbul ignore next */ []);
1537
+ categories = input.required(...ngDevMode ? [{ debugName: "categories" }] : /* istanbul ignore next */ []);
1538
+ label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
1539
+ height = input(240, {
1540
+ ...ngDevMode ? { debugName: "height" } : /* istanbul ignore next */ {},
1541
+ transform: numberAttribute
1542
+ });
1543
+ orientation = input("vertical", ...ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []);
1544
+ stacked = input(false, {
1545
+ ...ngDevMode ? { debugName: "stacked" } : /* istanbul ignore next */ {},
1546
+ transform: booleanAttribute
1547
+ });
1548
+ valueFormat = input(void 0, ...ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []);
1549
+ legend = input(void 0, ...ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []);
1550
+ interaction = new ChartInteraction();
1551
+ labels = inject(BF_LABELS);
1552
+ card = inject(BF_CHART_CARD, { optional: true });
1553
+ document = inject(DOCUMENT);
1554
+ frame = viewChild.required(BfChartFrameComponent, ...ngDevMode ? [{ debugName: "frame" }] : /* istanbul ignore next */ []);
1555
+ box = observeWidth(() => this.frame().plotElement(), FALLBACK_WIDTH$2);
1556
+ axisTextClasses = AXIS_TEXT;
1557
+ name = computed(() => this.label() || (this.card?.title() ?? "") || this.labels.chart, ...ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []);
1558
+ legendPosition = computed(() => this.legend() ?? this.card?.legend() ?? "bottom", ...ngDevMode ? [{ debugName: "legendPosition" }] : /* istanbul ignore next */ []);
1559
+ format = computed(() => this.valueFormat() ?? defaultValueFormat(this.document), ...ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []);
1560
+ generations = computed(() => [{
1561
+ series: this.series(),
1562
+ categories: this.categories(),
1563
+ stacked: this.stacked()
1564
+ }], ...ngDevMode ? [{ debugName: "generations" }] : /* istanbul ignore next */ []);
1565
+ viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []);
1566
+ visible = computed(() => visibleSeries(this.series(), this.interaction), ...ngDevMode ? [{ debugName: "visible" }] : /* istanbul ignore next */ []);
1567
+ extent = computed(() => {
1568
+ const series = this.series();
1569
+ const visible = this.visible();
1570
+ if (!this.stacked()) {
1571
+ const values = finiteValues(series, visible);
1572
+ return {
1573
+ lo: Math.min(0, ...values),
1574
+ hi: Math.max(0, ...values)
1575
+ };
1576
+ }
1577
+ let lo = 0;
1578
+ let hi = 0;
1579
+ this.categories().forEach((_, j) => {
1580
+ let up = 0;
1581
+ let down = 0;
1582
+ for (const index of visible) {
1583
+ const v = valueAt(series, index, j) ?? 0;
1584
+ if (v >= 0) up += v;
1585
+ else down += v;
1586
+ }
1587
+ hi = Math.max(hi, up);
1588
+ lo = Math.min(lo, down);
1589
+ });
1590
+ return {
1591
+ lo,
1592
+ hi
1593
+ };
1594
+ }, ...ngDevMode ? [{ debugName: "extent" }] : /* istanbul ignore next */ []);
1595
+ geometry = computed(() => {
1596
+ const width = this.box.width();
1597
+ const height = this.height();
1598
+ const rtl = this.box.rtl();
1599
+ const horizontal = this.orientation() === "horizontal";
1600
+ const categories = this.categories();
1601
+ const series = this.series();
1602
+ const visible = this.visible();
1603
+ const format = this.format();
1604
+ const n = Math.max(1, categories.length);
1605
+ const { lo, hi } = this.extent();
1606
+ const valueRoom = horizontal ? width : height - TOP - BOTTOM;
1607
+ const scale = niceTicks(lo, hi, Math.max(2, Math.floor(valueRoom / (horizontal ? 96 : 48))));
1608
+ const tickTexts = scale.ticks.map(format);
1609
+ const start = horizontal ? Math.min(Math.round(width * .4), Math.max(0, ...categories.map(textWidth)) + 12) : Math.max(...tickTexts.map(textWidth)) + 12;
1610
+ const plotWidth = Math.max(1, width - start - END);
1611
+ const plotHeight = Math.max(1, height - TOP - BOTTOM);
1612
+ const span = scale.max - scale.min || 1;
1613
+ const valuePos = (v) => horizontal ? start + (v - scale.min) / span * plotWidth : TOP + (1 - (v - scale.min) / span) * plotHeight;
1614
+ const zero = valuePos(clamp(0, scale.min, scale.max));
1615
+ const bandSize = (horizontal ? plotHeight : plotWidth) / n;
1616
+ const bandStart = (j) => (horizontal ? TOP : start) + j * bandSize;
1617
+ const bars = [];
1618
+ const k = Math.max(1, visible.length);
1619
+ const groupSize = this.stacked() ? Math.min(bandSize * BAND_FILL, BAR_MAX) : Math.min(bandSize * BAND_FILL, BAR_MAX * k + GAP * (k - 1));
1620
+ const barSize = this.stacked() ? groupSize : Math.max(1, (groupSize - GAP * (k - 1)) / k);
1621
+ categories.forEach((_, j) => {
1622
+ const groupStart = bandStart(j) + (bandSize - groupSize) / 2;
1623
+ let up = 0;
1624
+ let down = 0;
1625
+ visible.forEach((index, slot) => {
1626
+ const v = valueAt(series, index, j);
1627
+ if (v === null || v === 0) return;
1628
+ let from;
1629
+ let to;
1630
+ if (this.stacked()) {
1631
+ from = v > 0 ? up : down;
1632
+ to = from + v;
1633
+ if (v > 0) up = to;
1634
+ else down = to;
1635
+ } else {
1636
+ from = 0;
1637
+ to = v;
1638
+ }
1639
+ let a = valuePos(from);
1640
+ let b = valuePos(to);
1641
+ const inset = this.stacked() && Math.abs(b - a) > SEGMENT_GAP * 2 ? SEGMENT_GAP / 2 : 0;
1642
+ const along = this.stacked() ? groupStart : groupStart + slot * (barSize + GAP);
1643
+ [a, b] = [Math.min(a, b) + inset, Math.max(a, b) - inset];
1644
+ const positive = v > 0;
1645
+ if (horizontal) {
1646
+ const x = rtl ? width - b : a;
1647
+ bars.push({
1648
+ key: `${index}:${j}`,
1649
+ index,
1650
+ x: px(x),
1651
+ y: px(along),
1652
+ width: px(b - a),
1653
+ height: px(barSize),
1654
+ grow: positive !== rtl ? "left" : "right"
1655
+ });
1656
+ } else {
1657
+ const x = mirror(along, width, rtl) - (rtl ? barSize : 0);
1658
+ bars.push({
1659
+ key: `${index}:${j}`,
1660
+ index,
1661
+ x: px(x),
1662
+ y: px(a),
1663
+ width: px(barSize),
1664
+ height: px(b - a),
1665
+ grow: positive ? "up" : "down"
1666
+ });
1667
+ }
1668
+ });
1669
+ });
1670
+ const grid = scale.ticks.map((value) => {
1671
+ const p = valuePos(value);
1672
+ return horizontal ? {
1673
+ key: value,
1674
+ x1: px(mirror(p, width, rtl)),
1675
+ x2: px(mirror(p, width, rtl)),
1676
+ y1: TOP,
1677
+ y2: TOP + plotHeight
1678
+ } : {
1679
+ key: value,
1680
+ x1: px(mirror(start, width, rtl)),
1681
+ x2: px(mirror(start + plotWidth, width, rtl)),
1682
+ y1: px(p),
1683
+ y2: px(p)
1684
+ };
1685
+ });
1686
+ const axis = horizontal ? {
1687
+ x1: px(mirror(zero, width, rtl)),
1688
+ x2: px(mirror(zero, width, rtl)),
1689
+ y1: TOP,
1690
+ y2: TOP + plotHeight
1691
+ } : {
1692
+ x1: px(mirror(start, width, rtl)),
1693
+ x2: px(mirror(start + plotWidth, width, rtl)),
1694
+ y1: px(zero),
1695
+ y2: px(zero)
1696
+ };
1697
+ const tickLabels = scale.ticks.map((value, i) => {
1698
+ const text = tickTexts[i] ?? "";
1699
+ return horizontal ? {
1700
+ key: -1,
1701
+ text,
1702
+ x: px(mirror(valuePos(value), width, rtl)),
1703
+ y: height - 6,
1704
+ anchor: "middle"
1705
+ } : {
1706
+ key: -1,
1707
+ text,
1708
+ x: px(mirror(start - 8, width, rtl)),
1709
+ y: px(valuePos(value)),
1710
+ anchor: rtl ? "start" : "end"
1711
+ };
1712
+ });
1713
+ const every = horizontal ? Math.max(1, Math.ceil(16 / bandSize)) : labelEvery(categories, plotWidth, bandSize);
1714
+ const categoryLabels = categories.flatMap((text, j) => j % every !== 0 ? [] : horizontal ? [{
1715
+ key: j,
1716
+ text,
1717
+ x: px(mirror(start - 8, width, rtl)),
1718
+ y: px(bandStart(j) + bandSize / 2),
1719
+ anchor: rtl ? "start" : "end"
1720
+ }] : [{
1721
+ key: j,
1722
+ text,
1723
+ x: px(mirror(bandStart(j) + bandSize / 2, width, rtl)),
1724
+ y: TOP + plotHeight + 18,
1725
+ anchor: "middle"
1726
+ }]);
1727
+ return {
1728
+ bars,
1729
+ grid,
1730
+ axis,
1731
+ labels: [...tickLabels, ...categoryLabels],
1732
+ horizontal,
1733
+ rtl,
1734
+ width,
1735
+ start,
1736
+ plotWidth,
1737
+ plotHeight,
1738
+ bandSize,
1739
+ bandStart,
1740
+ zero
1741
+ };
1742
+ }, ...ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []);
1743
+ legendItems = computed(() => seriesLegend(this.series(), this.interaction), ...ngDevMode ? [{ debugName: "legendItems" }] : /* istanbul ignore next */ []);
1744
+ active = computed(() => {
1745
+ const at = this.interaction.active();
1746
+ return at !== null && at < this.categories().length ? at : null;
1747
+ }, ...ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []);
1748
+ activeBand = computed(() => {
1749
+ const at = this.active();
1750
+ if (at === null) return null;
1751
+ const g = this.geometry();
1752
+ const along = g.bandStart(at);
1753
+ return g.horizontal ? {
1754
+ x: px(g.rtl ? END : g.start),
1755
+ y: px(along),
1756
+ width: px(g.plotWidth),
1757
+ height: px(g.bandSize)
1758
+ } : {
1759
+ x: px(mirror(along, g.width, g.rtl) - (g.rtl ? g.bandSize : 0)),
1760
+ y: TOP,
1761
+ width: px(g.bandSize),
1762
+ height: px(g.plotHeight)
1763
+ };
1764
+ }, ...ngDevMode ? [{ debugName: "activeBand" }] : /* istanbul ignore next */ []);
1765
+ tooltip = computed(() => {
1766
+ const at = this.active();
1767
+ const band = this.activeBand();
1768
+ if (at === null || !band) return null;
1769
+ const g = this.geometry();
1770
+ return {
1771
+ title: this.categories()[at] ?? "",
1772
+ rows: seriesTooltipRows(this.series(), this.visible(), at, this.format()),
1773
+ x: g.horizontal ? px(g.width / 2) : px(band.x + band.width / 2),
1774
+ y: g.horizontal ? px(band.y + band.height / 2) : px(TOP + g.plotHeight / 2)
1775
+ };
1776
+ }, ...ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []);
1777
+ table = computed(() => seriesTable(this.series(), this.categories(), this.labels, this.format()), ...ngDevMode ? [{ debugName: "table" }] : /* istanbul ignore next */ []);
1778
+ barClasses(bar) {
1779
+ return `${BAR} ${GROW[bar.grow]} ${seriesFill(bar.index)}`;
1780
+ }
1781
+ onPointed(pointer) {
1782
+ const n = this.categories().length;
1783
+ if (n === 0) return;
1784
+ const g = this.geometry();
1785
+ const along = g.horizontal ? pointer.y - TOP : mirror(pointer.x, g.width, g.rtl) - g.start;
1786
+ this.interaction.point(clamp(Math.floor(along / g.bandSize), 0, n - 1));
1787
+ }
1788
+ onStep(step) {
1789
+ const targets = this.categories().map((_, i) => i);
1790
+ this.interaction.step(step, targets, (i) => describeCategory(this.series(), this.categories(), this.visible(), i, this.format()));
1791
+ }
1792
+ onFocus(focused) {
1793
+ if (!focused) this.interaction.point(null);
1794
+ else if (this.interaction.active() === null) this.onStep("first");
1795
+ }
1796
+ static ɵfac = i0.ɵɵngDeclareFactory({
1797
+ minVersion: "12.0.0",
1798
+ version: "22.1.7",
1799
+ ngImport: i0,
1800
+ type: BfBarChartComponent,
1801
+ deps: [],
1802
+ target: i0.ɵɵFactoryTarget.Component
1803
+ });
1804
+ static ɵcmp = i0.ɵɵngDeclareComponent({
1805
+ minVersion: "17.0.0",
1806
+ version: "22.1.7",
1807
+ type: BfBarChartComponent,
1808
+ isStandalone: true,
1809
+ selector: "bf-bar-chart",
1810
+ inputs: {
1811
+ series: {
1812
+ classPropertyName: "series",
1813
+ publicName: "series",
1814
+ isSignal: true,
1815
+ isRequired: true,
1816
+ transformFunction: null
1817
+ },
1818
+ categories: {
1819
+ classPropertyName: "categories",
1820
+ publicName: "categories",
1821
+ isSignal: true,
1822
+ isRequired: true,
1823
+ transformFunction: null
1824
+ },
1825
+ label: {
1826
+ classPropertyName: "label",
1827
+ publicName: "label",
1828
+ isSignal: true,
1829
+ isRequired: false,
1830
+ transformFunction: null
1831
+ },
1832
+ height: {
1833
+ classPropertyName: "height",
1834
+ publicName: "height",
1835
+ isSignal: true,
1836
+ isRequired: false,
1837
+ transformFunction: null
1838
+ },
1839
+ orientation: {
1840
+ classPropertyName: "orientation",
1841
+ publicName: "orientation",
1842
+ isSignal: true,
1843
+ isRequired: false,
1844
+ transformFunction: null
1845
+ },
1846
+ stacked: {
1847
+ classPropertyName: "stacked",
1848
+ publicName: "stacked",
1849
+ isSignal: true,
1850
+ isRequired: false,
1851
+ transformFunction: null
1852
+ },
1853
+ valueFormat: {
1854
+ classPropertyName: "valueFormat",
1855
+ publicName: "valueFormat",
1856
+ isSignal: true,
1857
+ isRequired: false,
1858
+ transformFunction: null
1859
+ },
1860
+ legend: {
1861
+ classPropertyName: "legend",
1862
+ publicName: "legend",
1863
+ isSignal: true,
1864
+ isRequired: false,
1865
+ transformFunction: null
1866
+ }
1867
+ },
1868
+ host: { classAttribute: "block w-full min-w-0" },
1869
+ viewQueries: [{
1870
+ propertyName: "frame",
1871
+ first: true,
1872
+ predicate: BfChartFrameComponent,
1873
+ descendants: true,
1874
+ isSignal: true
1875
+ }],
1876
+ ngImport: i0,
1877
+ template: `
1878
+ <bf-chart-frame
1879
+ [label]="name()"
1880
+ [height]="height()"
1881
+ [legend]="legendItems()"
1882
+ [legendPosition]="legendPosition()"
1883
+ [tooltip]="tooltip()"
1884
+ [announcement]="interaction.announcement()"
1885
+ [table]="table()"
1886
+ [vertical]="orientation() === 'horizontal'"
1887
+ (legendToggled)="interaction.toggle($event)"
1888
+ (pointed)="onPointed($event)"
1889
+ (left)="interaction.point(null)"
1890
+ (stepped)="onStep($event)"
1891
+ (focusChanged)="onFocus($event)"
1892
+ >
1893
+ <svg
1894
+ aria-hidden="true"
1895
+ focusable="false"
1896
+ direction="ltr"
1897
+ class="block w-full overflow-visible"
1898
+ [attr.height]="height()"
1899
+ [attr.viewBox]="viewBox()"
1900
+ >
1901
+ @let g = geometry();
1902
+ @let band = activeBand();
1903
+ @if (band) {
1904
+ <rect
1905
+ data-bf-chart-band
1906
+ class="fill-surface-muted"
1907
+ [attr.x]="band.x"
1908
+ [attr.y]="band.y"
1909
+ [attr.width]="band.width"
1910
+ [attr.height]="band.height"
1911
+ />
1912
+ }
1913
+ @for (line of g.grid; track line.key) {
1914
+ <line
1915
+ data-bf-chart-grid
1916
+ class="stroke-chart-grid"
1917
+ stroke-width="1"
1918
+ [attr.x1]="line.x1"
1919
+ [attr.x2]="line.x2"
1920
+ [attr.y1]="line.y1"
1921
+ [attr.y2]="line.y2"
1922
+ />
1923
+ }
1924
+ @for (label of g.labels; track $index) {
1925
+ <text
1926
+ [class]="axisTextClasses"
1927
+ [attr.data-bf-chart-category]="label.key >= 0 ? '' : null"
1928
+ [attr.dominant-baseline]="label.anchor === 'middle' ? null : 'middle'"
1929
+ [attr.x]="label.x"
1930
+ [attr.y]="label.y"
1931
+ [attr.text-anchor]="label.anchor"
1932
+ >
1933
+ {{ label.text }}
1934
+ </text>
1935
+ }
1936
+ <!-- Re-created on every data change, so the enter motion replays. -->
1937
+ @for (generation of generations(); track generation) {
1938
+ <g>
1939
+ @for (bar of g.bars; track bar.key) {
1940
+ <rect
1941
+ data-bf-chart-bar
1942
+ rx="2"
1943
+ [attr.x]="bar.x"
1944
+ [attr.y]="bar.y"
1945
+ [attr.width]="bar.width"
1946
+ [attr.height]="bar.height"
1947
+ [class]="barClasses(bar)"
1948
+ />
1949
+ }
1950
+ </g>
1951
+ }
1952
+ <line
1953
+ data-bf-chart-axis
1954
+ class="stroke-chart-axis"
1955
+ stroke-width="1"
1956
+ [attr.x1]="g.axis.x1"
1957
+ [attr.x2]="g.axis.x2"
1958
+ [attr.y1]="g.axis.y1"
1959
+ [attr.y2]="g.axis.y2"
1960
+ />
1961
+ </svg>
1962
+ </bf-chart-frame>
1963
+ `,
1964
+ isInline: true,
1965
+ dependencies: [{
1966
+ kind: "component",
1967
+ type: BfChartFrameComponent,
1968
+ selector: "bf-chart-frame",
1969
+ inputs: [
1970
+ "label",
1971
+ "height",
1972
+ "legend",
1973
+ "legendPosition",
1974
+ "tooltip",
1975
+ "announcement",
1976
+ "table",
1977
+ "dataToggle",
1978
+ "vertical"
1979
+ ],
1980
+ outputs: [
1981
+ "legendToggled",
1982
+ "pointed",
1983
+ "left",
1984
+ "stepped",
1985
+ "focusChanged"
1986
+ ]
1987
+ }]
1988
+ });
1989
+ };
1990
+ i0.ɵɵngDeclareClassMetadata({
1991
+ minVersion: "12.0.0",
1992
+ version: "22.1.7",
1993
+ ngImport: i0,
1994
+ type: BfBarChartComponent,
1995
+ decorators: [{
1996
+ type: Component,
1997
+ args: [{
1998
+ selector: "bf-bar-chart",
1999
+ imports: [BfChartFrameComponent],
2000
+ host: { class: "block w-full min-w-0" },
2001
+ template: `
2002
+ <bf-chart-frame
2003
+ [label]="name()"
2004
+ [height]="height()"
2005
+ [legend]="legendItems()"
2006
+ [legendPosition]="legendPosition()"
2007
+ [tooltip]="tooltip()"
2008
+ [announcement]="interaction.announcement()"
2009
+ [table]="table()"
2010
+ [vertical]="orientation() === 'horizontal'"
2011
+ (legendToggled)="interaction.toggle($event)"
2012
+ (pointed)="onPointed($event)"
2013
+ (left)="interaction.point(null)"
2014
+ (stepped)="onStep($event)"
2015
+ (focusChanged)="onFocus($event)"
2016
+ >
2017
+ <svg
2018
+ aria-hidden="true"
2019
+ focusable="false"
2020
+ direction="ltr"
2021
+ class="block w-full overflow-visible"
2022
+ [attr.height]="height()"
2023
+ [attr.viewBox]="viewBox()"
2024
+ >
2025
+ @let g = geometry();
2026
+ @let band = activeBand();
2027
+ @if (band) {
2028
+ <rect
2029
+ data-bf-chart-band
2030
+ class="fill-surface-muted"
2031
+ [attr.x]="band.x"
2032
+ [attr.y]="band.y"
2033
+ [attr.width]="band.width"
2034
+ [attr.height]="band.height"
2035
+ />
2036
+ }
2037
+ @for (line of g.grid; track line.key) {
2038
+ <line
2039
+ data-bf-chart-grid
2040
+ class="stroke-chart-grid"
2041
+ stroke-width="1"
2042
+ [attr.x1]="line.x1"
2043
+ [attr.x2]="line.x2"
2044
+ [attr.y1]="line.y1"
2045
+ [attr.y2]="line.y2"
2046
+ />
2047
+ }
2048
+ @for (label of g.labels; track $index) {
2049
+ <text
2050
+ [class]="axisTextClasses"
2051
+ [attr.data-bf-chart-category]="label.key >= 0 ? '' : null"
2052
+ [attr.dominant-baseline]="label.anchor === 'middle' ? null : 'middle'"
2053
+ [attr.x]="label.x"
2054
+ [attr.y]="label.y"
2055
+ [attr.text-anchor]="label.anchor"
2056
+ >
2057
+ {{ label.text }}
2058
+ </text>
2059
+ }
2060
+ <!-- Re-created on every data change, so the enter motion replays. -->
2061
+ @for (generation of generations(); track generation) {
2062
+ <g>
2063
+ @for (bar of g.bars; track bar.key) {
2064
+ <rect
2065
+ data-bf-chart-bar
2066
+ rx="2"
2067
+ [attr.x]="bar.x"
2068
+ [attr.y]="bar.y"
2069
+ [attr.width]="bar.width"
2070
+ [attr.height]="bar.height"
2071
+ [class]="barClasses(bar)"
2072
+ />
2073
+ }
2074
+ </g>
2075
+ }
2076
+ <line
2077
+ data-bf-chart-axis
2078
+ class="stroke-chart-axis"
2079
+ stroke-width="1"
2080
+ [attr.x1]="g.axis.x1"
2081
+ [attr.x2]="g.axis.x2"
2082
+ [attr.y1]="g.axis.y1"
2083
+ [attr.y2]="g.axis.y2"
2084
+ />
2085
+ </svg>
2086
+ </bf-chart-frame>
2087
+ `
2088
+ }]
2089
+ }],
2090
+ propDecorators: {
2091
+ series: [{
2092
+ type: i0.Input,
2093
+ args: [{
2094
+ isSignal: true,
2095
+ alias: "series",
2096
+ required: true
2097
+ }]
2098
+ }],
2099
+ categories: [{
2100
+ type: i0.Input,
2101
+ args: [{
2102
+ isSignal: true,
2103
+ alias: "categories",
2104
+ required: true
2105
+ }]
2106
+ }],
2107
+ label: [{
2108
+ type: i0.Input,
2109
+ args: [{
2110
+ isSignal: true,
2111
+ alias: "label",
2112
+ required: false
2113
+ }]
2114
+ }],
2115
+ height: [{
2116
+ type: i0.Input,
2117
+ args: [{
2118
+ isSignal: true,
2119
+ alias: "height",
2120
+ required: false
2121
+ }]
2122
+ }],
2123
+ orientation: [{
2124
+ type: i0.Input,
2125
+ args: [{
2126
+ isSignal: true,
2127
+ alias: "orientation",
2128
+ required: false
2129
+ }]
2130
+ }],
2131
+ stacked: [{
2132
+ type: i0.Input,
2133
+ args: [{
2134
+ isSignal: true,
2135
+ alias: "stacked",
2136
+ required: false
2137
+ }]
2138
+ }],
2139
+ valueFormat: [{
2140
+ type: i0.Input,
2141
+ args: [{
2142
+ isSignal: true,
2143
+ alias: "valueFormat",
2144
+ required: false
2145
+ }]
2146
+ }],
2147
+ legend: [{
2148
+ type: i0.Input,
2149
+ args: [{
2150
+ isSignal: true,
2151
+ alias: "legend",
2152
+ required: false
2153
+ }]
2154
+ }],
2155
+ frame: [{
2156
+ type: i0.ViewChild,
2157
+ args: [i0.forwardRef(() => BfChartFrameComponent), { isSignal: true }]
2158
+ }]
2159
+ }
2160
+ });
2161
+ const FALLBACK_WIDTH$1 = 320;
2162
+ const MARGIN = 4;
2163
+ const ACTIVE_GROW = 6;
2164
+ const SLICE_GAP = 2;
2165
+ const TAU = Math.PI * 2;
2166
+ const SLICE = "fill-none [stroke-dasharray:1] animate-chart-draw transition-[stroke-width] duration-150 motion-reduce:animate-none motion-reduce:transition-none";
2167
+ var BfDonutChartComponent = class BfDonutChartComponent {
2168
+ slices = input.required(...ngDevMode ? [{ debugName: "slices" }] : /* istanbul ignore next */ []);
2169
+ label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
2170
+ height = input(220, {
2171
+ ...ngDevMode ? { debugName: "height" } : /* istanbul ignore next */ {},
2172
+ transform: numberAttribute
2173
+ });
2174
+ thickness = input(28, {
2175
+ ...ngDevMode ? { debugName: "thickness" } : /* istanbul ignore next */ {},
2176
+ transform: numberAttribute
2177
+ });
2178
+ valueFormat = input(void 0, ...ngDevMode ? [{ debugName: "valueFormat" }] : /* istanbul ignore next */ []);
2179
+ legend = input(void 0, ...ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []);
2180
+ interaction = new ChartInteraction();
2181
+ labels = inject(BF_LABELS);
2182
+ card = inject(BF_CHART_CARD, { optional: true });
2183
+ document = inject(DOCUMENT);
2184
+ frame = viewChild.required(BfChartFrameComponent, ...ngDevMode ? [{ debugName: "frame" }] : /* istanbul ignore next */ []);
2185
+ box = observeWidth(() => this.frame().plotElement(), FALLBACK_WIDTH$1);
2186
+ percent = percentFormat(this.document);
2187
+ growBy = ACTIVE_GROW;
2188
+ name = computed(() => this.label() || (this.card?.title() ?? "") || this.labels.chart, ...ngDevMode ? [{ debugName: "name" }] : /* istanbul ignore next */ []);
2189
+ legendPosition = computed(() => this.legend() ?? this.card?.legend() ?? "bottom", ...ngDevMode ? [{ debugName: "legendPosition" }] : /* istanbul ignore next */ []);
2190
+ format = computed(() => this.valueFormat() ?? defaultValueFormat(this.document), ...ngDevMode ? [{ debugName: "format" }] : /* istanbul ignore next */ []);
2191
+ generations = computed(() => [{ slices: this.slices() }], ...ngDevMode ? [{ debugName: "generations" }] : /* istanbul ignore next */ []);
2192
+ viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []);
2193
+ drawn = computed(() => this.slices().map((_, i) => i).filter((i) => !this.interaction.isHidden(i) && this.share(i) > 0), ...ngDevMode ? [{ debugName: "drawn" }] : /* istanbul ignore next */ []);
2194
+ total = computed(() => this.drawn().reduce((sum, i) => sum + (this.slices()[i]?.value ?? 0), 0), ...ngDevMode ? [{ debugName: "total" }] : /* istanbul ignore next */ []);
2195
+ share(index) {
2196
+ const v = this.slices()[index]?.value ?? 0;
2197
+ return Number.isFinite(v) && v > 0 ? v : 0;
2198
+ }
2199
+ geometry = computed(() => {
2200
+ const width = this.box.width();
2201
+ const height = this.height();
2202
+ const rtl = this.box.rtl();
2203
+ const outer = Math.max(1, Math.min(width, height) / 2 - MARGIN - ACTIVE_GROW / 2);
2204
+ const thickness = clamp(this.thickness(), 1, outer);
2205
+ const r = outer - thickness / 2;
2206
+ const cx = width / 2;
2207
+ const cy = height / 2;
2208
+ const at = (angle, radius = r) => ({
2209
+ x: px(mirror(cx + radius * Math.sin(angle), width, rtl)),
2210
+ y: px(cy - radius * Math.cos(angle))
2211
+ });
2212
+ const sweep = rtl ? 0 : 1;
2213
+ const arc = (a0, a1) => {
2214
+ const p0 = at(a0);
2215
+ const p1 = at(a1);
2216
+ const large = a1 - a0 > Math.PI ? 1 : 0;
2217
+ return `M${p0.x},${p0.y}A${px(r)},${px(r)} 0 ${large} ${sweep} ${p1.x},${p1.y}`;
2218
+ };
2219
+ const total = this.total();
2220
+ const drawn = this.drawn();
2221
+ const pad = drawn.length > 1 ? SLICE_GAP / Math.max(1, r) : 0;
2222
+ let angle = 0;
2223
+ const slices = drawn.map((index) => {
2224
+ const sweepAngle = total > 0 ? this.share(index) / total * TAU : 0;
2225
+ const start = angle;
2226
+ const end = angle + sweepAngle;
2227
+ angle = end;
2228
+ const inset = sweepAngle > pad * 2 ? pad / 2 : 0;
2229
+ const a0 = start + inset;
2230
+ const a1 = end - inset;
2231
+ return {
2232
+ index,
2233
+ d: a1 - a0 >= TAU - 1e-6 ? arc(0, Math.PI) + arc(Math.PI, TAU).replace(/^M[^A]+/, "") : arc(a0, a1),
2234
+ start,
2235
+ end
2236
+ };
2237
+ });
2238
+ return {
2239
+ width,
2240
+ cx: px(cx),
2241
+ cy: px(cy),
2242
+ r: px(r),
2243
+ thickness,
2244
+ rtl,
2245
+ slices,
2246
+ at
2247
+ };
2248
+ }, ...ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []);
2249
+ legendItems = computed(() => {
2250
+ const slices = this.slices();
2251
+ return slices.length < 2 ? [] : slices.map((s, i) => ({
2252
+ name: s.label,
2253
+ swatch: seriesSwatch(i),
2254
+ hidden: this.interaction.isHidden(i)
2255
+ }));
2256
+ }, ...ngDevMode ? [{ debugName: "legendItems" }] : /* istanbul ignore next */ []);
2257
+ active = computed(() => {
2258
+ const at = this.interaction.active();
2259
+ return at !== null && this.drawn().includes(at) ? at : null;
2260
+ }, ...ngDevMode ? [{ debugName: "active" }] : /* istanbul ignore next */ []);
2261
+ valueText(index) {
2262
+ const total = this.total();
2263
+ const value = this.share(index);
2264
+ return `${this.format()(value)} (${this.percent(total > 0 ? value / total : 0)})`;
2265
+ }
2266
+ tooltip = computed(() => {
2267
+ const index = this.active();
2268
+ const g = this.geometry();
2269
+ const slice = g.slices.find((s) => s.index === index);
2270
+ if (index === null || !slice) return null;
2271
+ const point = g.at((slice.start + slice.end) / 2);
2272
+ return {
2273
+ title: "",
2274
+ rows: [{
2275
+ name: this.slices()[index]?.label ?? "",
2276
+ value: this.valueText(index),
2277
+ swatch: seriesSwatch(index)
2278
+ }],
2279
+ x: point.x,
2280
+ y: point.y
2281
+ };
2282
+ }, ...ngDevMode ? [{ debugName: "tooltip" }] : /* istanbul ignore next */ []);
2283
+ table = computed(() => ({
2284
+ head: [this.labels.chartCategory, this.labels.chartValue],
2285
+ rows: this.slices().map((s) => [s.label, this.format()(s.value)])
2286
+ }), ...ngDevMode ? [{ debugName: "table" }] : /* istanbul ignore next */ []);
2287
+ sliceClasses(index) {
2288
+ return `${SLICE} ${seriesStroke(index)}`;
2289
+ }
2290
+ onPointed(pointer) {
2291
+ const g = this.geometry();
2292
+ const dx = mirror(pointer.x, g.width, g.rtl) - g.cx;
2293
+ const dy = pointer.y - g.cy;
2294
+ const distance = Math.hypot(dx, dy);
2295
+ const reach = g.thickness / 2 + ACTIVE_GROW;
2296
+ if (Math.abs(distance - g.r) > reach) {
2297
+ this.interaction.point(null);
2298
+ return;
2299
+ }
2300
+ const angle = (Math.atan2(dx, -dy) + TAU) % TAU;
2301
+ const slice = g.slices.find((s) => angle >= s.start && angle < s.end);
2302
+ this.interaction.point(slice?.index ?? null);
2303
+ }
2304
+ onStep(step) {
2305
+ this.interaction.step(step, this.drawn(), (i) => `${this.slices()[i]?.label ?? ""}: ${this.valueText(i)}`);
2306
+ }
2307
+ onFocus(focused) {
2308
+ if (!focused) this.interaction.point(null);
2309
+ else if (this.interaction.active() === null) this.onStep("first");
2310
+ }
2311
+ static ɵfac = i0.ɵɵngDeclareFactory({
2312
+ minVersion: "12.0.0",
2313
+ version: "22.1.7",
2314
+ ngImport: i0,
2315
+ type: BfDonutChartComponent,
2316
+ deps: [],
2317
+ target: i0.ɵɵFactoryTarget.Component
2318
+ });
2319
+ static ɵcmp = i0.ɵɵngDeclareComponent({
2320
+ minVersion: "17.0.0",
2321
+ version: "22.1.7",
2322
+ type: BfDonutChartComponent,
2323
+ isStandalone: true,
2324
+ selector: "bf-donut-chart",
2325
+ inputs: {
2326
+ slices: {
2327
+ classPropertyName: "slices",
2328
+ publicName: "slices",
2329
+ isSignal: true,
2330
+ isRequired: true,
2331
+ transformFunction: null
2332
+ },
2333
+ label: {
2334
+ classPropertyName: "label",
2335
+ publicName: "label",
2336
+ isSignal: true,
2337
+ isRequired: false,
2338
+ transformFunction: null
2339
+ },
2340
+ height: {
2341
+ classPropertyName: "height",
2342
+ publicName: "height",
2343
+ isSignal: true,
2344
+ isRequired: false,
2345
+ transformFunction: null
2346
+ },
2347
+ thickness: {
2348
+ classPropertyName: "thickness",
2349
+ publicName: "thickness",
2350
+ isSignal: true,
2351
+ isRequired: false,
2352
+ transformFunction: null
2353
+ },
2354
+ valueFormat: {
2355
+ classPropertyName: "valueFormat",
2356
+ publicName: "valueFormat",
2357
+ isSignal: true,
2358
+ isRequired: false,
2359
+ transformFunction: null
2360
+ },
2361
+ legend: {
2362
+ classPropertyName: "legend",
2363
+ publicName: "legend",
2364
+ isSignal: true,
2365
+ isRequired: false,
2366
+ transformFunction: null
2367
+ }
2368
+ },
2369
+ host: { classAttribute: "block w-full min-w-0" },
2370
+ viewQueries: [{
2371
+ propertyName: "frame",
2372
+ first: true,
2373
+ predicate: BfChartFrameComponent,
2374
+ descendants: true,
2375
+ isSignal: true
2376
+ }],
2377
+ ngImport: i0,
2378
+ template: `
2379
+ <bf-chart-frame
2380
+ [label]="name()"
2381
+ [height]="height()"
2382
+ [legend]="legendItems()"
2383
+ [legendPosition]="legendPosition()"
2384
+ [tooltip]="tooltip()"
2385
+ [announcement]="interaction.announcement()"
2386
+ [table]="table()"
2387
+ (legendToggled)="interaction.toggle($event)"
2388
+ (pointed)="onPointed($event)"
2389
+ (left)="interaction.point(null)"
2390
+ (stepped)="onStep($event)"
2391
+ (focusChanged)="onFocus($event)"
2392
+ >
2393
+ <svg
2394
+ aria-hidden="true"
2395
+ focusable="false"
2396
+ direction="ltr"
2397
+ class="block w-full overflow-visible"
2398
+ [attr.height]="height()"
2399
+ [attr.viewBox]="viewBox()"
2400
+ >
2401
+ @let g = geometry();
2402
+ <circle
2403
+ data-bf-chart-track
2404
+ class="stroke-chart-grid fill-none"
2405
+ [attr.cx]="g.cx"
2406
+ [attr.cy]="g.cy"
2407
+ [attr.r]="g.r"
2408
+ [attr.stroke-width]="g.thickness"
2409
+ />
2410
+ <!-- Re-created on every data change, so the enter motion replays. -->
2411
+ @for (generation of generations(); track generation) {
2412
+ <g>
2413
+ @for (slice of g.slices; track slice.index) {
2414
+ <path
2415
+ data-bf-chart-slice
2416
+ pathLength="1"
2417
+ [attr.d]="slice.d"
2418
+ [attr.stroke-width]="slice.index === active() ? g.thickness + growBy : g.thickness"
2419
+ [class]="sliceClasses(slice.index)"
2420
+ />
2421
+ }
2422
+ </g>
2423
+ }
2424
+ </svg>
2425
+ <div
2426
+ data-bf-chart-center
2427
+ class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center empty:hidden"
2428
+ >
2429
+ <ng-content select="[bfSlot=center]" />
2430
+ </div>
2431
+ </bf-chart-frame>
2432
+ `,
2433
+ isInline: true,
2434
+ dependencies: [{
2435
+ kind: "component",
2436
+ type: BfChartFrameComponent,
2437
+ selector: "bf-chart-frame",
2438
+ inputs: [
2439
+ "label",
2440
+ "height",
2441
+ "legend",
2442
+ "legendPosition",
2443
+ "tooltip",
2444
+ "announcement",
2445
+ "table",
2446
+ "dataToggle",
2447
+ "vertical"
2448
+ ],
2449
+ outputs: [
2450
+ "legendToggled",
2451
+ "pointed",
2452
+ "left",
2453
+ "stepped",
2454
+ "focusChanged"
2455
+ ]
2456
+ }]
2457
+ });
2458
+ };
2459
+ i0.ɵɵngDeclareClassMetadata({
2460
+ minVersion: "12.0.0",
2461
+ version: "22.1.7",
2462
+ ngImport: i0,
2463
+ type: BfDonutChartComponent,
2464
+ decorators: [{
2465
+ type: Component,
2466
+ args: [{
2467
+ selector: "bf-donut-chart",
2468
+ imports: [BfChartFrameComponent],
2469
+ host: { class: "block w-full min-w-0" },
2470
+ template: `
2471
+ <bf-chart-frame
2472
+ [label]="name()"
2473
+ [height]="height()"
2474
+ [legend]="legendItems()"
2475
+ [legendPosition]="legendPosition()"
2476
+ [tooltip]="tooltip()"
2477
+ [announcement]="interaction.announcement()"
2478
+ [table]="table()"
2479
+ (legendToggled)="interaction.toggle($event)"
2480
+ (pointed)="onPointed($event)"
2481
+ (left)="interaction.point(null)"
2482
+ (stepped)="onStep($event)"
2483
+ (focusChanged)="onFocus($event)"
2484
+ >
2485
+ <svg
2486
+ aria-hidden="true"
2487
+ focusable="false"
2488
+ direction="ltr"
2489
+ class="block w-full overflow-visible"
2490
+ [attr.height]="height()"
2491
+ [attr.viewBox]="viewBox()"
2492
+ >
2493
+ @let g = geometry();
2494
+ <circle
2495
+ data-bf-chart-track
2496
+ class="stroke-chart-grid fill-none"
2497
+ [attr.cx]="g.cx"
2498
+ [attr.cy]="g.cy"
2499
+ [attr.r]="g.r"
2500
+ [attr.stroke-width]="g.thickness"
2501
+ />
2502
+ <!-- Re-created on every data change, so the enter motion replays. -->
2503
+ @for (generation of generations(); track generation) {
2504
+ <g>
2505
+ @for (slice of g.slices; track slice.index) {
2506
+ <path
2507
+ data-bf-chart-slice
2508
+ pathLength="1"
2509
+ [attr.d]="slice.d"
2510
+ [attr.stroke-width]="slice.index === active() ? g.thickness + growBy : g.thickness"
2511
+ [class]="sliceClasses(slice.index)"
2512
+ />
2513
+ }
2514
+ </g>
2515
+ }
2516
+ </svg>
2517
+ <div
2518
+ data-bf-chart-center
2519
+ class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center empty:hidden"
2520
+ >
2521
+ <ng-content select="[bfSlot=center]" />
2522
+ </div>
2523
+ </bf-chart-frame>
2524
+ `
2525
+ }]
2526
+ }],
2527
+ propDecorators: {
2528
+ slices: [{
2529
+ type: i0.Input,
2530
+ args: [{
2531
+ isSignal: true,
2532
+ alias: "slices",
2533
+ required: true
2534
+ }]
2535
+ }],
2536
+ label: [{
2537
+ type: i0.Input,
2538
+ args: [{
2539
+ isSignal: true,
2540
+ alias: "label",
2541
+ required: false
2542
+ }]
2543
+ }],
2544
+ height: [{
2545
+ type: i0.Input,
2546
+ args: [{
2547
+ isSignal: true,
2548
+ alias: "height",
2549
+ required: false
2550
+ }]
2551
+ }],
2552
+ thickness: [{
2553
+ type: i0.Input,
2554
+ args: [{
2555
+ isSignal: true,
2556
+ alias: "thickness",
2557
+ required: false
2558
+ }]
2559
+ }],
2560
+ valueFormat: [{
2561
+ type: i0.Input,
2562
+ args: [{
2563
+ isSignal: true,
2564
+ alias: "valueFormat",
2565
+ required: false
2566
+ }]
2567
+ }],
2568
+ legend: [{
2569
+ type: i0.Input,
2570
+ args: [{
2571
+ isSignal: true,
2572
+ alias: "legend",
2573
+ required: false
2574
+ }]
2575
+ }],
2576
+ frame: [{
2577
+ type: i0.ViewChild,
2578
+ args: [i0.forwardRef(() => BfChartFrameComponent), { isSignal: true }]
2579
+ }]
2580
+ }
2581
+ });
2582
+ const FALLBACK_WIDTH = 120;
2583
+ const PAD = 3;
2584
+ const LINE = "fill-none stroke-chart-1 [stroke-dasharray:1] animate-chart-draw motion-reduce:animate-none";
2585
+ const AREA = "fill-chart-1/16 stroke-none animate-chart-fade motion-reduce:animate-none";
2586
+ const DOT = "fill-chart-1 animate-chart-fade motion-reduce:animate-none";
2587
+ var BfSparklineComponent = class BfSparklineComponent {
2588
+ values = input.required(...ngDevMode ? [{ debugName: "values" }] : /* istanbul ignore next */ []);
2589
+ label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
2590
+ height = input(32, {
2591
+ ...ngDevMode ? { debugName: "height" } : /* istanbul ignore next */ {},
2592
+ transform: numberAttribute
2593
+ });
2594
+ area = input(false, {
2595
+ ...ngDevMode ? { debugName: "area" } : /* istanbul ignore next */ {},
2596
+ transform: booleanAttribute
2597
+ });
2598
+ curve = input("linear", ...ngDevMode ? [{ debugName: "curve" }] : /* istanbul ignore next */ []);
2599
+ host = inject(ElementRef);
2600
+ box = observeWidth(() => this.host.nativeElement, FALLBACK_WIDTH);
2601
+ lineClasses = LINE;
2602
+ areaClasses = AREA;
2603
+ dotClasses = DOT;
2604
+ generations = computed(() => [{ values: this.values() }], ...ngDevMode ? [{ debugName: "generations" }] : /* istanbul ignore next */ []);
2605
+ viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`, ...ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []);
2606
+ geometry = computed(() => {
2607
+ const width = this.box.width();
2608
+ const height = this.height();
2609
+ const rtl = this.box.rtl();
2610
+ const values = this.values();
2611
+ const finite = values.filter((v) => v !== null && Number.isFinite(v));
2612
+ const lo = Math.min(...finite);
2613
+ const span = Math.max(...finite) - lo;
2614
+ const n = values.length;
2615
+ const xAt = (i) => mirror(n > 1 ? PAD + i * (width - PAD * 2) / (n - 1) : width / 2, width, rtl);
2616
+ const yAt = (v) => span > 0 ? PAD + (1 - (v - lo) / span) * (height - PAD * 2) : height / 2;
2617
+ const points = values.map((v, i) => v === null || !Number.isFinite(v) ? null : {
2618
+ x: xAt(i),
2619
+ y: yAt(v)
2620
+ });
2621
+ const runs = segments(points);
2622
+ const lastRun = runs[runs.length - 1];
2623
+ const lastPoint = lastRun?.[lastRun.length - 1];
2624
+ return {
2625
+ line: linePath(points, this.curve()),
2626
+ area: areaPath(points, this.curve(), height),
2627
+ last: lastPoint ? {
2628
+ x: px(lastPoint.x),
2629
+ y: px(lastPoint.y)
2630
+ } : null
2631
+ };
2632
+ }, ...ngDevMode ? [{ debugName: "geometry" }] : /* istanbul ignore next */ []);
2633
+ static ɵfac = i0.ɵɵngDeclareFactory({
2634
+ minVersion: "12.0.0",
2635
+ version: "22.1.7",
2636
+ ngImport: i0,
2637
+ type: BfSparklineComponent,
2638
+ deps: [],
2639
+ target: i0.ɵɵFactoryTarget.Component
2640
+ });
2641
+ static ɵcmp = i0.ɵɵngDeclareComponent({
2642
+ minVersion: "17.0.0",
2643
+ version: "22.1.7",
2644
+ type: BfSparklineComponent,
2645
+ isStandalone: true,
2646
+ selector: "bf-sparkline",
2647
+ inputs: {
2648
+ values: {
2649
+ classPropertyName: "values",
2650
+ publicName: "values",
2651
+ isSignal: true,
2652
+ isRequired: true,
2653
+ transformFunction: null
2654
+ },
2655
+ label: {
2656
+ classPropertyName: "label",
2657
+ publicName: "label",
2658
+ isSignal: true,
2659
+ isRequired: false,
2660
+ transformFunction: null
2661
+ },
2662
+ height: {
2663
+ classPropertyName: "height",
2664
+ publicName: "height",
2665
+ isSignal: true,
2666
+ isRequired: false,
2667
+ transformFunction: null
2668
+ },
2669
+ area: {
2670
+ classPropertyName: "area",
2671
+ publicName: "area",
2672
+ isSignal: true,
2673
+ isRequired: false,
2674
+ transformFunction: null
2675
+ },
2676
+ curve: {
2677
+ classPropertyName: "curve",
2678
+ publicName: "curve",
2679
+ isSignal: true,
2680
+ isRequired: false,
2681
+ transformFunction: null
2682
+ }
2683
+ },
2684
+ host: { classAttribute: "block min-w-0" },
2685
+ ngImport: i0,
2686
+ template: `
2687
+ <svg
2688
+ focusable="false"
2689
+ direction="ltr"
2690
+ class="block w-full overflow-visible"
2691
+ [attr.role]="label() ? 'img' : null"
2692
+ [attr.aria-label]="label() || null"
2693
+ [attr.aria-hidden]="label() ? null : 'true'"
2694
+ [attr.height]="height()"
2695
+ [attr.viewBox]="viewBox()"
2696
+ >
2697
+ @let g = geometry();
2698
+ @for (generation of generations(); track generation) {
2699
+ <g>
2700
+ @if (area()) {
2701
+ <path data-bf-sparkline-area [attr.d]="g.area" [class]="areaClasses" />
2702
+ }
2703
+ <path
2704
+ data-bf-sparkline-line
2705
+ pathLength="1"
2706
+ stroke-width="2"
2707
+ stroke-linejoin="round"
2708
+ stroke-linecap="round"
2709
+ [attr.d]="g.line"
2710
+ [class]="lineClasses"
2711
+ />
2712
+ @if (g.last; as last) {
2713
+ <circle
2714
+ data-bf-sparkline-dot
2715
+ r="2.5"
2716
+ [attr.cx]="last.x"
2717
+ [attr.cy]="last.y"
2718
+ [class]="dotClasses"
2719
+ />
2720
+ }
2721
+ </g>
2722
+ }
2723
+ </svg>
2724
+ `,
2725
+ isInline: true
2726
+ });
2727
+ };
2728
+ i0.ɵɵngDeclareClassMetadata({
2729
+ minVersion: "12.0.0",
2730
+ version: "22.1.7",
2731
+ ngImport: i0,
2732
+ type: BfSparklineComponent,
2733
+ decorators: [{
2734
+ type: Component,
2735
+ args: [{
2736
+ selector: "bf-sparkline",
2737
+ host: { class: "block min-w-0" },
2738
+ template: `
2739
+ <svg
2740
+ focusable="false"
2741
+ direction="ltr"
2742
+ class="block w-full overflow-visible"
2743
+ [attr.role]="label() ? 'img' : null"
2744
+ [attr.aria-label]="label() || null"
2745
+ [attr.aria-hidden]="label() ? null : 'true'"
2746
+ [attr.height]="height()"
2747
+ [attr.viewBox]="viewBox()"
2748
+ >
2749
+ @let g = geometry();
2750
+ @for (generation of generations(); track generation) {
2751
+ <g>
2752
+ @if (area()) {
2753
+ <path data-bf-sparkline-area [attr.d]="g.area" [class]="areaClasses" />
2754
+ }
2755
+ <path
2756
+ data-bf-sparkline-line
2757
+ pathLength="1"
2758
+ stroke-width="2"
2759
+ stroke-linejoin="round"
2760
+ stroke-linecap="round"
2761
+ [attr.d]="g.line"
2762
+ [class]="lineClasses"
2763
+ />
2764
+ @if (g.last; as last) {
2765
+ <circle
2766
+ data-bf-sparkline-dot
2767
+ r="2.5"
2768
+ [attr.cx]="last.x"
2769
+ [attr.cy]="last.y"
2770
+ [class]="dotClasses"
2771
+ />
2772
+ }
2773
+ </g>
2774
+ }
2775
+ </svg>
2776
+ `
2777
+ }]
2778
+ }],
2779
+ propDecorators: {
2780
+ values: [{
2781
+ type: i0.Input,
2782
+ args: [{
2783
+ isSignal: true,
2784
+ alias: "values",
2785
+ required: true
2786
+ }]
2787
+ }],
2788
+ label: [{
2789
+ type: i0.Input,
2790
+ args: [{
2791
+ isSignal: true,
2792
+ alias: "label",
2793
+ required: false
2794
+ }]
2795
+ }],
2796
+ height: [{
2797
+ type: i0.Input,
2798
+ args: [{
2799
+ isSignal: true,
2800
+ alias: "height",
2801
+ required: false
2802
+ }]
2803
+ }],
2804
+ area: [{
2805
+ type: i0.Input,
2806
+ args: [{
2807
+ isSignal: true,
2808
+ alias: "area",
2809
+ required: false
2810
+ }]
2811
+ }],
2812
+ curve: [{
2813
+ type: i0.Input,
2814
+ args: [{
2815
+ isSignal: true,
2816
+ alias: "curve",
2817
+ required: false
2818
+ }]
2819
+ }]
2820
+ }
2821
+ });
2822
+ const HOST = "flex h-full min-w-0 flex-col gap-4 rounded-card border-[1.5px] border-border-strong bg-surface p-card text-start text-text";
2823
+ const STATE = "flex min-h-60 flex-col items-center justify-center gap-2 rounded-tile text-center text-body text-text-muted";
2824
+ var BfChartCardComponent = class BfChartCardComponent {
2825
+ title = input.required(...ngDevMode ? [{ debugName: "title" }] : /* istanbul ignore next */ []);
2826
+ headingLevel = input(2, ...ngDevMode ? [{ debugName: "headingLevel" }] : /* istanbul ignore next */ []);
2827
+ legend = input("bottom", ...ngDevMode ? [{ debugName: "legend" }] : /* istanbul ignore next */ []);
2828
+ loading = input(false, {
2829
+ ...ngDevMode ? { debugName: "loading" } : /* istanbul ignore next */ {},
2830
+ transform: booleanAttribute
2831
+ });
2832
+ empty = input(false, {
2833
+ ...ngDevMode ? { debugName: "empty" } : /* istanbul ignore next */ {},
2834
+ transform: booleanAttribute
2835
+ });
2836
+ error = input(false, {
2837
+ ...ngDevMode ? { debugName: "error" } : /* istanbul ignore next */ {},
2838
+ transform: booleanAttribute
2839
+ });
2840
+ labels = inject(BF_LABELS);
2841
+ hostClasses = HOST;
2842
+ stateClasses = STATE;
2843
+ static ɵfac = i0.ɵɵngDeclareFactory({
2844
+ minVersion: "12.0.0",
2845
+ version: "22.1.7",
2846
+ ngImport: i0,
2847
+ type: BfChartCardComponent,
2848
+ deps: [],
2849
+ target: i0.ɵɵFactoryTarget.Component
2850
+ });
2851
+ static ɵcmp = i0.ɵɵngDeclareComponent({
2852
+ minVersion: "17.0.0",
2853
+ version: "22.1.7",
2854
+ type: BfChartCardComponent,
2855
+ isStandalone: true,
2856
+ selector: "bf-chart-card",
2857
+ inputs: {
2858
+ title: {
2859
+ classPropertyName: "title",
2860
+ publicName: "title",
2861
+ isSignal: true,
2862
+ isRequired: true,
2863
+ transformFunction: null
2864
+ },
2865
+ headingLevel: {
2866
+ classPropertyName: "headingLevel",
2867
+ publicName: "headingLevel",
2868
+ isSignal: true,
2869
+ isRequired: false,
2870
+ transformFunction: null
2871
+ },
2872
+ legend: {
2873
+ classPropertyName: "legend",
2874
+ publicName: "legend",
2875
+ isSignal: true,
2876
+ isRequired: false,
2877
+ transformFunction: null
2878
+ },
2879
+ loading: {
2880
+ classPropertyName: "loading",
2881
+ publicName: "loading",
2882
+ isSignal: true,
2883
+ isRequired: false,
2884
+ transformFunction: null
2885
+ },
2886
+ empty: {
2887
+ classPropertyName: "empty",
2888
+ publicName: "empty",
2889
+ isSignal: true,
2890
+ isRequired: false,
2891
+ transformFunction: null
2892
+ },
2893
+ error: {
2894
+ classPropertyName: "error",
2895
+ publicName: "error",
2896
+ isSignal: true,
2897
+ isRequired: false,
2898
+ transformFunction: null
2899
+ }
2900
+ },
2901
+ host: { properties: { "class": "hostClasses" } },
2902
+ providers: [{
2903
+ provide: BF_CHART_CARD,
2904
+ useExisting: BfChartCardComponent
2905
+ }],
2906
+ ngImport: i0,
2907
+ template: `
2908
+ <div class="flex flex-wrap items-center justify-between gap-x-4 gap-y-2">
2909
+ @if (headingLevel() === 3) {
2910
+ <h3 class="text-heading text-text min-w-0">{{ title() }}</h3>
2911
+ } @else {
2912
+ <h2 class="text-heading text-text min-w-0">{{ title() }}</h2>
2913
+ }
2914
+ <div data-bf-chart-card-period class="shrink-0 empty:hidden">
2915
+ <ng-content select="[bfSlot=period]" />
2916
+ </div>
2917
+ </div>
2918
+ <div data-bf-chart-card-body class="min-w-0" [attr.aria-busy]="loading() ? 'true' : null">
2919
+ @if (loading()) {
2920
+ <bf-skeleton shape="rect" height="15rem" />
2921
+ } @else if (error()) {
2922
+ <div data-bf-chart-card-error role="status" [class]="stateClasses">
2923
+ <ng-content select="[bfSlot=error]">{{ labels.chartError }}</ng-content>
2924
+ </div>
2925
+ } @else if (empty()) {
2926
+ <div data-bf-chart-card-empty role="status" [class]="stateClasses">
2927
+ <ng-content select="[bfSlot=empty]">{{ labels.chartEmpty }}</ng-content>
2928
+ </div>
2929
+ } @else {
2930
+ <ng-content />
2931
+ }
2932
+ </div>
2933
+ `,
2934
+ isInline: true,
2935
+ dependencies: [{
2936
+ kind: "component",
2937
+ type: BfSkeletonComponent,
2938
+ selector: "bf-skeleton",
2939
+ inputs: [
2940
+ "shape",
2941
+ "lines",
2942
+ "width",
2943
+ "height"
2944
+ ]
2945
+ }]
2946
+ });
2947
+ };
2948
+ i0.ɵɵngDeclareClassMetadata({
2949
+ minVersion: "12.0.0",
2950
+ version: "22.1.7",
2951
+ ngImport: i0,
2952
+ type: BfChartCardComponent,
2953
+ decorators: [{
2954
+ type: Component,
2955
+ args: [{
2956
+ selector: "bf-chart-card",
2957
+ imports: [BfSkeletonComponent],
2958
+ host: { "[class]": "hostClasses" },
2959
+ providers: [{
2960
+ provide: BF_CHART_CARD,
2961
+ useExisting: BfChartCardComponent
2962
+ }],
2963
+ template: `
2964
+ <div class="flex flex-wrap items-center justify-between gap-x-4 gap-y-2">
2965
+ @if (headingLevel() === 3) {
2966
+ <h3 class="text-heading text-text min-w-0">{{ title() }}</h3>
2967
+ } @else {
2968
+ <h2 class="text-heading text-text min-w-0">{{ title() }}</h2>
2969
+ }
2970
+ <div data-bf-chart-card-period class="shrink-0 empty:hidden">
2971
+ <ng-content select="[bfSlot=period]" />
2972
+ </div>
2973
+ </div>
2974
+ <div data-bf-chart-card-body class="min-w-0" [attr.aria-busy]="loading() ? 'true' : null">
2975
+ @if (loading()) {
2976
+ <bf-skeleton shape="rect" height="15rem" />
2977
+ } @else if (error()) {
2978
+ <div data-bf-chart-card-error role="status" [class]="stateClasses">
2979
+ <ng-content select="[bfSlot=error]">{{ labels.chartError }}</ng-content>
2980
+ </div>
2981
+ } @else if (empty()) {
2982
+ <div data-bf-chart-card-empty role="status" [class]="stateClasses">
2983
+ <ng-content select="[bfSlot=empty]">{{ labels.chartEmpty }}</ng-content>
2984
+ </div>
2985
+ } @else {
2986
+ <ng-content />
2987
+ }
2988
+ </div>
2989
+ `
2990
+ }]
2991
+ }],
2992
+ propDecorators: {
2993
+ title: [{
2994
+ type: i0.Input,
2995
+ args: [{
2996
+ isSignal: true,
2997
+ alias: "title",
2998
+ required: true
2999
+ }]
3000
+ }],
3001
+ headingLevel: [{
3002
+ type: i0.Input,
3003
+ args: [{
3004
+ isSignal: true,
3005
+ alias: "headingLevel",
3006
+ required: false
3007
+ }]
3008
+ }],
3009
+ legend: [{
3010
+ type: i0.Input,
3011
+ args: [{
3012
+ isSignal: true,
3013
+ alias: "legend",
3014
+ required: false
3015
+ }]
3016
+ }],
3017
+ loading: [{
3018
+ type: i0.Input,
3019
+ args: [{
3020
+ isSignal: true,
3021
+ alias: "loading",
3022
+ required: false
3023
+ }]
3024
+ }],
3025
+ empty: [{
3026
+ type: i0.Input,
3027
+ args: [{
3028
+ isSignal: true,
3029
+ alias: "empty",
3030
+ required: false
3031
+ }]
3032
+ }],
3033
+ error: [{
3034
+ type: i0.Input,
3035
+ args: [{
3036
+ isSignal: true,
3037
+ alias: "error",
3038
+ required: false
3039
+ }]
3040
+ }]
3041
+ }
3042
+ });
3043
+ export { BfBarChartComponent, BfChartCardComponent, BfDonutChartComponent, BfLineChartComponent, BfSparklineComponent };
3044
+
3045
+ //# sourceMappingURL=bitforgehq-ui-charts.mjs.map