@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 @@
1
+ {"version":3,"file":"bitforgehq-ui-charts.mjs","names":[],"sources":["../../../projects/ui/charts/core/axis.ts","../../../projects/ui/charts/core/chart-card.token.ts","../../../projects/ui/charts/core/chart-format.ts","../../../projects/ui/charts/core/chart-swatch.ts","../../../projects/ui/charts/core/chart-tooltip.component.ts","../../../projects/ui/charts/core/chart-frame.component.ts","../../../projects/ui/charts/core/chart-interaction.ts","../../../projects/ui/charts/core/curve.ts","../../../projects/ui/charts/core/nice-ticks.ts","../../../projects/ui/charts/core/observe-width.ts","../../../projects/ui/charts/core/palette.ts","../../../projects/ui/charts/core/series-helpers.ts","../../../projects/ui/charts/line-chart/line-chart.component.ts","../../../projects/ui/charts/bar-chart/bar-chart.component.ts","../../../projects/ui/charts/donut-chart/donut-chart.component.ts","../../../projects/ui/charts/sparkline/sparkline.component.ts","../../../projects/ui/charts/chart-card/chart-card.component.ts"],"sourcesContent":["import { type BfChartSeries } from './chart-types';\n\n/* Axis text is `text-micro` (12 px); its width is estimated, not measured, so the geometry is a\n pure function of the data and the box (the same on the server and in a test). 7 px per\n character holds for digits and most Latin text in Manrope at 12 px. */\nconst CHAR_PX = 7;\n\n/** The estimated width in px of `text` set as axis text. */\nexport function textWidth(text: string): number {\n return text.length * CHAR_PX;\n}\n\n/**\n * Every how many categories a label fits along `room` px when each takes `slot` px: 1 shows\n * every label, 2 every other one, and so on.\n */\nexport function labelEvery(labels: readonly string[], room: number, slot: number): number {\n const widest = Math.max(0, ...labels.map(textWidth)) + 12;\n if (labels.length === 0 || room <= 0 || slot <= 0) {\n return 1;\n }\n return Math.max(1, Math.ceil(widest / slot));\n}\n\n/** The finite values of the series at `indexes`, each series' values in order. */\nexport function finiteValues(\n series: readonly BfChartSeries[],\n indexes: readonly number[],\n): number[] {\n return indexes.flatMap((i) =>\n (series[i]?.values ?? []).filter((v): v is number => v !== null && Number.isFinite(v)),\n );\n}\n\n/** Maps physical x to its mirror across a box `width` px wide under rtl, else keeps it. */\nexport function mirror(x: number, width: number, rtl: boolean): number {\n return rtl ? width - x : x;\n}\n\n/** A value in [lo, hi]. */\nexport function clamp(value: number, lo: number, hi: number): number {\n return Math.min(hi, Math.max(lo, value));\n}\n","import { InjectionToken, type Signal } from '@angular/core';\nimport { type BfChartLegendPosition } from './chart-types';\n\n/** What a `bf-chart-card` hands the chart inside it: its title and its legend placement. */\nexport interface ChartCardHost {\n /** The card's title, the chart's name when the chart has no `label`. */\n readonly title: Signal<string>;\n /** The card's legend placement, used when the chart sets none. */\n readonly legend: Signal<BfChartLegendPosition>;\n}\n\n/** Provided by `bf-chart-card` for the chart it holds. */\nexport const BF_CHART_CARD = new InjectionToken<ChartCardHost>('BF_CHART_CARD');\n","import { type BfChartValueFormat } from './chart-types';\n\n/** The document's `lang` as an `Intl` locale, or `undefined` (the runtime's) when it is empty or\n * not a valid tag. */\nexport function documentLocale(document: Document): string | undefined {\n const lang = document.documentElement.lang;\n if (!lang) {\n return undefined;\n }\n try {\n return Intl.NumberFormat.supportedLocalesOf(lang).length > 0 ? lang : undefined;\n } catch {\n return undefined;\n }\n}\n\n/** The default `valueFormat`: `Intl.NumberFormat` in the document's language. */\nexport function defaultValueFormat(document: Document): BfChartValueFormat {\n const format = new Intl.NumberFormat(documentLocale(document));\n return (value) => format.format(value);\n}\n\n/** A share (0…1) as a whole percentage in the document's language, such as `42%`. */\nexport function percentFormat(document: Document): (share: number) => string {\n const format = new Intl.NumberFormat(documentLocale(document), {\n style: 'percent',\n maximumFractionDigits: 0,\n });\n return (share) => format.format(share);\n}\n\n/** What a missing value reads as in the tooltip, the announcement and the table: an en dash. */\nexport const NO_VALUE = '–';\n\n/** Formats `value`, or the `NO_VALUE` dash for a gap. */\nexport function formatOrDash(value: number | null | undefined, format: BfChartValueFormat): string {\n return value === null || value === undefined || !Number.isFinite(value)\n ? NO_VALUE\n : format(value);\n}\n","/* A shown series' swatch is its colour; a hidden one is an empty ring, so hiding never rests on\n colour alone (the name is also struck through). Forced colours keep the ring in CanvasText. */\nconst SWATCH_BASE =\n 'size-2.5 shrink-0 rounded-full forced-colors:border forced-colors:border-[CanvasText]';\nconst SWATCH_HIDDEN = `${SWATCH_BASE} border-[1.5px] border-text-subtle bg-transparent`;\n/** A swatch's classes: its colour, or an empty ring while hidden. */\nexport function chartSwatchClasses(swatch: string, hidden: boolean): string {\n return hidden ? SWATCH_HIDDEN : `${SWATCH_BASE} ${swatch}`;\n}\n","import { Component, computed, input } from '@angular/core';\nimport { chartSwatchClasses } from './chart-swatch';\n\n/** One line of the tooltip: a swatch, a name and the formatted value. */\nexport interface ChartTooltipRow {\n readonly name: string;\n readonly value: string;\n readonly swatch: string;\n}\n\n/** The tooltip of the active point: a title (the category), its rows and where it points, in\n * px from the plot's physical top left. */\nexport interface ChartTooltip {\n readonly title: string;\n readonly rows: readonly ChartTooltipRow[];\n readonly x: number;\n readonly y: number;\n}\n\n/* The floating surface, never in the way of the pointer. */\nconst HOST =\n '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';\n\n/**\n * The tooltip of a chart's active point, placed beside it inside the plot. Physical `left`: the\n * plot's SVG coordinates are physical (the chart mirrors them under rtl), so the tooltip follows\n * them; past the middle of the plot it flips to the point's other side, so it stays inside.\n * Hidden from assistive technology: the live region reads the same values.\n * @internal Not exported: used by the chart frame only.\n */\n@Component({\n selector: 'bf-chart-tooltip',\n host: {\n 'aria-hidden': 'true',\n '[class]': 'hostClasses',\n '[style.left.px]': 'tip().x',\n '[style.top.px]': 'tip().y',\n '[style.transform]': 'shift()',\n },\n template: `\n @if (tip().title) {\n <span class=\"font-bold\">{{ tip().title }}</span>\n }\n @for (row of tip().rows; track $index) {\n <span class=\"flex items-center gap-2\">\n <span [class]=\"swatch(row.swatch)\"></span>\n <span class=\"text-text-secondary min-w-0 flex-1 truncate\">{{ row.name }}</span>\n <span class=\"font-bold tabular-nums\">{{ row.value }}</span>\n </span>\n }\n `,\n})\nexport class BfChartTooltipComponent {\n /** What the tooltip shows and where. */\n readonly tip = input.required<ChartTooltip>();\n /** The plot's width in px, to pick the side with room. */\n readonly plotWidth = input(0);\n\n protected readonly hostClasses = HOST;\n\n /** 12 px to the side with more room, centred on the point's height. */\n protected readonly shift = computed(() => {\n const width = this.plotWidth();\n const flip = width > 0 && this.tip().x > width / 2;\n return `translate(${flip ? 'calc(-100% - 12px)' : '12px'}, -50%)`;\n });\n\n /**\n * A row's swatch classes.\n * @internal\n */\n swatch(swatch: string): string {\n return chartSwatchClasses(swatch, false);\n }\n}\n","import { NgTemplateOutlet } from '@angular/common';\nimport {\n Component,\n type ElementRef,\n booleanAttribute,\n computed,\n inject,\n input,\n numberAttribute,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { BF_LABELS, ɵuniqueId as uniqueId } from '@bitforgehq/ui';\nimport { type ChartStep } from './chart-interaction';\nimport { chartSwatchClasses } from './chart-swatch';\nimport { BfChartTooltipComponent, type ChartTooltip } from './chart-tooltip.component';\n\nexport { type ChartTooltip, type ChartTooltipRow } from './chart-tooltip.component';\nimport { type BfChartLegendPosition } from './chart-types';\n\n/** One legend entry: a series (or slice) name, its swatch utility and whether it is hidden. */\nexport interface ChartLegendItem {\n readonly name: string;\n readonly swatch: string;\n readonly hidden: boolean;\n}\n\n/** The data as a table: the column headers, then one row per category (its first cell the\n * category, a row header). */\nexport interface ChartTable {\n readonly head: readonly string[];\n readonly rows: readonly (readonly string[])[];\n}\n\n/** A pointer position in px from the plot's physical top left. */\nexport interface ChartPointer {\n readonly x: number;\n readonly y: number;\n}\n\n/* The legend: a wrapping row of toggle buttons. Each is at least 24 px tall (44 px under a coarse\n pointer: its name is the button's own text, so a min-height, not an ::after). */\nconst LEGEND = 'flex flex-wrap items-center gap-x-1 gap-y-1';\nconst LEGEND_BUTTON =\n '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 ' +\n 'hover:bg-surface-muted active:bg-surface-pressed focus-visible:outline-hidden focus-visible:ring-4 focus-visible:ring-ring ' +\n 'aria-[pressed=false]:text-text-muted aria-[pressed=false]:line-through pointer-coarse:min-h-hit';\n/* The plot: the focus stop the arrow keys work in. The 4 px ring sits outside its box. */\nconst PLOT =\n 'relative block h-(--bf-chart-height) rounded-tile touch-pan-y focus-visible:outline-hidden focus-visible:ring-4 focus-visible:ring-ring';\n/* The Show data toggle: a small text button in primary-text, 24 px tall (44 px coarse). */\nconst DATA_BUTTON =\n '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 ' +\n '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';\n/* The data table: bf-table's look (header in label-xs text-muted, rows on divider lines). */\nconst TABLE = 'w-full border-collapse text-start';\nconst TH_HEAD =\n 'h-8 border-b border-border px-3 text-start align-middle text-label-xs font-bold text-text-muted';\nconst TH_ROW =\n 'h-10 border-b border-divider px-3 text-start align-middle text-label-sm font-bold text-text';\nconst TD =\n 'h-10 border-b border-divider px-3 text-end align-middle text-label-sm font-medium text-text tabular-nums';\nconst TH_VALUE = `${TH_HEAD} text-end`;\n\n/**\n * The shared figure around every chart's plot: the legend, the focusable plot with the tooltip,\n * the polite live region, the Show data toggle and the data table. The chart draws its SVG into\n * the default slot and owns every number; the frame only lays out and forwards input.\n * @internal Not exported: used by the `/charts` components only.\n */\n@Component({\n selector: 'bf-chart-frame',\n imports: [NgTemplateOutlet, BfChartTooltipComponent],\n host: { class: 'block', '[style.--bf-chart-height.px]': 'height()' },\n template: `\n <figure class=\"m-0 flex flex-col gap-2\" [attr.aria-label]=\"label()\">\n @if (legendPosition() === 'top') {\n <ng-container *ngTemplateOutlet=\"legendTpl\" />\n }\n <div\n #plot\n data-bf-chart-plot\n role=\"group\"\n tabindex=\"0\"\n [attr.aria-label]=\"labels.chartValues\"\n [class]=\"plotClasses\"\n (keydown)=\"onKeydown($event)\"\n (pointermove)=\"onPointer($event)\"\n (pointerdown)=\"onPointer($event)\"\n (pointerleave)=\"left.emit()\"\n (focus)=\"focusChanged.emit(true)\"\n (blur)=\"focusChanged.emit(false)\"\n >\n <ng-content />\n @if (tooltip(); as tip) {\n <bf-chart-tooltip data-bf-chart-tooltip [tip]=\"tip\" [plotWidth]=\"plotWidth()\" />\n }\n </div>\n @if (legendPosition() === 'bottom') {\n <ng-container *ngTemplateOutlet=\"legendTpl\" />\n }\n <div class=\"sr-only\" aria-live=\"polite\" data-bf-chart-live>{{ announcement() }}</div>\n @if (dataToggle()) {\n <div class=\"flex justify-end\">\n <button\n type=\"button\"\n data-bf-chart-data-toggle\n [class]=\"dataButtonClasses\"\n [attr.aria-expanded]=\"showData() ? 'true' : 'false'\"\n [attr.aria-controls]=\"tableId\"\n (click)=\"showData.set(!showData())\"\n >\n {{ showData() ? labels.chartHideData : labels.chartShowData }}\n </button>\n </div>\n }\n <div [id]=\"tableId\" [hidden]=\"!showData()\" class=\"overflow-x-auto\">\n @if (showData()) {\n <table data-bf-chart-table [class]=\"tableClasses\">\n <caption class=\"sr-only\">\n {{\n label()\n }}\n </caption>\n <thead>\n <tr>\n @for (cell of table().head; track $index; let first = $first) {\n <th scope=\"col\" [class]=\"first ? thHeadClasses : thValueClasses\">{{ cell }}</th>\n }\n </tr>\n </thead>\n <tbody>\n @for (row of table().rows; track $index) {\n <tr>\n @for (cell of row; track $index; let first = $first) {\n @if (first) {\n <th scope=\"row\" [class]=\"thRowClasses\">{{ cell }}</th>\n } @else {\n <td [class]=\"tdClasses\">{{ cell }}</td>\n }\n }\n </tr>\n }\n </tbody>\n </table>\n }\n </div>\n </figure>\n\n <ng-template #legendTpl>\n @if (legend().length > 0) {\n <div\n role=\"group\"\n data-bf-chart-legend\n [attr.aria-label]=\"labels.chartLegend\"\n [class]=\"legendClasses\"\n >\n @for (item of legend(); track $index; let i = $index) {\n <button\n type=\"button\"\n [class]=\"legendButtonClasses\"\n [attr.aria-pressed]=\"item.hidden ? 'false' : 'true'\"\n (click)=\"legendToggled.emit(i)\"\n >\n <span [class]=\"swatchClasses(item.swatch, item.hidden)\"></span>\n {{ item.name }}\n </button>\n }\n </div>\n }\n </ng-template>\n `,\n})\nexport class BfChartFrameComponent {\n /** The figure's accessible name. */\n readonly label = input.required<string>();\n /** The plot's height in px. */\n readonly height = input.required({ transform: numberAttribute });\n /** The legend entries; none draws no legend. */\n readonly legend = input<readonly ChartLegendItem[]>([]);\n /** Where the legend goes. */\n readonly legendPosition = input<BfChartLegendPosition>('bottom');\n /** The active point's tooltip, or `null`. */\n readonly tooltip = input<ChartTooltip | null>(null);\n /** The live region's text: the last keyboard move. */\n readonly announcement = input('');\n /** The data as a table, for the Show data toggle. */\n readonly table = input<ChartTable>({ head: [], rows: [] });\n /** Whether the Show data toggle is offered. */\n readonly dataToggle = input(true, { transform: booleanAttribute });\n /** Whether Arrow Up and Down move too (categories that run down the plot). */\n readonly vertical = input(false, { transform: booleanAttribute });\n\n /** Emitted with the index of the legend entry pressed. */\n readonly legendToggled = output<number>();\n /** Emitted with the pointer's position over the plot (a hover, or a tap). */\n readonly pointed = output<ChartPointer>();\n /** Emitted when the pointer leaves the plot. */\n readonly left = output<void>();\n /** Emitted with a keyboard move of the active point. */\n readonly stepped = output<ChartStep>();\n /** Emitted with `true` when the plot takes focus and `false` when it loses it. */\n readonly focusChanged = output<boolean>();\n\n protected readonly labels = inject(BF_LABELS);\n protected readonly tableId = uniqueId('bf-chart-data');\n /** Whether the data table shows. */\n protected readonly showData = signal(false);\n\n private readonly plot = viewChild.required<ElementRef<HTMLElement>>('plot');\n /** The plot element, which the chart measures. */\n readonly plotElement = computed(() => this.plot().nativeElement);\n\n /** The plot's width as last laid out, for the tooltip's side. */\n protected plotWidth(): number {\n return this.plot().nativeElement.clientWidth;\n }\n\n protected readonly plotClasses = PLOT;\n protected readonly legendClasses = LEGEND;\n protected readonly legendButtonClasses = LEGEND_BUTTON;\n protected readonly dataButtonClasses = DATA_BUTTON;\n protected readonly tableClasses = TABLE;\n protected readonly thHeadClasses = TH_HEAD;\n protected readonly thValueClasses = TH_VALUE;\n protected readonly thRowClasses = TH_ROW;\n protected readonly tdClasses = TD;\n\n /**\n * A swatch's classes: its colour, or an empty ring while hidden.\n * @internal\n */\n swatchClasses(swatch: string, hidden: boolean): string {\n return chartSwatchClasses(swatch, hidden);\n }\n\n /**\n * Arrow keys (mirrored under `dir=\"rtl\"`; Up and Down too for vertical categories), Home, End\n * and Escape.\n * @internal\n */\n onKeydown(event: KeyboardEvent): void {\n const rtl = this.plot().nativeElement.closest('[dir]')?.getAttribute('dir') === 'rtl';\n const forward = rtl ? 'ArrowLeft' : 'ArrowRight';\n const back = rtl ? 'ArrowRight' : 'ArrowLeft';\n let step: ChartStep | null = null;\n if (event.key === forward || (this.vertical() && event.key === 'ArrowDown')) {\n step = 'next';\n } else if (event.key === back || (this.vertical() && event.key === 'ArrowUp')) {\n step = 'previous';\n } else if (event.key === 'Home') {\n step = 'first';\n } else if (event.key === 'End') {\n step = 'last';\n } else if (event.key === 'Escape') {\n step = 'clear';\n }\n if (step) {\n event.preventDefault();\n this.stepped.emit(step);\n }\n }\n\n /**\n * Forwards the pointer's position over the plot.\n * @internal\n */\n onPointer(event: PointerEvent): void {\n const box = this.plot().nativeElement.getBoundingClientRect();\n this.pointed.emit({ x: event.clientX - box.left, y: event.clientY - box.top });\n }\n}\n","import { computed, signal } from '@angular/core';\n\n/** A keyboard move of a chart's active point. */\nexport type ChartStep = 'previous' | 'next' | 'first' | 'last' | 'clear';\n\n/**\n * The interaction state every chart with a legend and a tooltip shares: which series the legend\n * hides, which category (or slice) is active, and the polite announcement of a keyboard move.\n * A plain class, created once per chart component; it holds signals, no DOM and no services.\n */\nexport class ChartInteraction {\n private readonly hiddenSet = signal<ReadonlySet<number>>(new Set());\n private readonly activeIndex = signal<number | null>(null);\n private readonly spoken = signal('');\n\n /** The indexes the legend hides. */\n readonly hidden = this.hiddenSet.asReadonly();\n /** The active category or slice, or `null` (no tooltip). */\n readonly active = this.activeIndex.asReadonly();\n /** The last keyboard move, as read out by the live region. */\n readonly announcement = this.spoken.asReadonly();\n /** Whether anything is active. */\n readonly hasActive = computed(() => this.activeIndex() !== null);\n\n /** Whether the legend hides series (or slice) `index`. */\n isHidden(index: number): boolean {\n return this.hiddenSet().has(index);\n }\n\n /** Shows or hides series (or slice) `index`. */\n toggle(index: number): void {\n const next = new Set(this.hiddenSet());\n if (!next.delete(index)) {\n next.add(index);\n }\n this.hiddenSet.set(next);\n }\n\n /** Points at `index` (a hover), without an announcement; `null` clears. */\n point(index: number | null): void {\n this.activeIndex.set(index);\n }\n\n /**\n * Moves the active point by keyboard among `targets` (the indexes that can be active, in order)\n * and announces it with `describe`; `clear` hides the tooltip. From nothing, `next` and\n * `previous` start at the first and the last target.\n */\n step(step: ChartStep, targets: readonly number[], describe: (index: number) => string): void {\n if (step === 'clear' || targets.length === 0) {\n this.activeIndex.set(null);\n return;\n }\n const at = this.activeIndex();\n const position = at === null ? -1 : targets.indexOf(at);\n let next: number;\n if (step === 'first' || (step === 'next' && position === -1)) {\n next = 0;\n } else if (step === 'last' || (step === 'previous' && position === -1)) {\n next = targets.length - 1;\n } else if (step === 'next') {\n next = Math.min(targets.length - 1, position + 1);\n } else {\n next = Math.max(0, position - 1);\n }\n const index = targets[next] ?? null;\n this.activeIndex.set(index);\n if (index !== null) {\n this.spoken.set(describe(index));\n }\n }\n}\n","import { type BfChartCurve } from './chart-types';\n\n/** A point in the plot's pixel space. */\nexport interface ChartPoint {\n readonly x: number;\n readonly y: number;\n}\n\n/** A coordinate rounded to 0.01 px, so a path stays short and its text stable. */\nexport function px(value: number): number {\n return Math.round(value * 100) / 100 || 0;\n}\n\n/** The runs of consecutive points between the gaps (`null`), each with at least one point. */\nexport function segments(points: readonly (ChartPoint | null)[]): ChartPoint[][] {\n const runs: ChartPoint[][] = [];\n let run: ChartPoint[] = [];\n for (const point of points) {\n if (point) {\n run.push(point);\n } else if (run.length > 0) {\n runs.push(run);\n run = [];\n }\n }\n if (run.length > 0) {\n runs.push(run);\n }\n return runs;\n}\n\nconst sign = (n: number): number => (n < 0 ? -1 : 1);\n\n/**\n * The tangent at the middle of three points, limited so the curve never overshoots either\n * neighbour (Fritsch–Carlson, as d3's monotoneX).\n */\nfunction innerTangent(a: ChartPoint, b: ChartPoint, c: ChartPoint): number {\n const h0 = b.x - a.x;\n const h1 = c.x - b.x;\n const s0 = h0 === 0 ? 0 : (b.y - a.y) / h0;\n const s1 = h1 === 0 ? 0 : (c.y - b.y) / h1;\n const p = h0 + h1 === 0 ? 0 : (s0 * h1 + s1 * h0) / (h0 + h1);\n return (sign(s0) + sign(s1)) * Math.min(Math.abs(s0), Math.abs(s1), 0.5 * Math.abs(p)) || 0;\n}\n\n/** The tangent at an end point, from its neighbour's tangent `t` (a one-sided estimate). */\nfunction endTangent(a: ChartPoint, b: ChartPoint, t: number): number {\n const h = b.x - a.x;\n return h === 0 ? t : ((3 * (b.y - a.y)) / h - t) / 2;\n}\n\n/** Path commands (without the leading `M`) through one run of points. */\nfunction runCommands(run: readonly ChartPoint[], curve: BfChartCurve): string[] {\n if (curve === 'linear' || run.length < 3) {\n return run.slice(1).map((p) => `L${px(p.x)},${px(p.y)}`);\n }\n const n = run.length;\n const tangents = new Array<number>(n).fill(0);\n for (let i = 1; i < n - 1; i++) {\n tangents[i] = innerTangent(run[i - 1], run[i], run[i + 1]);\n }\n tangents[0] = endTangent(run[0], run[1], tangents[1]);\n tangents[n - 1] = endTangent(run[n - 2], run[n - 1], tangents[n - 2]);\n const commands: string[] = [];\n for (let i = 1; i < n; i++) {\n const a = run[i - 1];\n const b = run[i];\n const dx = (b.x - a.x) / 3;\n const ta = tangents[i - 1];\n const tb = tangents[i];\n commands.push(\n `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)}`,\n );\n }\n return commands;\n}\n\n/**\n * The SVG path of a line through `points`, broken at each gap; a run of one point is a dot-sized\n * move with no line (the chart draws it as a marker). `smooth` is a monotone cubic curve.\n */\nexport function linePath(points: readonly (ChartPoint | null)[], curve: BfChartCurve): string {\n return segments(points)\n .map((run) => {\n const first = run[0];\n return [`M${px(first.x)},${px(first.y)}`, ...runCommands(run, curve)].join('');\n })\n .join('');\n}\n\n/**\n * The SVG path of the area between the line through `points` and the horizontal `baseline`, one\n * closed shape per run between gaps.\n */\nexport function areaPath(\n points: readonly (ChartPoint | null)[],\n curve: BfChartCurve,\n baseline: number,\n): string {\n return segments(points)\n .map((run) => {\n const first = run[0];\n const last = run[run.length - 1];\n return [\n `M${px(first.x)},${px(baseline)}`,\n `L${px(first.x)},${px(first.y)}`,\n ...runCommands(run, curve),\n `L${px(last.x)},${px(baseline)}Z`,\n ].join('');\n })\n .join('');\n}\n","/** A value axis rounded out to nice numbers: its ends, the step between ticks and the ticks. */\nexport interface NiceScale {\n readonly min: number;\n readonly max: number;\n readonly step: number;\n readonly ticks: readonly number[];\n}\n\n/**\n * The nice step (1, 2 or 5 × 10ⁿ) closest above `span / count`, so about `count` steps cover the\n * span; 1 for a span that is zero or not finite.\n */\nexport function niceStep(span: number, count: number): number {\n const raw = span / Math.max(1, count);\n if (!Number.isFinite(raw) || raw <= 0) {\n return 1;\n }\n const magnitude = 10 ** Math.floor(Math.log10(raw));\n const normalized = raw / magnitude;\n const nice = normalized <= 1 ? 1 : normalized <= 2 ? 2 : normalized <= 5 ? 5 : 10;\n return nice * magnitude;\n}\n\n/** Rounds away the binary noise of `k × step` (0.30000000000000004 → 0.3), never giving -0. */\nfunction clean(value: number, step: number): number {\n const decimals = Math.max(0, -Math.floor(Math.log10(step)));\n return Number(value.toFixed(Math.min(20, decimals))) || 0;\n}\n\n/**\n * The value axis for data from `min` to `max`: both ends rounded out to a multiple of a nice step\n * (1, 2 or 5 × 10ⁿ) with about `count` steps between them, and every tick from end to end. An\n * empty range (`min === max`) widens around its value (to `0…1` at zero); a range that is not\n * finite (no data) gives `0…1`.\n */\nexport function niceTicks(min: number, max: number, count = 5): NiceScale {\n let lo = Math.min(min, max);\n let hi = Math.max(min, max);\n if (!Number.isFinite(lo) || !Number.isFinite(hi)) {\n lo = 0;\n hi = 1;\n } else if (lo === hi) {\n const pad = lo === 0 ? 1 : Math.abs(lo) * 0.1;\n lo = lo === 0 ? 0 : lo - pad;\n hi += pad;\n }\n const step = niceStep(hi - lo, count);\n const start = Math.floor(lo / step + 1e-9);\n const end = Math.ceil(hi / step - 1e-9);\n const ticks: number[] = [];\n for (let k = start; k <= end; k++) {\n ticks.push(clean(k * step, step));\n }\n return { min: clean(start * step, step), max: clean(end * step, step), step, ticks };\n}\n","import { DOCUMENT, DestroyRef, type Signal, afterNextRender, inject, signal } from '@angular/core';\n\n/** The measured box of a chart: its width in px and whether it sits in a right-to-left context. */\nexport interface ChartBox {\n readonly width: Signal<number>;\n readonly rtl: Signal<boolean>;\n}\n\n/**\n * Tracks the width of the element `target` returns with a `ResizeObserver`, from the first render\n * on; call it in an injection context. Until then, on the server and where there is no\n * `ResizeObserver`, the width is `fallback`, so a server render draws a fixed-width chart that the\n * browser re-measures. A width of 0 (the element is hidden) keeps the last one. `rtl` is read\n * from the nearest `dir` attribute on every measure.\n */\nexport function observeWidth(target: () => HTMLElement | undefined, fallback: number): ChartBox {\n const width = signal(fallback);\n const rtl = signal(false);\n const view = inject(DOCUMENT).defaultView;\n let observer: ResizeObserver | null = null;\n\n const measure = (): void => {\n const element = target();\n if (!element) {\n return;\n }\n const measured = Math.round(element.clientWidth);\n if (measured > 0) {\n width.set(measured);\n }\n rtl.set(element.closest('[dir]')?.getAttribute('dir') === 'rtl');\n };\n\n afterNextRender(() => {\n measure();\n const element = target();\n if (element && view && typeof view.ResizeObserver === 'function') {\n observer = new view.ResizeObserver(measure);\n observer.observe(element);\n }\n });\n inject(DestroyRef).onDestroy(() => observer?.disconnect());\n\n return { width: width.asReadonly(), rtl: rtl.asReadonly() };\n}\n","/*\n * The chart palette as literal utilities, so Tailwind (which scans the FESM through theme.css's\n * `@source`) generates each one. Series n always takes slot n (`--color-chart-<n>`): the colour\n * follows the series, so hiding one in the legend never repaints the others. Past eight series\n * the slots repeat; the docs say to fold the rest into an \"Other\" series instead.\n */\nconst STROKE = [\n 'stroke-chart-1',\n 'stroke-chart-2',\n 'stroke-chart-3',\n 'stroke-chart-4',\n 'stroke-chart-5',\n 'stroke-chart-6',\n 'stroke-chart-7',\n 'stroke-chart-8',\n] as const;\nconst FILL = [\n 'fill-chart-1',\n 'fill-chart-2',\n 'fill-chart-3',\n 'fill-chart-4',\n 'fill-chart-5',\n 'fill-chart-6',\n 'fill-chart-7',\n 'fill-chart-8',\n] as const;\n/* An area under a line: the series colour at 16 %, so lines over it stay legible. */\nconst AREA = [\n 'fill-chart-1/16',\n 'fill-chart-2/16',\n 'fill-chart-3/16',\n 'fill-chart-4/16',\n 'fill-chart-5/16',\n 'fill-chart-6/16',\n 'fill-chart-7/16',\n 'fill-chart-8/16',\n] as const;\n/* The legend and tooltip swatches (HTML, not SVG). */\nconst SWATCH = [\n 'bg-chart-1',\n 'bg-chart-2',\n 'bg-chart-3',\n 'bg-chart-4',\n 'bg-chart-5',\n 'bg-chart-6',\n 'bg-chart-7',\n 'bg-chart-8',\n] as const;\n\n/** The palette slot (0…7) of series `index`. */\nfunction slot(index: number): number {\n return ((index % STROKE.length) + STROKE.length) % STROKE.length;\n}\n\n/** The stroke utility of series `index`. */\nexport function seriesStroke(index: number): string {\n return STROKE[slot(index)];\n}\n\n/** The fill utility of series `index`. */\nexport function seriesFill(index: number): string {\n return FILL[slot(index)];\n}\n\n/** The translucent area fill utility of series `index`. */\nexport function seriesArea(index: number): string {\n return AREA[slot(index)];\n}\n\n/** The background utility of series `index`, for an HTML swatch. */\nexport function seriesSwatch(index: number): string {\n return SWATCH[slot(index)];\n}\n","import { type BfLabels } from '@bitforgehq/ui';\nimport { formatOrDash } from './chart-format';\nimport { type ChartLegendItem, type ChartTable } from './chart-frame.component';\nimport { type ChartInteraction } from './chart-interaction';\nimport { type BfChartSeries, type BfChartValueFormat } from './chart-types';\nimport { type ChartTooltipRow } from './chart-tooltip.component';\nimport { seriesSwatch } from './palette';\n\n/*\n * What the line and the bar chart share around their geometry: the legend, the table, the\n * tooltip rows and the announcement of one category, all from the same series and categories.\n */\n\n/** The legend of a series chart: every series, or none for a single series (its name is the\n * chart's). */\nexport function seriesLegend(\n series: readonly BfChartSeries[],\n interaction: ChartInteraction,\n): ChartLegendItem[] {\n return series.length < 2\n ? []\n : series.map((s, i) => ({\n name: s.name,\n swatch: seriesSwatch(i),\n hidden: interaction.isHidden(i),\n }));\n}\n\n/** The indexes of the series the legend shows. */\nexport function visibleSeries(\n series: readonly BfChartSeries[],\n interaction: ChartInteraction,\n): number[] {\n return series.map((_, i) => i).filter((i) => !interaction.isHidden(i));\n}\n\n/** The data table: a Category column, then one column per series (hidden ones too). */\nexport function seriesTable(\n series: readonly BfChartSeries[],\n categories: readonly string[],\n labels: BfLabels,\n format: BfChartValueFormat,\n): ChartTable {\n return {\n head: [labels.chartCategory, ...series.map((s) => s.name)],\n rows: categories.map((category, j) => [\n category,\n ...series.map((s) => formatOrDash(s.values[j], format)),\n ]),\n };\n}\n\n/** The tooltip rows of category `at`: one per shown series, a dash for a gap. */\nexport function seriesTooltipRows(\n series: readonly BfChartSeries[],\n visible: readonly number[],\n at: number,\n format: BfChartValueFormat,\n): ChartTooltipRow[] {\n return visible.map((index) => ({\n name: series[index]?.name ?? '',\n value: formatOrDash(series[index]?.values[at], format),\n swatch: seriesSwatch(index),\n }));\n}\n\n/** \"Mar: Online 15, Store 11\", what the live region reads for category `at`. */\nexport function describeCategory(\n series: readonly BfChartSeries[],\n categories: readonly string[],\n visible: readonly number[],\n at: number,\n format: BfChartValueFormat,\n): string {\n const values = seriesTooltipRows(series, visible, at, format)\n .map((row) => `${row.name} ${row.value}`)\n .join(', ');\n return `${categories[at] ?? ''}: ${values}`;\n}\n\n/** The value of series `index` at category `at`, or `null` for a gap (or a non-finite value). */\nexport function valueAt(\n series: readonly BfChartSeries[],\n index: number,\n at: number,\n): number | null {\n const v = series[index]?.values[at];\n return v === null || v === undefined || !Number.isFinite(v) ? null : v;\n}\n","import {\n Component,\n DOCUMENT,\n booleanAttribute,\n computed,\n inject,\n input,\n numberAttribute,\n viewChild,\n} from '@angular/core';\nimport { BF_LABELS } from '@bitforgehq/ui';\nimport { finiteValues, labelEvery, mirror, textWidth, clamp } from '../core/axis';\nimport { BF_CHART_CARD } from '../core/chart-card.token';\nimport { defaultValueFormat } from '../core/chart-format';\nimport {\n BfChartFrameComponent,\n type ChartPointer,\n type ChartTooltip,\n} from '../core/chart-frame.component';\nimport { ChartInteraction, type ChartStep } from '../core/chart-interaction';\nimport {\n type BfChartCurve,\n type BfChartLegendPosition,\n type BfChartSeries,\n type BfChartValueFormat,\n} from '../core/chart-types';\nimport { type ChartPoint, areaPath, linePath, px, segments } from '../core/curve';\nimport { niceTicks } from '../core/nice-ticks';\nimport { observeWidth } from '../core/observe-width';\nimport { seriesArea, seriesFill, seriesStroke } from '../core/palette';\nimport {\n describeCategory,\n seriesLegend,\n seriesTable,\n seriesTooltipRows,\n valueAt,\n visibleSeries,\n} from '../core/series-helpers';\n\n/** The width a line chart draws at before (or without) a measure, such as on the server. */\nconst FALLBACK_WIDTH = 600;\n/* Room above the plot (half a tick label) and below it (the category labels). */\nconst TOP = 8;\nconst BOTTOM = 24;\nconst END = 8;\n\n/* A line: 2 px with round joins, drawn along its path on enter (pathLength 1 makes the dash the\n whole line, so the draw needs no measuring); still under reduced motion. */\nconst LINE = 'fill-none [stroke-dasharray:1] animate-chart-draw motion-reduce:animate-none';\nconst AREA = 'stroke-none animate-chart-fade motion-reduce:animate-none';\nconst AXIS_TEXT = 'fill-text-muted text-micro';\nconst MARKER = 'fill-surface';\n\n/** One drawn series: its index (the palette slot) and its line and area paths. */\ninterface LineMark {\n readonly index: number;\n readonly line: string;\n readonly area: string;\n /** Points with no neighbour (between two gaps), drawn as dots so they show. */\n readonly dots: readonly ChartPoint[];\n}\n\n/** A text label on an axis. */\ninterface AxisLabel {\n readonly key: number;\n readonly text: string;\n readonly x: number;\n readonly y: number;\n readonly anchor: 'start' | 'middle' | 'end';\n}\n\n/**\n * A line chart of one or more series over shared categories (months, days, steps), drawn in SVG\n * with the chart palette: value axis with nice ticks and grid lines, a legend that shows and\n * hides series, a crosshair tooltip on hover and on keyboard focus (Arrow keys move between the\n * categories and a polite live region reads each one) and a Show data table. `area` fills under\n * each line; `curve=\"smooth\"` draws a monotone curve. The lines draw in on the first render and on\n * every data change, still under reduced motion; under `dir=\"rtl\"` the categories run from the\n * right.\n *\n * @example\n * <bf-line-chart\n * label=\"Revenue\"\n * [categories]=\"['Jan', 'Feb', 'Mar']\"\n * [series]=\"[{ name: 'Online', values: [12, 18, 15] }, { name: 'Store', values: [8, 9, 11] }]\"\n * />\n * @summary Line chart of series over categories, with tooltip, legend and data table\n * @category Data display\n * @since 0.3.1\n */\n@Component({\n selector: 'bf-line-chart',\n imports: [BfChartFrameComponent],\n // w-full: a chart fills its container's width, also as a shrink-to-fit flex item.\n host: { class: 'block w-full min-w-0' },\n template: `\n <bf-chart-frame\n [label]=\"name()\"\n [height]=\"height()\"\n [legend]=\"legendItems()\"\n [legendPosition]=\"legendPosition()\"\n [tooltip]=\"tooltip()\"\n [announcement]=\"interaction.announcement()\"\n [table]=\"table()\"\n (legendToggled)=\"interaction.toggle($event)\"\n (pointed)=\"onPointed($event)\"\n (left)=\"interaction.point(null)\"\n (stepped)=\"onStep($event)\"\n (focusChanged)=\"onFocus($event)\"\n >\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n direction=\"ltr\"\n class=\"block w-full overflow-visible\"\n [attr.height]=\"height()\"\n [attr.viewBox]=\"viewBox()\"\n >\n @let g = geometry();\n @for (tick of g.ticks; track tick.key) {\n <line\n data-bf-chart-grid\n class=\"stroke-chart-grid\"\n stroke-width=\"1\"\n [attr.x1]=\"g.left\"\n [attr.x2]=\"g.right\"\n [attr.y1]=\"tick.y\"\n [attr.y2]=\"tick.y\"\n />\n <text\n dominant-baseline=\"middle\"\n [class]=\"axisTextClasses\"\n [attr.x]=\"tick.x\"\n [attr.y]=\"tick.y\"\n [attr.text-anchor]=\"tick.anchor\"\n >\n {{ tick.text }}\n </text>\n }\n <line\n data-bf-chart-axis\n class=\"stroke-chart-axis\"\n stroke-width=\"1\"\n [attr.x1]=\"g.left\"\n [attr.x2]=\"g.right\"\n [attr.y1]=\"g.baseline\"\n [attr.y2]=\"g.baseline\"\n />\n @for (label of g.categoryLabels; track label.key) {\n <text\n data-bf-chart-category\n [class]=\"axisTextClasses\"\n [attr.x]=\"label.x\"\n [attr.y]=\"label.y\"\n [attr.text-anchor]=\"label.anchor\"\n >\n {{ label.text }}\n </text>\n }\n @let x = crosshairX();\n @if (x !== null) {\n <line\n data-bf-chart-crosshair\n class=\"stroke-chart-axis\"\n stroke-width=\"1\"\n stroke-dasharray=\"3 3\"\n [attr.x1]=\"x\"\n [attr.x2]=\"x\"\n [attr.y1]=\"g.top\"\n [attr.y2]=\"g.baseline\"\n />\n }\n <!-- Re-created on every data change, so the enter motion replays. -->\n @for (generation of generations(); track generation) {\n <g>\n @for (mark of g.marks; track mark.index) {\n @if (area()) {\n <path data-bf-chart-area [attr.d]=\"mark.area\" [class]=\"areaClasses(mark.index)\" />\n }\n <path\n data-bf-chart-line\n pathLength=\"1\"\n stroke-width=\"2\"\n stroke-linejoin=\"round\"\n stroke-linecap=\"round\"\n [attr.d]=\"mark.line\"\n [class]=\"lineClasses(mark.index)\"\n />\n @for (dot of mark.dots; track $index) {\n <circle\n r=\"2.5\"\n [attr.cx]=\"dot.x\"\n [attr.cy]=\"dot.y\"\n [class]=\"dotClasses(mark.index)\"\n />\n }\n }\n </g>\n }\n @for (marker of markers(); track marker.index) {\n <circle\n data-bf-chart-marker\n r=\"4\"\n stroke-width=\"2\"\n [attr.cx]=\"marker.x\"\n [attr.cy]=\"marker.y\"\n [class]=\"markerClasses(marker.index)\"\n />\n }\n </svg>\n </bf-chart-frame>\n `,\n})\nexport class BfLineChartComponent {\n /** The series to draw, each with one value per category. */\n readonly series = input.required<readonly BfChartSeries[]>();\n /** The category names along the horizontal axis, in order. */\n readonly categories = input.required<readonly string[]>();\n /** The chart's accessible name; empty falls back to the `bf-chart-card` title, then to\n * `provideBfLabels()`'s `chart` (\"Chart\"). */\n readonly label = input('');\n /** The plot's height in px; the width follows the container. */\n readonly height = input(240, { transform: numberAttribute });\n /** Fills the area under each line in the series' colour (the value axis then starts at zero). */\n readonly area = input(false, { transform: booleanAttribute });\n /** The line between points: `linear` (default) or `smooth`, a monotone curve. */\n readonly curve = input<BfChartCurve>('linear');\n /** Formats the values on the axis, in the tooltip and in the table; unset uses\n * `Intl.NumberFormat` in the document's language. */\n readonly valueFormat = input<BfChartValueFormat | undefined>(undefined);\n /** Where the legend goes; unset follows the `bf-chart-card`, else `bottom`. A single series\n * draws no legend. */\n readonly legend = input<BfChartLegendPosition | undefined>(undefined);\n\n protected readonly interaction = new ChartInteraction();\n private readonly labels = inject(BF_LABELS);\n private readonly card = inject(BF_CHART_CARD, { optional: true });\n private readonly document = inject(DOCUMENT);\n private readonly frame = viewChild.required(BfChartFrameComponent);\n private readonly box = observeWidth(() => this.frame().plotElement(), FALLBACK_WIDTH);\n\n protected readonly axisTextClasses = AXIS_TEXT;\n\n /** The figure's name: `label`, else the card's title, else the `chart` label. */\n protected readonly name = computed(\n () => this.label() || (this.card?.title() ?? '') || this.labels.chart,\n );\n protected readonly legendPosition = computed(\n () => this.legend() ?? this.card?.legend() ?? 'bottom',\n );\n private readonly format = computed(() => this.valueFormat() ?? defaultValueFormat(this.document));\n /** A new array on every data change: the key that re-creates the marks. */\n protected readonly generations = computed(() => [\n { series: this.series(), categories: this.categories() },\n ]);\n protected readonly viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`);\n\n /** The indexes of the series the legend shows. */\n private readonly visible = computed(() => visibleSeries(this.series(), this.interaction));\n\n /** Everything the SVG draws, in px of the plot's physical box. */\n protected readonly geometry = computed(() => {\n const width = this.box.width();\n const height = this.height();\n const rtl = this.box.rtl();\n const categories = this.categories();\n const format = this.format();\n const series = this.series();\n const visible = this.visible();\n const values = finiteValues(series, visible);\n const lo = Math.min(...values, ...(this.area() ? [0] : []));\n const hi = Math.max(...values, ...(this.area() ? [0] : []));\n const plotHeight = Math.max(1, height - TOP - BOTTOM);\n const scale = niceTicks(lo, hi, Math.max(2, Math.floor(plotHeight / 48)));\n const tickTexts = scale.ticks.map(format);\n const start = Math.max(...tickTexts.map(textWidth)) + 12;\n const plotWidth = Math.max(1, width - start - END);\n const n = categories.length;\n const xAt = (i: number): number =>\n mirror(n > 1 ? start + (i * plotWidth) / (n - 1) : start + plotWidth / 2, width, rtl);\n const yAt = (v: number): number =>\n TOP + (1 - (v - scale.min) / (scale.max - scale.min || 1)) * plotHeight;\n const baseline = TOP + plotHeight;\n const valueBase = yAt(clamp(0, scale.min, scale.max));\n\n const ticks: AxisLabel[] = scale.ticks.map((value, i) => ({\n key: value,\n text: tickTexts[i] ?? '',\n x: px(mirror(start - 8, width, rtl)),\n y: px(yAt(value)),\n anchor: rtl ? 'start' : 'end',\n }));\n const every = labelEvery(categories, plotWidth, n > 1 ? plotWidth / (n - 1) : plotWidth);\n const categoryLabels: AxisLabel[] = categories.flatMap((text, i) => {\n if (i % every !== 0) {\n return [];\n }\n const edge = n === 1 ? 'middle' : i === 0 ? 'first' : i === n - 1 ? 'last' : 'middle';\n const anchor = edge === 'middle' ? 'middle' : (edge === 'first') !== rtl ? 'start' : 'end';\n return [{ key: i, text, x: px(xAt(i)), y: baseline + 18, anchor }];\n });\n const marks: LineMark[] = visible.map((index) => {\n const points = categories.map((_, j) => {\n const v = valueAt(series, index, j);\n return v === null ? null : { x: xAt(j), y: yAt(v) };\n });\n return {\n index,\n line: linePath(points, this.curve()),\n area: areaPath(points, this.curve(), valueBase),\n dots: segments(points)\n .filter((run) => run.length === 1)\n .map(([p]) => ({ x: px(p.x), y: px(p.y) })),\n };\n });\n const [left, right] = rtl ? [END, width - start] : [start, width - END];\n return { width, top: TOP, baseline, left, right, ticks, categoryLabels, marks, xAt, yAt };\n });\n\n /** The legend: every series, or none for a single series. */\n protected readonly legendItems = computed(() => seriesLegend(this.series(), this.interaction));\n\n /** The active category, within range. */\n private readonly active = computed(() => {\n const at = this.interaction.active();\n return at !== null && at < this.categories().length ? at : null;\n });\n\n protected readonly crosshairX = computed(() => {\n const at = this.active();\n return at === null ? null : px(this.geometry().xAt(at));\n });\n\n protected readonly markers = computed(() => {\n const at = this.active();\n if (at === null) {\n return [];\n }\n const { xAt, yAt } = this.geometry();\n return this.visible().flatMap((index) => {\n const v = valueAt(this.series(), index, at);\n return v === null ? [] : [{ index, x: px(xAt(at)), y: px(yAt(v)) }];\n });\n });\n\n protected readonly tooltip = computed<ChartTooltip | null>(() => {\n const at = this.active();\n if (at === null) {\n return null;\n }\n const { xAt, top, baseline } = this.geometry();\n const ys = this.markers().map((m) => m.y);\n const y = ys.length > 0 ? Math.min(...ys) : (top + baseline) / 2;\n return {\n title: this.categories()[at] ?? '',\n rows: seriesTooltipRows(this.series(), this.visible(), at, this.format()),\n x: px(xAt(at)),\n y: px(clamp(y, top + 24, baseline - 24)),\n };\n });\n\n protected readonly table = computed(() =>\n seriesTable(this.series(), this.categories(), this.labels, this.format()),\n );\n\n /**\n * The stroke classes of series `index`'s line.\n * @internal\n */\n lineClasses(index: number): string {\n return `${LINE} ${seriesStroke(index)}`;\n }\n\n /**\n * The fill classes of series `index`'s area.\n * @internal\n */\n areaClasses(index: number): string {\n return `${AREA} ${seriesArea(index)}`;\n }\n\n /**\n * The fill of series `index`'s lone dots.\n * @internal\n */\n dotClasses(index: number): string {\n return `${seriesFill(index)} animate-chart-fade motion-reduce:animate-none`;\n }\n\n /**\n * The ring of series `index`'s hover marker.\n * @internal\n */\n markerClasses(index: number): string {\n return `${MARKER} ${seriesStroke(index)}`;\n }\n\n /**\n * Points at the category nearest the pointer.\n * @internal\n */\n onPointed(pointer: ChartPointer): void {\n const n = this.categories().length;\n if (n === 0) {\n return;\n }\n const { xAt } = this.geometry();\n let best = 0;\n for (let i = 1; i < n; i++) {\n if (Math.abs(xAt(i) - pointer.x) < Math.abs(xAt(best) - pointer.x)) {\n best = i;\n }\n }\n this.interaction.point(best);\n }\n\n /**\n * Moves the active category by keyboard and announces it.\n * @internal\n */\n onStep(step: ChartStep): void {\n const targets = this.categories().map((_, i) => i);\n this.interaction.step(step, targets, (i) =>\n describeCategory(this.series(), this.categories(), this.visible(), i, this.format()),\n );\n }\n\n /**\n * On focus, shows the first category (or keeps the hovered one); on blur, hides the tooltip.\n * @internal\n */\n onFocus(focused: boolean): void {\n if (!focused) {\n this.interaction.point(null);\n } else if (this.interaction.active() === null) {\n this.onStep('first');\n }\n }\n}\n","import {\n Component,\n DOCUMENT,\n booleanAttribute,\n computed,\n inject,\n input,\n numberAttribute,\n viewChild,\n} from '@angular/core';\nimport { BF_LABELS } from '@bitforgehq/ui';\nimport { clamp, finiteValues, labelEvery, mirror, textWidth } from '../core/axis';\nimport { BF_CHART_CARD } from '../core/chart-card.token';\nimport { defaultValueFormat } from '../core/chart-format';\nimport {\n BfChartFrameComponent,\n type ChartPointer,\n type ChartTooltip,\n} from '../core/chart-frame.component';\nimport { ChartInteraction, type ChartStep } from '../core/chart-interaction';\nimport {\n type BfChartLegendPosition,\n type BfChartSeries,\n type BfChartValueFormat,\n} from '../core/chart-types';\nimport { px } from '../core/curve';\nimport { niceTicks } from '../core/nice-ticks';\nimport { observeWidth } from '../core/observe-width';\nimport { seriesFill } from '../core/palette';\nimport {\n describeCategory,\n seriesLegend,\n seriesTable,\n seriesTooltipRows,\n valueAt,\n visibleSeries,\n} from '../core/series-helpers';\n\n/**\n * The direction of a `bf-bar-chart`'s bars: up from a horizontal baseline, or along from a\n * vertical one (for long category names or many categories).\n *\n * @summary The two bar directions, vertical columns or horizontal bars\n * @since 0.3.1\n */\nexport type BfBarChartOrientation = 'vertical' | 'horizontal';\n\n/** The width a bar chart draws at before (or without) a measure, such as on the server. */\nconst FALLBACK_WIDTH = 600;\n/* Room around the plot: half a tick label above, the labels below, a little past the end. */\nconst TOP = 8;\nconst BOTTOM = 24;\nconst END = 12;\n/* Bars fill this share of their category's band; a bar is never thicker than BAR_MAX px, and\n grouped bars keep GAP px between them. A stacked bar's segments are BAR_GAP px apart, so\n neighbouring colours never touch. */\nconst BAND_FILL = 0.72;\nconst BAR_MAX = 40;\nconst GAP = 2;\nconst SEGMENT_GAP = 2;\n\n/* A bar grows from its baseline on enter (a scale on its own box, origin at the baseline side:\n physical, as the SVG coordinates are, so a mirrored horizontal bar grows from the right);\n still under reduced motion. */\nconst BAR = 'transform-fill motion-reduce:animate-none';\nconst GROW: Record<'up' | 'down' | 'left' | 'right', string> = {\n up: 'origin-bottom animate-chart-grow-y',\n down: 'origin-top animate-chart-grow-y',\n left: 'origin-[0%_50%] animate-chart-grow-x',\n right: 'origin-[100%_50%] animate-chart-grow-x',\n};\nconst AXIS_TEXT = 'fill-text-muted text-micro';\n\n/** One bar (or stacked segment) in px of the plot's physical box. */\ninterface BarMark {\n readonly key: string;\n readonly index: number;\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n readonly grow: keyof typeof GROW;\n}\n\n/** A text label on an axis. */\ninterface AxisLabel {\n readonly key: number;\n readonly text: string;\n readonly x: number;\n readonly y: number;\n readonly anchor: 'start' | 'middle' | 'end';\n}\n\n/** A grid line from (x1, y1) to (x2, y2). */\ninterface GridLine {\n readonly key: number;\n readonly x1: number;\n readonly y1: number;\n readonly x2: number;\n readonly y2: number;\n}\n\n/**\n * A bar chart of one or more series over shared categories, drawn in SVG with the chart palette:\n * bars side by side per category (or `stacked`), up from the baseline (or `horizontal`, along\n * from it), with a value axis of nice ticks, a legend that shows and hides series, a tooltip on\n * hover and on keyboard focus (Arrow keys move between the categories and a polite live region\n * reads each one) and a Show data table. Bars grow in on the first render and on every data\n * change, still under reduced motion; under `dir=\"rtl\"` the horizontal axis runs from the right.\n *\n * @example\n * <bf-bar-chart\n * label=\"Tickets\"\n * [categories]=\"['Mon', 'Tue', 'Wed']\"\n * [series]=\"[{ name: 'Opened', values: [14, 9, 12] }, { name: 'Closed', values: [11, 12, 8] }]\"\n * />\n * @summary Bar chart of series over categories, grouped or stacked, vertical or horizontal\n * @category Data display\n * @since 0.3.1\n */\n@Component({\n selector: 'bf-bar-chart',\n imports: [BfChartFrameComponent],\n // w-full: a chart fills its container's width, also as a shrink-to-fit flex item.\n host: { class: 'block w-full min-w-0' },\n template: `\n <bf-chart-frame\n [label]=\"name()\"\n [height]=\"height()\"\n [legend]=\"legendItems()\"\n [legendPosition]=\"legendPosition()\"\n [tooltip]=\"tooltip()\"\n [announcement]=\"interaction.announcement()\"\n [table]=\"table()\"\n [vertical]=\"orientation() === 'horizontal'\"\n (legendToggled)=\"interaction.toggle($event)\"\n (pointed)=\"onPointed($event)\"\n (left)=\"interaction.point(null)\"\n (stepped)=\"onStep($event)\"\n (focusChanged)=\"onFocus($event)\"\n >\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n direction=\"ltr\"\n class=\"block w-full overflow-visible\"\n [attr.height]=\"height()\"\n [attr.viewBox]=\"viewBox()\"\n >\n @let g = geometry();\n @let band = activeBand();\n @if (band) {\n <rect\n data-bf-chart-band\n class=\"fill-surface-muted\"\n [attr.x]=\"band.x\"\n [attr.y]=\"band.y\"\n [attr.width]=\"band.width\"\n [attr.height]=\"band.height\"\n />\n }\n @for (line of g.grid; track line.key) {\n <line\n data-bf-chart-grid\n class=\"stroke-chart-grid\"\n stroke-width=\"1\"\n [attr.x1]=\"line.x1\"\n [attr.x2]=\"line.x2\"\n [attr.y1]=\"line.y1\"\n [attr.y2]=\"line.y2\"\n />\n }\n @for (label of g.labels; track $index) {\n <text\n [class]=\"axisTextClasses\"\n [attr.data-bf-chart-category]=\"label.key >= 0 ? '' : null\"\n [attr.dominant-baseline]=\"label.anchor === 'middle' ? null : 'middle'\"\n [attr.x]=\"label.x\"\n [attr.y]=\"label.y\"\n [attr.text-anchor]=\"label.anchor\"\n >\n {{ label.text }}\n </text>\n }\n <!-- Re-created on every data change, so the enter motion replays. -->\n @for (generation of generations(); track generation) {\n <g>\n @for (bar of g.bars; track bar.key) {\n <rect\n data-bf-chart-bar\n rx=\"2\"\n [attr.x]=\"bar.x\"\n [attr.y]=\"bar.y\"\n [attr.width]=\"bar.width\"\n [attr.height]=\"bar.height\"\n [class]=\"barClasses(bar)\"\n />\n }\n </g>\n }\n <line\n data-bf-chart-axis\n class=\"stroke-chart-axis\"\n stroke-width=\"1\"\n [attr.x1]=\"g.axis.x1\"\n [attr.x2]=\"g.axis.x2\"\n [attr.y1]=\"g.axis.y1\"\n [attr.y2]=\"g.axis.y2\"\n />\n </svg>\n </bf-chart-frame>\n `,\n})\nexport class BfBarChartComponent {\n /** The series to draw, each with one value per category. */\n readonly series = input.required<readonly BfChartSeries[]>();\n /** The category names along the category axis, in order. */\n readonly categories = input.required<readonly string[]>();\n /** The chart's accessible name; empty falls back to the `bf-chart-card` title, then to\n * `provideBfLabels()`'s `chart` (\"Chart\"). */\n readonly label = input('');\n /** The plot's height in px; the width follows the container. */\n readonly height = input(240, { transform: numberAttribute });\n /** `vertical` (default) bars rise from a horizontal baseline; `horizontal` bars run along from\n * a vertical one, the categories down the start side. */\n readonly orientation = input<BfBarChartOrientation>('vertical');\n /** Stacks the series of a category into one bar instead of side by side. */\n readonly stacked = input(false, { transform: booleanAttribute });\n /** Formats the values on the axis, in the tooltip and in the table; unset uses\n * `Intl.NumberFormat` in the document's language. */\n readonly valueFormat = input<BfChartValueFormat | undefined>(undefined);\n /** Where the legend goes; unset follows the `bf-chart-card`, else `bottom`. A single series\n * draws no legend. */\n readonly legend = input<BfChartLegendPosition | undefined>(undefined);\n\n protected readonly interaction = new ChartInteraction();\n private readonly labels = inject(BF_LABELS);\n private readonly card = inject(BF_CHART_CARD, { optional: true });\n private readonly document = inject(DOCUMENT);\n private readonly frame = viewChild.required(BfChartFrameComponent);\n private readonly box = observeWidth(() => this.frame().plotElement(), FALLBACK_WIDTH);\n\n protected readonly axisTextClasses = AXIS_TEXT;\n\n /** The figure's name: `label`, else the card's title, else the `chart` label. */\n protected readonly name = computed(\n () => this.label() || (this.card?.title() ?? '') || this.labels.chart,\n );\n protected readonly legendPosition = computed(\n () => this.legend() ?? this.card?.legend() ?? 'bottom',\n );\n private readonly format = computed(() => this.valueFormat() ?? defaultValueFormat(this.document));\n /** A new array on every data change: the key that re-creates the bars. */\n protected readonly generations = computed(() => [\n { series: this.series(), categories: this.categories(), stacked: this.stacked() },\n ]);\n protected readonly viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`);\n private readonly visible = computed(() => visibleSeries(this.series(), this.interaction));\n\n /** The value range the bars span: from zero, per bar or per stack. */\n private readonly extent = computed(() => {\n const series = this.series();\n const visible = this.visible();\n if (!this.stacked()) {\n const values = finiteValues(series, visible);\n return { lo: Math.min(0, ...values), hi: Math.max(0, ...values) };\n }\n let lo = 0;\n let hi = 0;\n this.categories().forEach((_, j) => {\n let up = 0;\n let down = 0;\n for (const index of visible) {\n const v = valueAt(series, index, j) ?? 0;\n if (v >= 0) up += v;\n else down += v;\n }\n hi = Math.max(hi, up);\n lo = Math.min(lo, down);\n });\n return { lo, hi };\n });\n\n /** Everything the SVG draws, in px of the plot's physical box. */\n protected readonly geometry = computed(() => {\n const width = this.box.width();\n const height = this.height();\n const rtl = this.box.rtl();\n const horizontal = this.orientation() === 'horizontal';\n const categories = this.categories();\n const series = this.series();\n const visible = this.visible();\n const format = this.format();\n const n = Math.max(1, categories.length);\n const { lo, hi } = this.extent();\n\n // The value axis: along the height (vertical) or the width (horizontal).\n const valueRoom = horizontal ? width : height - TOP - BOTTOM;\n const scale = niceTicks(lo, hi, Math.max(2, Math.floor(valueRoom / (horizontal ? 96 : 48))));\n const tickTexts = scale.ticks.map(format);\n const start = horizontal\n ? Math.min(Math.round(width * 0.4), Math.max(0, ...categories.map(textWidth)) + 12)\n : Math.max(...tickTexts.map(textWidth)) + 12;\n const plotWidth = Math.max(1, width - start - END);\n const plotHeight = Math.max(1, height - TOP - BOTTOM);\n const span = scale.max - scale.min || 1;\n /** A value's position along the value axis, in px from the axis start (LTR / top-down). */\n const valuePos = (v: number): number =>\n horizontal\n ? start + ((v - scale.min) / span) * plotWidth\n : TOP + (1 - (v - scale.min) / span) * plotHeight;\n const zero = valuePos(clamp(0, scale.min, scale.max));\n const bandSize = (horizontal ? plotHeight : plotWidth) / n;\n const bandStart = (j: number): number => (horizontal ? TOP : start) + j * bandSize;\n\n const bars: BarMark[] = [];\n const k = Math.max(1, visible.length);\n const groupSize = this.stacked()\n ? Math.min(bandSize * BAND_FILL, BAR_MAX)\n : Math.min(bandSize * BAND_FILL, BAR_MAX * k + GAP * (k - 1));\n const barSize = this.stacked() ? groupSize : Math.max(1, (groupSize - GAP * (k - 1)) / k);\n categories.forEach((_, j) => {\n const groupStart = bandStart(j) + (bandSize - groupSize) / 2;\n let up = 0;\n let down = 0;\n visible.forEach((index, slot) => {\n const v = valueAt(series, index, j);\n if (v === null || v === 0) {\n return;\n }\n let from: number;\n let to: number;\n if (this.stacked()) {\n from = v > 0 ? up : down;\n to = from + v;\n if (v > 0) up = to;\n else down = to;\n } else {\n from = 0;\n to = v;\n }\n let a = valuePos(from);\n let b = valuePos(to);\n const inset = this.stacked() && Math.abs(b - a) > SEGMENT_GAP * 2 ? SEGMENT_GAP / 2 : 0;\n const along = this.stacked() ? groupStart : groupStart + slot * (barSize + GAP);\n [a, b] = [Math.min(a, b) + inset, Math.max(a, b) - inset];\n const positive = v > 0;\n if (horizontal) {\n const x = rtl ? width - b : a;\n bars.push({\n key: `${index}:${j}`,\n index,\n x: px(x),\n y: px(along),\n width: px(b - a),\n height: px(barSize),\n grow: positive !== rtl ? 'left' : 'right',\n });\n } else {\n const x = mirror(along, width, rtl) - (rtl ? barSize : 0);\n bars.push({\n key: `${index}:${j}`,\n index,\n x: px(x),\n y: px(a),\n width: px(barSize),\n height: px(b - a),\n grow: positive ? 'up' : 'down',\n });\n }\n });\n });\n\n // Grid lines at the ticks, the axis line at zero, the tick and category labels.\n const grid: GridLine[] = scale.ticks.map((value) => {\n const p = valuePos(value);\n return horizontal\n ? {\n key: value,\n x1: px(mirror(p, width, rtl)),\n x2: px(mirror(p, width, rtl)),\n y1: TOP,\n y2: TOP + plotHeight,\n }\n : {\n key: value,\n x1: px(mirror(start, width, rtl)),\n x2: px(mirror(start + plotWidth, width, rtl)),\n y1: px(p),\n y2: px(p),\n };\n });\n const axis = horizontal\n ? {\n x1: px(mirror(zero, width, rtl)),\n x2: px(mirror(zero, width, rtl)),\n y1: TOP,\n y2: TOP + plotHeight,\n }\n : {\n x1: px(mirror(start, width, rtl)),\n x2: px(mirror(start + plotWidth, width, rtl)),\n y1: px(zero),\n y2: px(zero),\n };\n const tickLabels: AxisLabel[] = scale.ticks.map((value, i) => {\n const text = tickTexts[i] ?? '';\n return horizontal\n ? {\n key: -1,\n text,\n x: px(mirror(valuePos(value), width, rtl)),\n y: height - 6,\n anchor: 'middle',\n }\n : {\n key: -1,\n text,\n x: px(mirror(start - 8, width, rtl)),\n y: px(valuePos(value)),\n anchor: rtl ? 'start' : 'end',\n };\n });\n const every = horizontal\n ? Math.max(1, Math.ceil(16 / bandSize))\n : labelEvery(categories, plotWidth, bandSize);\n const categoryLabels: AxisLabel[] = categories.flatMap((text, j): AxisLabel[] =>\n j % every !== 0\n ? []\n : horizontal\n ? [\n {\n key: j,\n text,\n x: px(mirror(start - 8, width, rtl)),\n y: px(bandStart(j) + bandSize / 2),\n anchor: rtl ? 'start' : 'end',\n },\n ]\n : [\n {\n key: j,\n text,\n x: px(mirror(bandStart(j) + bandSize / 2, width, rtl)),\n y: TOP + plotHeight + 18,\n anchor: 'middle',\n },\n ],\n );\n return {\n bars,\n grid,\n axis,\n labels: [...tickLabels, ...categoryLabels],\n horizontal,\n rtl,\n width,\n start,\n plotWidth,\n plotHeight,\n bandSize,\n bandStart,\n zero,\n };\n });\n\n protected readonly legendItems = computed(() => seriesLegend(this.series(), this.interaction));\n\n /** The active category, within range. */\n private readonly active = computed(() => {\n const at = this.interaction.active();\n return at !== null && at < this.categories().length ? at : null;\n });\n\n /** The highlight band behind the active category. */\n protected readonly activeBand = computed(() => {\n const at = this.active();\n if (at === null) {\n return null;\n }\n const g = this.geometry();\n const along = g.bandStart(at);\n return g.horizontal\n ? {\n x: px(g.rtl ? END : g.start),\n y: px(along),\n width: px(g.plotWidth),\n height: px(g.bandSize),\n }\n : {\n x: px(mirror(along, g.width, g.rtl) - (g.rtl ? g.bandSize : 0)),\n y: TOP,\n width: px(g.bandSize),\n height: px(g.plotHeight),\n };\n });\n\n protected readonly tooltip = computed<ChartTooltip | null>(() => {\n const at = this.active();\n const band = this.activeBand();\n if (at === null || !band) {\n return null;\n }\n const g = this.geometry();\n return {\n title: this.categories()[at] ?? '',\n rows: seriesTooltipRows(this.series(), this.visible(), at, this.format()),\n x: g.horizontal ? px(g.width / 2) : px(band.x + band.width / 2),\n y: g.horizontal ? px(band.y + band.height / 2) : px(TOP + g.plotHeight / 2),\n };\n });\n\n protected readonly table = computed(() =>\n seriesTable(this.series(), this.categories(), this.labels, this.format()),\n );\n\n /**\n * The classes of one bar: its series colour and its grow motion.\n * @internal\n */\n barClasses(bar: BarMark): string {\n return `${BAR} ${GROW[bar.grow]} ${seriesFill(bar.index)}`;\n }\n\n /**\n * Points at the category under the pointer.\n * @internal\n */\n onPointed(pointer: ChartPointer): void {\n const n = this.categories().length;\n if (n === 0) {\n return;\n }\n const g = this.geometry();\n const along = g.horizontal ? pointer.y - TOP : mirror(pointer.x, g.width, g.rtl) - g.start;\n this.interaction.point(clamp(Math.floor(along / g.bandSize), 0, n - 1));\n }\n\n /**\n * Moves the active category by keyboard and announces it.\n * @internal\n */\n onStep(step: ChartStep): void {\n const targets = this.categories().map((_, i) => i);\n this.interaction.step(step, targets, (i) =>\n describeCategory(this.series(), this.categories(), this.visible(), i, this.format()),\n );\n }\n\n /**\n * On focus, shows the first category (or keeps the hovered one); on blur, hides the tooltip.\n * @internal\n */\n onFocus(focused: boolean): void {\n if (!focused) {\n this.interaction.point(null);\n } else if (this.interaction.active() === null) {\n this.onStep('first');\n }\n }\n}\n","import {\n Component,\n DOCUMENT,\n computed,\n inject,\n input,\n numberAttribute,\n viewChild,\n} from '@angular/core';\nimport { BF_LABELS } from '@bitforgehq/ui';\nimport { clamp, mirror } from '../core/axis';\nimport { BF_CHART_CARD } from '../core/chart-card.token';\nimport { defaultValueFormat, percentFormat } from '../core/chart-format';\nimport {\n BfChartFrameComponent,\n type ChartLegendItem,\n type ChartPointer,\n type ChartTable,\n type ChartTooltip,\n} from '../core/chart-frame.component';\nimport { ChartInteraction, type ChartStep } from '../core/chart-interaction';\nimport {\n type BfChartLegendPosition,\n type BfChartValueFormat,\n type BfDonutSlice,\n} from '../core/chart-types';\nimport { px } from '../core/curve';\nimport { observeWidth } from '../core/observe-width';\nimport { seriesStroke, seriesSwatch } from '../core/palette';\n\n/** The width a donut chart lays out in before (or without) a measure, such as on the server. */\nconst FALLBACK_WIDTH = 320;\n/* Room around the ring, so the active slice can grow by ACTIVE_GROW px. */\nconst MARGIN = 4;\nconst ACTIVE_GROW = 6;\n/* The gap between two slices, in px along the ring. */\nconst SLICE_GAP = 2;\nconst TAU = Math.PI * 2;\n\n/* A slice is a stroked arc: it draws along the ring on enter (pathLength 1, as a line), still\n under reduced motion; the active one thickens. */\nconst SLICE =\n 'fill-none [stroke-dasharray:1] animate-chart-draw transition-[stroke-width] duration-150 motion-reduce:animate-none motion-reduce:transition-none';\n\n/** One drawn slice: its index (the palette slot), its arc and its angles (0 at the top,\n * clockwise, in radians). */\ninterface SliceMark {\n readonly index: number;\n readonly d: string;\n readonly start: number;\n readonly end: number;\n}\n\n/**\n * A donut chart of one set of slices, the parts of a whole (a budget by category, traffic by\n * source), drawn in SVG with the chart palette: each slice's angle is its share of the total.\n * A legend shows and hides slices (the total follows), a tooltip shows a slice's value and share\n * on hover and on keyboard focus (Arrow keys move between the slices and a polite live region\n * reads each one), and a Show data table lists them. The `center` slot holds a total or a label\n * in the ring's hole. Slices draw in on the first render and on every data change, still under\n * reduced motion; under `dir=\"rtl\"` the slices run counter-clockwise.\n *\n * @example\n * <bf-donut-chart\n * label=\"Budget\"\n * [slices]=\"[{ label: 'Rent', value: 1200 }, { label: 'Food', value: 450 }]\"\n * >\n * <span bfSlot=\"center\" class=\"text-title\">1,650</span>\n * </bf-donut-chart>\n * @summary Donut chart of the parts of a whole, with a legend, tooltip and centre slot\n * @category Data display\n * @since 0.3.1\n * @slot center Content in the ring's hole, such as the total and its label.\n */\n@Component({\n selector: 'bf-donut-chart',\n imports: [BfChartFrameComponent],\n // w-full: a chart fills its container's width, also as a shrink-to-fit flex item.\n host: { class: 'block w-full min-w-0' },\n template: `\n <bf-chart-frame\n [label]=\"name()\"\n [height]=\"height()\"\n [legend]=\"legendItems()\"\n [legendPosition]=\"legendPosition()\"\n [tooltip]=\"tooltip()\"\n [announcement]=\"interaction.announcement()\"\n [table]=\"table()\"\n (legendToggled)=\"interaction.toggle($event)\"\n (pointed)=\"onPointed($event)\"\n (left)=\"interaction.point(null)\"\n (stepped)=\"onStep($event)\"\n (focusChanged)=\"onFocus($event)\"\n >\n <svg\n aria-hidden=\"true\"\n focusable=\"false\"\n direction=\"ltr\"\n class=\"block w-full overflow-visible\"\n [attr.height]=\"height()\"\n [attr.viewBox]=\"viewBox()\"\n >\n @let g = geometry();\n <circle\n data-bf-chart-track\n class=\"stroke-chart-grid fill-none\"\n [attr.cx]=\"g.cx\"\n [attr.cy]=\"g.cy\"\n [attr.r]=\"g.r\"\n [attr.stroke-width]=\"g.thickness\"\n />\n <!-- Re-created on every data change, so the enter motion replays. -->\n @for (generation of generations(); track generation) {\n <g>\n @for (slice of g.slices; track slice.index) {\n <path\n data-bf-chart-slice\n pathLength=\"1\"\n [attr.d]=\"slice.d\"\n [attr.stroke-width]=\"slice.index === active() ? g.thickness + growBy : g.thickness\"\n [class]=\"sliceClasses(slice.index)\"\n />\n }\n </g>\n }\n </svg>\n <div\n data-bf-chart-center\n class=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center text-center empty:hidden\"\n >\n <ng-content select=\"[bfSlot=center]\" />\n </div>\n </bf-chart-frame>\n `,\n})\nexport class BfDonutChartComponent {\n /** The slices, in order clockwise from the top. */\n readonly slices = input.required<readonly BfDonutSlice[]>();\n /** The chart's accessible name; empty falls back to the `bf-chart-card` title, then to\n * `provideBfLabels()`'s `chart` (\"Chart\"). */\n readonly label = input('');\n /** The plot's height in px; the ring fits the smaller of it and the container's width. */\n readonly height = input(220, { transform: numberAttribute });\n /** The ring's thickness in px (at most the radius, a full pie). */\n readonly thickness = input(28, { transform: numberAttribute });\n /** Formats the values in the tooltip, the announcements and the table; unset uses\n * `Intl.NumberFormat` in the document's language. */\n readonly valueFormat = input<BfChartValueFormat | undefined>(undefined);\n /** Where the legend goes; unset follows the `bf-chart-card`, else `bottom`. A single slice\n * draws no legend. */\n readonly legend = input<BfChartLegendPosition | undefined>(undefined);\n\n protected readonly interaction = new ChartInteraction();\n private readonly labels = inject(BF_LABELS);\n private readonly card = inject(BF_CHART_CARD, { optional: true });\n private readonly document = inject(DOCUMENT);\n private readonly frame = viewChild.required(BfChartFrameComponent);\n private readonly box = observeWidth(() => this.frame().plotElement(), FALLBACK_WIDTH);\n private readonly percent = percentFormat(this.document);\n\n protected readonly growBy = ACTIVE_GROW;\n\n /** The figure's name: `label`, else the card's title, else the `chart` label. */\n protected readonly name = computed(\n () => this.label() || (this.card?.title() ?? '') || this.labels.chart,\n );\n protected readonly legendPosition = computed(\n () => this.legend() ?? this.card?.legend() ?? 'bottom',\n );\n private readonly format = computed(() => this.valueFormat() ?? defaultValueFormat(this.document));\n /** A new array on every data change: the key that re-creates the slices. */\n protected readonly generations = computed(() => [{ slices: this.slices() }]);\n protected readonly viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`);\n\n /** The indexes of the slices drawn: shown in the legend, with a positive value. */\n private readonly drawn = computed(() =>\n this.slices()\n .map((_, i) => i)\n .filter((i) => !this.interaction.isHidden(i) && this.share(i) > 0),\n );\n /** The total of the drawn slices. */\n private readonly total = computed(() =>\n this.drawn().reduce((sum, i) => sum + (this.slices()[i]?.value ?? 0), 0),\n );\n\n /** Slice `index`'s positive, finite value, else 0. */\n private share(index: number): number {\n const v = this.slices()[index]?.value ?? 0;\n return Number.isFinite(v) && v > 0 ? v : 0;\n }\n\n /** The ring and its arcs, in px of the plot's physical box. */\n protected readonly geometry = computed(() => {\n const width = this.box.width();\n const height = this.height();\n const rtl = this.box.rtl();\n const outer = Math.max(1, Math.min(width, height) / 2 - MARGIN - ACTIVE_GROW / 2);\n const thickness = clamp(this.thickness(), 1, outer);\n const r = outer - thickness / 2;\n const cx = width / 2;\n const cy = height / 2;\n /** The physical point at `angle` (0 at the top, clockwise; mirrored under rtl). */\n const at = (angle: number, radius = r): { x: number; y: number } => ({\n x: px(mirror(cx + radius * Math.sin(angle), width, rtl)),\n y: px(cy - radius * Math.cos(angle)),\n });\n const sweep = rtl ? 0 : 1;\n const arc = (a0: number, a1: number): string => {\n const p0 = at(a0);\n const p1 = at(a1);\n const large = a1 - a0 > Math.PI ? 1 : 0;\n return `M${p0.x},${p0.y}A${px(r)},${px(r)} 0 ${large} ${sweep} ${p1.x},${p1.y}`;\n };\n const total = this.total();\n const drawn = this.drawn();\n const pad = drawn.length > 1 ? SLICE_GAP / Math.max(1, r) : 0;\n let angle = 0;\n const slices: SliceMark[] = drawn.map((index) => {\n const sweepAngle = total > 0 ? (this.share(index) / total) * TAU : 0;\n const start = angle;\n const end = angle + sweepAngle;\n angle = end;\n const inset = sweepAngle > pad * 2 ? pad / 2 : 0;\n const a0 = start + inset;\n const a1 = end - inset;\n // A whole ring cannot be one arc (its ends meet): two halves.\n const d =\n a1 - a0 >= TAU - 1e-6\n ? arc(0, Math.PI) + arc(Math.PI, TAU).replace(/^M[^A]+/, '')\n : arc(a0, a1);\n return { index, d, start, end };\n });\n return { width, cx: px(cx), cy: px(cy), r: px(r), thickness, rtl, slices, at };\n });\n\n protected readonly legendItems = computed<ChartLegendItem[]>(() => {\n const slices = this.slices();\n return slices.length < 2\n ? []\n : slices.map((s, i) => ({\n name: s.label,\n swatch: seriesSwatch(i),\n hidden: this.interaction.isHidden(i),\n }));\n });\n\n /** The active slice, if it is drawn. */\n protected readonly active = computed(() => {\n const at = this.interaction.active();\n return at !== null && this.drawn().includes(at) ? at : null;\n });\n\n /** \"Rent: 1,200 (73%)\", the value of slice `index` with its share. */\n private valueText(index: number): string {\n const total = this.total();\n const value = this.share(index);\n return `${this.format()(value)} (${this.percent(total > 0 ? value / total : 0)})`;\n }\n\n protected readonly tooltip = computed<ChartTooltip | null>(() => {\n const index = this.active();\n const g = this.geometry();\n const slice = g.slices.find((s) => s.index === index);\n if (index === null || !slice) {\n return null;\n }\n const point = g.at((slice.start + slice.end) / 2);\n return {\n title: '',\n rows: [\n {\n name: this.slices()[index]?.label ?? '',\n value: this.valueText(index),\n swatch: seriesSwatch(index),\n },\n ],\n x: point.x,\n y: point.y,\n };\n });\n\n protected readonly table = computed<ChartTable>(() => ({\n head: [this.labels.chartCategory, this.labels.chartValue],\n rows: this.slices().map((s) => [s.label, this.format()(s.value)]),\n }));\n\n /**\n * The stroke classes of slice `index`.\n * @internal\n */\n sliceClasses(index: number): string {\n return `${SLICE} ${seriesStroke(index)}`;\n }\n\n /**\n * Points at the slice under the pointer, or at none off the ring.\n * @internal\n */\n onPointed(pointer: ChartPointer): void {\n const g = this.geometry();\n const dx = mirror(pointer.x, g.width, g.rtl) - g.cx;\n const dy = pointer.y - g.cy;\n const distance = Math.hypot(dx, dy);\n const reach = g.thickness / 2 + ACTIVE_GROW;\n if (Math.abs(distance - g.r) > reach) {\n this.interaction.point(null);\n return;\n }\n const angle = (Math.atan2(dx, -dy) + TAU) % TAU;\n const slice = g.slices.find((s) => angle >= s.start && angle < s.end);\n this.interaction.point(slice?.index ?? null);\n }\n\n /**\n * Moves the active slice by keyboard and announces it.\n * @internal\n */\n onStep(step: ChartStep): void {\n this.interaction.step(\n step,\n this.drawn(),\n (i) => `${this.slices()[i]?.label ?? ''}: ${this.valueText(i)}`,\n );\n }\n\n /**\n * On focus, shows the first slice (or keeps the hovered one); on blur, hides the tooltip.\n * @internal\n */\n onFocus(focused: boolean): void {\n if (!focused) {\n this.interaction.point(null);\n } else if (this.interaction.active() === null) {\n this.onStep('first');\n }\n }\n}\n","import {\n Component,\n ElementRef,\n booleanAttribute,\n computed,\n inject,\n input,\n numberAttribute,\n} from '@angular/core';\nimport { mirror } from '../core/axis';\nimport { type BfChartCurve } from '../core/chart-types';\nimport { areaPath, linePath, px, segments } from '../core/curve';\nimport { observeWidth } from '../core/observe-width';\n\n/** The width a sparkline draws at before (or without) a measure, such as on the server. */\nconst FALLBACK_WIDTH = 120;\n/* Room for the 2 px line and the end dot, so neither is clipped at the edges. */\nconst PAD = 3;\n\nconst LINE =\n 'fill-none stroke-chart-1 [stroke-dasharray:1] animate-chart-draw motion-reduce:animate-none';\nconst AREA = 'fill-chart-1/16 stroke-none animate-chart-fade motion-reduce:animate-none';\nconst DOT = 'fill-chart-1 animate-chart-fade motion-reduce:animate-none';\n\n/**\n * A tiny line of one series with no axes, legend or tooltip, for a trend beside a figure (in a\n * `bf-stat`'s supporting line, a table cell). Its scale spans the values' own range, so it shows\n * the shape of the trend, not its size; a dot marks the latest value. With a `label` it is an\n * image with that name (say what the trend means, such as \"Revenue up 12% over 30 days\"); without\n * one it is decorative and hidden from assistive technology. It draws in on the first render and\n * on every data change, still under reduced motion; under `dir=\"rtl\"` it runs from the right.\n *\n * @example\n * <bf-stat label=\"Revenue\" value=\"$48,200\">\n * <bf-sparkline [values]=\"[31, 34, 33, 39, 42, 48]\" label=\"Revenue rising over six months\" />\n * </bf-stat>\n * @summary Tiny trend line with no axes or legend, for stats and table cells\n * @category Data display\n * @since 0.3.1\n */\n@Component({\n selector: 'bf-sparkline',\n host: { class: 'block min-w-0' },\n template: `\n <svg\n focusable=\"false\"\n direction=\"ltr\"\n class=\"block w-full overflow-visible\"\n [attr.role]=\"label() ? 'img' : null\"\n [attr.aria-label]=\"label() || null\"\n [attr.aria-hidden]=\"label() ? null : 'true'\"\n [attr.height]=\"height()\"\n [attr.viewBox]=\"viewBox()\"\n >\n @let g = geometry();\n @for (generation of generations(); track generation) {\n <g>\n @if (area()) {\n <path data-bf-sparkline-area [attr.d]=\"g.area\" [class]=\"areaClasses\" />\n }\n <path\n data-bf-sparkline-line\n pathLength=\"1\"\n stroke-width=\"2\"\n stroke-linejoin=\"round\"\n stroke-linecap=\"round\"\n [attr.d]=\"g.line\"\n [class]=\"lineClasses\"\n />\n @if (g.last; as last) {\n <circle\n data-bf-sparkline-dot\n r=\"2.5\"\n [attr.cx]=\"last.x\"\n [attr.cy]=\"last.y\"\n [class]=\"dotClasses\"\n />\n }\n </g>\n }\n </svg>\n `,\n})\nexport class BfSparklineComponent {\n /** The values in order, oldest first; `null` leaves a gap. */\n readonly values = input.required<readonly (number | null)[]>();\n /** What the trend means, its accessible name (\"Revenue up 12% this month\"); empty makes the\n * sparkline decorative. */\n readonly label = input('');\n /** Height in px; the width follows the container. */\n readonly height = input(32, { transform: numberAttribute });\n /** Fills the area under the line. */\n readonly area = input(false, { transform: booleanAttribute });\n /** The line between points: `linear` (default) or `smooth`, a monotone curve. */\n readonly curve = input<BfChartCurve>('linear');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly box = observeWidth(() => this.host.nativeElement, FALLBACK_WIDTH);\n\n protected readonly lineClasses = LINE;\n protected readonly areaClasses = AREA;\n protected readonly dotClasses = DOT;\n\n /** A new array on every data change: the key that re-creates the line. */\n protected readonly generations = computed(() => [{ values: this.values() }]);\n protected readonly viewBox = computed(() => `0 0 ${this.box.width()} ${this.height()}`);\n\n protected readonly geometry = computed(() => {\n const width = this.box.width();\n const height = this.height();\n const rtl = this.box.rtl();\n const values = this.values();\n const finite = values.filter((v): v is number => v !== null && Number.isFinite(v));\n const lo = Math.min(...finite);\n const hi = Math.max(...finite);\n const span = hi - lo;\n const n = values.length;\n const xAt = (i: number): number =>\n mirror(n > 1 ? PAD + (i * (width - PAD * 2)) / (n - 1) : width / 2, width, rtl);\n // A flat line sits in the middle.\n const yAt = (v: number): number =>\n span > 0 ? PAD + (1 - (v - lo) / span) * (height - PAD * 2) : height / 2;\n const points = values.map((v, i) =>\n v === null || !Number.isFinite(v) ? null : { x: xAt(i), y: yAt(v) },\n );\n const runs = segments(points);\n const lastRun = runs[runs.length - 1];\n const lastPoint = lastRun?.[lastRun.length - 1];\n return {\n line: linePath(points, this.curve()),\n area: areaPath(points, this.curve(), height),\n last: lastPoint ? { x: px(lastPoint.x), y: px(lastPoint.y) } : null,\n };\n });\n}\n","import { Component, booleanAttribute, inject, input } from '@angular/core';\nimport { BF_LABELS, BfSkeletonComponent } from '@bitforgehq/ui';\nimport { BF_CHART_CARD, type ChartCardHost } from '../core/chart-card.token';\nimport { type BfChartLegendPosition } from '../core/chart-types';\n\n/**\n * The heading level of a `bf-chart-card` title: `2` for a card on a page, `3` inside a section.\n *\n * @summary Heading level of a chart card title, two on a page or three inside\n * @since 0.3.1\n */\nexport type BfChartCardHeadingLevel = 2 | 3;\n\n/* The `flat` bf-card surface: `surface`, the card radius and padding, a 1.5 px `border-strong`\n edge. `h-full`: in a grid of cards every card stretches to the row's height. */\nconst HOST =\n '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';\n/* The loading, empty and error states take the default chart's height, so the card never jumps\n when the data arrives. */\nconst STATE =\n 'flex min-h-60 flex-col items-center justify-center gap-2 rounded-tile text-center text-body text-text-muted';\n\n/**\n * A card around one chart: a title, a `period` slot for the range control (a `bf-segmented` or a\n * `bf-select`), and the chart, or its loading placeholder (a `bf-skeleton`), its empty state or\n * its error. The chart inside takes the card's title as its name when it has no `label`, and the\n * card's `legend` placement when it sets none.\n *\n * @example\n * <bf-chart-card title=\"Revenue\" [loading]=\"revenue.isLoading()\">\n * <bf-segmented bfSlot=\"period\" label=\"Period\" [options]=\"periods\" [(value)]=\"period\" />\n * <bf-line-chart [series]=\"series()\" [categories]=\"months()\" />\n * </bf-chart-card>\n * @summary Card around one chart with a title, period control and loading, empty and error states\n * @category Data display\n * @since 0.3.1\n * @slot default The chart.\n * @slot period The range control at the top end, such as a bf-segmented or a bf-select.\n * @slot empty What shows when `empty` is set; without it, the `chartEmpty` label.\n * @slot error What shows when `error` is set, such as a message and a retry button; without it,\n * the `chartError` label.\n */\n@Component({\n selector: 'bf-chart-card',\n imports: [BfSkeletonComponent],\n host: { '[class]': 'hostClasses' },\n providers: [{ provide: BF_CHART_CARD, useExisting: BfChartCardComponent }],\n template: `\n <div class=\"flex flex-wrap items-center justify-between gap-x-4 gap-y-2\">\n @if (headingLevel() === 3) {\n <h3 class=\"text-heading text-text min-w-0\">{{ title() }}</h3>\n } @else {\n <h2 class=\"text-heading text-text min-w-0\">{{ title() }}</h2>\n }\n <div data-bf-chart-card-period class=\"shrink-0 empty:hidden\">\n <ng-content select=\"[bfSlot=period]\" />\n </div>\n </div>\n <div data-bf-chart-card-body class=\"min-w-0\" [attr.aria-busy]=\"loading() ? 'true' : null\">\n @if (loading()) {\n <bf-skeleton shape=\"rect\" height=\"15rem\" />\n } @else if (error()) {\n <div data-bf-chart-card-error role=\"status\" [class]=\"stateClasses\">\n <ng-content select=\"[bfSlot=error]\">{{ labels.chartError }}</ng-content>\n </div>\n } @else if (empty()) {\n <div data-bf-chart-card-empty role=\"status\" [class]=\"stateClasses\">\n <ng-content select=\"[bfSlot=empty]\">{{ labels.chartEmpty }}</ng-content>\n </div>\n } @else {\n <ng-content />\n }\n </div>\n `,\n})\nexport class BfChartCardComponent implements ChartCardHost {\n /** The card's heading; also the chart's name when the chart has no `label`. */\n readonly title = input.required<string>();\n /** Heading level of the title so the card fits the page outline. */\n readonly headingLevel = input<BfChartCardHeadingLevel>(2);\n /** Where the chart inside draws its legend, unless it sets its own `legend`. */\n readonly legend = input<BfChartLegendPosition>('bottom');\n /** Shows a placeholder instead of the chart while its data loads, and marks the body\n * `aria-busy`. */\n readonly loading = input(false, { transform: booleanAttribute });\n /** Shows the `empty` slot (or the `chartEmpty` label) instead of the chart: there is no data\n * for the period. */\n readonly empty = input(false, { transform: booleanAttribute });\n /** Shows the `error` slot (or the `chartError` label) instead of the chart: the data failed to\n * load. Wins over `empty`; `loading` wins over both. */\n readonly error = input(false, { transform: booleanAttribute });\n\n protected readonly labels = inject(BF_LABELS);\n protected readonly hostClasses = HOST;\n protected readonly stateClasses = STATE;\n}\n"],"mappings":"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"}
@@ -1,5 +1,89 @@
1
1
  import * as i0 from "@angular/core";
2
- import { Component, computed, input } from "@angular/core";
2
+ import { Component, booleanAttribute, computed, input } from "@angular/core";
3
+ const NUMBER = /[-+]?(?:\d+\.?\d*|\.\d+)(?:[eE][-+]?\d+)?/y;
4
+ const PARAMS = {
5
+ M: 2,
6
+ L: 2,
7
+ H: 1,
8
+ V: 1,
9
+ C: 6,
10
+ S: 4,
11
+ Q: 4,
12
+ T: 2,
13
+ A: 7,
14
+ Z: 0
15
+ };
16
+ const EPSILON = .01;
17
+ function readNumber(d, index, flag) {
18
+ let i = index;
19
+ while (i < d.length && /[\s,]/.test(d[i] ?? "")) i++;
20
+ if (flag) {
21
+ const char = d[i];
22
+ return char === "0" || char === "1" ? [Number(char), i + 1] : null;
23
+ }
24
+ NUMBER.lastIndex = i;
25
+ const match = NUMBER.exec(d);
26
+ return match ? [Number(match[0]), NUMBER.lastIndex] : null;
27
+ }
28
+ function isClosedPath(d) {
29
+ let current = [0, 0];
30
+ let start = [0, 0];
31
+ let open = false;
32
+ let index = 0;
33
+ let command = "";
34
+ const close = () => {
35
+ open = false;
36
+ current = start;
37
+ };
38
+ const finishSubpath = () => !open || Math.hypot(current[0] - start[0], current[1] - start[1]) <= EPSILON;
39
+ while (index < d.length) {
40
+ const char = d[index] ?? "";
41
+ if (/[\s,]/.test(char)) {
42
+ index++;
43
+ continue;
44
+ }
45
+ if (/[a-zA-Z]/.test(char)) {
46
+ const upper = char.toUpperCase();
47
+ if (!(upper in PARAMS)) return false;
48
+ command = char;
49
+ index++;
50
+ if (upper === "Z") {
51
+ close();
52
+ continue;
53
+ }
54
+ if (upper === "M" && !finishSubpath()) return false;
55
+ } else if (!command || command.toUpperCase() === "Z") return false;
56
+ const upper = command.toUpperCase();
57
+ const relative = command !== upper;
58
+ const values = [];
59
+ for (let n = 0; n < (PARAMS[upper] ?? 0); n++) {
60
+ const read = readNumber(d, index, upper === "A" && (n === 3 || n === 4));
61
+ if (!read) return false;
62
+ values.push(read[0]);
63
+ index = read[1];
64
+ }
65
+ const [x, y] = upper === "H" ? [(relative ? current[0] : 0) + (values[0] ?? 0), current[1]] : upper === "V" ? [current[0], (relative ? current[1] : 0) + (values[0] ?? 0)] : [(relative ? current[0] : 0) + (values[values.length - 2] ?? 0), (relative ? current[1] : 0) + (values[values.length - 1] ?? 0)];
66
+ current = [x, y];
67
+ if (upper === "M") {
68
+ start = current;
69
+ open = true;
70
+ command = relative ? "l" : "L";
71
+ }
72
+ }
73
+ return finishSubpath();
74
+ }
75
+ function isFillable(icon) {
76
+ return icon.length > 0 && icon.every(([tag, attrs]) => {
77
+ switch (tag) {
78
+ case "circle":
79
+ case "ellipse":
80
+ case "rect":
81
+ case "polygon": return true;
82
+ case "path": return typeof attrs["d"] === "string" && isClosedPath(attrs["d"]);
83
+ default: return false;
84
+ }
85
+ });
86
+ }
3
87
  const SIZE_PX = {
4
88
  sm: 16,
5
89
  md: 20,
@@ -9,7 +93,12 @@ var BfIconComponent = class BfIconComponent {
9
93
  icon = input.required(...ngDevMode ? [{ debugName: "icon" }] : /* istanbul ignore next */ []);
10
94
  size = input("md", ...ngDevMode ? [{ debugName: "size" }] : /* istanbul ignore next */ []);
11
95
  label = input("", ...ngDevMode ? [{ debugName: "label" }] : /* istanbul ignore next */ []);
96
+ filled = input(false, {
97
+ ...ngDevMode ? { debugName: "filled" } : /* istanbul ignore next */ {},
98
+ transform: booleanAttribute
99
+ });
12
100
  px = computed(() => SIZE_PX[this.size()], ...ngDevMode ? [{ debugName: "px" }] : /* istanbul ignore next */ []);
101
+ fillsShape = computed(() => this.filled() && isFillable(this.icon()), ...ngDevMode ? [{ debugName: "fillsShape" }] : /* istanbul ignore next */ []);
13
102
  static ɵfac = i0.ɵɵngDeclareFactory({
14
103
  minVersion: "12.0.0",
15
104
  version: "22.1.7",
@@ -45,6 +134,13 @@ var BfIconComponent = class BfIconComponent {
45
134
  isSignal: true,
46
135
  isRequired: false,
47
136
  transformFunction: null
137
+ },
138
+ filled: {
139
+ classPropertyName: "filled",
140
+ publicName: "filled",
141
+ isSignal: true,
142
+ isRequired: false,
143
+ transformFunction: null
48
144
  }
49
145
  },
50
146
  host: { classAttribute: "inline-flex shrink-0" },
@@ -55,7 +151,7 @@ var BfIconComponent = class BfIconComponent {
55
151
  [attr.width]="px()"
56
152
  [attr.height]="px()"
57
153
  viewBox="0 0 24 24"
58
- fill="none"
154
+ [attr.fill]="fillsShape() ? 'currentColor' : 'none'"
59
155
  stroke="currentColor"
60
156
  stroke-width="2"
61
157
  stroke-linecap="round"
@@ -135,7 +231,7 @@ i0.ɵɵngDeclareClassMetadata({
135
231
  [attr.width]="px()"
136
232
  [attr.height]="px()"
137
233
  viewBox="0 0 24 24"
138
- fill="none"
234
+ [attr.fill]="fillsShape() ? 'currentColor' : 'none'"
139
235
  stroke="currentColor"
140
236
  stroke-width="2"
141
237
  stroke-linecap="round"
@@ -222,6 +318,14 @@ i0.ɵɵngDeclareClassMetadata({
222
318
  alias: "label",
223
319
  required: false
224
320
  }]
321
+ }],
322
+ filled: [{
323
+ type: i0.Input,
324
+ args: [{
325
+ isSignal: true,
326
+ alias: "filled",
327
+ required: false
328
+ }]
225
329
  }]
226
330
  }
227
331
  });
@@ -1 +1 @@
1
- {"version":3,"file":"bitforgehq-ui-icons.mjs","names":[],"sources":["../../../projects/ui/icons/icon.component.ts"],"sourcesContent":["import { Component, computed, input } from '@angular/core';\nimport { type IconNode } from 'lucide';\n\n/**\n * The size of a `bf-icon`: sm 16, md 20 or lg 24 px.\n *\n * @summary The three icon sizes, 16, 20 and 24 pixels, matching the text sizes\n * @since 0.1.0\n */\nexport type BfIconSize = 'sm' | 'md' | 'lg';\n\nconst SIZE_PX: Record<BfIconSize, number> = { sm: 16, md: 20, lg: 24 };\n\n/**\n * Renders a Lucide icon from its data, tree-shakably and without a registry.\n * Import the icon you need from `lucide` (e.g. `import { Search } from 'lucide'`) and bind it.\n * Decorative by default; pass `label` when the icon carries meaning on its own (e.g. an icon-only\n * control without visible text).\n *\n * @example\n * <bf-icon [icon]=\"Search\" />\n * <bf-icon [icon]=\"Search\" label=\"Search\" size=\"lg\" />\n * @summary Tree-shakable Lucide icon renderer, decorative by default or labelled when meaningful\n * @category Icons\n * @since 0.1.0\n */\n@Component({\n selector: 'bf-icon',\n host: { class: 'inline-flex shrink-0' },\n template: `\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n [attr.width]=\"px()\"\n [attr.height]=\"px()\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n [attr.role]=\"label() ? 'img' : null\"\n [attr.aria-label]=\"label() || null\"\n [attr.aria-hidden]=\"label() ? null : 'true'\"\n >\n @for (node of icon(); track $index) {\n @switch (node[0]) {\n @case ('path') {\n <path [attr.d]=\"node[1]['d']\" [attr.fill]=\"node[1]['fill'] ?? null\" />\n }\n @case ('circle') {\n <circle\n [attr.cx]=\"node[1]['cx']\"\n [attr.cy]=\"node[1]['cy']\"\n [attr.r]=\"node[1]['r']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n @case ('ellipse') {\n <ellipse\n [attr.cx]=\"node[1]['cx']\"\n [attr.cy]=\"node[1]['cy']\"\n [attr.rx]=\"node[1]['rx']\"\n [attr.ry]=\"node[1]['ry']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n @case ('line') {\n <line\n [attr.x1]=\"node[1]['x1']\"\n [attr.y1]=\"node[1]['y1']\"\n [attr.x2]=\"node[1]['x2']\"\n [attr.y2]=\"node[1]['y2']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n @case ('polyline') {\n <polyline [attr.points]=\"node[1]['points']\" [attr.fill]=\"node[1]['fill'] ?? null\" />\n }\n @case ('polygon') {\n <polygon [attr.points]=\"node[1]['points']\" [attr.fill]=\"node[1]['fill'] ?? null\" />\n }\n @case ('rect') {\n <rect\n [attr.x]=\"node[1]['x']\"\n [attr.y]=\"node[1]['y']\"\n [attr.width]=\"node[1]['width']\"\n [attr.height]=\"node[1]['height']\"\n [attr.rx]=\"node[1]['rx']\"\n [attr.ry]=\"node[1]['ry']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n }\n }\n </svg>\n `,\n})\nexport class BfIconComponent {\n /** Lucide icon data, e.g. `Search` from `lucide`. */\n readonly icon = input.required<IconNode>();\n /** Visual size: 16, 20 or 24 px. */\n readonly size = input<BfIconSize>('md');\n /** Accessible name. Leave empty for decorative icons next to visible text. */\n readonly label = input('');\n\n readonly px = computed(() => SIZE_PX[this.size()]);\n}\n"],"mappings":";;AAWA,MAAM,UAAsC;CAAE,IAAI;CAAI,IAAI;CAAI,IAAI;AAAE;AAsFpE,IAAa,kBAAb,MAAa,gBAAe;CAEjB,OAAO,MAAM,SAAoB,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,gCAAA,CAAA,CAAA;CAEjC,OAAO,MAAkB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,gCAAA,CAAA,CAAA;CAE9B,QAAQ,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,gCAAA,CAAA,CAAA;CAEjB,KAAK,eAAe,QAAQ,KAAK,KAAI,IAAI,GAAA,YAAA,CAAA,EAAA,WAAA,KAAA,CAAA,gCAAA,CAAA,CAAA;CARvC,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAe,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAf,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAe,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,MAAA,EAAA,gBAAA,uBAAA;EAAA,UAAA;EAAA,UApEhB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAkET,UAAA;CAAA,CAAA;;AAEU,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAe,YAAA,CAAA;EAvE3B,MAAA;EAAU,MAAA,CAAA;GACT,UAAU;GACV,MAAM,EAAE,OAAO,uBAAsB;GACrC,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmEX,CAAA"}
1
+ {"version":3,"file":"bitforgehq-ui-icons.mjs","names":[],"sources":["../../../projects/ui/icons/icon-fill.ts","../../../projects/ui/icons/icon.component.ts"],"sourcesContent":["import { type IconNode } from 'lucide';\n\n/* Whether a Lucide icon can be filled without harm: every element is a closed shape. A filled\n open stroke (a check mark, a line) would paint the area its ends enclose, and a filled outline\n holding inner strokes (a circle around a check) would hide them under the same colour, so an\n icon with any open element is never filled. */\n\ntype Point = readonly [number, number];\n\n/* Path data numbers: signed decimals with an optional exponent, including the compact `.5.5` and\n `1-2` forms Lucide uses. */\nconst NUMBER = /[-+]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?/y;\nconst PARAMS: Readonly<Record<string, number>> = {\n M: 2,\n L: 2,\n H: 1,\n V: 1,\n C: 6,\n S: 4,\n Q: 4,\n T: 2,\n A: 7,\n Z: 0,\n};\n/* Closing within this distance (in the 24-unit viewBox) counts as closed. */\nconst EPSILON = 0.01;\n\n/** Reads the next number (or, for an arc flag, the next single digit) from `d` at `index`. */\nfunction readNumber(d: string, index: number, flag: boolean): [number, number] | null {\n let i = index;\n while (i < d.length && /[\\s,]/.test(d[i] ?? '')) {\n i++;\n }\n if (flag) {\n const char = d[i];\n return char === '0' || char === '1' ? [Number(char), i + 1] : null;\n }\n NUMBER.lastIndex = i;\n const match = NUMBER.exec(d);\n return match ? [Number(match[0]), NUMBER.lastIndex] : null;\n}\n\n/** Whether every subpath of the path data `d` ends where it started (or with `Z`). */\nexport function isClosedPath(d: string): boolean {\n let current: Point = [0, 0];\n let start: Point = [0, 0];\n let open = false;\n let index = 0;\n let command = '';\n const close = (): void => {\n open = false;\n current = start;\n };\n const finishSubpath = (): boolean =>\n !open || Math.hypot(current[0] - start[0], current[1] - start[1]) <= EPSILON;\n\n while (index < d.length) {\n const char = d[index] ?? '';\n if (/[\\s,]/.test(char)) {\n index++;\n continue;\n }\n if (/[a-zA-Z]/.test(char)) {\n const upper = char.toUpperCase();\n if (!(upper in PARAMS)) {\n return false;\n }\n command = char;\n index++;\n if (upper === 'Z') {\n close();\n continue;\n }\n if (upper === 'M' && !finishSubpath()) {\n return false;\n }\n } else if (!command || command.toUpperCase() === 'Z') {\n return false;\n }\n\n const upper = command.toUpperCase();\n const relative = command !== upper;\n const values: number[] = [];\n for (let n = 0; n < (PARAMS[upper] ?? 0); n++) {\n const read = readNumber(d, index, upper === 'A' && (n === 3 || n === 4));\n if (!read) {\n return false;\n }\n values.push(read[0]);\n index = read[1];\n }\n const [x, y] =\n upper === 'H'\n ? [(relative ? current[0] : 0) + (values[0] ?? 0), current[1]]\n : upper === 'V'\n ? [current[0], (relative ? current[1] : 0) + (values[0] ?? 0)]\n : [\n (relative ? current[0] : 0) + (values[values.length - 2] ?? 0),\n (relative ? current[1] : 0) + (values[values.length - 1] ?? 0),\n ];\n current = [x, y];\n if (upper === 'M') {\n start = current;\n open = true;\n // Further coordinate pairs after a moveto are linetos.\n command = relative ? 'l' : 'L';\n }\n }\n return finishSubpath();\n}\n\n/** Whether every element of the icon is a closed shape, so filling it hides nothing. */\nexport function isFillable(icon: IconNode): boolean {\n return (\n icon.length > 0 &&\n icon.every(([tag, attrs]) => {\n switch (tag) {\n case 'circle':\n case 'ellipse':\n case 'rect':\n case 'polygon':\n return true;\n case 'path':\n return typeof attrs['d'] === 'string' && isClosedPath(attrs['d']);\n default:\n return false;\n }\n })\n );\n}\n","import { Component, booleanAttribute, computed, input } from '@angular/core';\nimport { type IconNode } from 'lucide';\nimport { isFillable } from './icon-fill';\n\n/**\n * The size of a `bf-icon`: sm 16, md 20 or lg 24 px.\n *\n * @summary The three icon sizes, 16, 20 and 24 pixels, matching the text sizes\n * @since 0.1.0\n */\nexport type BfIconSize = 'sm' | 'md' | 'lg';\n\nconst SIZE_PX: Record<BfIconSize, number> = { sm: 16, md: 20, lg: 24 };\n\n/**\n * Renders a Lucide icon from its data, tree-shakably and without a registry.\n * Import the icon you need from `lucide` (e.g. `import { Search } from 'lucide'`) and bind it.\n * Decorative by default; pass `label` when the icon carries meaning on its own (e.g. an icon-only\n * control without visible text). `filled` fills a solid shape such as a heart or a star.\n *\n * @example\n * <bf-icon [icon]=\"Search\" />\n * <bf-icon [icon]=\"Search\" label=\"Search\" size=\"lg\" />\n * <bf-icon [icon]=\"Heart\" [filled]=\"favourite()\" />\n * @summary Tree-shakable Lucide icon renderer, decorative by default or labelled when meaningful\n * @category Icons\n * @since 0.1.0\n */\n@Component({\n selector: 'bf-icon',\n host: { class: 'inline-flex shrink-0' },\n template: `\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n [attr.width]=\"px()\"\n [attr.height]=\"px()\"\n viewBox=\"0 0 24 24\"\n [attr.fill]=\"fillsShape() ? 'currentColor' : 'none'\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n [attr.role]=\"label() ? 'img' : null\"\n [attr.aria-label]=\"label() || null\"\n [attr.aria-hidden]=\"label() ? null : 'true'\"\n >\n @for (node of icon(); track $index) {\n @switch (node[0]) {\n @case ('path') {\n <path [attr.d]=\"node[1]['d']\" [attr.fill]=\"node[1]['fill'] ?? null\" />\n }\n @case ('circle') {\n <circle\n [attr.cx]=\"node[1]['cx']\"\n [attr.cy]=\"node[1]['cy']\"\n [attr.r]=\"node[1]['r']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n @case ('ellipse') {\n <ellipse\n [attr.cx]=\"node[1]['cx']\"\n [attr.cy]=\"node[1]['cy']\"\n [attr.rx]=\"node[1]['rx']\"\n [attr.ry]=\"node[1]['ry']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n @case ('line') {\n <line\n [attr.x1]=\"node[1]['x1']\"\n [attr.y1]=\"node[1]['y1']\"\n [attr.x2]=\"node[1]['x2']\"\n [attr.y2]=\"node[1]['y2']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n @case ('polyline') {\n <polyline [attr.points]=\"node[1]['points']\" [attr.fill]=\"node[1]['fill'] ?? null\" />\n }\n @case ('polygon') {\n <polygon [attr.points]=\"node[1]['points']\" [attr.fill]=\"node[1]['fill'] ?? null\" />\n }\n @case ('rect') {\n <rect\n [attr.x]=\"node[1]['x']\"\n [attr.y]=\"node[1]['y']\"\n [attr.width]=\"node[1]['width']\"\n [attr.height]=\"node[1]['height']\"\n [attr.rx]=\"node[1]['rx']\"\n [attr.ry]=\"node[1]['ry']\"\n [attr.fill]=\"node[1]['fill'] ?? null\"\n />\n }\n }\n }\n </svg>\n `,\n})\nexport class BfIconComponent {\n /** Lucide icon data, e.g. `Search` from `lucide`. */\n readonly icon = input.required<IconNode>();\n /** Visual size: 16, 20 or 24 px. */\n readonly size = input<BfIconSize>('md');\n /** Accessible name. Leave empty for decorative icons next to visible text. */\n readonly label = input('');\n /** Fills the shape with `currentColor` (a favourite heart, a starred item); the stroke stays.\n * Only icons whose every shape is closed are filled; a stroke icon (a check, a line) or an\n * outline holding inner strokes renders as usual. */\n readonly filled = input(false, { transform: booleanAttribute });\n\n readonly px = computed(() => SIZE_PX[this.size()]);\n /** Whether the shape is filled: `filled`, on an icon that can take it without hiding a stroke. */\n protected readonly fillsShape = computed(() => this.filled() && isFillable(this.icon()));\n}\n"],"mappings":"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"}