@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,283 @@
1
+ # bf-chart-card
2
+
3
+ Card around one chart with a title, period control and loading, empty and error states
4
+
5
+ `BfChartCardComponent` from `@bitforgehq/ui/charts` · Data display · since 0.3.1
6
+
7
+ ## Example
8
+
9
+ ```ts
10
+ import { Component, computed, signal } from '@angular/core';
11
+ import { BfSegmentedComponent, type BfSegmentOption } from '@bitforgehq/ui';
12
+ import {
13
+ BfBarChartComponent,
14
+ BfChartCardComponent,
15
+ type BfChartSeries,
16
+ } from '@bitforgehq/ui/charts';
17
+
18
+ type Period = 'week' | 'month';
19
+ type CardState = 'data' | 'loading' | 'empty' | 'error';
20
+
21
+ const SERIES: Record<Period, { categories: readonly string[]; series: readonly BfChartSeries[] }> =
22
+ {
23
+ week: {
24
+ categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'],
25
+ series: [{ name: 'Deploys', values: [4, 7, 3, 6, 2] }],
26
+ },
27
+ month: {
28
+ categories: ['W40', 'W41', 'W42', 'W43'],
29
+ series: [{ name: 'Deploys', values: [21, 18, 26, 22] }],
30
+ },
31
+ };
32
+
33
+ /**
34
+ * The bf-chart-card overview.
35
+ *
36
+ * Live demo of `bf-chart-card`: deploys per day or per week, with the period switch in the
37
+ * card's `period` slot. The second control shows the card's loading, empty and error states.
38
+ */
39
+ @Component({
40
+ selector: 'app-example-chart-card-overview',
41
+ imports: [BfChartCardComponent, BfBarChartComponent, BfSegmentedComponent],
42
+ template: `
43
+ <div class="flex w-full flex-col gap-4">
44
+ <bf-segmented size="sm" label="Card state" [options]="states" [(value)]="state" />
45
+ <bf-chart-card
46
+ title="Deploys"
47
+ [loading]="state() === 'loading'"
48
+ [empty]="state() === 'empty'"
49
+ [error]="state() === 'error'"
50
+ >
51
+ <bf-segmented
52
+ bfSlot="period"
53
+ size="sm"
54
+ label="Period"
55
+ [options]="periods"
56
+ [(value)]="period"
57
+ />
58
+ <bf-bar-chart [series]="data().series" [categories]="data().categories" [height]="200" />
59
+ </bf-chart-card>
60
+ <p data-status aria-live="polite" class="text-caption text-text-muted">
61
+ Period: {{ period() }} · {{ state() }}
62
+ </p>
63
+ </div>
64
+ `,
65
+ })
66
+ export class ChartCardOverviewExampleComponent {
67
+ readonly periods: BfSegmentOption<Period>[] = [
68
+ { value: 'week', label: 'Week' },
69
+ { value: 'month', label: 'Month' },
70
+ ];
71
+ readonly states: BfSegmentOption<CardState>[] = [
72
+ { value: 'data', label: 'Data' },
73
+ { value: 'loading', label: 'Loading' },
74
+ { value: 'empty', label: 'Empty' },
75
+ { value: 'error', label: 'Error' },
76
+ ];
77
+ readonly period = signal<Period | null>('week');
78
+ readonly state = signal<CardState | null>('data');
79
+ readonly data = computed(() => SERIES[this.period() ?? 'week']);
80
+ }
81
+ ```
82
+
83
+ ## Overview
84
+
85
+ A card around one chart: a title, a `period` slot for the range control (a `bf-segmented` or a
86
+ `bf-select`), and the chart, or its loading placeholder (a `bf-skeleton`), its empty state or
87
+ its error. The chart inside takes the card's title as its name when it has no `label`, and the
88
+ card's `legend` placement when it sets none.
89
+
90
+ A chart card frames one chart on a dashboard: a title, a range control at the top end, and the chart, or what stands in for it while the data loads, when there is none and when it failed. `bf-chart-card` draws the `flat` card surface around them; the chart inside takes the card's title as its name and the card's `legend` placement. It lives in `@bitforgehq/ui/charts` (`import { BfChartCardComponent } from '@bitforgehq/ui/charts'`) and works the same in a desktop web app and in the Capacitor shell.
91
+
92
+ ## When to use
93
+
94
+ Use `bf-chart-card` around a [bf-line-chart](https://bitforge-ui.web.app/components/line-chart), [bf-bar-chart](https://bitforge-ui.web.app/components/bar-chart) or [bf-donut-chart](https://bitforge-ui.web.app/components/donut-chart) on a dashboard or a detail page. Use [bf-card](https://bitforge-ui.web.app/components/card) instead for a card that holds more than one chart or other content, and [bf-stat](https://bitforge-ui.web.app/components/stat) with a [bf-sparkline](https://bitforge-ui.web.app/components/sparkline) for a headline figure with a small trend.
95
+
96
+ ## A dashboard
97
+
98
+ Stats in a row over chart cards in a grid: the cards stretch to their row's height, so their charts line up. The `period` slot holds a `bf-segmented` (three or four ranges) or a `bf-select` (more); the app reloads the data when it changes.
99
+
100
+ ```ts
101
+ import { Component, computed, signal } from '@angular/core';
102
+ import { BfSegmentedComponent, BfStatComponent, type BfSegmentOption } from '@bitforgehq/ui';
103
+ import {
104
+ BfBarChartComponent,
105
+ BfChartCardComponent,
106
+ BfDonutChartComponent,
107
+ BfLineChartComponent,
108
+ BfSparklineComponent,
109
+ type BfChartSeries,
110
+ type BfDonutSlice,
111
+ } from '@bitforgehq/ui/charts';
112
+
113
+ type Range = '30d' | '90d';
114
+
115
+ const REVENUE: Record<Range, { categories: readonly string[]; series: readonly BfChartSeries[] }> =
116
+ {
117
+ '30d': {
118
+ categories: ['Oct 1', 'Oct 8', 'Oct 15', 'Oct 22', 'Oct 29'],
119
+ series: [
120
+ { name: 'Subscriptions', values: [9.1, 9.4, 9.8, 10.2, 10.9] },
121
+ { name: 'Services', values: [2.4, 3.1, 2.2, 2.9, 3.4] },
122
+ ],
123
+ },
124
+ '90d': {
125
+ categories: ['Aug', 'Sep', 'Oct'],
126
+ series: [
127
+ { name: 'Subscriptions', values: [36.2, 38.9, 41.5] },
128
+ { name: 'Services', values: [9.8, 11.2, 12.0] },
129
+ ],
130
+ },
131
+ };
132
+
133
+ /**
134
+ * A dashboard of stats and chart cards.
135
+ *
136
+ * Three stats with sparklines over a grid of chart cards: revenue as a line chart with a range
137
+ * switch, sign-ups by source as a donut, and tickets per weekday as stacked bars. The grid wraps
138
+ * to one column on a narrow screen.
139
+ */
140
+ @Component({
141
+ selector: 'app-example-chart-card-dashboard',
142
+ imports: [
143
+ BfStatComponent,
144
+ BfSparklineComponent,
145
+ BfSegmentedComponent,
146
+ BfChartCardComponent,
147
+ BfLineChartComponent,
148
+ BfDonutChartComponent,
149
+ BfBarChartComponent,
150
+ ],
151
+ template: `
152
+ <div class="flex w-full flex-col gap-4">
153
+ <div class="grid grid-cols-[repeat(auto-fit,minmax(10rem,1fr))] gap-3">
154
+ <bf-stat label="Monthly revenue" value="CHF 54.4k" variant="card">
155
+ <span class="flex flex-col gap-1">
156
+ <bf-sparkline [values]="[46, 47, 49, 48, 51, 54]" />
157
+ Up 6% on September
158
+ </span>
159
+ </bf-stat>
160
+ <bf-stat label="Active accounts" value="3,812" variant="card">
161
+ <span class="flex flex-col gap-1">
162
+ <bf-sparkline [values]="[3510, 3580, 3620, 3700, 3760, 3812]" />
163
+ Up 2% on September
164
+ </span>
165
+ </bf-stat>
166
+ <bf-stat label="Open tickets" value="41" variant="card">
167
+ <span class="flex flex-col gap-1">
168
+ <bf-sparkline [values]="[58, 52, 55, 47, 44, 41]" />
169
+ Down 7 this week
170
+ </span>
171
+ </bf-stat>
172
+ </div>
173
+ <div class="grid grid-cols-[repeat(auto-fit,minmax(min(18rem,100%),1fr))] gap-4">
174
+ <bf-chart-card class="col-span-full" title="Revenue (CHF thousands)" [headingLevel]="3">
175
+ <bf-segmented
176
+ bfSlot="period"
177
+ size="sm"
178
+ label="Range"
179
+ [options]="ranges"
180
+ [(value)]="range"
181
+ />
182
+ <bf-line-chart
183
+ area
184
+ curve="smooth"
185
+ [series]="revenue().series"
186
+ [categories]="revenue().categories"
187
+ />
188
+ </bf-chart-card>
189
+ <bf-chart-card title="Sign-ups by source" [headingLevel]="3">
190
+ <bf-donut-chart [slices]="sources" [height]="200">
191
+ <span bfSlot="center" class="text-heading text-text">612</span>
192
+ <span bfSlot="center" class="text-caption text-text-muted">this month</span>
193
+ </bf-donut-chart>
194
+ </bf-chart-card>
195
+ <bf-chart-card title="Tickets per weekday" [headingLevel]="3">
196
+ <bf-bar-chart stacked [series]="tickets" [categories]="days" [height]="200" />
197
+ </bf-chart-card>
198
+ </div>
199
+ <p data-status aria-live="polite" class="text-caption text-text-muted">
200
+ Revenue range: {{ range() }}
201
+ </p>
202
+ </div>
203
+ `,
204
+ })
205
+ export class ChartCardDashboardExampleComponent {
206
+ readonly ranges: BfSegmentOption<Range>[] = [
207
+ { value: '30d', label: '30 days' },
208
+ { value: '90d', label: '90 days' },
209
+ ];
210
+ readonly range = signal<Range | null>('30d');
211
+ readonly revenue = computed(() => REVENUE[this.range() ?? '30d']);
212
+ readonly sources: readonly BfDonutSlice[] = [
213
+ { label: 'Search', value: 248 },
214
+ { label: 'Referral', value: 171 },
215
+ { label: 'Social', value: 118 },
216
+ { label: 'Direct', value: 75 },
217
+ ];
218
+ readonly days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri'];
219
+ readonly tickets: readonly BfChartSeries[] = [
220
+ { name: 'Billing', values: [6, 4, 5, 7, 3] },
221
+ { name: 'Technical', values: [9, 11, 8, 10, 6] },
222
+ ];
223
+ }
224
+ ```
225
+
226
+ ## Loading, empty and error
227
+
228
+ `loading` shows a `bf-skeleton` the height of the default chart instead of the chart and marks the body `aria-busy`; with a resource, bind `[loading]="revenue.isLoading()"`. `empty` shows the `empty` slot, else the `chartEmpty` label ("No data to show"); `error` shows the `error` slot, such as a message and a retry button, else the `chartError` label. `loading` wins over `error`, and `error` over `empty`. Each state keeps the chart's height, so the card does not jump when the data arrives.
229
+
230
+ ## Desktop
231
+
232
+ The card itself is not interactive; its chart and its period control are. The title is a heading (`headingLevel` 2 by default, 3 inside a section), so a dashboard of cards has an outline to move through. Inside `provideBfShell()` it renders and behaves the same; on a phone, stack the cards in one column.
233
+
234
+ ## Theming
235
+
236
+ - Surface: `surface`, the `card` radius, `--spacing-card` padding (`p-card`) and a 1.5 px `border-strong` edge, as the `flat` `bf-card`.
237
+ - Title: `text-heading` in `text`.
238
+ - Empty and error text: `text-body` in `text-muted`, centred in the chart's height.
239
+ - Loading: `bf-skeleton`'s `surface-sunken` bar with its shimmer.
240
+
241
+ ## Accessibility
242
+
243
+ The title is an `h2` (or `h3` with `headingLevel`), and the chart inside is a `figure` named by it unless the chart has its own `label`. While `loading`, the body is `aria-busy="true"` and the skeleton is hidden from assistive technology. The empty and error states are `role="status"`, so a screen reader reads them when they replace the chart. Give the period control its own `label` ("Period").
244
+
245
+ ## Inputs
246
+
247
+ | Name | Type | Default | Description |
248
+ | -------------- | ------------------------------------------------------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
249
+ | `title` | `string` | required | The card's heading; also the chart's name when the chart has no `label`. |
250
+ | `headingLevel` | `BfChartCardHeadingLevel` (`2 \| 3`) | `2` | Heading level of the title so the card fits the page outline. |
251
+ | `legend` | `BfChartLegendPosition` (`'top' \| 'bottom' \| 'none'`) | `'bottom'` | Where the chart inside draws its legend, unless it sets its own `legend`. |
252
+ | `loading` | `boolean` | `false` | Shows a placeholder instead of the chart while its data loads, and marks the body `aria-busy`. |
253
+ | `empty` | `boolean` | `false` | Shows the `empty` slot (or the `chartEmpty` label) instead of the chart: there is no data for the period. |
254
+ | `error` | `boolean` | `false` | Shows the `error` slot (or the `chartError` label) instead of the chart: the data failed to load. Wins over `empty`; `loading` wins over both. |
255
+
256
+ ## Slots
257
+
258
+ - `period`: The range control at the top end, such as a bf-segmented or a bf-select.
259
+ - `error`: What shows when `error` is set, such as a message and a retry button; without it, the `chartError` label.
260
+ - `empty`: What shows when `empty` is set; without it, the `chartEmpty` label.
261
+ - `default`: The chart.
262
+
263
+ ## Notes
264
+
265
+ ### Do
266
+
267
+ - Keep the title short and name the measure ("Revenue"), with the range in the period control.
268
+ - Put a retry button in the `error` slot when the app can load the data again.
269
+
270
+ ### Don't
271
+
272
+ - Don't put more than one chart in a card; give each its own.
273
+ - Don't wrap the `empty` and `error` slot content in an `@if`; the card decides when to show it.
274
+
275
+ ## Migration notes
276
+
277
+ ### 0.3.1
278
+
279
+ New `bf-chart-card` in `@bitforgehq/ui/charts`: the `flat` card surface around one chart, with a
280
+ `title` (the chart's name when it has no `label`; `headingLevel`, `BfChartCardHeadingLevel` 2 or
281
+ 3), a `period` slot for the range control, the `legend` placement for the chart inside, and
282
+ `loading` (a `bf-skeleton`, `aria-busy`), `empty` and `error` states with slots of the same names
283
+ and the `chartEmpty` and `chartError` labels as fallbacks.