@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
package/ai/components/header.md
CHANGED
|
@@ -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
|
|
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
|
|
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. Below the breakpoint, [bf-app-frame](https://bitforge-ui.web.app/components/app-frame) supplies the app-level header bar (brand, navigation menu, actions) above the page header. 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,15 @@ 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.2
|
|
752
|
+
|
|
753
|
+
The `## Desktop` docs say `bf-app-frame` supplies the app-level header bar below its breakpoint.
|
|
754
|
+
|
|
755
|
+
### 0.3.1
|
|
756
|
+
|
|
757
|
+
The `## Desktop` docs and When to use name the desktop replacement, `bf-page-header` (with
|
|
758
|
+
`bf-breadcrumb` and `bf-toolbar`), with an example. No code change.
|
|
759
|
+
|
|
691
760
|
### 0.3.0
|
|
692
761
|
|
|
693
762
|
JSDoc of `header.component.ts` for the API reference: `@slot` docs for `start`, `default`, `end`. No
|
|
@@ -60,8 +60,12 @@ export class IconButtonOverviewExampleComponent {
|
|
|
60
60
|
|
|
61
61
|
## Overview
|
|
62
62
|
|
|
63
|
+
Also matches: `a[bfIconButton]`
|
|
64
|
+
|
|
63
65
|
Round button that holds a single icon, for toolbars, headers and list rows. The `label` is
|
|
64
|
-
required because the icon alone gives assistive tech no name.
|
|
66
|
+
required because the icon alone gives assistive tech no name. For navigation, put
|
|
67
|
+
`bfIconButton` on your own `<a>` (with `href` or `routerLink`): it renders as a real link that
|
|
68
|
+
looks like the icon button.
|
|
65
69
|
|
|
66
70
|
A round button for a single icon: search in a header, close on a sheet, more-actions on a row. `label` is required and becomes the accessible name.
|
|
67
71
|
|
|
@@ -133,6 +137,47 @@ export class IconButtonVariantsExampleComponent {
|
|
|
133
137
|
}
|
|
134
138
|
```
|
|
135
139
|
|
|
140
|
+
## As a link
|
|
141
|
+
|
|
142
|
+
An icon-only "back", "open" or "edit" that navigates is a link: put `bfIconButton` on your own `<a>` and give it `href` or `routerLink`. The `<a>` takes the icon button's variant, size, focus ring and hit area itself (no inner `<button>`, no underline), and `label` becomes its `aria-label`, so it still has a name. The browser treats it as a link: Enter follows it (Space does not), Ctrl/Cmd-click and a middle click open it in a new tab, and the URL shows on hover. `clicked` still emits on every click. `type` and `disabled` do not apply: a link is never disabled, so render a disabled `bf-icon-button` while the destination is unavailable. This mirrors `a[bfButton]` ([bf-button](https://bitforge-ui.web.app/components/button)).
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { Component } from '@angular/core';
|
|
146
|
+
import { RouterLink } from '@angular/router';
|
|
147
|
+
import { BfIconButtonComponent } from '@bitforgehq/ui';
|
|
148
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
149
|
+
import { ArrowLeft, ExternalLink, Pencil } from 'lucide';
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Icon-only links.
|
|
153
|
+
*
|
|
154
|
+
* `bfIconButton` on your own `<a>`: a back link and an edit link with `routerLink`, and an
|
|
155
|
+
* external link with `href`. Each `label` is the link's accessible name.
|
|
156
|
+
*/
|
|
157
|
+
@Component({
|
|
158
|
+
selector: 'app-example-icon-button-link',
|
|
159
|
+
imports: [RouterLink, BfIconButtonComponent, BfIconComponent],
|
|
160
|
+
template: `
|
|
161
|
+
<div class="flex items-center gap-3">
|
|
162
|
+
<a bfIconButton variant="text" label="Back to components" routerLink="/components">
|
|
163
|
+
<bf-icon [icon]="arrowLeft" />
|
|
164
|
+
</a>
|
|
165
|
+
<a bfIconButton label="Edit the button page" routerLink="/components/button">
|
|
166
|
+
<bf-icon [icon]="pencil" />
|
|
167
|
+
</a>
|
|
168
|
+
<a bfIconButton variant="outline" label="Open bitforge.ch" href="https://bitforge.ch">
|
|
169
|
+
<bf-icon [icon]="externalLink" />
|
|
170
|
+
</a>
|
|
171
|
+
</div>
|
|
172
|
+
`,
|
|
173
|
+
})
|
|
174
|
+
export class IconButtonLinkExampleComponent {
|
|
175
|
+
protected readonly arrowLeft = ArrowLeft;
|
|
176
|
+
protected readonly pencil = Pencil;
|
|
177
|
+
protected readonly externalLink = ExternalLink;
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
136
181
|
## Desktop
|
|
137
182
|
|
|
138
183
|
Hover tints the button (`tonal`, `text`) or darkens it (`primary`, the `outline` border), with the pointer cursor; disabled shows `not-allowed`. Hover styles apply only on devices that can hover, so a tap never leaves one stuck. The focus ring shows on keyboard focus only. There is no built-in tooltip, and `label` is read by assistive tech only, so keep to icons whose meaning is clear without one. Under a fine pointer the 32/40/48 px square is the hit area. Desktop density is the default `md` step; `provideBfDefaults({ size: 'sm' })`, or `{ size: 'sm' }` in a component's `providers`, makes a dense toolbar, table or sidebar ([density guide](https://bitforge-ui.web.app/density)).
|
|
@@ -154,30 +199,33 @@ Cursor: `pointer` while enabled, `not-allowed` when disabled. Disabled (any vari
|
|
|
154
199
|
|
|
155
200
|
## Accessibility
|
|
156
201
|
|
|
157
|
-
|
|
202
|
+
`bf-icon-button` renders a native `<button>`; its `type` reflects the `type` input. `label` is required and becomes the button's `aria-label`, since the icon inside carries no text of its own. `disabled` sets the native attribute, which also removes it from the tab order and swallows clicks.
|
|
203
|
+
|
|
204
|
+
`a[bfIconButton]` is your own `<a>`, so it keeps the link role and link keyboard behaviour ([WAI-ARIA APG link pattern](https://www.w3.org/WAI/ARIA/apg/patterns/link/)), with `label` as its `aria-label`. It is in the tab order while it has an `href` (in Safari and iOS WKWebView, Tab reaches links only when the user turns on "Press Tab to highlight each item" (Option+Tab otherwise); VoiceOver and Full Keyboard Access are unaffected). Use it whenever activation navigates to a URL.
|
|
158
205
|
|
|
159
206
|
### Keyboard
|
|
160
207
|
|
|
161
|
-
| Key | Action
|
|
162
|
-
| ----------------------------------- |
|
|
163
|
-
| <kbd>Tab</kbd> | Moves focus to the button; a `disabled` one is skipped
|
|
164
|
-
| <kbd>Enter</kbd> / <kbd>Space</kbd> |
|
|
208
|
+
| Key | Action |
|
|
209
|
+
| ----------------------------------- | -------------------------------------------------------------- |
|
|
210
|
+
| <kbd>Tab</kbd> | Moves focus to the button; a `disabled` one is skipped |
|
|
211
|
+
| <kbd>Enter</kbd> / <kbd>Space</kbd> | `bf-icon-button`: activates it and emits `clicked` |
|
|
212
|
+
| <kbd>Enter</kbd> | `a[bfIconButton]`: follows the link; <kbd>Space</kbd> does not |
|
|
165
213
|
|
|
166
214
|
## Inputs
|
|
167
215
|
|
|
168
|
-
| Name | Type | Default | Description
|
|
169
|
-
| ---------- | --------------------------------------------------------------------- | ----------- |
|
|
170
|
-
| `variant` | `BfIconButtonVariant` (`'tonal' \| 'primary' \| 'outline' \| 'text'`) | `'tonal'` | Visual style: tonal (soft tint, default), primary, outline, text.
|
|
171
|
-
| `size` | `BfSize \| undefined` (`'sm' \| 'md' \| 'lg' \| undefined`) | `undefined` | Height step: sm 32, md 40, lg 48 px (square); unset follows `provideBfDefaults()` (`controlSize`, `md` by default).
|
|
172
|
-
| `type` | `BfButtonType` (`'button' \| 'submit' \| 'reset'`) | `'button'` | Native button type.
|
|
173
|
-
| `disabled` | `boolean` | `false` | Disables the control and swallows clicks.
|
|
174
|
-
| `label` | `string` | required | Accessible name announced instead of the icon
|
|
216
|
+
| Name | Type | Default | Description |
|
|
217
|
+
| ---------- | --------------------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
218
|
+
| `variant` | `BfIconButtonVariant` (`'tonal' \| 'primary' \| 'outline' \| 'text'`) | `'tonal'` | Visual style: tonal (soft tint, default), primary, outline, text. |
|
|
219
|
+
| `size` | `BfSize \| undefined` (`'sm' \| 'md' \| 'lg' \| undefined`) | `undefined` | Height step: sm 32, md 40, lg 48 px (square); unset follows `provideBfDefaults()` (`controlSize`, `md` by default). |
|
|
220
|
+
| `type` | `BfButtonType` (`'button' \| 'submit' \| 'reset'`) | `'button'` | Native button type. Ignored on `a[bfIconButton]`. |
|
|
221
|
+
| `disabled` | `boolean` | `false` | Disables the control and swallows clicks. Ignored on `a[bfIconButton]`: a link is never disabled; render a disabled `bf-icon-button` instead. |
|
|
222
|
+
| `label` | `string` | required | Accessible name announced instead of the icon; on `a[bfIconButton]`, the link's `aria-label`. |
|
|
175
223
|
|
|
176
224
|
## Outputs
|
|
177
225
|
|
|
178
|
-
| Name | Payload | Description
|
|
179
|
-
| --------- | ------- |
|
|
180
|
-
| `clicked` | `Event` | Emitted on click while enabled. |
|
|
226
|
+
| Name | Payload | Description |
|
|
227
|
+
| --------- | ------- | ------------------------------------------------------------------------------------------------ |
|
|
228
|
+
| `clicked` | `Event` | Emitted on click while enabled; on `a[bfIconButton]`, on every click (the link still navigates). |
|
|
181
229
|
|
|
182
230
|
## Slots
|
|
183
231
|
|
|
@@ -189,13 +237,23 @@ Native `<button>`; its `type` reflects the `type` input. `label` is required and
|
|
|
189
237
|
|
|
190
238
|
- Write the label as the action ("Search", "Close"), not the icon name.
|
|
191
239
|
- Use `text` inside list rows and cards so the row stays calm.
|
|
240
|
+
- Use `a[bfIconButton]` for an icon-only link (back, open, edit page), never a `bf-icon-button` that navigates in `(clicked)`.
|
|
192
241
|
|
|
193
242
|
### Don't
|
|
194
243
|
|
|
195
244
|
- Don't put text in the slot; use `bf-button` with an icon slot instead.
|
|
245
|
+
- Don't disable a link; render a disabled `bf-icon-button` while the destination is unavailable.
|
|
196
246
|
|
|
197
247
|
## Migration notes
|
|
198
248
|
|
|
249
|
+
### 0.3.1
|
|
250
|
+
|
|
251
|
+
New `a[bfIconButton]` selector: put `bfIconButton` on your own `<a>` (with `href` or `routerLink`)
|
|
252
|
+
for an icon-only link such as back, open or edit. The `<a>` takes the variant, size, focus ring
|
|
253
|
+
and touch hit area, `label` becomes its `aria-label` (still required), and it behaves as a link
|
|
254
|
+
(Enter, Ctrl/Cmd-click and middle click open it; `clicked` emits on every click). `type` and
|
|
255
|
+
`disabled` do not apply, as on `a[bfButton]`. The `bf-icon-button` element is unchanged.
|
|
256
|
+
|
|
199
257
|
### 0.3.0
|
|
200
258
|
|
|
201
259
|
**Behaviour:** `size` is a `BfSize` and, unset, follows `provideBfDefaults()`'s `controlSize`. The
|
package/ai/components/icon.md
CHANGED
|
@@ -45,7 +45,7 @@ export class IconOverviewExampleComponent {
|
|
|
45
45
|
Renders a Lucide icon from its data, tree-shakably and without a registry.
|
|
46
46
|
Import the icon you need from `lucide` (e.g. `import { Search } from 'lucide'`) and bind it.
|
|
47
47
|
Decorative by default; pass `label` when the icon carries meaning on its own (e.g. an icon-only
|
|
48
|
-
control without visible text).
|
|
48
|
+
control without visible text). `filled` fills a solid shape such as a heart or a star.
|
|
49
49
|
|
|
50
50
|
Renders a Lucide icon from its data. Import the icon you need from `lucide` and bind it; nothing is registered globally and unused icons are tree-shaken. Every widget's icon slot accepts a `bf-icon`, and also any other SVG or component, including privately licensed icon sets.
|
|
51
51
|
|
|
@@ -119,9 +119,52 @@ export class IconFilledExampleComponent {
|
|
|
119
119
|
}
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
+
## Filled shapes
|
|
123
|
+
|
|
124
|
+
`filled` fills the whole shape with `currentColor` and keeps the stroke, for a state that an outline alone makes too easy to miss: a favourite heart, a starred item, a saved bookmark. Bind it to the state (`[filled]="favourite()"`). Only icons whose every shape is closed are filled (`Heart`, `Star`, `Bookmark`, `Circle`, `Square`); an icon with an open stroke stays an outline, because filling it would paint the area a check mark or a line encloses, or hide inner strokes (the check of `CircleCheck`, the clapper of `Bell`) under the same colour. So `filled` on a pure line icon does nothing.
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import { Component, signal } from '@angular/core';
|
|
128
|
+
import { BfButtonComponent, BfIconButtonComponent } from '@bitforgehq/ui';
|
|
129
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
130
|
+
import { Heart, Star } from 'lucide';
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Filled heart and star toggles.
|
|
134
|
+
*
|
|
135
|
+
* `filled` follows the state, and the control's name says it too: the icon button's label
|
|
136
|
+
* changes, and the button's text does.
|
|
137
|
+
*/
|
|
138
|
+
@Component({
|
|
139
|
+
selector: 'app-example-icon-filled-shape',
|
|
140
|
+
imports: [BfButtonComponent, BfIconButtonComponent, BfIconComponent],
|
|
141
|
+
template: `
|
|
142
|
+
<div class="flex flex-wrap items-center gap-3">
|
|
143
|
+
<bf-icon-button
|
|
144
|
+
variant="text"
|
|
145
|
+
[label]="favourite() ? 'Remove from favourites' : 'Add to favourites'"
|
|
146
|
+
(clicked)="favourite.update((on) => !on)"
|
|
147
|
+
>
|
|
148
|
+
<bf-icon [icon]="heart" [filled]="favourite()" [class.text-danger]="favourite()" />
|
|
149
|
+
</bf-icon-button>
|
|
150
|
+
<bf-button variant="ghost" (clicked)="starred.update((on) => !on)">
|
|
151
|
+
<bf-icon bfSlot="icon-start" [icon]="star" [filled]="starred()" />
|
|
152
|
+
{{ starred() ? 'Starred' : 'Star' }}
|
|
153
|
+
</bf-button>
|
|
154
|
+
</div>
|
|
155
|
+
`,
|
|
156
|
+
})
|
|
157
|
+
export class IconFilledShapeExampleComponent {
|
|
158
|
+
protected readonly heart = Heart;
|
|
159
|
+
protected readonly star = Star;
|
|
160
|
+
protected readonly favourite = signal(true);
|
|
161
|
+
protected readonly starred = signal(false);
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
122
165
|
## Theming
|
|
123
166
|
|
|
124
|
-
`bf-icon` defines no color of its own; its stroke (and any fill Lucide sets) uses `currentColor`, so it takes on whatever text color its parent sets (a class like `text-text-muted`, or the button/link text color around it).
|
|
167
|
+
`bf-icon` defines no color of its own; its stroke (and any fill Lucide sets, and the `filled` shape) uses `currentColor`, so it takes on whatever text color its parent sets (a class like `text-text-muted`, or the button/link text color around it).
|
|
125
168
|
|
|
126
169
|
## Accessibility
|
|
127
170
|
|
|
@@ -143,13 +186,16 @@ export class IconLabelledExampleComponent {
|
|
|
143
186
|
}
|
|
144
187
|
```
|
|
145
188
|
|
|
189
|
+
A filled icon is a picture of a state, and assistive tech never sees it: put the state in the control as well, in its name ("Remove from favourites", "Starred") or with `aria-pressed` on a toggle button, never in the fill alone. The fill also must not be the only visible cue where colour carries the meaning; a filled shape plus a changed label is enough.
|
|
190
|
+
|
|
146
191
|
## Inputs
|
|
147
192
|
|
|
148
|
-
| Name
|
|
149
|
-
|
|
|
150
|
-
| `icon`
|
|
151
|
-
| `size`
|
|
152
|
-
| `label`
|
|
193
|
+
| Name | Type | Default | Description |
|
|
194
|
+
| -------- | ------------------------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
195
|
+
| `icon` | `IconNode` | required | Lucide icon data, e.g. `Search` from `lucide`. |
|
|
196
|
+
| `size` | `BfIconSize` (`'sm' \| 'md' \| 'lg'`) | `'md'` | Visual size: 16, 20 or 24 px. |
|
|
197
|
+
| `label` | `string` | `''` | Accessible name. Leave empty for decorative icons next to visible text. |
|
|
198
|
+
| `filled` | `boolean` | `false` | Fills the shape with `currentColor` (a favourite heart, a starred item); the stroke stays. Only icons whose every shape is closed are filled; a stroke icon (a check, a line) or an outline holding inner strokes renders as usual. |
|
|
153
199
|
|
|
154
200
|
## Notes
|
|
155
201
|
|
|
@@ -157,14 +203,24 @@ export class IconLabelledExampleComponent {
|
|
|
157
203
|
|
|
158
204
|
- Put icons in a widget's `icon-start` / `icon-end` slot rather than in its default slot.
|
|
159
205
|
- Use `label` only when there is no visible text saying the same thing.
|
|
206
|
+
- Bind `filled` to a state and put the same state in the control's name or `aria-pressed`.
|
|
160
207
|
|
|
161
208
|
### Don't
|
|
162
209
|
|
|
163
210
|
- Don't inline `<svg>` markup in app templates; use `bf-icon` or an icon component.
|
|
211
|
+
- Don't expect `filled` to fill a stroke icon (a check, an arrow); it leaves those as outlines.
|
|
164
212
|
- Don't ship Streamline pro icons in a public package; use them in your app's private code through the slots.
|
|
165
213
|
|
|
166
214
|
## Migration notes
|
|
167
215
|
|
|
216
|
+
### 0.3.1
|
|
217
|
+
|
|
218
|
+
New `filled` input: fills the shape with `currentColor` and keeps the stroke, for a favourite
|
|
219
|
+
heart or a starred item. Only icons whose every shape is closed are filled (`Heart`, `Star`,
|
|
220
|
+
`Bookmark`, …); a stroke icon or an outline holding inner strokes renders as before, so `filled`
|
|
221
|
+
never paints the area a check mark encloses or hides a stroke. Put the state in the control's name
|
|
222
|
+
or `aria-pressed` too.
|
|
223
|
+
|
|
168
224
|
### 0.3.0
|
|
169
225
|
|
|
170
226
|
JSDoc of `icon.component.ts` for the API reference: `@summary`/`@since` on the exported symbols. No
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
# bf-line-chart
|
|
2
|
+
|
|
3
|
+
Line chart of series over categories, with tooltip, legend and data table
|
|
4
|
+
|
|
5
|
+
`BfLineChartComponent` 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 { BfLineChartComponent, type BfChartSeries } from '@bitforgehq/ui/charts';
|
|
13
|
+
|
|
14
|
+
type Period = 'week' | 'quarter' | 'year';
|
|
15
|
+
|
|
16
|
+
interface PeriodData {
|
|
17
|
+
readonly categories: readonly string[];
|
|
18
|
+
readonly series: readonly BfChartSeries[];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const DATA: Record<Period, PeriodData> = {
|
|
22
|
+
week: {
|
|
23
|
+
categories: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
|
|
24
|
+
series: [
|
|
25
|
+
{ name: 'Online', values: [3.2, 3.8, 3.5, 4.1, 4.6, 5.9, 5.2] },
|
|
26
|
+
{ name: 'In store', values: [2.1, 2.4, 2.2, 2.6, 3.4, 4.8, 3.1] },
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
quarter: {
|
|
30
|
+
categories: ['Jul', 'Aug', 'Sep'],
|
|
31
|
+
series: [
|
|
32
|
+
{ name: 'Online', values: [96, 104, 121] },
|
|
33
|
+
{ name: 'In store', values: [71, 64, 78] },
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
year: {
|
|
37
|
+
categories: [
|
|
38
|
+
'Jan',
|
|
39
|
+
'Feb',
|
|
40
|
+
'Mar',
|
|
41
|
+
'Apr',
|
|
42
|
+
'May',
|
|
43
|
+
'Jun',
|
|
44
|
+
'Jul',
|
|
45
|
+
'Aug',
|
|
46
|
+
'Sep',
|
|
47
|
+
'Oct',
|
|
48
|
+
'Nov',
|
|
49
|
+
'Dec',
|
|
50
|
+
],
|
|
51
|
+
series: [
|
|
52
|
+
{ name: 'Online', values: [62, 58, 71, 76, 83, 88, 96, 104, 121, 118, 139, 162] },
|
|
53
|
+
{ name: 'In store', values: [54, 51, 57, 60, 66, 69, 71, 64, 78, 80, 92, 121] },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* The bf-line-chart overview.
|
|
60
|
+
*
|
|
61
|
+
* Live demo of `bf-line-chart`: revenue online and in store in thousands of francs, with a
|
|
62
|
+
* segmented period switch above it. Hover the plot, or focus it and use the arrow keys; hide a
|
|
63
|
+
* series in the legend; open Show data for the table.
|
|
64
|
+
*/
|
|
65
|
+
@Component({
|
|
66
|
+
selector: 'app-example-line-chart-overview',
|
|
67
|
+
imports: [BfLineChartComponent, BfSegmentedComponent],
|
|
68
|
+
template: `
|
|
69
|
+
<div class="flex w-full flex-col gap-4">
|
|
70
|
+
<bf-segmented label="Period" [options]="periods" [(value)]="period" />
|
|
71
|
+
<bf-line-chart
|
|
72
|
+
label="Revenue by channel"
|
|
73
|
+
[series]="data().series"
|
|
74
|
+
[categories]="data().categories"
|
|
75
|
+
[valueFormat]="format"
|
|
76
|
+
/>
|
|
77
|
+
<p data-status aria-live="polite" class="text-caption text-text-muted">
|
|
78
|
+
Showing {{ data().categories.length }} points: {{ periodLabel() }}
|
|
79
|
+
</p>
|
|
80
|
+
</div>
|
|
81
|
+
`,
|
|
82
|
+
})
|
|
83
|
+
export class LineChartOverviewExampleComponent {
|
|
84
|
+
readonly periods: BfSegmentOption<Period>[] = [
|
|
85
|
+
{ value: 'week', label: 'Week' },
|
|
86
|
+
{ value: 'quarter', label: 'Quarter' },
|
|
87
|
+
{ value: 'year', label: 'Year' },
|
|
88
|
+
];
|
|
89
|
+
readonly period = signal<Period | null>('year');
|
|
90
|
+
readonly data = computed(() => DATA[this.period() ?? 'year']);
|
|
91
|
+
readonly periodLabel = computed(
|
|
92
|
+
() => this.periods.find((p) => p.value === this.period())?.label ?? '',
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
private readonly francs = new Intl.NumberFormat('en', { maximumFractionDigits: 1 });
|
|
96
|
+
/** Thousands of francs, as "CHF 121k". */
|
|
97
|
+
readonly format = (value: number): string => `CHF ${this.francs.format(value)}k`;
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Overview
|
|
102
|
+
|
|
103
|
+
A line chart of one or more series over shared categories (months, days, steps), drawn in SVG
|
|
104
|
+
with the chart palette: value axis with nice ticks and grid lines, a legend that shows and
|
|
105
|
+
hides series, a crosshair tooltip on hover and on keyboard focus (Arrow keys move between the
|
|
106
|
+
categories and a polite live region reads each one) and a Show data table. `area` fills under
|
|
107
|
+
each line; `curve="smooth"` draws a monotone curve. The lines draw in on the first render and on
|
|
108
|
+
every data change, still under reduced motion; under `dir="rtl"` the categories run from the
|
|
109
|
+
right.
|
|
110
|
+
|
|
111
|
+
A line chart shows how one or more values change over shared categories: revenue per month, sign-ups per day, response time per release. `bf-line-chart` draws it in SVG from `series` (each a `name` and one value per category, `null` for a gap) and `categories`, with a value axis of nice ticks, a legend that shows and hides series, a crosshair tooltip on hover and on keyboard focus, and a Show data table. It lives in its own entry point, `@bitforgehq/ui/charts` (`import { BfLineChartComponent } from '@bitforgehq/ui/charts'`), which needs nothing beyond the widgets entry, and it works the same in a desktop web app and in the Capacitor shell.
|
|
112
|
+
|
|
113
|
+
## When to use
|
|
114
|
+
|
|
115
|
+
Use `bf-line-chart` for a trend over an ordered axis (time, steps, versions), with up to about eight series. Our charts are themed with the `--color-chart-*` tokens, follow dark mode, density and `dir="rtl"`, and bring their own legend, tooltip, keyboard reading and data table, so reach for them before a chart library; bring a library (and theme it with the same chart tokens) only for a form they do not draw, such as a scatter plot, a map or a zoomable time series of thousands of points. Use [bf-bar-chart](https://bitforge-ui.web.app/components/bar-chart) instead to compare amounts between categories that have no order, [bf-sparkline](https://bitforge-ui.web.app/components/sparkline) for a tiny trend beside a figure, and put the chart in a [bf-chart-card](https://bitforge-ui.web.app/components/chart-card) for a title, a period control and loading states.
|
|
116
|
+
|
|
117
|
+
## Area and curve
|
|
118
|
+
|
|
119
|
+
`area` fills under each line in its series' colour at 16 %, and starts the value axis at zero so the filled area stays honest. `curve="smooth"` draws a monotone cubic curve through the points: it never overshoots a value, so a plateau stays flat and a peak is never drawn higher than it was. Without `area` the value axis spans the data, rounded out to nice numbers.
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
import { Component } from '@angular/core';
|
|
123
|
+
import { BfLineChartComponent, type BfChartSeries } from '@bitforgehq/ui/charts';
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* A smooth area chart.
|
|
127
|
+
*
|
|
128
|
+
* `area` fills under the line and starts the value axis at zero; `curve="smooth"` draws a
|
|
129
|
+
* monotone curve that never overshoots a value. Active users per week, with a gap where the
|
|
130
|
+
* tracking was down.
|
|
131
|
+
*/
|
|
132
|
+
@Component({
|
|
133
|
+
selector: 'app-example-line-chart-area',
|
|
134
|
+
imports: [BfLineChartComponent],
|
|
135
|
+
template: `
|
|
136
|
+
<bf-line-chart
|
|
137
|
+
label="Weekly active users"
|
|
138
|
+
area
|
|
139
|
+
curve="smooth"
|
|
140
|
+
[height]="200"
|
|
141
|
+
[series]="series"
|
|
142
|
+
[categories]="weeks"
|
|
143
|
+
/>
|
|
144
|
+
`,
|
|
145
|
+
})
|
|
146
|
+
export class LineChartAreaExampleComponent {
|
|
147
|
+
readonly weeks = ['W1', 'W2', 'W3', 'W4', 'W5', 'W6', 'W7', 'W8'];
|
|
148
|
+
readonly series: readonly BfChartSeries[] = [
|
|
149
|
+
{ name: 'Active users', values: [1240, 1310, 1290, null, 1480, 1620, 1610, 1790] },
|
|
150
|
+
];
|
|
151
|
+
}
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Data and formatting
|
|
155
|
+
|
|
156
|
+
Each series has one value per category, in the categories' order; `null` (or a missing value) leaves a gap in the line, and a point with gaps on both sides draws as a dot. `valueFormat` formats every value on the axis, in the tooltip, the announcement and the table, for a unit or a currency (`(v) => formatter.format(v)`); unset, values use `Intl.NumberFormat` in the document's language. The colour of a series follows its position (`--color-chart-1` for the first): hiding one in the legend never repaints the others. The lines draw in on the first render and again whenever `series` or `categories` change.
|
|
157
|
+
|
|
158
|
+
## Size
|
|
159
|
+
|
|
160
|
+
`height` sets the plot's height in px (240 by default); the width follows the container, measured with a `ResizeObserver`, so a chart in a grid column or a card reflows by itself. Category labels thin out when they would collide. On the server, before the first measure, the chart draws at 600 px wide and scales to its box.
|
|
161
|
+
|
|
162
|
+
## Desktop
|
|
163
|
+
|
|
164
|
+
Under a mouse, hovering the plot shows the crosshair, a ring marker on each line and the tooltip of the nearest category; leaving the plot hides them. The legend's buttons take a `surface-muted` fill on hover. The plot is one stop in the tab order, with the focus ring on keyboard focus: focusing it shows the first category, and the arrow keys move from there. Under a coarse pointer (touch) a tap or a drag across the plot moves the tooltip, and the legend buttons and the Show data button are at least 44 px tall. Inside `provideBfShell()` it renders and behaves the same.
|
|
165
|
+
|
|
166
|
+
## Theming
|
|
167
|
+
|
|
168
|
+
- Lines: `--color-chart-1` … `--color-chart-8` by series (`stroke-chart-n`), 2 px; areas the same colour at 16 % (`fill-chart-n/16`).
|
|
169
|
+
- Grid lines: `chart-grid`; the baseline and the crosshair: `chart-axis`; axis text: `text-micro` in `text-muted`.
|
|
170
|
+
- Markers: `surface` fill with the series' colour as a 2 px ring.
|
|
171
|
+
- Tooltip: `surface`, a `border` edge, `shadow-floating`, `rounded-tile`, `text-caption`.
|
|
172
|
+
- Legend: `text-caption` in `text-secondary` (a hidden series in `text-muted`, struck through, its swatch an empty `text-subtle` ring); hover `surface-muted`.
|
|
173
|
+
- Show data: `text-label-xs` in `primary-text`; the table takes `bf-table`'s look (`border`, `divider`, `text-label-xs` headers in `text-muted`).
|
|
174
|
+
- Motion: `--animate-chart-draw` (the line) and `--animate-chart-fade` (the area); none under `prefers-reduced-motion`.
|
|
175
|
+
|
|
176
|
+
## Accessibility
|
|
177
|
+
|
|
178
|
+
The chart is a native `figure` named by `label` (else the `bf-chart-card` title, else `provideBfLabels()`'s `chart`); the SVG is hidden from assistive technology. The plot is a focusable `role="group"` named by the `chartValues` label: the arrow keys move between the categories and a polite live region reads each one ("Mar: Online 15, Store 11", a dash for a gap). The tooltip repeats what the region reads and is hidden from assistive technology. The legend is a group of toggle buttons (`aria-pressed`) named by the `chartLegend` label. The Show data button (`aria-expanded`, `aria-controls`) shows the data as a native `table` with a `caption`, a header row and a row header per category. Every series is ≥ 3:1 against `surface` and `bg` in both modes, and the legend names each colour, so no value rests on colour alone.
|
|
179
|
+
|
|
180
|
+
### Keyboard
|
|
181
|
+
|
|
182
|
+
| Key | Action |
|
|
183
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------------- |
|
|
184
|
+
| <kbd>Tab</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> | Moves through the plot, the legend buttons and the Show data button |
|
|
185
|
+
| <kbd>ArrowRight</kbd> | Moves to the next category and reads it (the previous one under `dir="rtl"`) |
|
|
186
|
+
| <kbd>ArrowLeft</kbd> | Moves to the previous category and reads it (the next one under `dir="rtl"`) |
|
|
187
|
+
| <kbd>Home</kbd> / <kbd>End</kbd> | Moves to the first / last category |
|
|
188
|
+
| <kbd>Escape</kbd> | Hides the tooltip |
|
|
189
|
+
| <kbd>Enter</kbd> / <kbd>Space</kbd> | On a legend button, shows or hides its series; on Show data, shows or hides the table |
|
|
190
|
+
|
|
191
|
+
## Inputs
|
|
192
|
+
|
|
193
|
+
| Name | Type | Default | Description |
|
|
194
|
+
| ------------- | --------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
195
|
+
| `series` | `readonly BfChartSeries[]` | required | The series to draw, each with one value per category. |
|
|
196
|
+
| `categories` | `readonly string[]` | required | The category names along the horizontal axis, in order. |
|
|
197
|
+
| `label` | `string` | `''` | The chart's accessible name; empty falls back to the `bf-chart-card` title, then to `provideBfLabels()`'s `chart` ("Chart"). |
|
|
198
|
+
| `height` | `number` | `240` | The plot's height in px; the width follows the container. |
|
|
199
|
+
| `area` | `boolean` | `false` | Fills the area under each line in the series' colour (the value axis then starts at zero). |
|
|
200
|
+
| `curve` | `BfChartCurve` (`'linear' \| 'smooth'`) | `'linear'` | The line between points: `linear` (default) or `smooth`, a monotone curve. |
|
|
201
|
+
| `valueFormat` | `BfChartValueFormat \| undefined` | `undefined` | Formats the values on the axis, in the tooltip and in the table; unset uses `Intl.NumberFormat` in the document's language. |
|
|
202
|
+
| `legend` | `BfChartLegendPosition \| undefined` (`'top' \| 'bottom' \| 'none' \| undefined`) | `undefined` | Where the legend goes; unset follows the `bf-chart-card`, else `bottom`. A single series draws no legend. |
|
|
203
|
+
|
|
204
|
+
## Notes
|
|
205
|
+
|
|
206
|
+
### Do
|
|
207
|
+
|
|
208
|
+
- Give every chart a `label` that says what it shows ("Revenue by month, 2026"), or put it in a `bf-chart-card` with a title.
|
|
209
|
+
- Format values with their unit in `valueFormat`, so the axis, the tooltip and the table read the same.
|
|
210
|
+
|
|
211
|
+
### Don't
|
|
212
|
+
|
|
213
|
+
- Don't draw more than eight series; fold the smallest into an "Other" series or split the chart.
|
|
214
|
+
- Don't put two measures of different scale on one chart; draw two charts.
|
|
215
|
+
|
|
216
|
+
## Migration notes
|
|
217
|
+
|
|
218
|
+
### 0.3.1
|
|
219
|
+
|
|
220
|
+
New `bf-line-chart` in the new `@bitforgehq/ui/charts` entry (which imports only Angular core and
|
|
221
|
+
common and the root entry): one or more `series` (`BfChartSeries`: `name`, `values` with `null`
|
|
222
|
+
for a gap) over `categories`, drawn in SVG with the `--color-chart-*` tokens. A value axis of nice
|
|
223
|
+
ticks (1, 2 or 5 × 10ⁿ), a legend that shows and hides series (`aria-pressed`; `legend`:
|
|
224
|
+
`BfChartLegendPosition` `top`, `bottom` or `none`), a crosshair tooltip with markers on hover and
|
|
225
|
+
on keyboard focus (the plot is focusable; the arrow keys, `Home`, `End` and `Escape` move between
|
|
226
|
+
the categories and a polite live region reads each one), and a Show data toggle that shows the data
|
|
227
|
+
as a table. `area` fills under the lines, `curve` (`BfChartCurve`: `linear` or `smooth`, a monotone
|
|
228
|
+
cubic) shapes them, `valueFormat` formats every value (default `Intl.NumberFormat` in the document's
|
|
229
|
+
language), `height` sets the plot's height and the width follows the container (`ResizeObserver`;
|
|
230
|
+
600 px on the server). Lines draw in on the first render and on every data change, not under
|
|
231
|
+
reduced motion; `dir="rtl"` mirrors the category axis.
|
|
232
|
+
New `BfChartHarness` in `@bitforgehq/ui/testing` for the line, bar and donut charts:
|
|
233
|
+
`getLabel()`, `getSeriesNames()`, `isSeriesShown()`, `toggleSeries()` and `showData()` (the data
|
|
234
|
+
table's rows).
|