@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,121 @@
|
|
|
1
|
+
# li[bfBreadcrumbItem]
|
|
2
|
+
|
|
3
|
+
One level of a breadcrumb trail: a link, or the current page as text
|
|
4
|
+
|
|
5
|
+
`BfBreadcrumbItemComponent` from `@bitforgehq/ui` · Navigation · since 0.3.1
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Component } from '@angular/core';
|
|
11
|
+
import { RouterLink } from '@angular/router';
|
|
12
|
+
import { BfBreadcrumbComponent, BfBreadcrumbItemComponent } from '@bitforgehq/ui';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The li[bfBreadcrumbItem] overview.
|
|
16
|
+
*
|
|
17
|
+
* Three levels of a `bf-breadcrumb`: two ancestor pages as router links, each followed by a
|
|
18
|
+
* chevron, and the current page as plain text, marked `aria-current="page"`.
|
|
19
|
+
*/
|
|
20
|
+
@Component({
|
|
21
|
+
selector: 'app-example-breadcrumb-item-overview',
|
|
22
|
+
imports: [RouterLink, BfBreadcrumbComponent, BfBreadcrumbItemComponent],
|
|
23
|
+
template: `
|
|
24
|
+
<bf-breadcrumb label="Component breadcrumb">
|
|
25
|
+
<li bfBreadcrumbItem><a routerLink="/components">Components</a></li>
|
|
26
|
+
<li bfBreadcrumbItem><a routerLink="/components/breadcrumb">Breadcrumb</a></li>
|
|
27
|
+
<li bfBreadcrumbItem>Breadcrumb item</li>
|
|
28
|
+
</bf-breadcrumb>
|
|
29
|
+
`,
|
|
30
|
+
})
|
|
31
|
+
export class BreadcrumbItemOverviewExampleComponent {}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Overview
|
|
35
|
+
|
|
36
|
+
One level of a `bf-breadcrumb` trail, on the consumer's own `<li>` so the list stays `ol > li`.
|
|
37
|
+
Project an `<a routerLink>` for an ancestor page, or plain text for the current page; the last
|
|
38
|
+
item is the current page (`aria-current="page"`, no link look, no separator), every other one is
|
|
39
|
+
followed by a chevron.
|
|
40
|
+
|
|
41
|
+
One level of a [`bf-breadcrumb`](https://bitforge-ui.web.app/components/breadcrumb) trail, as an attribute on the app's own `<li>`. It styles the link projected into it, adds the chevron after it and, on the last level, marks the current page. An item lives only inside a `bf-breadcrumb`, which decides which level is current and which ones a collapsed trail hides.
|
|
42
|
+
|
|
43
|
+
## When to use
|
|
44
|
+
|
|
45
|
+
Use `li[bfBreadcrumbItem]` for each level of a [bf-breadcrumb](https://bitforge-ui.web.app/components/breadcrumb), and only there. On mobile, in the Capacitor shell, use [bf-back-button](https://bitforge-ui.web.app/components/back-button) in [bf-header](https://bitforge-ui.web.app/components/header) instead.
|
|
46
|
+
|
|
47
|
+
## Links and the current page
|
|
48
|
+
|
|
49
|
+
Put an `<a routerLink>` (or `href`) straight inside the `li` for a page above the current one: as a direct child it takes the link look, the hover underline and the focus ring. Put plain text in the last item, the current page: it is wrapped in a span with `aria-current="page"` and shown semibold, and no chevron follows it.
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { Component } from '@angular/core';
|
|
53
|
+
import { RouterLink } from '@angular/router';
|
|
54
|
+
import { BfBreadcrumbComponent, BfBreadcrumbItemComponent } from '@bitforgehq/ui';
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* A breadcrumb trail.
|
|
58
|
+
*
|
|
59
|
+
* Each level is the app's own `<li bfBreadcrumbItem>` holding a router link; the last one is the
|
|
60
|
+
* current page as plain text. `label` names the `nav`; this one is not the page's only breadcrumb
|
|
61
|
+
* (the docs site has its own), so it gets a name of its own.
|
|
62
|
+
*/
|
|
63
|
+
@Component({
|
|
64
|
+
selector: 'app-example-breadcrumb-basic',
|
|
65
|
+
imports: [RouterLink, BfBreadcrumbComponent, BfBreadcrumbItemComponent],
|
|
66
|
+
template: `
|
|
67
|
+
<bf-breadcrumb label="Docs breadcrumb">
|
|
68
|
+
<li bfBreadcrumbItem><a routerLink="/">Docs</a></li>
|
|
69
|
+
<li bfBreadcrumbItem><a routerLink="/components">Components</a></li>
|
|
70
|
+
<li bfBreadcrumbItem>Breadcrumb</li>
|
|
71
|
+
</bf-breadcrumb>
|
|
72
|
+
`,
|
|
73
|
+
})
|
|
74
|
+
export class BreadcrumbBasicExampleComponent {}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Desktop
|
|
78
|
+
|
|
79
|
+
A linked level turns from `text-muted` to `text` and is underlined on hover, with the pointer cursor; the ring shows on keyboard focus only. A link is at least 24 px tall under a fine pointer and 44 px under a coarse one (`pointer-coarse:min-h-hit`), through a min height rather than an `::after`, because it is your content. See the [bf-breadcrumb](https://bitforge-ui.web.app/components/breadcrumb) page for collapsing.
|
|
80
|
+
|
|
81
|
+
## Theming
|
|
82
|
+
|
|
83
|
+
- Ancestor level: `text-muted`, `text` on hover with an underline (`underline-offset-4`); `rounded-tile` with the `ring` focus ring.
|
|
84
|
+
- Current page: `text`, semibold.
|
|
85
|
+
- Separator: a 1.5 px CSS chevron in `text-subtle`, pointing to the inline end and mirrored under `dir="rtl"`.
|
|
86
|
+
|
|
87
|
+
## Accessibility
|
|
88
|
+
|
|
89
|
+
The host is your native `<li>`, so the trail stays an ordered list. Only the last item carries `aria-current="page"`. The chevron is an empty `aria-hidden` element, never announced. A level a collapsed trail hides carries `hidden`; when the ellipsis shows it and it has no link, the item takes focus itself (`tabindex="-1"`).
|
|
90
|
+
|
|
91
|
+
### Keyboard
|
|
92
|
+
|
|
93
|
+
| Key | Action |
|
|
94
|
+
| ---------------- | ------------------------- |
|
|
95
|
+
| <kbd>Tab</kbd> | Moves to the level's link |
|
|
96
|
+
| <kbd>Enter</kbd> | Follows the focused link |
|
|
97
|
+
|
|
98
|
+
## Slots
|
|
99
|
+
|
|
100
|
+
- `default`: The level: an `<a>` link to the page, or plain text for the current page.
|
|
101
|
+
|
|
102
|
+
## Notes
|
|
103
|
+
|
|
104
|
+
### Do
|
|
105
|
+
|
|
106
|
+
- Project the link as the direct child of the `li`, so it takes the link look.
|
|
107
|
+
- Keep the current page plain text.
|
|
108
|
+
|
|
109
|
+
### Don't
|
|
110
|
+
|
|
111
|
+
- Don't use `li[bfBreadcrumbItem]` outside a `bf-breadcrumb`.
|
|
112
|
+
- Don't put more than one link, or a control, in one level.
|
|
113
|
+
|
|
114
|
+
## Migration notes
|
|
115
|
+
|
|
116
|
+
### 0.3.1
|
|
117
|
+
|
|
118
|
+
New `li[bfBreadcrumbItem]` in `@bitforgehq/ui`: one level of a `bf-breadcrumb` on the app's own
|
|
119
|
+
`<li>`. A projected link takes the muted link look, the hover underline and the focus ring (at
|
|
120
|
+
least 24 px tall, 44 px under a coarse pointer); the last level is the current page, wrapped in
|
|
121
|
+
`aria-current="page"` with no chevron.
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
# bf-breadcrumb
|
|
2
|
+
|
|
3
|
+
Desktop breadcrumb trail of links to the current page, with optional collapsing
|
|
4
|
+
|
|
5
|
+
`BfBreadcrumbComponent` from `@bitforgehq/ui` · Navigation · since 0.3.1
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Component, signal } from '@angular/core';
|
|
11
|
+
import { RouterLink } from '@angular/router';
|
|
12
|
+
import { BfBreadcrumbComponent, BfBreadcrumbItemComponent } from '@bitforgehq/ui';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The bf-breadcrumb overview.
|
|
16
|
+
*
|
|
17
|
+
* Live demo of `bf-breadcrumb`: a five-level trail collapsed to three with `maxItems`; the ellipsis
|
|
18
|
+
* shows the hidden levels in place and moves focus to the first one, which the result line
|
|
19
|
+
* reports. The demo's links stay on this page (a fragment per level); an app links each level to
|
|
20
|
+
* its route.
|
|
21
|
+
*/
|
|
22
|
+
@Component({
|
|
23
|
+
selector: 'app-example-breadcrumb-overview',
|
|
24
|
+
imports: [RouterLink, BfBreadcrumbComponent, BfBreadcrumbItemComponent],
|
|
25
|
+
template: `
|
|
26
|
+
<div class="flex flex-col gap-3" (focusin)="onFocus($event)">
|
|
27
|
+
<bf-breadcrumb label="Release breadcrumb" [maxItems]="3">
|
|
28
|
+
@for (level of trail; track level.id) {
|
|
29
|
+
<li bfBreadcrumbItem>
|
|
30
|
+
<a routerLink="." [fragment]="level.id">{{ level.label }}</a>
|
|
31
|
+
</li>
|
|
32
|
+
}
|
|
33
|
+
<li bfBreadcrumbItem>Release 2.4</li>
|
|
34
|
+
</bf-breadcrumb>
|
|
35
|
+
<p data-status aria-live="polite" class="text-caption text-text-muted">{{ status() }}</p>
|
|
36
|
+
</div>
|
|
37
|
+
`,
|
|
38
|
+
})
|
|
39
|
+
export class BreadcrumbOverviewExampleComponent {
|
|
40
|
+
readonly status = signal('Two levels are hidden.');
|
|
41
|
+
readonly trail: readonly { id: string; label: string }[] = [
|
|
42
|
+
{ id: 'workspace', label: 'Workspace' },
|
|
43
|
+
{ id: 'projects', label: 'Projects' },
|
|
44
|
+
{ id: 'atlas', label: 'Atlas' },
|
|
45
|
+
{ id: 'releases', label: 'Releases' },
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
onFocus(event: FocusEvent): void {
|
|
49
|
+
if (event.target instanceof HTMLAnchorElement) {
|
|
50
|
+
this.status.set(`Focus on ${event.target.text.trim()}.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Overview
|
|
57
|
+
|
|
58
|
+
Desktop breadcrumb trail: a `nav` named "Breadcrumb" around an ordered list of
|
|
59
|
+
`li[bfBreadcrumbItem]` levels, the last one the current page, a CSS chevron between them. With
|
|
60
|
+
`maxItems` set and a longer trail it keeps the first level and the last `maxItems - 1`, and hides
|
|
61
|
+
the middle ones behind an ellipsis button that shows them in place, or behind the consumer's own
|
|
62
|
+
`bfSlot="overflow"` content (a menu button of the hidden levels).
|
|
63
|
+
|
|
64
|
+
A breadcrumb trail for desktop web apps: a `nav` named "Breadcrumb" around an ordered list of the pages above the current one, each a link, with the current page last. Every level is the app's own `<li bfBreadcrumbItem>`, so the list stays `ol > li` and the links stay the app's `routerLink`s; the widget draws the chevrons between them, marks the current page and, with `maxItems`, collapses a long trail behind an ellipsis.
|
|
65
|
+
|
|
66
|
+
## When to use
|
|
67
|
+
|
|
68
|
+
Use `bf-breadcrumb` on a desktop page that sits deep in a hierarchy (a client's billing settings, a file in a folder), so the user sees where they are and can go up any number of levels. Don't use it for a flat app with one level, where the sidebar or the top nav already says where the user is. On mobile, in the Capacitor shell, use [bf-back-button](https://bitforge-ui.web.app/components/back-button) in [bf-header](https://bitforge-ui.web.app/components/header) instead.
|
|
69
|
+
|
|
70
|
+
## Basic usage
|
|
71
|
+
|
|
72
|
+
Put one `li[bfBreadcrumbItem]` per level inside `bf-breadcrumb`, from the root down: an `<a routerLink>` for each page above, plain text for the current page. The last item is always the current page; it gets `aria-current="page"` and no chevron. Import `BfBreadcrumbComponent` and `BfBreadcrumbItemComponent` from `@bitforgehq/ui`. The `nav` is named "Breadcrumb"; when a page shows more than one breadcrumb (as this page does, beside the site's own), give each a distinct `label`.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
import { Component } from '@angular/core';
|
|
76
|
+
import { RouterLink } from '@angular/router';
|
|
77
|
+
import { BfBreadcrumbComponent, BfBreadcrumbItemComponent } from '@bitforgehq/ui';
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* A breadcrumb trail.
|
|
81
|
+
*
|
|
82
|
+
* Each level is the app's own `<li bfBreadcrumbItem>` holding a router link; the last one is the
|
|
83
|
+
* current page as plain text. `label` names the `nav`; this one is not the page's only breadcrumb
|
|
84
|
+
* (the docs site has its own), so it gets a name of its own.
|
|
85
|
+
*/
|
|
86
|
+
@Component({
|
|
87
|
+
selector: 'app-example-breadcrumb-basic',
|
|
88
|
+
imports: [RouterLink, BfBreadcrumbComponent, BfBreadcrumbItemComponent],
|
|
89
|
+
template: `
|
|
90
|
+
<bf-breadcrumb label="Docs breadcrumb">
|
|
91
|
+
<li bfBreadcrumbItem><a routerLink="/">Docs</a></li>
|
|
92
|
+
<li bfBreadcrumbItem><a routerLink="/components">Components</a></li>
|
|
93
|
+
<li bfBreadcrumbItem>Breadcrumb</li>
|
|
94
|
+
</bf-breadcrumb>
|
|
95
|
+
`,
|
|
96
|
+
})
|
|
97
|
+
export class BreadcrumbBasicExampleComponent {}
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Collapsing a long trail
|
|
101
|
+
|
|
102
|
+
Set `maxItems` to collapse a trail with more levels than that: the first level and the last `maxItems - 1` stay, and the middle ones are hidden behind an ellipsis button ("Show 2 more levels", `provideBfLabels()`'s `breadcrumbExpand`). Pressing it shows every level in place and moves focus to the first one it revealed, so a keyboard user carries on from there. The trail collapses again when its levels change (on the next page). `0`, the default, never collapses; a value below 2 acts as 2, so the first level and the current page always stay.
|
|
103
|
+
|
|
104
|
+
```ts
|
|
105
|
+
import { Component } from '@angular/core';
|
|
106
|
+
import { RouterLink } from '@angular/router';
|
|
107
|
+
import { BfBreadcrumbComponent, BfBreadcrumbItemComponent } from '@bitforgehq/ui';
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* A long trail collapsed in place.
|
|
111
|
+
*
|
|
112
|
+
* `maxItems="4"` keeps the first level and the last three; the ellipsis button shows the two
|
|
113
|
+
* hidden ones in place and moves focus to the first of them. The demo's links stay on this page.
|
|
114
|
+
*/
|
|
115
|
+
@Component({
|
|
116
|
+
selector: 'app-example-breadcrumb-collapsed',
|
|
117
|
+
imports: [RouterLink, BfBreadcrumbComponent, BfBreadcrumbItemComponent],
|
|
118
|
+
template: `
|
|
119
|
+
<bf-breadcrumb label="Invoice breadcrumb" maxItems="4">
|
|
120
|
+
@for (level of trail; track level.id) {
|
|
121
|
+
<li bfBreadcrumbItem>
|
|
122
|
+
<a routerLink="." [fragment]="level.id">{{ level.label }}</a>
|
|
123
|
+
</li>
|
|
124
|
+
}
|
|
125
|
+
<li bfBreadcrumbItem>Invoice INV-204</li>
|
|
126
|
+
</bf-breadcrumb>
|
|
127
|
+
`,
|
|
128
|
+
})
|
|
129
|
+
export class BreadcrumbCollapsedExampleComponent {
|
|
130
|
+
readonly trail: readonly { id: string; label: string }[] = [
|
|
131
|
+
{ id: 'home', label: 'Home' },
|
|
132
|
+
{ id: 'clients', label: 'Clients' },
|
|
133
|
+
{ id: 'meadow', label: 'Meadow Studio' },
|
|
134
|
+
{ id: 'billing', label: 'Billing' },
|
|
135
|
+
{ id: 'invoices', label: 'Invoices' },
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## A menu of the hidden levels
|
|
141
|
+
|
|
142
|
+
To keep the trail on one line, project your own control in `bfSlot="overflow"`: it takes the ellipsis button's place, after the first level. A `bf-menu-button` from `@bitforgehq/ui/overlay` with an `a[bfMenuItem]` link per hidden level is the usual one (a root widget cannot open a menu itself). The hidden levels are a slice of the array you already render: `trail.slice(1, count - maxItems + 1)`, where `count` includes the current page. Name the menu button with its `label`.
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import { Component, computed } from '@angular/core';
|
|
146
|
+
import { RouterLink } from '@angular/router';
|
|
147
|
+
import { BfBreadcrumbComponent, BfBreadcrumbItemComponent } from '@bitforgehq/ui';
|
|
148
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
149
|
+
import {
|
|
150
|
+
BfMenuButtonComponent,
|
|
151
|
+
BfMenuComponent,
|
|
152
|
+
BfMenuItemDirective,
|
|
153
|
+
} from '@bitforgehq/ui/overlay';
|
|
154
|
+
import { Ellipsis } from 'lucide';
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* A long trail collapsed behind a menu.
|
|
158
|
+
*
|
|
159
|
+
* A `bf-menu-button` in `bfSlot="overflow"` replaces the ellipsis button: its menu links to the
|
|
160
|
+
* levels the trail hides, the same slice of the app's own array (`maxItems` 3 keeps the first
|
|
161
|
+
* level and the last two). The demo's links stay on this page.
|
|
162
|
+
*/
|
|
163
|
+
@Component({
|
|
164
|
+
selector: 'app-example-breadcrumb-collapsed-menu',
|
|
165
|
+
imports: [
|
|
166
|
+
RouterLink,
|
|
167
|
+
BfBreadcrumbComponent,
|
|
168
|
+
BfBreadcrumbItemComponent,
|
|
169
|
+
BfIconComponent,
|
|
170
|
+
BfMenuButtonComponent,
|
|
171
|
+
BfMenuComponent,
|
|
172
|
+
BfMenuItemDirective,
|
|
173
|
+
],
|
|
174
|
+
template: `
|
|
175
|
+
<bf-breadcrumb label="Client breadcrumb" [maxItems]="maxItems">
|
|
176
|
+
<bf-menu-button
|
|
177
|
+
bfSlot="overflow"
|
|
178
|
+
[menu]="hiddenLevels"
|
|
179
|
+
iconOnly
|
|
180
|
+
label="Hidden levels"
|
|
181
|
+
variant="text"
|
|
182
|
+
size="sm"
|
|
183
|
+
>
|
|
184
|
+
<bf-icon [icon]="ellipsis" />
|
|
185
|
+
</bf-menu-button>
|
|
186
|
+
@for (level of trail; track level.id) {
|
|
187
|
+
<li bfBreadcrumbItem>
|
|
188
|
+
<a routerLink="." [fragment]="level.id">{{ level.label }}</a>
|
|
189
|
+
</li>
|
|
190
|
+
}
|
|
191
|
+
<li bfBreadcrumbItem>Invoice INV-204</li>
|
|
192
|
+
</bf-breadcrumb>
|
|
193
|
+
|
|
194
|
+
<ng-template #hiddenLevels>
|
|
195
|
+
<bf-menu>
|
|
196
|
+
@for (level of hidden(); track level.id) {
|
|
197
|
+
<a bfMenuItem routerLink="." [fragment]="level.id">{{ level.label }}</a>
|
|
198
|
+
}
|
|
199
|
+
</bf-menu>
|
|
200
|
+
</ng-template>
|
|
201
|
+
`,
|
|
202
|
+
})
|
|
203
|
+
export class BreadcrumbCollapsedMenuExampleComponent {
|
|
204
|
+
readonly ellipsis = Ellipsis;
|
|
205
|
+
readonly maxItems = 3;
|
|
206
|
+
readonly trail: readonly { id: string; label: string }[] = [
|
|
207
|
+
{ id: 'home', label: 'Home' },
|
|
208
|
+
{ id: 'clients', label: 'Clients' },
|
|
209
|
+
{ id: 'meadow', label: 'Meadow Studio' },
|
|
210
|
+
{ id: 'billing', label: 'Billing' },
|
|
211
|
+
{ id: 'invoices', label: 'Invoices' },
|
|
212
|
+
];
|
|
213
|
+
/** The levels between the first and the last `maxItems - 1` (the current page counts as one). */
|
|
214
|
+
readonly hidden = computed(() =>
|
|
215
|
+
this.trail.slice(1, this.trail.length + 1 - (this.maxItems - 1)),
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Desktop
|
|
221
|
+
|
|
222
|
+
`bf-breadcrumb` is a desktop pattern. A link turns from `text-muted` to `text` and is underlined on hover, with the pointer cursor; the ellipsis button takes a `surface-muted` fill on hover. The focus ring shows on keyboard focus only. Links keep the browser's behaviour: Ctrl/Cmd-click and a middle click open a level in a new tab. Under a coarse pointer (a touch laptop) every link is at least 44 px tall (`pointer-coarse:min-h-hit`) and the ellipsis button's hit area extends to 44 px. The trail wraps onto more lines when it does not fit; collapse it with `maxItems` to keep it short.
|
|
223
|
+
|
|
224
|
+
## Theming
|
|
225
|
+
|
|
226
|
+
- Text: `text-label-sm`; ancestor levels `text-muted`, `text` on hover; the current page `text`, semibold.
|
|
227
|
+
- Separators: a 1.5 px CSS chevron in `text-subtle`, mirrored under `dir="rtl"`.
|
|
228
|
+
- Links and the ellipsis button: `rounded-tile` and the `ring` focus ring; the ellipsis button's hover fill is `surface-muted`, its pressed fill `surface-pressed`.
|
|
229
|
+
|
|
230
|
+
## Accessibility
|
|
231
|
+
|
|
232
|
+
The host renders a `nav` landmark named by `label` (default "Breadcrumb", `provideBfLabels()`'s `breadcrumb`) around an `ol`, so a screen reader announces the number of levels; give a second breadcrumb on the same page another `label`. The current page is wrapped in a span with `aria-current="page"`. The chevrons are empty, `aria-hidden` elements, so the trail reads as its level names only. Hidden levels carry `hidden`, so they leave the accessibility tree until the ellipsis shows them; the ellipsis is a native `<button>` named "Show N more levels", and pressing it moves focus to the first revealed level's link (a level without a link takes focus itself). Content in `bfSlot="overflow"` brings its own name and keyboard handling.
|
|
233
|
+
|
|
234
|
+
### Keyboard
|
|
235
|
+
|
|
236
|
+
| Key | Action |
|
|
237
|
+
| ----------------------------------- | ----------------------------------------------------------------------------- |
|
|
238
|
+
| <kbd>Tab</kbd> | Moves through the links of the visible levels and the ellipsis button |
|
|
239
|
+
| <kbd>Enter</kbd> | Follows the focused link |
|
|
240
|
+
| <kbd>Enter</kbd> / <kbd>Space</kbd> | On the ellipsis button: shows the hidden levels and focuses the first of them |
|
|
241
|
+
|
|
242
|
+
## Inputs
|
|
243
|
+
|
|
244
|
+
| Name | Type | Default | Description |
|
|
245
|
+
| ---------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
246
|
+
| `label` | `string` | `''` | Accessible name of the navigation; empty falls back to `provideBfLabels()`'s `breadcrumb` ("Breadcrumb"). |
|
|
247
|
+
| `maxItems` | `number` | `0` | Collapse a trail longer than this: keep the first level and the last `maxItems - 1` and hide the middle ones behind an ellipsis. `0` never collapses; values below 2 act as 2, so the current page always stays. |
|
|
248
|
+
|
|
249
|
+
## Slots
|
|
250
|
+
|
|
251
|
+
- `overflow`: Replaces the ellipsis button of a collapsed trail, e.g. a menu of the hidden levels.
|
|
252
|
+
- `default`: The levels, each a `li[bfBreadcrumbItem]`, the current page last.
|
|
253
|
+
|
|
254
|
+
## Notes
|
|
255
|
+
|
|
256
|
+
### Do
|
|
257
|
+
|
|
258
|
+
- Keep the labels short, the page titles users know, and the current page last as plain text.
|
|
259
|
+
- Collapse a trail deeper than four or five levels with `maxItems`.
|
|
260
|
+
|
|
261
|
+
### Don't
|
|
262
|
+
|
|
263
|
+
- Don't link the current page, and don't put anything but `li[bfBreadcrumbItem]` levels (and the `overflow` slot) inside `bf-breadcrumb`.
|
|
264
|
+
- Don't use a breadcrumb as the app's main navigation, and don't show it in the Capacitor shell.
|
|
265
|
+
|
|
266
|
+
## Migration notes
|
|
267
|
+
|
|
268
|
+
### 0.3.1
|
|
269
|
+
|
|
270
|
+
New `bf-breadcrumb` in `@bitforgehq/ui`, the desktop breadcrumb trail: a `nav` (named by
|
|
271
|
+
`label`, default `provideBfLabels()`'s new `breadcrumb` key, "Breadcrumb") around an `ol` of
|
|
272
|
+
`li[bfBreadcrumbItem]` levels, with CSS chevrons between them that are never announced.
|
|
273
|
+
`maxItems` collapses a longer trail to the first level and the last `maxItems - 1`, behind an
|
|
274
|
+
ellipsis button (the new `breadcrumbExpand` label, "Show 2 more levels") that shows the hidden
|
|
275
|
+
levels in place and focuses the first one; `bfSlot="overflow"` replaces that button with the app's
|
|
276
|
+
own control, such as a `bf-menu-button` of the hidden levels. It replaces the hand-built
|
|
277
|
+
breadcrumb the back-button docs showed.
|
package/ai/components/button.md
CHANGED
|
@@ -95,12 +95,12 @@ export class ButtonOverviewExampleComponent {
|
|
|
95
95
|
|
|
96
96
|
Also matches: `a[bfButton]`
|
|
97
97
|
|
|
98
|
-
Pill-shaped action button with
|
|
98
|
+
Pill-shaped action button with six variants, three sizes, a loading state and icon slots. Put
|
|
99
99
|
the label in the default slot and icons in the `icon-start` / `icon-end` slots; never place a
|
|
100
100
|
`bf-button` inside another interactive element. For navigation, put `bfButton` on your own `<a>`
|
|
101
101
|
(with `href` or `routerLink`): it renders as a real link that looks like the button.
|
|
102
102
|
|
|
103
|
-
Buttons trigger an action or move the user forward. The shape is a pill in every variant; the variant encodes emphasis, so a screen reads correctly at a glance: one `primary`, `tonal` beside it, `text` for low-emphasis actions inside cards and rows.
|
|
103
|
+
Buttons trigger an action or move the user forward. The shape is a pill in every variant; the variant encodes emphasis, so a screen reads correctly at a glance: one `primary`, `tonal` beside it, `text` for low-emphasis actions inside cards and rows, `ghost` for quiet neutral actions and navigation.
|
|
104
104
|
|
|
105
105
|
## When to use
|
|
106
106
|
|
|
@@ -140,13 +140,13 @@ export class ButtonBasicExampleComponent {
|
|
|
140
140
|
|
|
141
141
|
## Variants
|
|
142
142
|
|
|
143
|
-
`primary` (filled
|
|
143
|
+
`primary` (filled), `tonal` (soft tint), `outline`, `text`, `danger` and `ghost`. `ghost` is the quiet neutral one: muted text with no fill at rest and a neutral surface on hover, with the `text` variant's padding. Use it for secondary toolbar actions and navigation rows, where a row of `text` buttons would read as a row of coloured links and `tonal` would tint every one. `variant` takes a `BfButtonAppearance` (the five `BfButtonVariant` styles plus `ghost`).
|
|
144
144
|
|
|
145
145
|
```ts
|
|
146
146
|
import { Component } from '@angular/core';
|
|
147
147
|
import { BfButtonComponent } from '@bitforgehq/ui';
|
|
148
148
|
|
|
149
|
-
/** The
|
|
149
|
+
/** The six button variants. */
|
|
150
150
|
@Component({
|
|
151
151
|
selector: 'app-example-button-variants',
|
|
152
152
|
imports: [BfButtonComponent],
|
|
@@ -157,6 +157,7 @@ import { BfButtonComponent } from '@bitforgehq/ui';
|
|
|
157
157
|
<bf-button variant="outline">Outline</bf-button>
|
|
158
158
|
<bf-button variant="text">Text</bf-button>
|
|
159
159
|
<bf-button variant="danger">Delete</bf-button>
|
|
160
|
+
<bf-button variant="ghost">Ghost</bf-button>
|
|
160
161
|
</div>
|
|
161
162
|
`,
|
|
162
163
|
})
|
|
@@ -300,9 +301,57 @@ export class ButtonLinkExampleComponent {
|
|
|
300
301
|
}
|
|
301
302
|
```
|
|
302
303
|
|
|
304
|
+
## Navigation
|
|
305
|
+
|
|
306
|
+
A row of `a[bfButton variant="ghost"]` is a top navigation or a sidebar. The link of the current page shows it: `ghost` and `text` links with `aria-current="page"` take the tonal fill (`outline` draws its border in primary), so the template needs no `[variant]` switch. With the router, add `routerLinkActive` and `ariaCurrentWhenActive="page"` to each link and the router sets `aria-current` for you. Put the links in a `<nav>` with an `aria-label`.
|
|
307
|
+
|
|
308
|
+
```ts
|
|
309
|
+
import { Component, signal } from '@angular/core';
|
|
310
|
+
import { BfButtonComponent } from '@bitforgehq/ui';
|
|
311
|
+
|
|
312
|
+
interface NavLink {
|
|
313
|
+
readonly id: string;
|
|
314
|
+
readonly label: string;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* A top navigation of ghost links.
|
|
319
|
+
*
|
|
320
|
+
* The current page carries `aria-current="page"` and shows it; with the router,
|
|
321
|
+
* `routerLinkActive` and `ariaCurrentWhenActive="page"` set it instead of the click handler.
|
|
322
|
+
*/
|
|
323
|
+
@Component({
|
|
324
|
+
selector: 'app-example-button-nav',
|
|
325
|
+
imports: [BfButtonComponent],
|
|
326
|
+
template: `
|
|
327
|
+
<nav aria-label="Main" class="flex flex-wrap items-center gap-1">
|
|
328
|
+
@for (link of links; track link.id) {
|
|
329
|
+
<a
|
|
330
|
+
bfButton
|
|
331
|
+
variant="ghost"
|
|
332
|
+
[href]="'#' + link.id"
|
|
333
|
+
[attr.aria-current]="link.id === current() ? 'page' : null"
|
|
334
|
+
(click)="$event.preventDefault(); current.set(link.id)"
|
|
335
|
+
>{{ link.label }}</a
|
|
336
|
+
>
|
|
337
|
+
}
|
|
338
|
+
</nav>
|
|
339
|
+
`,
|
|
340
|
+
})
|
|
341
|
+
export class ButtonNavExampleComponent {
|
|
342
|
+
protected readonly links: readonly NavLink[] = [
|
|
343
|
+
{ id: 'overview', label: 'Overview' },
|
|
344
|
+
{ id: 'projects', label: 'Projects' },
|
|
345
|
+
{ id: 'team', label: 'Team' },
|
|
346
|
+
{ id: 'settings', label: 'Settings' },
|
|
347
|
+
];
|
|
348
|
+
protected readonly current = signal('overview');
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
303
352
|
## Desktop
|
|
304
353
|
|
|
305
|
-
Hover darkens the fill (`primary`, `tonal`, `danger`), the border (`outline`) or the text (`text`), with the pointer cursor; a disabled button 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 (`focus-visible`), never after a mouse click. Under a fine pointer the visible box is the hit area, so `sm` (32 px) buttons sit side by side in toolbars and table rows without overlapping hit areas. 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)).
|
|
354
|
+
Hover darkens the fill (`primary`, `tonal`, `danger`), the border (`outline`) or the text (`text`), or lays a neutral surface under `ghost`, with the pointer cursor; a disabled button 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 (`focus-visible`), never after a mouse click. Under a fine pointer the visible box is the hit area, so `sm` (32 px) buttons sit side by side in toolbars and table rows without overlapping hit areas. 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)).
|
|
306
355
|
|
|
307
356
|
## Theming
|
|
308
357
|
|
|
@@ -313,10 +362,16 @@ Consumes tokens by variant, rest → hover:
|
|
|
313
362
|
- `outline`: `surface` / `text` / `border-strong` (the control boundary, ≥ 3:1) → `text-muted` border; focus swaps the border to `primary`
|
|
314
363
|
- `text`: `primary-text` (primary as text, ≥ 4.5:1 on `bg` and `surface`) → `primary-strong`
|
|
315
364
|
- `danger`: `danger-soft` / `danger` → `danger` / `danger-soft`
|
|
365
|
+
- `ghost`: transparent / `text-muted` → `surface-muted` / `text`
|
|
366
|
+
|
|
367
|
+
Current page (`a[bfButton]` with `aria-current="page"`): `ghost` and `text` take `primary-soft` /
|
|
368
|
+
`primary-strong` (→ `primary-soft-hover` on hover, `primary-soft-pressed` while pressed), `outline` a `primary` border with
|
|
369
|
+
`primary-strong` text; under forced colours a `LinkText` outline marks it instead.
|
|
316
370
|
|
|
317
371
|
Pressed (while the mouse button, a touch or the Space key holds it down): `primary` →
|
|
318
372
|
`primary-pressed`; `tonal`, `outline` and `text` → `primary-soft-pressed` (the `text` label turns
|
|
319
|
-
`primary-strong`); `danger` → `danger-pressed` with `danger-soft` text
|
|
373
|
+
`primary-strong`); `danger` → `danger-pressed` with `danger-soft` text; `ghost` →
|
|
374
|
+
`surface-pressed` with `text`. `a[bfButton]` presses the
|
|
320
375
|
same way. A disabled or loading button has no pressed state, and under forced colours the system
|
|
321
376
|
colours win.
|
|
322
377
|
|
|
@@ -328,7 +383,7 @@ Icon and label sit 8 px apart. A label longer than its container truncates with
|
|
|
328
383
|
|
|
329
384
|
`bf-button` renders a native `<button>`; its `type` reflects the `type` input. Native `disabled` is set only by `disabled`. While `loading`, the button stays focusable and in the tab order with `aria-disabled="true"` and `aria-busy="true"`, so focus does not fall to `<body>` when an action starts; a click or Enter/Space is cancelled (`preventDefault`) and emits nothing. The spinner inside is `decorative`, so it adds no second status announcement; announce the outcome in your own message. Being a real button, it gets keyboard activation (Enter/Space) and the button role for free — no ARIA role is added. The focus-visible ring uses the `ring` token.
|
|
330
385
|
|
|
331
|
-
`a[bfButton]` 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/)): it is exposed as `link`, 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), activates with Enter only, and opens in a new tab with Ctrl/Cmd-click. Use it whenever activation navigates to a URL, and `bf-button` whenever it performs an action on the page ([APG button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/)). No ARIA is added, and none of `disabled`, `loading` or `type` applies.
|
|
386
|
+
`a[bfButton]` 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/)): it is exposed as `link`, 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), activates with Enter only, and opens in a new tab with Ctrl/Cmd-click. Use it whenever activation navigates to a URL, and `bf-button` whenever it performs an action on the page ([APG button pattern](https://www.w3.org/WAI/ARIA/apg/patterns/button/)). No ARIA is added, and none of `disabled`, `loading` or `type` applies. The current page is the `aria-current="page"` you (or `routerLinkActive` with `ariaCurrentWhenActive`) set: screen readers announce it ("current page"), and the fill only mirrors it.
|
|
332
387
|
|
|
333
388
|
### Keyboard
|
|
334
389
|
|
|
@@ -340,14 +395,14 @@ Icon and label sit 8 px apart. A label longer than its container truncates with
|
|
|
340
395
|
|
|
341
396
|
## Inputs
|
|
342
397
|
|
|
343
|
-
| Name | Type
|
|
344
|
-
| ----------- |
|
|
345
|
-
| `variant` | `
|
|
346
|
-
| `size` | `BfSize \| undefined` (`'sm' \| 'md' \| 'lg' \| undefined`)
|
|
347
|
-
| `type` | `BfButtonType` (`'button' \| 'submit' \| 'reset'`)
|
|
348
|
-
| `disabled` | `boolean`
|
|
349
|
-
| `loading` | `boolean`
|
|
350
|
-
| `fullWidth` | `boolean`
|
|
398
|
+
| Name | Type | Default | Description |
|
|
399
|
+
| ----------- | ------------------------------------------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
400
|
+
| `variant` | `BfButtonAppearance` (`'primary' \| 'tonal' \| 'outline' \| 'text' \| 'danger' \| 'ghost'`) | `'primary'` | Visual style: primary (filled), tonal (soft tint), outline, text, danger, or ghost (quiet neutral). On `a[bfButton]`, `ghost`, `text` and `outline` also show `aria-current="page"`. |
|
|
401
|
+
| `size` | `BfSize \| undefined` (`'sm' \| 'md' \| 'lg' \| undefined`) | `undefined` | Height step: sm 32, md 40, lg 48 px; unset follows `provideBfDefaults()` (`controlSize`, `md` by default). |
|
|
402
|
+
| `type` | `BfButtonType` (`'button' \| 'submit' \| 'reset'`) | `'button'` | Native button type. Use `submit` inside a form. Ignored on `a[bfButton]`. |
|
|
403
|
+
| `disabled` | `boolean` | `false` | Disables the control and swallows clicks. Ignored on `a[bfButton]`: a link is never disabled; render a disabled `bf-button` instead. |
|
|
404
|
+
| `loading` | `boolean` | `false` | Shows a spinner instead of the start icon and blocks activation. The button stays focusable (`aria-disabled` and `aria-busy`, never native `disabled`) and keeps its variant fill. Ignored on `a[bfButton]`. |
|
|
405
|
+
| `fullWidth` | `boolean` | `false` | Stretches the button to its container's width. |
|
|
351
406
|
|
|
352
407
|
## Outputs
|
|
353
408
|
|
|
@@ -368,10 +423,12 @@ Icon and label sit 8 px apart. A label longer than its container truncates with
|
|
|
368
423
|
- Use `primary` once per screen for the main action; `tonal` for secondary actions next to it; `text` for low-emphasis actions inside cards and lists.
|
|
369
424
|
- Bind `[loading]` to the pending state of the action so the user gets feedback and cannot double-submit.
|
|
370
425
|
- Use `type="submit"` inside a `<form>` so Enter submits.
|
|
426
|
+
- Build a top nav or a sidebar from `a[bfButton variant="ghost"]` with `routerLinkActive` and `ariaCurrentWhenActive="page"`.
|
|
371
427
|
|
|
372
428
|
### Don't
|
|
373
429
|
|
|
374
430
|
- Don't nest `bf-button` in an `<a>` or another button, and don't navigate from `(clicked)`; put `bfButton` on the `<a>` itself (`<a bfButton routerLink="…">`).
|
|
431
|
+
- Don't switch `[variant]` to mark the current page; set `aria-current="page"` and the link shows it.
|
|
375
432
|
- Don't disable a link; render a disabled `bf-button` while the destination is unavailable.
|
|
376
433
|
- Don't add `dark:` classes or colors on the element; the theme handles both.
|
|
377
434
|
- Don't put a `bf-icon` in the default slot; use the `icon-start` / `icon-end` slots so spacing stays right.
|
|
@@ -379,6 +436,16 @@ Icon and label sit 8 px apart. A label longer than its container truncates with
|
|
|
379
436
|
|
|
380
437
|
## Migration notes
|
|
381
438
|
|
|
439
|
+
### 0.3.1
|
|
440
|
+
|
|
441
|
+
New `ghost` variant: quiet and neutral (`text-muted` label, no fill at rest, `surface-muted` on
|
|
442
|
+
hover, `surface-pressed` on press), with the `text` variant's sizes, padding and disabled state,
|
|
443
|
+
for secondary toolbar actions and navigation rows. `a[bfButton]` with `aria-current="page"` shows
|
|
444
|
+
the current page: `ghost` and `text` links take the tonal fill, `outline` a primary border, so a
|
|
445
|
+
top nav built with `routerLinkActive` and `ariaCurrentWhenActive="page"` needs no `[variant]`
|
|
446
|
+
switch. `variant` is now typed `BfButtonAppearance` (the five `BfButtonVariant` styles plus
|
|
447
|
+
`ghost`); `BfButtonVariant` keeps its five members, so code that maps over it keeps compiling.
|
|
448
|
+
|
|
382
449
|
### 0.3.0
|
|
383
450
|
|
|
384
451
|
**Behaviour:** `size` is a `BfSize` and, unset, follows `provideBfDefaults()`'s `controlSize`
|