@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,111 @@
1
+ # div[bfDescriptionItem]
2
+
3
+ One label and value pair of a description list, label as term, content as value
4
+
5
+ `BfDescriptionItemComponent` from `@bitforgehq/ui` · Data display · since 0.3.1
6
+
7
+ ## Example
8
+
9
+ ```ts
10
+ import { Component } from '@angular/core';
11
+ import { BfDescriptionItemComponent, BfDescriptionListComponent } from '@bitforgehq/ui';
12
+
13
+ /**
14
+ * The bf-description-item overview.
15
+ *
16
+ * Live demo of `div[bfDescriptionItem]`: three pairs of a recipe, each a label and its value, in a
17
+ * `bf-description-list`.
18
+ */
19
+ @Component({
20
+ selector: 'app-example-description-item-overview',
21
+ imports: [BfDescriptionItemComponent, BfDescriptionListComponent],
22
+ template: `
23
+ <bf-description-list>
24
+ <div bfDescriptionItem label="Oven">200 °C, fan 180 °C</div>
25
+ <div bfDescriptionItem label="Keeps">2 days in the fridge</div>
26
+ <div bfDescriptionItem label="Freezes">Yes, up to 3 months</div>
27
+ </bf-description-list>
28
+ `,
29
+ })
30
+ export class DescriptionItemOverviewExampleComponent {}
31
+ ```
32
+
33
+ ## Overview
34
+
35
+ One label-value pair of a `bf-description-list`: the `label` becomes the `dt`, the content the
36
+ `dd`. Put it on a `div` inside the list.
37
+
38
+ One label-value pair of a [`bf-description-list`](https://bitforge-ui.web.app/components/description-list): put `bfDescriptionItem` on a `div` inside the list, set its `label`, and put the value in its content. The `label` becomes the pair's `dt` and the content its `dd`; the item takes its look (a divided row or a tile) from the list's `layout`. It works the same in both shells.
39
+
40
+ ## When to use
41
+
42
+ Use `div[bfDescriptionItem]` for each fact inside a `bf-description-list`. Use [bf-list-item](https://bitforge-ui.web.app/components/list-item) instead for a row the user can open or act on, and [bf-stat](https://bitforge-ui.web.app/components/stat) instead for a single headline figure.
43
+
44
+ ## Basic usage
45
+
46
+ `label` is required; the value is the content, so it can be text, a badge or a link. A class on the item (such as `col-span-full` in the grid layout) is kept alongside the item's own classes.
47
+
48
+ ```ts
49
+ import { Component } from '@angular/core';
50
+ import { BfDescriptionItemComponent, BfDescriptionListComponent } from '@bitforgehq/ui';
51
+
52
+ /**
53
+ * The bf-description-item overview.
54
+ *
55
+ * Live demo of `div[bfDescriptionItem]`: three pairs of a recipe, each a label and its value, in a
56
+ * `bf-description-list`.
57
+ */
58
+ @Component({
59
+ selector: 'app-example-description-item-overview',
60
+ imports: [BfDescriptionItemComponent, BfDescriptionListComponent],
61
+ template: `
62
+ <bf-description-list>
63
+ <div bfDescriptionItem label="Oven">200 °C, fan 180 °C</div>
64
+ <div bfDescriptionItem label="Keeps">2 days in the fridge</div>
65
+ <div bfDescriptionItem label="Freezes">Yes, up to 3 months</div>
66
+ </bf-description-list>
67
+ `,
68
+ })
69
+ export class DescriptionItemOverviewExampleComponent {}
70
+ ```
71
+
72
+ ## Desktop
73
+
74
+ The item is not interactive: no hover, no pointer cursor, no focus stop; only a link or button in its value takes focus. It renders the same inside `provideBfShell()`.
75
+
76
+ ## Theming
77
+
78
+ - Label (`dt`): `text-caption` in `text-muted`. Value (`dd`): `text-body` in `text`; a long value wraps anywhere rather than overflow.
79
+ - In the `rows` layout the item has `py-3` and, from a 28rem wide list, a one-third label column; in the `grid` layout it is a tile with the label over the value.
80
+
81
+ ## Accessibility
82
+
83
+ The item is the `div` that groups one `dt` with its `dd` inside the list's `dl`, which HTML allows, so the pair is announced as a term and its description. It adds no ARIA.
84
+
85
+ ## Inputs
86
+
87
+ | Name | Type | Default | Description |
88
+ | ------- | -------- | -------- | ------------------------------------ |
89
+ | `label` | `string` | required | The term, shown as the pair's label. |
90
+
91
+ ## Slots
92
+
93
+ - `default`: The value: text or rich content such as a badge or a link.
94
+
95
+ ## Notes
96
+
97
+ ### Do
98
+
99
+ - Use one item per fact, with a short noun as the `label`.
100
+
101
+ ### Don't
102
+
103
+ - Don't use `bfDescriptionItem` outside a `bf-description-list`: without the `dl` around it, its `dt` and `dd` are invalid HTML.
104
+ - Don't put a second term in one item; give each its own.
105
+
106
+ ## Migration notes
107
+
108
+ ### 0.3.1
109
+
110
+ New: `div[bfDescriptionItem]`, one pair of a `bf-description-list`: its required `label` is the
111
+ `dt`, its content (text, a badge, a link) the `dd`.
@@ -0,0 +1,160 @@
1
+ # bf-description-list
2
+
3
+ Native description list of label-value pairs, as divided rows or a tile grid
4
+
5
+ `BfDescriptionListComponent` from `@bitforgehq/ui` · Data display · since 0.3.1
6
+
7
+ ## Example
8
+
9
+ ```ts
10
+ import { Component } from '@angular/core';
11
+ import {
12
+ BfBadgeComponent,
13
+ BfDescriptionItemComponent,
14
+ BfDescriptionListComponent,
15
+ } from '@bitforgehq/ui';
16
+
17
+ /**
18
+ * The bf-description-list overview.
19
+ *
20
+ * Live demo of `bf-description-list`: a recipe's details as divided rows, with a badge and a link
21
+ * as values; the labels move beside the values once the list is wide enough.
22
+ */
23
+ @Component({
24
+ selector: 'app-example-description-list-overview',
25
+ imports: [BfBadgeComponent, BfDescriptionItemComponent, BfDescriptionListComponent],
26
+ template: `
27
+ <bf-description-list>
28
+ <div bfDescriptionItem label="Recipe">Lemon risotto with peas</div>
29
+ <div bfDescriptionItem label="Cuisine">Italian</div>
30
+ <div bfDescriptionItem label="Difficulty"><bf-badge variant="success">Easy</bf-badge></div>
31
+ <div bfDescriptionItem label="Diet">Vegetarian, gluten-free</div>
32
+ <div bfDescriptionItem label="Source">
33
+ <a href="#source" class="text-primary underline">Nonna's notebook, page 42</a>
34
+ </div>
35
+ <div bfDescriptionItem label="Added">12 October 2026</div>
36
+ </bf-description-list>
37
+ `,
38
+ })
39
+ export class DescriptionListOverviewExampleComponent {}
40
+ ```
41
+
42
+ ## Overview
43
+
44
+ A list of label-value pairs, such as a record's details: a native `dl` around
45
+ `div[bfDescriptionItem]`s, as divided rows (label beside value) or a grid of tiles.
46
+
47
+ A description list shows the details of one record as label-value pairs: a recipe's cuisine and difficulty, an order's status and date, a person's role and email. `bf-description-list` renders the native `dl`; each pair is a [`div[bfDescriptionItem]`](https://bitforge-ui.web.app/components/description-item) whose `label` becomes the `dt` and whose content becomes the `dd`. It works the same in both shells: in the Capacitor shell and in a desktop web app.
48
+
49
+ ## When to use
50
+
51
+ Use `bf-description-list` for read-only facts about one thing, where the reader looks up a value by its label. Use [bf-list](https://bitforge-ui.web.app/components/list) instead when the rows are actions or links, and [bf-stat](https://bitforge-ui.web.app/components/stat) instead for a few headline figures (a duration, a count, a total) that should read at a glance. A table compares many records across columns; a description list describes one.
52
+
53
+ ## Rows
54
+
55
+ `layout="rows"` (the default) separates the pairs with a `border` line, as a divided `bf-list`. Once the list is 28rem wide or more, the label sits beside its value in a one-third column; in a narrower list (a phone, a side pane) the label stacks over the value. The width that counts is the list's own (the host is an inline-size container), not the viewport's, so the same list stacks in a narrow pane and sits side by side on a wide page. The value can be rich content: a badge, a link, a short sentence.
56
+
57
+ ```ts
58
+ import { Component } from '@angular/core';
59
+ import {
60
+ BfBadgeComponent,
61
+ BfDescriptionItemComponent,
62
+ BfDescriptionListComponent,
63
+ } from '@bitforgehq/ui';
64
+
65
+ /**
66
+ * The bf-description-list overview.
67
+ *
68
+ * Live demo of `bf-description-list`: a recipe's details as divided rows, with a badge and a link
69
+ * as values; the labels move beside the values once the list is wide enough.
70
+ */
71
+ @Component({
72
+ selector: 'app-example-description-list-overview',
73
+ imports: [BfBadgeComponent, BfDescriptionItemComponent, BfDescriptionListComponent],
74
+ template: `
75
+ <bf-description-list>
76
+ <div bfDescriptionItem label="Recipe">Lemon risotto with peas</div>
77
+ <div bfDescriptionItem label="Cuisine">Italian</div>
78
+ <div bfDescriptionItem label="Difficulty"><bf-badge variant="success">Easy</bf-badge></div>
79
+ <div bfDescriptionItem label="Diet">Vegetarian, gluten-free</div>
80
+ <div bfDescriptionItem label="Source">
81
+ <a href="#source" class="text-primary underline">Nonna's notebook, page 42</a>
82
+ </div>
83
+ <div bfDescriptionItem label="Added">12 October 2026</div>
84
+ </bf-description-list>
85
+ `,
86
+ })
87
+ export class DescriptionListOverviewExampleComponent {}
88
+ ```
89
+
90
+ ## Grid
91
+
92
+ `layout="grid"` lays the pairs out as tiles with the label over the value, in as many columns of at least 10rem as fit, so the tiles wrap on their own without a breakpoint. Use it for short values that read well side by side; a long value belongs in the rows layout.
93
+
94
+ ```ts
95
+ import { Component } from '@angular/core';
96
+ import { BfDescriptionItemComponent, BfDescriptionListComponent } from '@bitforgehq/ui';
97
+
98
+ /** A recipe's nutrition per serving as a grid of tiles that wraps by itself. */
99
+ @Component({
100
+ selector: 'app-example-description-list-grid',
101
+ imports: [BfDescriptionItemComponent, BfDescriptionListComponent],
102
+ template: `
103
+ <bf-description-list layout="grid">
104
+ <div bfDescriptionItem label="Energy">520 kcal</div>
105
+ <div bfDescriptionItem label="Protein">16 g</div>
106
+ <div bfDescriptionItem label="Carbohydrates">78 g</div>
107
+ <div bfDescriptionItem label="Fat">14 g</div>
108
+ <div bfDescriptionItem label="Note" class="col-span-full">
109
+ Values per serving, with parmesan.
110
+ </div>
111
+ </bf-description-list>
112
+ `,
113
+ })
114
+ export class DescriptionListGridExampleComponent {}
115
+ ```
116
+
117
+ ## Desktop
118
+
119
+ The list is not interactive: it has no hover, no pointer cursor and no focus stop of its own, and only the links or buttons you put in a value take focus. Its spacing does not follow `provideBfDefaults()`; the rows keep one rhythm on every density. Inside `provideBfShell()` (the Capacitor shell) it renders and behaves exactly the same. Because the host is an inline-size container, give it a width when you place it in a flex row (`flex-1` or a `basis-*`), or it shrinks to nothing.
120
+
121
+ ## Theming
122
+
123
+ - Label (`dt`): `text-caption` in `text-muted`. Value (`dd`): `text-body` in `text`.
124
+ - `rows`: the lines between the pairs are `border`; each pair has `py-3` (12 px) of block padding.
125
+ - `grid`: `gap-x-6` / `gap-y-4` between the tiles, columns of at least 10rem.
126
+
127
+ ## Accessibility
128
+
129
+ `bf-description-list` renders a native `dl`, and each `div[bfDescriptionItem]` is a `div` holding one `dt` and one `dd`, which is valid HTML, so screen readers announce a list of terms with their descriptions. The list adds no ARIA. Content in a value carries its own semantics: a badge's text is read with the value, a link stays a link.
130
+
131
+ ## Inputs
132
+
133
+ | Name | Type | Default | Description |
134
+ | -------- | ---------------------------------------------- | -------- | --------------------------------------------------------------------------------------------------------------------- |
135
+ | `layout` | `BfDescriptionListLayout` (`'rows' \| 'grid'`) | `'rows'` | `rows` (default): label beside value, divided, stacked in a narrow list; `grid`: tiles with the label over the value. |
136
+
137
+ ## Slots
138
+
139
+ - `default`: The pairs, each a `div[bfDescriptionItem]`.
140
+
141
+ ## Notes
142
+
143
+ ### Do
144
+
145
+ - Keep labels short nouns ("Cuisine", "Servings") and put the unit in the value ("45 min").
146
+ - Put a badge or a link in a value when the value is a status or points elsewhere.
147
+
148
+ ### Don't
149
+
150
+ - Don't put anything but `div[bfDescriptionItem]` pairs in a `bf-description-list`; a `dl` expects term and description groups.
151
+ - Don't use it for rows the user acts on; that is a `bf-list` of `bf-list-item` rows.
152
+
153
+ ## Migration notes
154
+
155
+ ### 0.3.1
156
+
157
+ New: `bf-description-list`, a native `dl` of label-value pairs for the details of one record, in
158
+ both shells. `layout="rows"` (default) divides the pairs with a `border` line and puts the label
159
+ beside the value once the list is 28rem wide (a container query, so a narrow pane stacks them);
160
+ `layout="grid"` lays them out as wrapping tiles. New type `BfDescriptionListLayout`.
@@ -0,0 +1,169 @@
1
+ # bf-donut-chart
2
+
3
+ Donut chart of the parts of a whole, with a legend, tooltip and centre slot
4
+
5
+ `BfDonutChartComponent` from `@bitforgehq/ui/charts` · Data display · since 0.3.1
6
+
7
+ ## Example
8
+
9
+ ```ts
10
+ import { Component, computed } from '@angular/core';
11
+ import { BfDonutChartComponent, type BfDonutSlice } from '@bitforgehq/ui/charts';
12
+
13
+ /**
14
+ * The bf-donut-chart overview.
15
+ *
16
+ * Live demo of `bf-donut-chart`: a month's spending by category with the total in the centre.
17
+ * Hover a slice, or focus the chart and use the arrow keys; hide a slice in the legend and the
18
+ * others share the rest.
19
+ */
20
+ @Component({
21
+ selector: 'app-example-donut-chart-overview',
22
+ imports: [BfDonutChartComponent],
23
+ template: `
24
+ <bf-donut-chart label="Spending in October" [slices]="slices" [valueFormat]="francs">
25
+ <span bfSlot="center" class="text-heading text-text">{{ total() }}</span>
26
+ <span bfSlot="center" class="text-caption text-text-muted">October</span>
27
+ </bf-donut-chart>
28
+ `,
29
+ })
30
+ export class DonutChartOverviewExampleComponent {
31
+ readonly slices: readonly BfDonutSlice[] = [
32
+ { label: 'Rent', value: 1850 },
33
+ { label: 'Groceries', value: 640 },
34
+ { label: 'Transport', value: 310 },
35
+ { label: 'Leisure', value: 280 },
36
+ { label: 'Other', value: 170 },
37
+ ];
38
+ private readonly format = new Intl.NumberFormat('en', {
39
+ style: 'currency',
40
+ currency: 'CHF',
41
+ maximumFractionDigits: 0,
42
+ });
43
+ readonly francs = (value: number): string => this.format.format(value);
44
+ readonly total = computed(() => this.francs(this.slices.reduce((sum, s) => sum + s.value, 0)));
45
+ }
46
+ ```
47
+
48
+ ## Overview
49
+
50
+ A donut chart of one set of slices, the parts of a whole (a budget by category, traffic by
51
+ source), drawn in SVG with the chart palette: each slice's angle is its share of the total.
52
+ A legend shows and hides slices (the total follows), a tooltip shows a slice's value and share
53
+ on hover and on keyboard focus (Arrow keys move between the slices and a polite live region
54
+ reads each one), and a Show data table lists them. The `center` slot holds a total or a label
55
+ in the ring's hole. Slices draw in on the first render and on every data change, still under
56
+ reduced motion; under `dir="rtl"` the slices run counter-clockwise.
57
+
58
+ A donut chart shows the parts of one whole: a budget by category, traffic by source, tasks by status. `bf-donut-chart` draws it in SVG from `slices` (each a `label` and a `value`); each slice's angle is its share of the total. A legend shows and hides slices, a tooltip shows a slice's value and share on hover and on keyboard focus, a Show data table lists them, and the `center` slot holds a total in the ring's hole. It lives in `@bitforgehq/ui/charts` (`import { BfDonutChartComponent } from '@bitforgehq/ui/charts'`) and works the same in a desktop web app and in the Capacitor shell.
59
+
60
+ ## When to use
61
+
62
+ Use `bf-donut-chart` for the shares of one whole with a few parts (two to six read well). Our charts are themed with the `--color-chart-*` tokens and bring their own legend, tooltip, keyboard reading and data table; bring a chart library (themed with the same tokens) only for a form they do not draw. Use [bf-bar-chart](https://bitforge-ui.web.app/components/bar-chart) instead to compare the parts precisely or when there are many, and [bf-stat](https://bitforge-ui.web.app/components/stat) for a single share ("42 % done").
63
+
64
+ ## Centre and thickness
65
+
66
+ Content with `bfSlot="center"` sits in the ring's hole: the total and a caption, such as `1,800 CHF` over `this month`. Keep it short; it does not take pointer events, so hovering the hole never hides the tooltip of a slice. `thickness` sets the ring's width in px (28 by default); a thickness as large as the radius draws a full pie.
67
+
68
+ ```ts
69
+ import { Component } from '@angular/core';
70
+ import { BfDonutChartComponent, type BfDonutSlice } from '@bitforgehq/ui/charts';
71
+
72
+ /**
73
+ * A thin ring and a pie.
74
+ *
75
+ * `thickness` sets the ring's width: a thin ring leaves room for the centre, a thickness as large
76
+ * as the radius draws a full pie. Tasks by status, the legend above the ring.
77
+ */
78
+ @Component({
79
+ selector: 'app-example-donut-chart-thickness',
80
+ imports: [BfDonutChartComponent],
81
+ template: `
82
+ <div class="grid w-full grid-cols-[repeat(auto-fit,minmax(min(14rem,100%),1fr))] gap-4">
83
+ <bf-donut-chart label="Tasks by status" legend="top" [thickness]="12" [slices]="tasks">
84
+ <span bfSlot="center" class="text-heading text-text">48</span>
85
+ <span bfSlot="center" class="text-caption text-text-muted">tasks</span>
86
+ </bf-donut-chart>
87
+ <bf-donut-chart
88
+ label="Tasks by status, as a pie"
89
+ legend="top"
90
+ [thickness]="200"
91
+ [slices]="tasks"
92
+ />
93
+ </div>
94
+ `,
95
+ })
96
+ export class DonutChartThicknessExampleComponent {
97
+ readonly tasks: readonly BfDonutSlice[] = [
98
+ { label: 'Done', value: 27 },
99
+ { label: 'In progress', value: 13 },
100
+ { label: 'Blocked', value: 8 },
101
+ ];
102
+ }
103
+ ```
104
+
105
+ ## Data and formatting
106
+
107
+ Slices run clockwise from the top in their order (counter-clockwise under `dir="rtl"`), with a 2 px gap between them; a slice of zero or less draws nothing, but stays in the legend and the table. Hiding a slice in the legend removes it from the total, so the other shares grow. `valueFormat` formats the values in the tooltip, the announcement and the table; unset, values use `Intl.NumberFormat` in the document's language, and shares are whole percentages. The slices draw in along the ring on the first render and whenever `slices` change. `height` sets the plot's height in px (220 by default); the ring fits the smaller of it and the container's width.
108
+
109
+ ## Desktop
110
+
111
+ Under a mouse, hovering a slice thickens it and shows its tooltip; the hole and the space around the ring show none. The plot is one stop in the tab order, with the focus ring on keyboard focus: focusing it shows the first slice. Under a coarse pointer (touch) a tap shows a slice's tooltip, and the legend buttons and the Show data button are at least 44 px tall. Inside `provideBfShell()` it renders and behaves the same.
112
+
113
+ ## Theming
114
+
115
+ - Slices: `--color-chart-1` … `--color-chart-8` in order (`stroke-chart-n`); the ring's track: `chart-grid`.
116
+ - Tooltip, legend and data table: as in [bf-line-chart](https://bitforge-ui.web.app/components/line-chart).
117
+ - Motion: `--animate-chart-draw` along each slice; the active slice thickens over 150 ms; none under `prefers-reduced-motion`.
118
+
119
+ ## Accessibility
120
+
121
+ The chart is a native `figure` named by `label` (else the `bf-chart-card` title, else the `chart` label); the SVG is hidden from assistive technology, and the centre slot's text is read as part of the figure. The plot is a focusable `role="group"` named by the `chartValues` label: the arrow keys move between the slices and a polite live region reads each one with its share ("Rent: 900 CHF (50%)"). The legend is a group of toggle buttons (`aria-pressed`); the Show data button (`aria-expanded`) shows the slices as a native `table` (`chartCategory` and `chartValue` headers). Every slice colour is ≥ 3:1 against `surface` and `bg`, and the legend names each one.
122
+
123
+ ### Keyboard
124
+
125
+ | Key | Action |
126
+ | ------------------------------------------------ | ------------------------------------------------------------------------------------ |
127
+ | <kbd>Tab</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> | Moves through the plot, the legend buttons and the Show data button |
128
+ | <kbd>ArrowRight</kbd> | Moves to the next slice and reads it (the previous one under `dir="rtl"`) |
129
+ | <kbd>ArrowLeft</kbd> | Moves to the previous slice and reads it (the next one under `dir="rtl"`) |
130
+ | <kbd>Home</kbd> / <kbd>End</kbd> | Moves to the first / last slice |
131
+ | <kbd>Escape</kbd> | Hides the tooltip |
132
+ | <kbd>Enter</kbd> / <kbd>Space</kbd> | On a legend button, shows or hides its slice; on Show data, shows or hides the table |
133
+
134
+ ## Inputs
135
+
136
+ | Name | Type | Default | Description |
137
+ | ------------- | --------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------ |
138
+ | `slices` | `readonly BfDonutSlice[]` | required | The slices, in order clockwise from the top. |
139
+ | `label` | `string` | `''` | The chart's accessible name; empty falls back to the `bf-chart-card` title, then to `provideBfLabels()`'s `chart` ("Chart"). |
140
+ | `height` | `number` | `220` | The plot's height in px; the ring fits the smaller of it and the container's width. |
141
+ | `thickness` | `number` | `28` | The ring's thickness in px (at most the radius, a full pie). |
142
+ | `valueFormat` | `BfChartValueFormat \| undefined` | `undefined` | Formats the values in the tooltip, the announcements and the table; unset uses `Intl.NumberFormat` in the document's language. |
143
+ | `legend` | `BfChartLegendPosition \| undefined` (`'top' \| 'bottom' \| 'none' \| undefined`) | `undefined` | Where the legend goes; unset follows the `bf-chart-card`, else `bottom`. A single slice draws no legend. |
144
+
145
+ ## Slots
146
+
147
+ - `center`: Content in the ring's hole, such as the total and its label.
148
+
149
+ ## Notes
150
+
151
+ ### Do
152
+
153
+ - Order the slices from largest to smallest, starting at the top.
154
+ - Put the total in the `center` slot, so the shares have a whole to refer to.
155
+
156
+ ### Don't
157
+
158
+ - Don't use a donut for more than about six slices or for slices of nearly equal size; use a bar chart.
159
+ - Don't use it for values that do not add up to a whole.
160
+
161
+ ## Migration notes
162
+
163
+ ### 0.3.1
164
+
165
+ New `bf-donut-chart` in `@bitforgehq/ui/charts`: `slices` (`BfDonutSlice`: `label`, `value`) as
166
+ the parts of a whole, with a `thickness`, a `center` slot for a total, a legend that hides slices
167
+ (the shares follow), a tooltip with each slice's value and share, keyboard reading and a data
168
+ table. Slices draw in along the ring, not under reduced motion, and run counter-clockwise under
169
+ `dir="rtl"`.
@@ -103,7 +103,7 @@ the collapse is pure CSS and scrolling never schedules Angular change detection.
103
103
 
104
104
  ## When to use
105
105
 
106
- Use `bf-header` at the top of every `bf-page` in the Capacitor shell: the bar with its start and end actions and the collapsing large title. Use a plain `h1` and a toolbar row of [bf-button](https://bitforge-ui.web.app/components/button)s instead on a desktop web page, and [bf-back-button](https://bitforge-ui.web.app/components/back-button) in its `start` slot on a pushed page.
106
+ Use `bf-header` at the top of every `bf-page` in the Capacitor shell: the bar with its start and end actions and the collapsing large title. Use [bf-page-header](https://bitforge-ui.web.app/components/page-header) instead on a desktop web page, and [bf-back-button](https://bitforge-ui.web.app/components/back-button) in its `start` slot on a pushed page.
107
107
 
108
108
  ## Basic usage
109
109
 
@@ -608,7 +608,67 @@ inside one.
608
608
 
609
609
  ## Desktop
610
610
 
611
- `bf-header` is part of the Capacitor shell (`provideBfShell()`), shaped like an iOS or Material app bar. On a desktop web page, give the page a plain `h1` and put its actions in a toolbar row of [bf-button](https://bitforge-ui.web.app/components/button)s and a [bf-menu-button](https://bitforge-ui.web.app/components/menu-button); the large title and the scroll-under surface are phone patterns. Under the shell, a browser window shorter than 500 px gets the compact bar (no large title), as a phone in landscape does.
611
+ `bf-header` is part of the Capacitor shell (`provideBfShell()`), shaped like an iOS or Material app bar. On a desktop web page use [bf-page-header](https://bitforge-ui.web.app/components/page-header): the page's one `h1` (`title`) with an optional `subtitle`, badges in `meta`, and the actions in `actions` (the main action as a primary [bf-button](https://bitforge-ui.web.app/components/button), secondary ones as `ghost` or `outline` buttons, the rest in an icon-only [bf-menu-button](https://bitforge-ui.web.app/components/menu-button) labelled "More actions"); the actions wrap under the title in a narrow window. On a nested page, put a [bf-breadcrumb](https://bitforge-ui.web.app/components/breadcrumb) in its `breadcrumb` slot, and a [bf-toolbar](https://bitforge-ui.web.app/components/toolbar) under it for search and filters. The two are siblings rather than one shell-aware widget: the large title and the scroll-under surface are phone patterns that depend on `bf-content`.
612
+
613
+ ```ts
614
+ import { Component, signal } from '@angular/core';
615
+ import { BfButtonComponent, BfPageHeaderComponent } from '@bitforgehq/ui';
616
+ import { BfIconComponent } from '@bitforgehq/ui/icons';
617
+ import {
618
+ BfMenuButtonComponent,
619
+ BfMenuComponent,
620
+ BfMenuItemDirective,
621
+ } from '@bitforgehq/ui/overlay';
622
+ import { Ellipsis, Plus } from 'lucide';
623
+
624
+ /**
625
+ * The desktop replacement for a header: a bf-page-header.
626
+ *
627
+ * The page's `h1` with a subtitle, and its actions in the `actions` slot: a ghost button, the
628
+ * primary action and a menu button for the rest; the actions wrap under the title in a narrow
629
+ * window.
630
+ */
631
+ @Component({
632
+ selector: 'app-example-header-desktop-header',
633
+ imports: [
634
+ BfButtonComponent,
635
+ BfIconComponent,
636
+ BfMenuButtonComponent,
637
+ BfMenuComponent,
638
+ BfMenuItemDirective,
639
+ BfPageHeaderComponent,
640
+ ],
641
+ template: `
642
+ <bf-page-header title="Atlas rebrand" subtitle="12 of 18 tasks done · due Friday">
643
+ <bf-button bfSlot="actions" variant="ghost" (clicked)="status.set('Shared.')"
644
+ >Share</bf-button
645
+ >
646
+ <bf-button bfSlot="actions" (clicked)="status.set('New task.')">
647
+ <bf-icon bfSlot="icon-start" [icon]="plus" />
648
+ New task
649
+ </bf-button>
650
+ <bf-menu-button bfSlot="actions" [menu]="more" iconOnly label="More actions" variant="text">
651
+ <bf-icon [icon]="ellipsis" />
652
+ </bf-menu-button>
653
+ </bf-page-header>
654
+ <p aria-live="polite" class="text-caption text-text-muted mt-3">{{ status() }}</p>
655
+
656
+ <ng-template #more>
657
+ <bf-menu>
658
+ <button bfMenuItem (triggered)="status.set('Renamed.')">Rename</button>
659
+ <button bfMenuItem (triggered)="status.set('Archived.')">Archive</button>
660
+ </bf-menu>
661
+ </ng-template>
662
+ `,
663
+ })
664
+ export class HeaderDesktopHeaderExampleComponent {
665
+ protected readonly plus = Plus;
666
+ protected readonly ellipsis = Ellipsis;
667
+ protected readonly status = signal('');
668
+ }
669
+ ```
670
+
671
+ Under the shell, a browser window shorter than 500 px gets the compact bar (no large title), as a phone in landscape does.
612
672
 
613
673
  ## Theming
614
674
 
@@ -688,6 +748,11 @@ The title is not in the tab order; after a push, `bf-stack-outlet` focuses it wi
688
748
 
689
749
  ## Migration notes
690
750
 
751
+ ### 0.3.1
752
+
753
+ The `## Desktop` docs and When to use name the desktop replacement, `bf-page-header` (with
754
+ `bf-breadcrumb` and `bf-toolbar`), with an example. No code change.
755
+
691
756
  ### 0.3.0
692
757
 
693
758
  JSDoc of `header.component.ts` for the API reference: `@slot` docs for `start`, `default`, `end`. No