@bitforgehq/ui 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +598 -0
- package/README.md +18 -11
- package/ai/MANIFEST.index.json +306 -0
- package/ai/MANIFEST.json +8915 -3788
- package/ai/REFERENCE.index.json +476 -0
- package/ai/REFERENCE.json +5810 -2905
- package/ai/UI_GUIDE.md +212 -58
- package/ai/components/app-frame.md +328 -0
- package/ai/components/back-button.md +42 -2
- package/ai/components/badge.md +17 -7
- package/ai/components/bar-chart.md +188 -0
- package/ai/components/breadcrumb-item.md +121 -0
- package/ai/components/breadcrumb.md +277 -0
- package/ai/components/button.md +82 -15
- package/ai/components/calendar.md +300 -0
- package/ai/components/card.md +119 -4
- package/ai/components/chart-card.md +283 -0
- package/ai/components/combobox.md +411 -0
- package/ai/components/date-input.md +396 -0
- package/ai/components/datetime-input.md +215 -0
- package/ai/components/description-item.md +111 -0
- package/ai/components/description-list.md +160 -0
- package/ai/components/donut-chart.md +169 -0
- package/ai/components/empty-state.md +99 -6
- package/ai/components/header.md +71 -2
- package/ai/components/icon-button.md +74 -16
- package/ai/components/icon.md +63 -7
- package/ai/components/line-chart.md +234 -0
- package/ai/components/list.md +70 -6
- package/ai/components/menu.md +5 -0
- package/ai/components/multi-combobox.md +257 -0
- package/ai/components/nav-group.md +178 -0
- package/ai/components/nav-item.md +210 -0
- package/ai/components/page-header.md +237 -0
- package/ai/components/pagination.md +173 -0
- package/ai/components/popover.md +250 -0
- package/ai/components/side-panel.md +391 -0
- package/ai/components/sidebar-toggle.md +287 -0
- package/ai/components/sidebar.md +541 -0
- package/ai/components/skeleton.md +215 -0
- package/ai/components/sparkline.md +188 -0
- package/ai/components/stat.md +297 -0
- package/ai/components/tab-group.md +226 -0
- package/ai/components/tab-panel.md +163 -0
- package/ai/components/table.md +697 -0
- package/ai/components/tabs.md +46 -2
- package/ai/components/theme-menu-button.md +182 -0
- package/ai/components/theme-switch.md +170 -0
- package/ai/components/time-input.md +240 -0
- package/ai/components/toolbar.md +354 -0
- package/ai/components/tooltip.md +230 -0
- package/ai/components/top-nav.md +159 -0
- package/ai/reference/bf-app-frame-breakpoint.md +27 -0
- package/ai/reference/bf-app-frame-content-width.md +29 -0
- package/ai/reference/bf-badge-appearance.md +36 -0
- package/ai/reference/bf-badge-variant.md +1 -1
- package/ai/reference/bf-bar-chart-orientation.md +27 -0
- package/ai/reference/bf-button-appearance.md +36 -0
- package/ai/reference/bf-button-variant.md +1 -1
- package/ai/reference/bf-calendar-disabled-date.md +23 -0
- package/ai/reference/bf-calendar-harness.md +51 -0
- package/ai/reference/bf-calendar-weekday.md +31 -0
- package/ai/reference/bf-chart-card-heading-level.md +26 -0
- package/ai/reference/bf-chart-curve.md +28 -0
- package/ai/reference/bf-chart-harness.md +51 -0
- package/ai/reference/bf-chart-legend-position.md +30 -0
- package/ai/reference/bf-chart-series.md +23 -0
- package/ai/reference/bf-chart-value-format.md +23 -0
- package/ai/reference/bf-color-scheme-service.md +30 -0
- package/ai/reference/bf-color-scheme.md +31 -0
- package/ai/reference/bf-combobox-filter.md +27 -0
- package/ai/reference/bf-combobox-harness.md +89 -0
- package/ai/reference/bf-combobox-option.md +33 -0
- package/ai/reference/bf-compare-with.md +2 -0
- package/ai/reference/bf-date-input-harness.md +67 -0
- package/ai/reference/bf-date-input-picker.md +27 -0
- package/ai/reference/bf-date-time-input-harness.md +76 -0
- package/ai/reference/bf-date-time-input-picker.md +27 -0
- package/ai/reference/bf-description-list-layout.md +26 -0
- package/ai/reference/bf-donut-slice.md +22 -0
- package/ai/reference/bf-empty-state-heading-level.md +1 -1
- package/ai/reference/bf-empty-state-heading.md +33 -0
- package/ai/reference/bf-labels.md +73 -20
- package/ai/reference/bf-menu-button-variant.md +1 -0
- package/ai/reference/bf-menu-placement.md +1 -0
- package/ai/reference/bf-overlay-options.md +28 -27
- package/ai/reference/bf-overlay-placement.md +34 -0
- package/ai/reference/bf-overlay-position.md +1 -1
- package/ai/reference/bf-overlay-service.md +5 -3
- package/ai/reference/bf-page-header-heading-level.md +26 -0
- package/ai/reference/bf-pagination-harness.md +61 -0
- package/ai/reference/bf-platform-service.md +17 -15
- package/ai/reference/bf-popover-harness.md +42 -0
- package/ai/reference/bf-popover-placement.md +28 -0
- package/ai/reference/bf-popover-trigger-directive.md +56 -0
- package/ai/reference/bf-side-panel-config.md +35 -0
- package/ai/reference/bf-side-panel-harness.md +34 -0
- package/ai/reference/bf-side-panel-ref.md +44 -0
- package/ai/reference/bf-side-panel-service.md +43 -0
- package/ai/reference/bf-side-panel-template-context.md +32 -0
- package/ai/reference/bf-side-panel-width.md +28 -0
- package/ai/reference/bf-sidebar-state-service.md +21 -0
- package/ai/reference/bf-sidebar-toggle-harness.md +32 -0
- package/ai/reference/bf-size.md +13 -0
- package/ai/reference/bf-skeleton-shape.md +28 -0
- package/ai/reference/bf-stat-appearance.md +33 -0
- package/ai/reference/bf-stat-trend-intent.md +27 -0
- package/ai/reference/bf-stat-trend.md +27 -0
- package/ai/reference/bf-stat-variant.md +26 -0
- package/ai/reference/bf-tab-group-harness.md +44 -0
- package/ai/reference/bf-table-align.md +26 -0
- package/ai/reference/bf-table-cell-context.md +24 -0
- package/ai/reference/bf-table-cell-directive.md +22 -0
- package/ai/reference/bf-table-column.md +28 -0
- package/ai/reference/bf-table-harness.md +77 -0
- package/ai/reference/bf-table-row-key.md +21 -0
- package/ai/reference/bf-table-sort-direction.md +26 -0
- package/ai/reference/bf-table-sort.md +27 -0
- package/ai/reference/bf-table-stack.md +29 -0
- package/ai/reference/bf-theme.md +5 -4
- package/ai/reference/bf-time-input-harness.md +67 -0
- package/ai/reference/bf-time-input-hour-cycle.md +27 -0
- package/ai/reference/bf-time-input-picker.md +27 -0
- package/ai/reference/bf-tooltip-directive.md +43 -0
- package/ai/reference/bf-tooltip-harness.md +43 -0
- package/ai/reference/bf-tooltip-placement.md +28 -0
- package/ai/reference/bf_color_scheme_storage.md +20 -0
- package/ai/reference/bf_side_panel_data.md +17 -0
- package/ai/reference/bf_sidebar_state_storage.md +20 -0
- package/ai/reference/bf_theme_storage.md +3 -1
- package/ai/reference/provide-bf-color-scheme.md +20 -0
- package/ai/reference/provide-bf-labels.md +13 -4
- package/ai/reference/provide-bf-sidebar-state.md +20 -0
- package/ai/reference/slide-in-from-end.md +24 -0
- package/ai/reference/slide-out-to-end.md +24 -0
- package/bin/bf-ui.js +433 -3
- package/fesm2022/bitforgehq-ui-charts.mjs +3045 -0
- package/fesm2022/bitforgehq-ui-charts.mjs.map +1 -0
- package/fesm2022/bitforgehq-ui-icons.mjs +107 -3
- package/fesm2022/bitforgehq-ui-icons.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui-mobile.mjs +14 -59
- package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui-overlay.mjs +6566 -38
- package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui-testing.mjs +634 -1
- package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui.mjs +5708 -137
- package/fesm2022/bitforgehq-ui.mjs.map +1 -1
- package/llms-full.txt +26766 -14470
- package/llms.txt +106 -1
- package/package.json +7 -3
- package/theme.css +101 -0
- package/types/bitforgehq-ui-charts.d.ts +967 -0
- package/types/bitforgehq-ui-icons.d.ts +13 -1
- package/types/bitforgehq-ui-mobile.d.ts +25 -18
- package/types/bitforgehq-ui-overlay.d.ts +1895 -7
- package/types/bitforgehq-ui-testing.d.ts +782 -1
- package/types/bitforgehq-ui.d.ts +2393 -45
|
@@ -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"`.
|
|
@@ -98,6 +98,89 @@ export class EmptyStateActionExampleComponent {
|
|
|
98
98
|
|
|
99
99
|
Set `headingLevel` to `3` when the empty state sits inside a section that already opened with an `h2`, so the page outline stays in order.
|
|
100
100
|
|
|
101
|
+
## As the page
|
|
102
|
+
|
|
103
|
+
When the empty state is the whole page (a not-found page, a no-access page, an app's first run), its title is the page's heading: set `headingLevel` to `1` so it renders the `h1`, and give the page no other `h1`. Centre it in the content area: a column with a minimum height (`min-h-[60vh]`) and `justify-center`. Put the primary action first in the `actions` slot (a `bfButton` link home) and an optional secondary link after it (a `text` `bfButton`, such as "Contact support").
|
|
104
|
+
|
|
105
|
+
The preview below sits inside this docs page, which already has its `h1`, so it keeps `headingLevel` 2 in a shorter area; a real page uses `1`, as in the code-only example after it.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { Component } from '@angular/core';
|
|
109
|
+
import { RouterLink } from '@angular/router';
|
|
110
|
+
import { BfButtonComponent, BfEmptyStateComponent } from '@bitforgehq/ui';
|
|
111
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
112
|
+
import { FileQuestionMark } from 'lucide';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* An empty state as a whole page.
|
|
116
|
+
*
|
|
117
|
+
* Centred in a tall content area, with a primary action and a secondary link. This preview sits
|
|
118
|
+
* inside a docs page that has its own `h1`, so it uses `headingLevel` 2; on a real not-found page
|
|
119
|
+
* the empty state is the page, so set it to 1 (see the next example).
|
|
120
|
+
*/
|
|
121
|
+
@Component({
|
|
122
|
+
selector: 'app-example-empty-state-page',
|
|
123
|
+
imports: [RouterLink, BfButtonComponent, BfEmptyStateComponent, BfIconComponent],
|
|
124
|
+
template: `
|
|
125
|
+
<div class="flex min-h-96 flex-col justify-center">
|
|
126
|
+
<bf-empty-state
|
|
127
|
+
title="Page not found"
|
|
128
|
+
description="The page may have moved, or the link has a typo."
|
|
129
|
+
[headingLevel]="2"
|
|
130
|
+
>
|
|
131
|
+
<bf-icon bfSlot="icon" [icon]="fileQuestion" size="lg" />
|
|
132
|
+
<a bfSlot="actions" bfButton routerLink="/">Go to the home page</a>
|
|
133
|
+
<a bfSlot="actions" bfButton variant="text" href="mailto:support@example.com">
|
|
134
|
+
Contact support
|
|
135
|
+
</a>
|
|
136
|
+
</bf-empty-state>
|
|
137
|
+
</div>
|
|
138
|
+
`,
|
|
139
|
+
})
|
|
140
|
+
export class EmptyStatePageExampleComponent {
|
|
141
|
+
protected readonly fileQuestion = FileQuestionMark;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { Component } from '@angular/core';
|
|
147
|
+
import { RouterLink } from '@angular/router';
|
|
148
|
+
import { BfButtonComponent, BfEmptyStateComponent } from '@bitforgehq/ui';
|
|
149
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
150
|
+
import { FileQuestionMark } from 'lucide';
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* A not-found page whose empty state is the page heading.
|
|
154
|
+
*
|
|
155
|
+
* The route's whole content: `headingLevel` 1 renders the title as the page's `h1`, and the
|
|
156
|
+
* `min-h-[60vh]` area centres the empty state vertically in the content column.
|
|
157
|
+
*
|
|
158
|
+
* @preview none
|
|
159
|
+
*/
|
|
160
|
+
@Component({
|
|
161
|
+
selector: 'app-example-empty-state-not-found-page',
|
|
162
|
+
imports: [RouterLink, BfButtonComponent, BfEmptyStateComponent, BfIconComponent],
|
|
163
|
+
template: `
|
|
164
|
+
<div class="flex min-h-[60vh] flex-col justify-center">
|
|
165
|
+
<bf-empty-state
|
|
166
|
+
title="Page not found"
|
|
167
|
+
description="The page may have moved, or the link has a typo."
|
|
168
|
+
[headingLevel]="1"
|
|
169
|
+
>
|
|
170
|
+
<bf-icon bfSlot="icon" [icon]="fileQuestion" size="lg" />
|
|
171
|
+
<a bfSlot="actions" bfButton routerLink="/">Go to the home page</a>
|
|
172
|
+
<a bfSlot="actions" bfButton variant="text" href="mailto:support@example.com">
|
|
173
|
+
Contact support
|
|
174
|
+
</a>
|
|
175
|
+
</bf-empty-state>
|
|
176
|
+
</div>
|
|
177
|
+
`,
|
|
178
|
+
})
|
|
179
|
+
export class EmptyStateNotFoundPageExampleComponent {
|
|
180
|
+
protected readonly fileQuestion = FileQuestionMark;
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
101
184
|
## Theming
|
|
102
185
|
|
|
103
186
|
- Icon tile: `surface-sunken` background, `text-muted` icon color, `tile` radius.
|
|
@@ -105,15 +188,15 @@ Set `headingLevel` to `3` when the empty state sits inside a section that alread
|
|
|
105
188
|
|
|
106
189
|
## Accessibility
|
|
107
190
|
|
|
108
|
-
The title renders as an `<h2>` by default
|
|
191
|
+
The title renders as an `<h2>` by default, an `<h3>` when `headingLevel` is `3` and an `<h1>` when it is `1` (only when the empty state is the page and the page has no other `h1`), so it slots into the surrounding page outline instead of always claiming the top level. The icon and action slots carry their own accessibility — an icon should stay decorative, and the action needs its own accessible name.
|
|
109
192
|
|
|
110
193
|
## Inputs
|
|
111
194
|
|
|
112
|
-
| Name | Type | Default | Description
|
|
113
|
-
| -------------- | ------------------------------------- | -------- |
|
|
114
|
-
| `title` | `string` | required | What is missing, as a short title.
|
|
115
|
-
| `description` | `string` | `''` | One sentence on how to fill it.
|
|
116
|
-
| `headingLevel` | `
|
|
195
|
+
| Name | Type | Default | Description |
|
|
196
|
+
| -------------- | ------------------------------------- | -------- | ------------------------------------------------------------------------------------------- |
|
|
197
|
+
| `title` | `string` | required | What is missing, as a short title. |
|
|
198
|
+
| `description` | `string` | `''` | One sentence on how to fill it. |
|
|
199
|
+
| `headingLevel` | `BfEmptyStateHeading` (`2 \| 3 \| 1`) | `2` | Heading level of the title so the empty state fits the page outline; 1 when it is the page. |
|
|
117
200
|
|
|
118
201
|
## Slots
|
|
119
202
|
|
|
@@ -129,10 +212,20 @@ The title renders as an `<h2>` by default and an `<h3>` when `headingLevel` is `
|
|
|
129
212
|
|
|
130
213
|
### Don't
|
|
131
214
|
|
|
215
|
+
- Don't set `headingLevel` to `1` on an empty state inside a page that already has its own `h1`.
|
|
132
216
|
- Don't use `bf-empty-state` for a loading screen; that is `bf-spinner`.
|
|
133
217
|
|
|
134
218
|
## Migration notes
|
|
135
219
|
|
|
220
|
+
### 0.3.2
|
|
221
|
+
|
|
222
|
+
`headingLevel` now takes the new named type `BfEmptyStateHeading` (`BfEmptyStateHeadingLevel |
|
|
223
|
+
1`): `1` renders the title as the page's `h1`, for an empty state that is the page (a not-found
|
|
224
|
+
or no-access page). The released `BfEmptyStateHeadingLevel` keeps its two members, so `Record`s
|
|
225
|
+
over it keep compiling. New "As the page" docs section with the `empty-state/page` example
|
|
226
|
+
(centred in a tall area, a primary action and a secondary link) and the code-only
|
|
227
|
+
`empty-state/not-found-page`.
|
|
228
|
+
|
|
136
229
|
### 0.3.0
|
|
137
230
|
|
|
138
231
|
New exported `BfEmptyStateHeadingLevel` (`2 | 3`), the type of `headingLevel` (was an inline union
|