@bitforgehq/ui 0.3.3 → 0.4.0
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 +91 -0
- package/README.md +4 -4
- package/ai/MANIFEST.index.json +36 -0
- package/ai/MANIFEST.json +414 -14
- package/ai/REFERENCE.index.json +35 -0
- package/ai/REFERENCE.json +184 -8
- package/ai/UI_GUIDE.md +25 -4
- package/ai/components/badge.md +39 -2
- package/ai/components/list-item.md +105 -9
- package/ai/components/step.md +112 -0
- package/ai/components/steps.md +124 -0
- package/ai/components/table.md +98 -2
- package/ai/components/timeline-event.md +144 -0
- package/ai/components/timeline.md +201 -0
- package/ai/components/toggle.md +11 -1
- package/ai/reference/bf-action-directive.md +3 -1
- package/ai/reference/bf-badge-emphasis.md +27 -0
- package/ai/reference/bf-labels.md +1 -0
- package/ai/reference/bf-step-heading-level.md +28 -0
- package/ai/reference/bf-table-align.md +1 -1
- package/ai/reference/bf-table-column-align.md +33 -0
- package/ai/reference/bf-table-column.md +7 -7
- package/ai/reference/bf-table-harness.md +12 -0
- package/ai/reference/bf-timeline-tone.md +31 -0
- package/ai/reference/bf-toggle-harness.md +55 -0
- package/ai/reference/provide-bf-labels.md +1 -1
- package/dark-ink.css +124 -0
- package/fesm2022/bitforgehq-ui-mobile.mjs +2 -1
- package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui-testing.mjs +51 -2
- package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui.mjs +682 -32
- package/fesm2022/bitforgehq-ui.mjs.map +1 -1
- package/llms-full.txt +1072 -15
- package/llms.txt +9 -0
- package/package.json +2 -1
- package/theme.css +24 -0
- package/types/bitforgehq-ui-testing.d.ts +76 -1
- package/types/bitforgehq-ui.d.ts +288 -8
package/llms-full.txt
CHANGED
|
@@ -72,7 +72,7 @@ In `src/index.html`, give `<body>` the theme background and text colour, so the
|
|
|
72
72
|
|
|
73
73
|
### 7. Switch to dark mode
|
|
74
74
|
|
|
75
|
-
Add the `dark` class to `<html>` (and remove it for light mode). Every token is redefined under `.dark`, and the theme sets `color-scheme`, so scrollbars and native controls follow too. Components need no `dark:` classes. To let users choose System, Light or Dark, add `provideBfColorScheme()` to the app providers: it sets the class, follows the OS and remembers the choice.
|
|
75
|
+
Add the `dark` class to `<html>` (and remove it for light mode). Every token is redefined under `.dark`, and the theme sets `color-scheme`, so scrollbars and native controls follow too. Components need no `dark:` classes. To let users choose System, Light or Dark, add `provideBfColorScheme()` to the app providers: it sets the class, follows the OS and remembers the choice. For a near-black dark mode, add `@import '@bitforgehq/ui/dark-ink.css';` right after the theme import: the Ink preset, which changes dark mode only.
|
|
76
76
|
|
|
77
77
|
```html
|
|
78
78
|
<html lang="en" class="dark">
|
|
@@ -123,6 +123,10 @@ pressed, soft and strong steps, `on-primary`, `primary-text`, `selected`, `ring`
|
|
|
123
123
|
and a `.dark` block with each contrast pair's ratio, and exits 1 naming the pairs below their
|
|
124
124
|
minimum and a shade that passes; paste its output, never hand-pick the steps. Example (the
|
|
125
125
|
Meadow Sage green): `bunx bf-ui theme '#238652' --dark '#5cc48a'`.
|
|
126
|
+
For a near-black dark mode, import the opt-in Ink preset right after the theme,
|
|
127
|
+
`@import '@bitforgehq/ui/dark-ink.css';`: it redefines every dark token but the brand set under
|
|
128
|
+
`.dark` (light mode and the default dark stay as they are), so a brand `.dark` block goes after
|
|
129
|
+
it. Never copy its values into `.dark` by hand, and never put `dark:` classes on widgets for it.
|
|
126
130
|
`--radius-control` (`9999px`, pills) reshapes buttons, chips, badges, segmented, the tab bar, the
|
|
127
131
|
action bar and toggles at once:
|
|
128
132
|
|
|
@@ -143,10 +147,10 @@ Render library components only in the browser, for example in a `@defer` block o
|
|
|
143
147
|
route. Support will be decided before 1.0.
|
|
144
148
|
|
|
145
149
|
The one server-side check is a render smoke, not a support test: the library repository's
|
|
146
|
-
`tools/ssr-smoke.ts` renders
|
|
150
|
+
`tools/ssr-smoke.ts` renders 45 fixtures with `renderApplication()` (every root widget, `bf-icon`,
|
|
147
151
|
`bf-number-input`, a `/charts` line chart, a `/mobile` page with `provideBfShell()`, `bf-page`,
|
|
148
152
|
`bf-header` and `bf-content`, `bf-tabs` with `bf-stack-outlet` under the router, and an `/overlay`
|
|
149
|
-
dialog), and all of them render without an error.
|
|
153
|
+
dialog), and all of them render without an error. 29 of them render identically twice. The other 16
|
|
150
154
|
number their ids differently on every render, from a module-level counter, so they could not
|
|
151
155
|
hydrate: `bf-app-frame`, `bf-calendar`, `bf-checkbox`, `bf-input`, `bf-radio-group`, `bf-segmented`,
|
|
152
156
|
`bf-select`, `bf-sidebar`, `bf-tab-group`, `bf-table`, `bf-textarea`, `bf-theme-switch`,
|
|
@@ -374,8 +378,14 @@ protected readonly colorScheme = inject(BfColorSchemeService);
|
|
|
374
378
|
sorts the rows in a `computed()`, and a selection shows a `bf-action-bar`. `stack="narrow"`
|
|
375
379
|
(below 36rem of its own width) or `stack="coarse"` turns each row into a label/value tile with
|
|
376
380
|
a sort and select bar; in the Capacitor shell use `bf-list-item` rows instead.
|
|
381
|
+
A settings matrix puts a `bf-toggle` in each cell (`align: 'center'` columns, the row label
|
|
382
|
+
first, every toggle named `[ariaLabel]="column + ', ' + row"`).
|
|
377
383
|
- **Details:** `bf-description-list` of `div[bfDescriptionItem]` label/value pairs, and `bf-stat`
|
|
378
384
|
figure tiles in a grid; both work in both shells.
|
|
385
|
+
- **History:** `<bf-timeline label="…">` of `<bf-timeline-event actor="…" [time]="iso" tone="…">`
|
|
386
|
+
(text with inline links in the content, a small action in `bfSlot="end"`) for a record's
|
|
387
|
+
history or an audit trail, in the order the app gives; times follow `LOCALE_ID` (`timeFormat`,
|
|
388
|
+
`timeText` for a relative time). Not for navigation or steps.
|
|
379
389
|
- **Cards in a grid:** the grid stretches each `bf-card` and its `bfSlot="footer"` sits on the
|
|
380
390
|
bottom edge, so footers line up; put a footer's parts in one element.
|
|
381
391
|
- **Rows on a card:** `<bf-list [inset]="false" divided class="-mx-card">`, flush to the card's
|
|
@@ -408,6 +418,13 @@ protected readonly colorScheme = inject(BfColorSchemeService);
|
|
|
408
418
|
- **Empty pages:** a 404, "no access" or "nothing here yet" page is a `bf-empty-state` with
|
|
409
419
|
`headingLevel` 1, centred in the content area, with the main action and an optional link.
|
|
410
420
|
- **Toolbar on a phone:** `bf-toolbar` keeps its status and actions together on the last row.
|
|
421
|
+
- **Severity:** soft `bf-badge` tones for most states; `emphasis="strong"` (a solid fill, also on
|
|
422
|
+
a count pill) only for the one that must stand out, such as `variant="danger"` "Critical".
|
|
423
|
+
- **Inbox and notifications:** `bf-list-item [unread]="!item.read"` (dot, bolder title, "Unread"
|
|
424
|
+
read before the title, also in its `bfAction`'s name); clear it when the row is opened.
|
|
425
|
+
- **Instructions in order:** `<bf-steps>` of `<bf-step title="Install the app">…details…</bf-step>`
|
|
426
|
+
(`start` to continue a list) for setup steps in both shells; not a wizard (a multi-page flow
|
|
427
|
+
with state is a set of pages).
|
|
411
428
|
|
|
412
429
|
## Overlays (`@bitforgehq/ui/overlay`)
|
|
413
430
|
|
|
@@ -976,7 +993,7 @@ describe('bf-button in a consumer app (Vitest)', () => {
|
|
|
976
993
|
|
|
977
994
|
### 6. Drive a form widget through its harness
|
|
978
995
|
|
|
979
|
-
The entry ships CDK harnesses for the widgets whose markup is not obvious to drive: `BfSelectHarness`, `BfRadioGroupHarness`, `BfSegmentedHarness`, `BfDialogHarness`, `BfMenuHarness`, `BfMenuItemHarness`, `BfMenuButtonHarness`, `BfDesktopToastHarness`, `BfTableHarness`, `BfPaginationHarness` `BfTabGroupHarness`, `BfCalendarHarness` and `BfChartHarness`. `with({ label })` finds a widget by its label. Load an in-page widget with `TestbedHarnessEnvironment.loader(fixture)`.
|
|
996
|
+
The entry ships CDK harnesses for the widgets whose markup is not obvious to drive: `BfSelectHarness`, `BfRadioGroupHarness`, `BfSegmentedHarness`, `BfDialogHarness`, `BfMenuHarness`, `BfMenuItemHarness`, `BfMenuButtonHarness`, `BfDesktopToastHarness`, `BfTableHarness`, `BfToggleHarness`, `BfPaginationHarness` `BfTabGroupHarness`, `BfCalendarHarness` and `BfChartHarness`. `with({ label })` finds a widget by its label. Load an in-page widget with `TestbedHarnessEnvironment.loader(fixture)`.
|
|
980
997
|
|
|
981
998
|
`select-harness.spec.ts`:
|
|
982
999
|
|
|
@@ -1239,7 +1256,11 @@ notes.
|
|
|
1239
1256
|
| `bf-progress` | `@bitforgehq/ui` | Progress bar in two sizes and four tones for completion, quotas and unknown waits |
|
|
1240
1257
|
| `bf-sparkline` | `@bitforgehq/ui/charts` | Tiny trend line with no axes or legend, for stats and table cells |
|
|
1241
1258
|
| `bf-stat` | `@bitforgehq/ui` | One labelled figure with an optional icon tile and a supporting line |
|
|
1259
|
+
| `bf-step` | `@bitforgehq/ui` | One numbered step of an instruction list, with a title and its details |
|
|
1260
|
+
| `bf-steps` | `@bitforgehq/ui` | Numbered instruction steps a user follows in order, with joined markers |
|
|
1242
1261
|
| `bf-table` | `@bitforgehq/ui` | Desktop data table with sortable headers, row selection, custom cells and an empty slot |
|
|
1262
|
+
| `bf-timeline` | `@bitforgehq/ui` | Dated list of events with who did what and when, on a vertical line |
|
|
1263
|
+
| `bf-timeline-event` | `@bitforgehq/ui` | One timeline event with a coloured marker, its text, actor and time |
|
|
1243
1264
|
|
|
1244
1265
|
### Feedback
|
|
1245
1266
|
|
|
@@ -3830,6 +3851,31 @@ import { BfBadgeComponent } from '@bitforgehq/ui';
|
|
|
3830
3851
|
export class BadgeStatusExampleComponent {}
|
|
3831
3852
|
```
|
|
3832
3853
|
|
|
3854
|
+
## Emphasis
|
|
3855
|
+
|
|
3856
|
+
`emphasis="strong"` turns the soft tint into a solid fill with contrasting text, for the one state that must stand out from the rest: a "Critical" finding among "High" and "Medium" ones. It takes every variant (`primary` uses the brand fill) and the count pill too: a strong count takes its fill from `variant`, so `variant="danger" emphasis="strong" [count]="3"` is a red pill, while a soft count stays the primary pill. `emphasis` takes a `BfBadgeEmphasis` (`soft`, the default, or `strong`).
|
|
3857
|
+
|
|
3858
|
+
```ts
|
|
3859
|
+
import { Component } from '@angular/core';
|
|
3860
|
+
import { BfBadgeComponent } from '@bitforgehq/ui';
|
|
3861
|
+
|
|
3862
|
+
/** A strong badge marks the one critical finding among soft status badges. */
|
|
3863
|
+
@Component({
|
|
3864
|
+
selector: 'app-example-badge-strong',
|
|
3865
|
+
imports: [BfBadgeComponent],
|
|
3866
|
+
template: `
|
|
3867
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
3868
|
+
<bf-badge variant="danger" emphasis="strong">Critical</bf-badge>
|
|
3869
|
+
<bf-badge variant="danger">High</bf-badge>
|
|
3870
|
+
<bf-badge variant="warning">Medium</bf-badge>
|
|
3871
|
+
<bf-badge>Low</bf-badge>
|
|
3872
|
+
<bf-badge variant="danger" emphasis="strong" [count]="3" countLabel="critical findings" />
|
|
3873
|
+
</div>
|
|
3874
|
+
`,
|
|
3875
|
+
})
|
|
3876
|
+
export class BadgeStrongExampleComponent {}
|
|
3877
|
+
```
|
|
3878
|
+
|
|
3833
3879
|
## Count pill
|
|
3834
3880
|
|
|
3835
3881
|
Setting `count` switches to the compact primary pill. Values above 99 render as "99+"; zero renders as "0".
|
|
@@ -3892,17 +3938,19 @@ Consumes tokens by variant, background then text:
|
|
|
3892
3938
|
- `danger`: `danger-soft` / `danger`
|
|
3893
3939
|
- `info`: `info-soft` / `info` (≥ 4.5:1 in both modes; it is not derived from the primary, so a custom brand colour leaves it unchanged)
|
|
3894
3940
|
- Count pill (`count` set): `primary` / `on-primary`, ignoring `variant`
|
|
3941
|
+
- Strong (`emphasis="strong"`, label and count pill): `<variant>-strong` / `on-<variant>-strong` (`neutral-strong`, `success-strong`, `warning-strong`, `danger-strong`, `info-strong`, each with its `on-` text token; ≥ 4.5:1 in both modes and the fill ≥ 3:1 on `bg`, `surface` and `surface-sunken`); `primary` uses `primary` / `on-primary`. An app can retune `--color-danger-strong` and `--color-on-danger-strong` (and the others) in `@theme` and `.dark` like any status token
|
|
3895
3942
|
- Shape (label and count pill): `rounded-control` (`--radius-control`, `9999px` by default).
|
|
3896
3943
|
|
|
3897
3944
|
## Accessibility
|
|
3898
3945
|
|
|
3899
|
-
A badge is a plain `<span>` with no role or ARIA attributes; its text is read as part of the surrounding content, so pair it with a label or context that says what it means rather than relying on color alone. A count pill with `countLabel` carries that context itself: a visually hidden (`sr-only`) span after the number, read as one phrase with it ("99+ unread messages").
|
|
3946
|
+
A badge is a plain `<span>` with no role or ARIA attributes; its text is read as part of the surrounding content, so pair it with a label or context that says what it means rather than relying on color alone. A count pill with `countLabel` carries that context itself: a visually hidden (`sr-only`) span after the number, read as one phrase with it ("99+ unread messages"). A strong badge is louder, not more meaningful: its text ("Critical", "Kritisch") still says the state. In forced colours (Windows High Contrast) the fills give way to the system colours, so a strong badge draws a `CanvasText` outline and still reads as a filled pill next to a soft one.
|
|
3900
3947
|
|
|
3901
3948
|
## Inputs
|
|
3902
3949
|
|
|
3903
3950
|
| Name | Type | Default | Description |
|
|
3904
3951
|
| --- | --- | --- | --- |
|
|
3905
|
-
| `variant` | `BfBadgeAppearance` (`'neutral' \| 'primary' \| 'success' \| 'warning' \| 'danger' \| 'info'`) | `'neutral'` | Tint for the label style: neutral, primary, success, warning, danger or info. Ignored
|
|
3952
|
+
| `variant` | `BfBadgeAppearance` (`'neutral' \| 'primary' \| 'success' \| 'warning' \| 'danger' \| 'info'`) | `'neutral'` | Tint for the label style: neutral, primary, success, warning, danger or info. Ignored by a soft count pill; a strong one takes its fill from it. |
|
|
3953
|
+
| `emphasis` | `BfBadgeEmphasis` (`'soft' \| 'strong'`) | `'soft'` | `soft` (a pale tint, the default) or `strong` (a solid fill with contrasting text, also for the count pill). |
|
|
3906
3954
|
| `count` | `number \| undefined` | `undefined` | Switches to the count pill; values above 99 render as "99+". |
|
|
3907
3955
|
| `countLabel` | `string` | `''` | What the count counts ("unread messages"), read by assistive tech after the number ("99+ unread messages"); visually hidden. Only used with `count`. |
|
|
3908
3956
|
|
|
@@ -3916,15 +3964,25 @@ A badge is a plain `<span>` with no role or ARIA attributes; its text is read as
|
|
|
3916
3964
|
|
|
3917
3965
|
- Keep labels to one or two words; badges are scanned, not read.
|
|
3918
3966
|
- Pair a count pill with a label or icon that says what is being counted, and set `countLabel` so the number is not read alone.
|
|
3967
|
+
- Keep `emphasis="strong"` for the one state that must stand out on the screen, such as critical findings.
|
|
3919
3968
|
|
|
3920
3969
|
### Don't
|
|
3921
3970
|
|
|
3922
3971
|
- Don't use a badge as a button; it has no interactive states.
|
|
3923
3972
|
- Don't invent new colors on it; pick the variant that matches the meaning.
|
|
3924
3973
|
- Don't use `primary` or `success` for a category; use `info`, so the status tones keep their meaning.
|
|
3974
|
+
- Don't make every badge strong: when all of them shout, none stands out.
|
|
3925
3975
|
|
|
3926
3976
|
## Migration notes
|
|
3927
3977
|
|
|
3978
|
+
### 0.4.0
|
|
3979
|
+
|
|
3980
|
+
New `emphasis` input (`BfBadgeEmphasis`: `soft`, the default, or `strong`). `strong` is a solid
|
|
3981
|
+
fill with contrasting text in every variant, for the one state that must stand out ("Critical");
|
|
3982
|
+
`primary` uses the brand fill. A strong count pill takes its fill from `variant` (a soft count pill
|
|
3983
|
+
stays primary, as before). In forced colours a strong badge keeps a `CanvasText` outline. Opt-in:
|
|
3984
|
+
without `emphasis` nothing changes.
|
|
3985
|
+
|
|
3928
3986
|
### 0.3.1
|
|
3929
3987
|
|
|
3930
3988
|
New `info` tone for informational labels such as a category, on the new `info` / `info-soft`
|
|
@@ -13342,6 +13400,7 @@ export class ListItemOverviewExampleComponent {
|
|
|
13342
13400
|
One row of a list: leading slot (avatar, icon tile), title and subtitle, trailing slot
|
|
13343
13401
|
(time, toggle, badge) and an optional chevron for rows that navigate. A navigation row puts a
|
|
13344
13402
|
`bfAction` link in the `title` slot, so the row stays a list item and the link covers it.
|
|
13403
|
+
`unread` marks a row not yet opened with a dot and a bolder title.
|
|
13345
13404
|
|
|
13346
13405
|
A row of a list: a leading slot (an avatar, an icon), the title and subtitle, a trailing slot (a time, a toggle, a chip) and an optional chevron. Place rows in a [`bf-list`](https://bitforge-ui.web.app/components/list), which gives them the list semantics and the inset container; a row can also stand alone. A row is static text, a navigation link or an action button, never more than one of them.
|
|
13347
13406
|
|
|
@@ -13472,6 +13531,87 @@ export class ListItemActionsExampleComponent {
|
|
|
13472
13531
|
}
|
|
13473
13532
|
```
|
|
13474
13533
|
|
|
13534
|
+
## Unread rows
|
|
13535
|
+
|
|
13536
|
+
`unread` marks a row the user has not opened yet, such as a new message or notification: a small `primary` dot at the row's inline start, on the title line, and the title in a bolder weight. It is not colour alone: the row also reads a visually hidden state before the title, from the `listItemUnread` label ("Unread"; set it with `provideBfLabels({ listItemUnread: 'Ungelesen' })` in a German app), so a screen reader says "Unread, Scan finished". The dot sits in the row's own inline-start padding (or the gap after a leading avatar or icon), so read and unread rows keep their text aligned and nothing moves when a row is marked read; without `unread` nothing changes. Clear `unread` when the row is opened.
|
|
13537
|
+
|
|
13538
|
+
```ts
|
|
13539
|
+
import { Component, computed, signal } from '@angular/core';
|
|
13540
|
+
import { BfActionDirective, BfListComponent, BfListItemComponent } from '@bitforgehq/ui';
|
|
13541
|
+
|
|
13542
|
+
interface Notice {
|
|
13543
|
+
readonly id: string;
|
|
13544
|
+
readonly title: string;
|
|
13545
|
+
readonly subtitle: string;
|
|
13546
|
+
readonly time: string;
|
|
13547
|
+
readonly unread: boolean;
|
|
13548
|
+
}
|
|
13549
|
+
|
|
13550
|
+
/**
|
|
13551
|
+
* An inbox with unread rows.
|
|
13552
|
+
*
|
|
13553
|
+
* Each title is a stretched `<button bfAction>`; opening a row marks it read.
|
|
13554
|
+
*/
|
|
13555
|
+
@Component({
|
|
13556
|
+
selector: 'app-example-list-item-unread',
|
|
13557
|
+
imports: [BfActionDirective, BfListComponent, BfListItemComponent],
|
|
13558
|
+
template: `
|
|
13559
|
+
<bf-list>
|
|
13560
|
+
@for (notice of notices(); track notice.id) {
|
|
13561
|
+
<bf-list-item [unread]="notice.unread" [subtitle]="notice.subtitle">
|
|
13562
|
+
<button bfSlot="title" bfAction type="button" class="text-start" (click)="open(notice)">
|
|
13563
|
+
{{ notice.title }}
|
|
13564
|
+
</button>
|
|
13565
|
+
<span bfSlot="trailing" class="text-caption text-text-muted">{{ notice.time }}</span>
|
|
13566
|
+
</bf-list-item>
|
|
13567
|
+
}
|
|
13568
|
+
</bf-list>
|
|
13569
|
+
<p data-status aria-live="polite" class="text-caption text-text-muted mt-3">{{ status() }}</p>
|
|
13570
|
+
`,
|
|
13571
|
+
})
|
|
13572
|
+
export class ListItemUnreadExampleComponent {
|
|
13573
|
+
protected readonly notices = signal<readonly Notice[]>([
|
|
13574
|
+
{
|
|
13575
|
+
id: 'scan',
|
|
13576
|
+
title: 'Scan finished',
|
|
13577
|
+
subtitle: '3 new findings on api.example.com',
|
|
13578
|
+
time: '9:41',
|
|
13579
|
+
unread: true,
|
|
13580
|
+
},
|
|
13581
|
+
{
|
|
13582
|
+
id: 'cert',
|
|
13583
|
+
title: 'Certificate expires soon',
|
|
13584
|
+
subtitle: 'shop.example.com, in 12 days',
|
|
13585
|
+
time: '8:15',
|
|
13586
|
+
unread: true,
|
|
13587
|
+
},
|
|
13588
|
+
{
|
|
13589
|
+
id: 'report',
|
|
13590
|
+
title: 'Weekly report',
|
|
13591
|
+
subtitle: 'Ready to download',
|
|
13592
|
+
time: 'Mon',
|
|
13593
|
+
unread: false,
|
|
13594
|
+
},
|
|
13595
|
+
]);
|
|
13596
|
+
private readonly opened = signal('');
|
|
13597
|
+
|
|
13598
|
+
protected readonly status = computed(() => {
|
|
13599
|
+
const unread = this.notices().filter((notice) => notice.unread).length;
|
|
13600
|
+
const opened = this.opened();
|
|
13601
|
+
return opened ? `${unread} unread · Opened: ${opened}` : `${unread} unread`;
|
|
13602
|
+
});
|
|
13603
|
+
|
|
13604
|
+
protected open(notice: Notice): void {
|
|
13605
|
+
this.opened.set(notice.title);
|
|
13606
|
+
this.notices.update((list) =>
|
|
13607
|
+
list.map((item) => (item.id === notice.id ? { ...item, unread: false } : item)),
|
|
13608
|
+
);
|
|
13609
|
+
}
|
|
13610
|
+
}
|
|
13611
|
+
```
|
|
13612
|
+
|
|
13613
|
+
With a `bfAction` link or button in the `title` slot, the state becomes part of that element's accessible name: the directive sets `aria-labelledby` to the state text and the element itself (it gives the element an id if it has none, and keeps an `aria-labelledby` of its own after the state), so the link reads "Unread, Scan finished" when tabbed to or listed, and the state text is hidden from the tree so it is read once. An `interactive` row holds the state text inside its button, so its name starts with it too.
|
|
13614
|
+
|
|
13475
13615
|
## Desktop
|
|
13476
13616
|
|
|
13477
13617
|
An `interactive` row and a row holding a `bfAction` link take a `surface-muted` fill and the pointer cursor while hovered; a static row has none. Hover styles apply only on devices that can hover, so a tap never leaves one stuck. The ring is drawn around the row on keyboard focus only. A navigation row keeps the browser's link behaviour: Ctrl/Cmd-click and a middle click open it in a new tab. The trailing slot sits above the stretched link, so a toggle or button there takes its own click. Rows have one height; they do not follow `provideBfDefaults()`.
|
|
@@ -13482,10 +13622,11 @@ An `interactive` row and a row holding a `bfAction` link take a `surface-muted`
|
|
|
13482
13622
|
- Text: the title, the title slot and the subtitle wrap (`wrap-anywhere`); with `truncate` each keeps one line (`truncate`).
|
|
13483
13623
|
- `interactive` rows and rows holding a `bfAction` link add a pointer, a `surface-muted` hover, a `surface-pressed` fill while pressed (the row's action, for a `bfAction` row) and a `ring` focus ring; `interactive` rows dim to `text-disabled` when `disabled` and have no pressed state then.
|
|
13484
13624
|
- The `chevron` mark uses `text-subtle`.
|
|
13625
|
+
- `unread`: the dot is `primary` (`CanvasText` in forced colours), `rounded-full` and 8 px (`size-2`); the title turns `font-extrabold`.
|
|
13485
13626
|
|
|
13486
13627
|
## Accessibility
|
|
13487
13628
|
|
|
13488
|
-
`bf-list-item` sets `role="listitem"` on its host only inside a `bf-list`; a standalone row has no role, so it never claims a list parent that is not there. A non-interactive row is a plain `<div>`, while `[interactive]="true"` renders it as a native `<button>` so it gets keyboard activation and the button role for free. A navigation row's `bfAction` link in the `title` slot is a real `<a>` inside the list item ([WAI-ARIA APG link pattern](https://www.w3.org/WAI/ARIA/apg/patterns/link/)): exposed as `link` with the title as its name, reached with Tab (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), followed with Enter (not Space), opened in a new tab with Ctrl/Cmd-click; under forced colours a system-coloured outline around the whole row marks the focused link. Making the host itself a link would take the row out of the list's `listitem` structure, so the link lives inside it. `chevron` is a purely visual CSS mark (an `::after` pseudo-element), so it adds nothing to the accessibility tree.
|
|
13629
|
+
`bf-list-item` sets `role="listitem"` on its host only inside a `bf-list`; a standalone row has no role, so it never claims a list parent that is not there. A non-interactive row is a plain `<div>`, while `[interactive]="true"` renders it as a native `<button>` so it gets keyboard activation and the button role for free. A navigation row's `bfAction` link in the `title` slot is a real `<a>` inside the list item ([WAI-ARIA APG link pattern](https://www.w3.org/WAI/ARIA/apg/patterns/link/)): exposed as `link` with the title as its name, reached with Tab (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), followed with Enter (not Space), opened in a new tab with Ctrl/Cmd-click; under forced colours a system-coloured outline around the whole row marks the focused link. Making the host itself a link would take the row out of the list's `listitem` structure, so the link lives inside it. `chevron` is a purely visual CSS mark (an `::after` pseudo-element), so it adds nothing to the accessibility tree. An `unread` row's dot carries a visually hidden (`sr-only`) state text from the `listItemUnread` label, read before the title ("Unread, Scan finished"); on a row with a `bfAction` the text is `aria-hidden` and the action names itself with `aria-labelledby` from it and its own content, so the state is part of the link's or button's name and is read once. The row stays a `listitem`.
|
|
13489
13630
|
|
|
13490
13631
|
### Keyboard
|
|
13491
13632
|
|
|
@@ -13505,6 +13646,7 @@ An `interactive` row and a row holding a `bfAction` link take a `surface-muted`
|
|
|
13505
13646
|
| `chevron` | `boolean` | `false` | Show a trailing chevron (navigation rows). |
|
|
13506
13647
|
| `disabled` | `boolean` | `false` | Disable an interactive row. |
|
|
13507
13648
|
| `truncate` | `boolean` | `false` | Keep the title, the title slot and the subtitle on one line each, cut with an ellipsis. By default they wrap, so nothing is lost at large text sizes. |
|
|
13649
|
+
| `unread` | `boolean` | `false` | Mark the row as not yet opened: a dot at the inline start, a bolder title and a visually hidden state (the `listItemUnread` label) read before the title. |
|
|
13508
13650
|
|
|
13509
13651
|
## Outputs
|
|
13510
13652
|
|
|
@@ -13525,14 +13667,26 @@ An `interactive` row and a row holding a `bfAction` link take a `surface-muted`
|
|
|
13525
13667
|
|
|
13526
13668
|
- Keep titles short; a long one wraps. Add `truncate` only where one line per row is the pattern (a mail list).
|
|
13527
13669
|
- Make a row that navigates a `bfAction` link in the `title` slot, and a row that acts on the page `interactive`; put secondary actions in the trailing slot.
|
|
13670
|
+
- Set `unread` on rows not yet opened (messages, notifications) and clear it when the row is opened.
|
|
13528
13671
|
|
|
13529
13672
|
### Don't
|
|
13530
13673
|
|
|
13531
13674
|
- Don't nest interactive controls inside an `interactive` row (it is one button); use a navigation row with a trailing control instead.
|
|
13532
13675
|
- Don't wrap a `bf-list-item` in an `<a>`, and don't navigate from an `interactive` row's `(clicked)`.
|
|
13676
|
+
- Don't mark unread rows with a coloured title or a badge of your own; `unread` gives the dot, the weight and the screen-reader state together.
|
|
13533
13677
|
|
|
13534
13678
|
## Migration notes
|
|
13535
13679
|
|
|
13680
|
+
### 0.4.0
|
|
13681
|
+
|
|
13682
|
+
New `unread` input (boolean, default false) for a row not yet opened: a `primary` dot at the
|
|
13683
|
+
row's inline start on the title line, a bolder title (`font-extrabold`) and a visually hidden
|
|
13684
|
+
state read before the title, from the new label key `listItemUnread` ("Unread"). A row's
|
|
13685
|
+
`bfAction` link or button then names itself `aria-labelledby="<state> <itself>"` ("Unread,
|
|
13686
|
+
Report"; an id is added if it has none, and its own `aria-labelledby` is kept after the state).
|
|
13687
|
+
The dot sits in the row's own inline-start padding, so read and unread rows stay aligned. Opt-in: without `unread` nothing
|
|
13688
|
+
changes.
|
|
13689
|
+
|
|
13536
13690
|
### 0.3.0
|
|
13537
13691
|
|
|
13538
13692
|
**Behaviour:** logical properties: text aligns to the inline start and the chevron sits at the
|
|
@@ -22974,6 +23128,248 @@ hidden word (new labels `statTrendUp`, `statTrendDown`, `statTrendFlat`). `trend
|
|
|
22974
23128
|
|
|
22975
23129
|
---
|
|
22976
23130
|
|
|
23131
|
+
# bf-step
|
|
23132
|
+
|
|
23133
|
+
One numbered step of an instruction list, with a title and its details
|
|
23134
|
+
|
|
23135
|
+
`BfStepComponent` from `@bitforgehq/ui` · Data display · since 0.4.0
|
|
23136
|
+
|
|
23137
|
+
## Example
|
|
23138
|
+
|
|
23139
|
+
```ts
|
|
23140
|
+
import { Component } from '@angular/core';
|
|
23141
|
+
import { BfStepComponent, BfStepsComponent } from '@bitforgehq/ui';
|
|
23142
|
+
|
|
23143
|
+
/** Steps with a short instruction as the title and the details in the content. */
|
|
23144
|
+
@Component({
|
|
23145
|
+
selector: 'app-example-step-overview',
|
|
23146
|
+
imports: [BfStepComponent, BfStepsComponent],
|
|
23147
|
+
template: `
|
|
23148
|
+
<bf-steps>
|
|
23149
|
+
<bf-step title="Export your contacts"
|
|
23150
|
+
>In your old app, choose Export and save the file.</bf-step
|
|
23151
|
+
>
|
|
23152
|
+
<bf-step title="Import the file">
|
|
23153
|
+
Pick the file you saved. Contacts that are already in your address book are merged, not
|
|
23154
|
+
added twice.
|
|
23155
|
+
</bf-step>
|
|
23156
|
+
<bf-step title="Check the result" />
|
|
23157
|
+
</bf-steps>
|
|
23158
|
+
`,
|
|
23159
|
+
})
|
|
23160
|
+
export class StepOverviewExampleComponent {}
|
|
23161
|
+
```
|
|
23162
|
+
|
|
23163
|
+
## Overview
|
|
23164
|
+
|
|
23165
|
+
One step of a `bf-steps` list: a numbered marker, a short instruction as its title and the
|
|
23166
|
+
step's details in the content.
|
|
23167
|
+
|
|
23168
|
+
One step of a [`bf-steps`](https://bitforge-ui.web.app/components/steps) list: `title` is the step's short instruction and the content holds its details (text, a code to type, an image or a button). The list numbers the steps by position; the step draws the numbered circle and the line to the next one. It works the same in both shells.
|
|
23169
|
+
|
|
23170
|
+
## When to use
|
|
23171
|
+
|
|
23172
|
+
Use `bf-step` for each instruction inside a `bf-steps` list. Use [bf-list-item](https://bitforge-ui.web.app/components/list-item) instead for a row the user opens or acts on, and [bf-description-list](https://bitforge-ui.web.app/components/description-list) for facts with no order.
|
|
23173
|
+
|
|
23174
|
+
## Headings
|
|
23175
|
+
|
|
23176
|
+
The title is text by default, which suits short steps. For a long guide whose steps hold screenshots or code, set `headingLevel` (`2`, `3` or `4`, a `BfStepHeadingLevel`) to the level that fits the page outline, so a screen-reader user can move from step to step by heading. The look does not change.
|
|
23177
|
+
|
|
23178
|
+
```ts
|
|
23179
|
+
import { Component } from '@angular/core';
|
|
23180
|
+
import { BfStepComponent, BfStepsComponent } from '@bitforgehq/ui';
|
|
23181
|
+
|
|
23182
|
+
/** Long steps with level 3 headings, so a screen-reader user can move between them. */
|
|
23183
|
+
@Component({
|
|
23184
|
+
selector: 'app-example-step-headings',
|
|
23185
|
+
imports: [BfStepComponent, BfStepsComponent],
|
|
23186
|
+
template: `
|
|
23187
|
+
<bf-steps>
|
|
23188
|
+
<bf-step title="Create an API key" [headingLevel]="3">
|
|
23189
|
+
In the console, open Settings, then API keys, and choose New key. Give it a name that says
|
|
23190
|
+
where it is used, such as "CI pipeline", and copy it: it is shown only once.
|
|
23191
|
+
</bf-step>
|
|
23192
|
+
<bf-step title="Store the key as a secret" [headingLevel]="3">
|
|
23193
|
+
Add it to your CI provider's secrets as BITFORGE_API_KEY. Never commit it to the repository.
|
|
23194
|
+
</bf-step>
|
|
23195
|
+
</bf-steps>
|
|
23196
|
+
`,
|
|
23197
|
+
})
|
|
23198
|
+
export class StepHeadingsExampleComponent {}
|
|
23199
|
+
```
|
|
23200
|
+
|
|
23201
|
+
## Desktop
|
|
23202
|
+
|
|
23203
|
+
A step is not interactive: no hover, no pointer cursor, no focus stop; only a link or button in its content takes focus. It renders the same inside `provideBfShell()`.
|
|
23204
|
+
|
|
23205
|
+
## Theming
|
|
23206
|
+
|
|
23207
|
+
- Marker: `bg-primary-soft` / `text-primary-strong`, `text-label-sm` bold, a 24 px `rounded-full` circle; the line under it is `border-border`, hidden on the last step.
|
|
23208
|
+
- Title: `text-label` bold in `text`, wrapping anywhere; content: `text-body` in `text-secondary`.
|
|
23209
|
+
|
|
23210
|
+
## Accessibility
|
|
23211
|
+
|
|
23212
|
+
Inside `bf-steps` the host is a `role="listitem"`, so its position is announced ("2 of 3"); the visible number is `aria-hidden`. The title is a `p`, or an `h2`, `h3` or `h4` with `headingLevel`. Outside `bf-steps` the host claims no role.
|
|
23213
|
+
|
|
23214
|
+
## Inputs
|
|
23215
|
+
|
|
23216
|
+
| Name | Type | Default | Description |
|
|
23217
|
+
| --- | --- | --- | --- |
|
|
23218
|
+
| `title` | `string` | `''` | The step's short instruction ("Install the app"), shown next to the number. |
|
|
23219
|
+
| `headingLevel` | `BfStepHeadingLevel \| undefined` (`2 \| 3 \| 4 \| undefined`) | `undefined` | Renders the title as a heading of this level instead of text; leave it off for short steps. |
|
|
23220
|
+
|
|
23221
|
+
## Slots
|
|
23222
|
+
|
|
23223
|
+
- `default`: The step's details: text, a code snippet, an image or a button.
|
|
23224
|
+
|
|
23225
|
+
## Notes
|
|
23226
|
+
|
|
23227
|
+
### Do
|
|
23228
|
+
|
|
23229
|
+
- Keep the title to one instruction and put everything else in the content.
|
|
23230
|
+
|
|
23231
|
+
### Don't
|
|
23232
|
+
|
|
23233
|
+
- Don't use `bf-step` outside a `bf-steps` list: it then has no number to show but 1.
|
|
23234
|
+
|
|
23235
|
+
## Migration notes
|
|
23236
|
+
|
|
23237
|
+
### 0.4.0
|
|
23238
|
+
|
|
23239
|
+
New `bf-step`: one step of a `bf-steps` list, with `title` (the short instruction, text by
|
|
23240
|
+
default; `headingLevel` 2, 3 or 4, a `BfStepHeadingLevel`, makes it a heading) and the details
|
|
23241
|
+
in the default slot. Its number is drawn in a `primary-soft` circle and hidden from assistive
|
|
23242
|
+
technology, which reads the list position instead.
|
|
23243
|
+
|
|
23244
|
+
---
|
|
23245
|
+
|
|
23246
|
+
# bf-steps
|
|
23247
|
+
|
|
23248
|
+
Numbered instruction steps a user follows in order, with joined markers
|
|
23249
|
+
|
|
23250
|
+
`BfStepsComponent` from `@bitforgehq/ui` · Data display · since 0.4.0
|
|
23251
|
+
|
|
23252
|
+
## Example
|
|
23253
|
+
|
|
23254
|
+
```ts
|
|
23255
|
+
import { Component } from '@angular/core';
|
|
23256
|
+
import { RouterLink } from '@angular/router';
|
|
23257
|
+
import { BfStepComponent, BfStepsComponent } from '@bitforgehq/ui';
|
|
23258
|
+
|
|
23259
|
+
/** Setting up the app on a phone, in four numbered steps with a code to type and a link. */
|
|
23260
|
+
@Component({
|
|
23261
|
+
selector: 'app-example-steps-overview',
|
|
23262
|
+
imports: [RouterLink, BfStepComponent, BfStepsComponent],
|
|
23263
|
+
template: `
|
|
23264
|
+
<bf-steps>
|
|
23265
|
+
<bf-step title="Install the app">
|
|
23266
|
+
Download Bitforge Guard from the App Store or Google Play.
|
|
23267
|
+
</bf-step>
|
|
23268
|
+
<bf-step title="Sign in">Use your work email address and the password you chose.</bf-step>
|
|
23269
|
+
<bf-step title="Pair your phone">
|
|
23270
|
+
Open Settings, then Devices, and enter this code:
|
|
23271
|
+
<code
|
|
23272
|
+
class="rounded-tile bg-surface-sunken text-label-sm text-text mt-2 block w-fit px-3 py-1.5 font-mono"
|
|
23273
|
+
>K7F-29Q</code
|
|
23274
|
+
>
|
|
23275
|
+
</bf-step>
|
|
23276
|
+
<bf-step title="Turn on notifications">
|
|
23277
|
+
Allow them when the app asks, or later in
|
|
23278
|
+
<a routerLink="/components/steps" class="text-primary-text underline"
|
|
23279
|
+
>notification settings</a
|
|
23280
|
+
>.
|
|
23281
|
+
</bf-step>
|
|
23282
|
+
</bf-steps>
|
|
23283
|
+
`,
|
|
23284
|
+
})
|
|
23285
|
+
export class StepsOverviewExampleComponent {}
|
|
23286
|
+
```
|
|
23287
|
+
|
|
23288
|
+
## Overview
|
|
23289
|
+
|
|
23290
|
+
Numbered instructions a user follows in order, such as setting up an app on a phone: an
|
|
23291
|
+
ordered list of `bf-step` items, each with a numbered marker joined to the next by a line.
|
|
23292
|
+
|
|
23293
|
+
Numbered instructions a user follows in order: a `bf-steps` list of `bf-step` items, each with a numbered circle, a short instruction as its title and the details under it, the circles joined by a thin line. It works the same in a desktop web app and in the Capacitor shell.
|
|
23294
|
+
|
|
23295
|
+
## When to use
|
|
23296
|
+
|
|
23297
|
+
Use `bf-steps` for instructions the user carries out in order, outside the app or across it: "Set up the app on your phone", "Connect your domain". It is static content, not a wizard: a multi-page stepper that holds state and moves the user from step to step is a flow of pages (in the Capacitor shell, pages pushed in [bf-tabs](https://bitforge-ui.web.app/components/tabs) stacks), and a progress figure for such a flow is a [bf-progress](https://bitforge-ui.web.app/components/progress). Use [bf-list](https://bitforge-ui.web.app/components/list) instead for items that have no order.
|
|
23298
|
+
|
|
23299
|
+
## Continued lists
|
|
23300
|
+
|
|
23301
|
+
`start` sets the number of the first step, for a list continued after a paragraph or on another part of the page: `start="3"` numbers the steps 3, 4, 5. It takes a number or a plain attribute.
|
|
23302
|
+
|
|
23303
|
+
```ts
|
|
23304
|
+
import { Component } from '@angular/core';
|
|
23305
|
+
import { BfStepComponent, BfStepsComponent } from '@bitforgehq/ui';
|
|
23306
|
+
|
|
23307
|
+
/** A list continued after a paragraph: the second list starts at 3. */
|
|
23308
|
+
@Component({
|
|
23309
|
+
selector: 'app-example-steps-continued',
|
|
23310
|
+
imports: [BfStepComponent, BfStepsComponent],
|
|
23311
|
+
template: `
|
|
23312
|
+
<bf-steps>
|
|
23313
|
+
<bf-step title="Open the admin console">Sign in with an administrator account.</bf-step>
|
|
23314
|
+
<bf-step title="Add your domain">Enter it without https:// in front.</bf-step>
|
|
23315
|
+
</bf-steps>
|
|
23316
|
+
<p class="text-body text-text-muted my-4">The console now shows a TXT record for the domain.</p>
|
|
23317
|
+
<bf-steps start="3">
|
|
23318
|
+
<bf-step title="Add the TXT record">Paste it at your DNS provider.</bf-step>
|
|
23319
|
+
<bf-step title="Verify the domain">Changes can take up to an hour to arrive.</bf-step>
|
|
23320
|
+
</bf-steps>
|
|
23321
|
+
`,
|
|
23322
|
+
})
|
|
23323
|
+
export class StepsContinuedExampleComponent {}
|
|
23324
|
+
```
|
|
23325
|
+
|
|
23326
|
+
## Desktop
|
|
23327
|
+
|
|
23328
|
+
Steps are not interactive: no hover, no pointer cursor and no focus stop of their own; only a link or button in a step's content takes focus, with its own focus ring. They render the same at every width: the marker column keeps its 24 px and the content wraps (a long word or URL breaks anywhere), so nothing scrolls sideways at 320 px. Put a code snippet that must not wrap in its own `overflow-x-auto` block.
|
|
23329
|
+
|
|
23330
|
+
## Theming
|
|
23331
|
+
|
|
23332
|
+
- Marker: `bg-primary-soft` / `text-primary-strong` (the tonal pair, ≥ 4.5:1 in both modes), `text-label-sm` bold in a 24 px circle (`size-6`, `rounded-full`); a `CanvasText` outline in forced colours.
|
|
23333
|
+
- Line: `border-border`, 1 px, hidden after the last step.
|
|
23334
|
+
- Title: `text-label` bold in `text`; content: `text-body` in `text-secondary`; `pb-6` between steps.
|
|
23335
|
+
|
|
23336
|
+
## Accessibility
|
|
23337
|
+
|
|
23338
|
+
`bf-steps` renders a `role="list"` container and each `bf-step` host is a `role="listitem"` directly inside it, so a screen reader announces the list and each step's position ("1 of 3"). The visible number is `aria-hidden`, so it is not read twice. A list with a `start` other than 1 also sets `aria-posinset` and `aria-setsize` on each step (the size counts the earlier steps too: steps 3 to 5 read "3 of 5"), so the announcement matches the number on screen. The title is text by default; give long steps `headingLevel` on `bf-step` so users can move between them by heading. A lone `bf-step` outside `bf-steps` claims no role.
|
|
23339
|
+
|
|
23340
|
+
## Inputs
|
|
23341
|
+
|
|
23342
|
+
| Name | Type | Default | Description |
|
|
23343
|
+
| --- | --- | --- | --- |
|
|
23344
|
+
| `start` | `number` | `1` | The number of the first step, for a list continued from an earlier one. |
|
|
23345
|
+
|
|
23346
|
+
## Slots
|
|
23347
|
+
|
|
23348
|
+
- `default`: The steps, each a `bf-step`.
|
|
23349
|
+
|
|
23350
|
+
## Notes
|
|
23351
|
+
|
|
23352
|
+
### Do
|
|
23353
|
+
|
|
23354
|
+
- Start each title with a verb and keep it to one instruction ("Install the app").
|
|
23355
|
+
- Put the details, a code to type or a link to open, in the step's content.
|
|
23356
|
+
|
|
23357
|
+
### Don't
|
|
23358
|
+
|
|
23359
|
+
- Don't use steps for a multi-page flow that tracks where the user is; that is a set of pages.
|
|
23360
|
+
- Don't number steps yourself in the title; the marker shows the number.
|
|
23361
|
+
|
|
23362
|
+
## Migration notes
|
|
23363
|
+
|
|
23364
|
+
### 0.4.0
|
|
23365
|
+
|
|
23366
|
+
New `bf-steps`: numbered instructions a user follows in order ("Set up the app on your phone"),
|
|
23367
|
+
a `role="list"` of `bf-step` items whose markers are joined by a line. `start` (a number, 1 by
|
|
23368
|
+
default) continues a list; a continued list sets `aria-posinset` and `aria-setsize` on its steps
|
|
23369
|
+
so the announced position matches the visible number.
|
|
23370
|
+
|
|
23371
|
+
---
|
|
23372
|
+
|
|
22977
23373
|
# bf-tab
|
|
22978
23374
|
|
|
22979
23375
|
One tab bar destination with an icon, a label and an optional count badge
|
|
@@ -24213,7 +24609,7 @@ Use `bf-table` on a desktop page for records the user scans and compares column
|
|
|
24213
24609
|
|
|
24214
24610
|
## Columns and rows
|
|
24215
24611
|
|
|
24216
|
-
`columns` is an array of `BfTableColumn`: the row property `key`, the header `label`, `sortable` and `align`. A default cell shows the row's `key` property as text when it is a string, a number or a boolean, and is empty otherwise (`null`, `undefined`, an object): render a date or an object with a custom cell. `align: 'end'` lines the header and cells up at the inline end and sets tabular figures, for numbers and amounts.
|
|
24612
|
+
`columns` is an array of `BfTableColumn`: the row property `key`, the header `label`, `sortable` and `align`. A default cell shows the row's `key` property as text when it is a string, a number or a boolean, and is empty otherwise (`null`, `undefined`, an object): render a date or an object with a custom cell. `align: 'end'` lines the header and cells up at the inline end and sets tabular figures, for numbers and amounts; `align: 'center'` centres the header and each cell's control, for a column of toggles or checkboxes (see Toggle cells). `BfTableColumn.align` is a `BfTableColumnAlign`, the released `BfTableAlign` (`start`, `end`) plus `center`.
|
|
24217
24613
|
|
|
24218
24614
|
`rowKey` returns the string that identifies a row in `selection` and keeps each row's DOM when the rows change. By default it reads the row's `id` (a string or a number), and falls back to the row's index when a row has none; pass `[rowKey]="byEmail"` when the key is another property.
|
|
24219
24615
|
|
|
@@ -24339,6 +24735,90 @@ export class TableCustomCellsExampleComponent {
|
|
|
24339
24735
|
}
|
|
24340
24736
|
```
|
|
24341
24737
|
|
|
24738
|
+
## Toggle cells
|
|
24739
|
+
|
|
24740
|
+
A settings matrix is a table of switches: rows are what the setting applies to (alert kinds), columns are the options (channels: Email, Push, Slack), and each cell is a `bf-toggle` from a `bfTableCell` template. Keep the row label as the first column, and give the toggle columns `align: 'center'`, which centres the header and the switch in each cell. A toggle in a cell shows no label of its own, so name each one after its column and row with `ariaLabel` (`[ariaLabel]="channel.label + ', ' + alert.label"`, "Push, New CVE"); a screen reader also announces the column header as it moves across. Write the change back from `(changed)` and save it right away, as for any toggle. With `stack="narrow"` (or `coarse` in the Capacitor shell) a phone shows each alert as a tile with the channel labels at the start and the toggles at the end, centred on their label line. In a test, `BfTableHarness.getCellHarness(row, 'Push', BfToggleHarness)` returns a cell's toggle.
|
|
24741
|
+
|
|
24742
|
+
```ts
|
|
24743
|
+
import { Component, signal } from '@angular/core';
|
|
24744
|
+
import {
|
|
24745
|
+
BfTableCellDirective,
|
|
24746
|
+
BfTableComponent,
|
|
24747
|
+
BfToggleComponent,
|
|
24748
|
+
type BfTableColumn,
|
|
24749
|
+
} from '@bitforgehq/ui';
|
|
24750
|
+
|
|
24751
|
+
type Channel = 'email' | 'push' | 'slack';
|
|
24752
|
+
|
|
24753
|
+
interface AlertSetting {
|
|
24754
|
+
id: string;
|
|
24755
|
+
label: string;
|
|
24756
|
+
email: boolean;
|
|
24757
|
+
push: boolean;
|
|
24758
|
+
slack: boolean;
|
|
24759
|
+
}
|
|
24760
|
+
|
|
24761
|
+
const CHANNELS: readonly { key: Channel; label: string }[] = [
|
|
24762
|
+
{ key: 'email', label: 'Email' },
|
|
24763
|
+
{ key: 'push', label: 'Push' },
|
|
24764
|
+
{ key: 'slack', label: 'Slack' },
|
|
24765
|
+
];
|
|
24766
|
+
|
|
24767
|
+
/**
|
|
24768
|
+
* A settings matrix of toggle cells.
|
|
24769
|
+
*
|
|
24770
|
+
* Rows are alert kinds and columns are channels, each cell a `bf-toggle` named after its column
|
|
24771
|
+
* and row ("Push, New CVE") with `ariaLabel`, in centred columns (`align: 'center'`). The row label
|
|
24772
|
+
* stays the first column, and `stack="narrow"` turns each row into a tile with the toggles at its
|
|
24773
|
+
* end in a narrow panel or on a phone.
|
|
24774
|
+
*/
|
|
24775
|
+
@Component({
|
|
24776
|
+
selector: 'app-example-table-toggle-matrix',
|
|
24777
|
+
imports: [BfTableComponent, BfTableCellDirective, BfToggleComponent],
|
|
24778
|
+
template: `
|
|
24779
|
+
<div class="flex w-152 max-w-full flex-col gap-3">
|
|
24780
|
+
<bf-table label="Alert channels" stack="narrow" [rows]="alerts()" [columns]="columns">
|
|
24781
|
+
@for (channel of channels; track channel.key) {
|
|
24782
|
+
<ng-template [bfTableCell]="channel.key" [bfTableCellOf]="alerts()" let-alert>
|
|
24783
|
+
<bf-toggle
|
|
24784
|
+
[ariaLabel]="channel.label + ', ' + alert.label"
|
|
24785
|
+
[checked]="alert[channel.key]"
|
|
24786
|
+
(changed)="set(alert, channel.key, $event)"
|
|
24787
|
+
/>
|
|
24788
|
+
</ng-template>
|
|
24789
|
+
}
|
|
24790
|
+
</bf-table>
|
|
24791
|
+
<p data-status aria-live="polite" class="text-caption text-text-muted">{{ status() }}</p>
|
|
24792
|
+
</div>
|
|
24793
|
+
`,
|
|
24794
|
+
})
|
|
24795
|
+
export class TableToggleMatrixExampleComponent {
|
|
24796
|
+
readonly channels = CHANNELS;
|
|
24797
|
+
readonly columns: readonly BfTableColumn[] = [
|
|
24798
|
+
{ key: 'label', label: 'Alert' },
|
|
24799
|
+
...CHANNELS.map((channel): BfTableColumn => ({ ...channel, align: 'center' })),
|
|
24800
|
+
];
|
|
24801
|
+
readonly alerts = signal<readonly AlertSetting[]>([
|
|
24802
|
+
{ id: 'critical', label: 'Critical finding', email: true, push: true, slack: true },
|
|
24803
|
+
{ id: 'cve', label: 'New CVE', email: true, push: false, slack: true },
|
|
24804
|
+
{ id: 'ci', label: 'Failed CI run', email: false, push: false, slack: true },
|
|
24805
|
+
{ id: 'digest', label: 'Weekly digest', email: true, push: false, slack: false },
|
|
24806
|
+
]);
|
|
24807
|
+
readonly status = signal('No change yet.');
|
|
24808
|
+
|
|
24809
|
+
/** Writes one cell back; a real app saves the setting right away. */
|
|
24810
|
+
set(alert: AlertSetting, channel: Channel, on: boolean): void {
|
|
24811
|
+
this.alerts.update((rows) =>
|
|
24812
|
+
rows.map((row) => (row.id === alert.id ? { ...row, [channel]: on } : row)),
|
|
24813
|
+
);
|
|
24814
|
+
const name = CHANNELS.find((c) => c.key === channel)?.label ?? channel;
|
|
24815
|
+
this.status.set(`${name} for ${alert.label} turned ${on ? 'on' : 'off'}.`);
|
|
24816
|
+
}
|
|
24817
|
+
}
|
|
24818
|
+
```
|
|
24819
|
+
|
|
24820
|
+
Under a coarse pointer every toggle is a 44 px target inside its own cell (a row grows to fit it), and a cell's horizontal padding keeps neighbouring toggles apart, so no two hit areas overlap. A `sm` toggle (40 px wide) takes a 44 px width under touch as well. ArrowUp and ArrowDown move between the toggles of one column.
|
|
24821
|
+
|
|
24342
24822
|
## Empty state
|
|
24343
24823
|
|
|
24344
24824
|
While `rows` is empty the table shows one full-width row that holds the `empty` slot, such as a `bf-empty-state` with the action that creates the first record. The header stays, so the user still sees what the table holds.
|
|
@@ -24685,7 +25165,7 @@ Put the table on a `bf-card` (or another surface) yourself; it has no background
|
|
|
24685
25165
|
|
|
24686
25166
|
## Accessibility
|
|
24687
25167
|
|
|
24688
|
-
A native `table` with a visually hidden `caption` from `label`, `th scope="col"` headers and one `tr` per row. A sorted column's `th` carries `aria-sort="ascending"` or `"descending"`; the others carry none. A sortable header is a native `button` inside the `th`, so its name is the column label; the arrow is `aria-hidden`. The header checkbox is named by `selectAllLabel`, else `provideBfLabels()`'s `tableSelectAll` ("Select all rows"), and is mixed (`indeterminate`) while some rows are selected. Each row checkbox is named by the row's first data cell through `aria-labelledby`, so it reads as the row's title. The empty row's cell spans every column.
|
|
25168
|
+
A native `table` with a visually hidden `caption` from `label`, `th scope="col"` headers and one `tr` per row. A sorted column's `th` carries `aria-sort="ascending"` or `"descending"`; the others carry none. A sortable header is a native `button` inside the `th`, so its name is the column label; the arrow is `aria-hidden`. The header checkbox is named by `selectAllLabel`, else `provideBfLabels()`'s `tableSelectAll` ("Select all rows"), and is mixed (`indeterminate`) while some rows are selected. Each row checkbox is named by the row's first data cell through `aria-labelledby`, so it reads as the row's title. A control in a custom cell brings its own name: give a label-less one (a toggle in a settings matrix) `ariaLabel` from its column and row, such as "Email, Critical finding", so it is named the same in the table and in a stacked tile. The empty row's cell spans every column.
|
|
24689
25169
|
|
|
24690
25170
|
A table that can stack (`stack` other than `never`) sets explicit `table`, `rowgroup`, `row`, `columnheader` and `cell` roles and names the table from its caption with `aria-labelledby`, because Safari and some screen readers drop a table's semantics once CSS changes its display; so a stacked table still reads as a table with its column headers. Stacked, the header row is visually hidden but stays in the accessibility tree; its sort buttons and checkbox are hidden (a plain label takes a sortable header's place), so no control is focusable where nobody can see it, and the bar's Select all checkbox and Sort by select replace them. A cell's visible label is CSS generated content with empty alternative text (`content: attr(data-label) / ""`, the `content-data-label` utility of `theme.css`), so a screen reader reads the column header once, not the label as well.
|
|
24691
25171
|
|
|
@@ -24754,6 +25234,7 @@ Selects or clears one row.
|
|
|
24754
25234
|
### Do
|
|
24755
25235
|
|
|
24756
25236
|
- Give every table a `label`, and every sortable column a short header.
|
|
25237
|
+
- In a settings matrix, keep the row label as the first column, centre the toggle columns and name every toggle after its column and row.
|
|
24757
25238
|
- Sort and filter the rows in a `computed()` from `sort` and your filters.
|
|
24758
25239
|
- Use `stack="narrow"` for a table that may sit in a narrow column, or `stack="coarse"` in the Capacitor shell; otherwise render the rows as `bf-list-item`s below `md`.
|
|
24759
25240
|
|
|
@@ -24765,6 +25246,17 @@ Selects or clears one row.
|
|
|
24765
25246
|
|
|
24766
25247
|
## Migration notes
|
|
24767
25248
|
|
|
25249
|
+
### 0.4.0
|
|
25250
|
+
|
|
25251
|
+
New: toggle cells for a settings matrix (rows of alert kinds, columns of channels, a `bf-toggle`
|
|
25252
|
+
in each cell), documented with the `table/toggle-matrix` example. `BfTableColumn.align` takes
|
|
25253
|
+
`'center'`: the header and each cell's control are centred, and while stacked the control sits at
|
|
25254
|
+
the tile's end, centred on its label line. New type `BfTableColumnAlign` (`BfTableAlign` plus
|
|
25255
|
+
`'center'`; `BfTableAlign` keeps its two members). A stacked cell of a start or end column keeps
|
|
25256
|
+
its baseline alignment. `@bitforgehq/ui/testing`: new `BfTableHarness.getCellHarness(row, column,
|
|
25257
|
+
query)` returns the harness of a control in one cell, and `selectRow()`, `getSelectedCount()`
|
|
25258
|
+
read only the selection column's checkboxes, never a checkbox or toggle in a custom cell.
|
|
25259
|
+
|
|
24768
25260
|
### 0.3.3
|
|
24769
25261
|
|
|
24770
25262
|
Fix: stacked rows (`stack="narrow"` and `stack="coarse"`) show their column labels again when the
|
|
@@ -26245,6 +26737,357 @@ New label keys `timeInputHour`, `timeInputMinute`, `timeInputSecond`, `timeInput
|
|
|
26245
26737
|
|
|
26246
26738
|
---
|
|
26247
26739
|
|
|
26740
|
+
# bf-timeline
|
|
26741
|
+
|
|
26742
|
+
Dated list of events with who did what and when, on a vertical line
|
|
26743
|
+
|
|
26744
|
+
`BfTimelineComponent` from `@bitforgehq/ui` · Data display · since 0.4.0
|
|
26745
|
+
|
|
26746
|
+
## Example
|
|
26747
|
+
|
|
26748
|
+
```ts
|
|
26749
|
+
import { Component } from '@angular/core';
|
|
26750
|
+
import { RouterLink } from '@angular/router';
|
|
26751
|
+
import { BfTimelineComponent, BfTimelineEventComponent } from '@bitforgehq/ui';
|
|
26752
|
+
|
|
26753
|
+
/**
|
|
26754
|
+
* The bf-timeline overview.
|
|
26755
|
+
*
|
|
26756
|
+
* Live demo of `bf-timeline`: the history of a security finding, newest first. A system event has
|
|
26757
|
+
* no actor, the pull request is a link in the event text, the failed CI run is `danger` and the
|
|
26758
|
+
* fix `success`.
|
|
26759
|
+
*/
|
|
26760
|
+
@Component({
|
|
26761
|
+
selector: 'app-example-timeline-overview',
|
|
26762
|
+
imports: [RouterLink, BfTimelineComponent, BfTimelineEventComponent],
|
|
26763
|
+
template: `
|
|
26764
|
+
<bf-timeline label="Finding history" class="max-w-xl">
|
|
26765
|
+
<bf-timeline-event actor="Lena Meier" time="2026-10-28T15:40:00Z" tone="success">
|
|
26766
|
+
Marked the finding as fixed
|
|
26767
|
+
</bf-timeline-event>
|
|
26768
|
+
<bf-timeline-event actor="CI" time="2026-10-28T13:05:00Z" tone="danger">
|
|
26769
|
+
CI failed on the security scan
|
|
26770
|
+
</bf-timeline-event>
|
|
26771
|
+
<bf-timeline-event actor="Jonas Keller" time="2026-10-28T11:20:00Z" tone="primary">
|
|
26772
|
+
Linked
|
|
26773
|
+
<a routerLink="." fragment="links-in-events">PR #123</a>
|
|
26774
|
+
to the finding
|
|
26775
|
+
</bf-timeline-event>
|
|
26776
|
+
<bf-timeline-event actor="Jonas Keller" time="2026-10-27T16:02:00Z">
|
|
26777
|
+
Assigned the finding to Lena Meier
|
|
26778
|
+
</bf-timeline-event>
|
|
26779
|
+
<bf-timeline-event time="2026-10-27T08:14:00Z">
|
|
26780
|
+
Created by the nightly dependency scan
|
|
26781
|
+
</bf-timeline-event>
|
|
26782
|
+
</bf-timeline>
|
|
26783
|
+
`,
|
|
26784
|
+
})
|
|
26785
|
+
export class TimelineOverviewExampleComponent {}
|
|
26786
|
+
```
|
|
26787
|
+
|
|
26788
|
+
## Overview
|
|
26789
|
+
|
|
26790
|
+
A dated history of events, newest first or oldest first as the consumer orders them: who did
|
|
26791
|
+
what and when, each event a `bf-timeline-event` with a marker on a vertical line.
|
|
26792
|
+
|
|
26793
|
+
A timeline shows the history of one thing as dated events: who did what, and when. Each event is a [`bf-timeline-event`](https://bitforge-ui.web.app/components/timeline-event) with a coloured marker on a vertical line, its text (which may link the objects it names), then the actor and the time. The timeline shows the events in the order you give them, newest first or oldest first; it never sorts. It works the same in a desktop web app, a narrow side panel and the Capacitor shell.
|
|
26794
|
+
|
|
26795
|
+
## When to use
|
|
26796
|
+
|
|
26797
|
+
Use `bf-timeline` for a record's history or an audit trail: a finding that was created, assigned, linked to a pull request and fixed; the changes in a CVE side panel; who changed a setting. Use [bf-list](https://bitforge-ui.web.app/components/list) instead for items the user opens or acts on, and for navigation; a timeline is not a stepper through a process either, nor a feed the user scrolls for new items. For the details of one record, use a [bf-description-list](https://bitforge-ui.web.app/components/description-list).
|
|
26798
|
+
|
|
26799
|
+
## Events and tones
|
|
26800
|
+
|
|
26801
|
+
`actor` names who did it (leave it empty for a system event), `time` says when (a `Date` or an ISO 8601 string), and the content is the event text. `tone` colours the marker: `neutral` (the default) for routine events, `primary` for the current or most important one, `success` (fixed, merged), `warning`, `danger` (CI failed, a regression) and `info`. The colour only supports the text, so say what happened in words ("CI failed"), never by the colour alone. The line runs from each marker to the next and ends at the last event.
|
|
26802
|
+
|
|
26803
|
+
## Links in events
|
|
26804
|
+
|
|
26805
|
+
The event text is the default slot, so the objects it names can be links: a pull request, a repository, a CVE. Put a plain `<a href>` (or `<a routerLink>`) inline in the text; the event styles every link in its text in `primary-text`, underlined, with a thicker underline on hover and the focus ring on keyboard focus. Keep the link text the object's name ("PR #123"), not "here".
|
|
26806
|
+
|
|
26807
|
+
## Time format
|
|
26808
|
+
|
|
26809
|
+
The time is formatted with `Intl.DateTimeFormat` in the app's `LOCALE_ID`: a medium date and a short time by default (`28 Oct 2026, 14:30` in `en-GB`, `28.10.2026, 14:30` in `de-CH`), in the browser's time zone. `timeFormat` on the timeline takes any `Intl.DateTimeFormatOptions` for all its events (`{ dateStyle: 'short' }`, or a `timeZone`), and `locale` overrides the language for one timeline. `timeText` on an event shows your own text in place of the formatted time, such as a relative "vor 2 Std."; the `time` element's `datetime` keeps the exact value. An empty or invalid `time` shows no time, and a locale or options the browser refuses fall back to the defaults, so a bad value never throws.
|
|
26810
|
+
|
|
26811
|
+
## Audit trail
|
|
26812
|
+
|
|
26813
|
+
An audit trail is actor-heavy: every event names a person or a bot. The `end` slot holds a small action for one event, such as a Show diff button: it sits at the inline end while the timeline is wide, and wraps under the text in a narrow side panel or on a phone (once the text would get narrower than 16rem). It takes no space while empty.
|
|
26814
|
+
|
|
26815
|
+
```ts
|
|
26816
|
+
import { Component, signal } from '@angular/core';
|
|
26817
|
+
import { BfButtonComponent, BfTimelineComponent, BfTimelineEventComponent } from '@bitforgehq/ui';
|
|
26818
|
+
|
|
26819
|
+
interface AuditEntry {
|
|
26820
|
+
id: string;
|
|
26821
|
+
actor: string;
|
|
26822
|
+
action: string;
|
|
26823
|
+
time: string;
|
|
26824
|
+
ago: string;
|
|
26825
|
+
diff: boolean;
|
|
26826
|
+
}
|
|
26827
|
+
|
|
26828
|
+
const ENTRIES: readonly AuditEntry[] = [
|
|
26829
|
+
{
|
|
26830
|
+
id: 'severity',
|
|
26831
|
+
actor: 'Lena Meier',
|
|
26832
|
+
action: 'Raised the severity from Medium to High',
|
|
26833
|
+
time: '2026-10-28T14:10:00Z',
|
|
26834
|
+
ago: '2 hours ago',
|
|
26835
|
+
diff: true,
|
|
26836
|
+
},
|
|
26837
|
+
{
|
|
26838
|
+
id: 'policy',
|
|
26839
|
+
actor: 'Policy bot',
|
|
26840
|
+
action: 'Applied the "Critical CVEs block releases" policy',
|
|
26841
|
+
time: '2026-10-28T09:30:00Z',
|
|
26842
|
+
ago: '7 hours ago',
|
|
26843
|
+
diff: true,
|
|
26844
|
+
},
|
|
26845
|
+
{
|
|
26846
|
+
id: 'owner',
|
|
26847
|
+
actor: 'Jonas Keller',
|
|
26848
|
+
action: 'Set the owner to the Platform team',
|
|
26849
|
+
time: '2026-10-27T16:45:00Z',
|
|
26850
|
+
ago: 'Yesterday',
|
|
26851
|
+
diff: false,
|
|
26852
|
+
},
|
|
26853
|
+
];
|
|
26854
|
+
|
|
26855
|
+
/**
|
|
26856
|
+
* An audit trail with relative times and an action per event.
|
|
26857
|
+
*
|
|
26858
|
+
* Every event names its actor, `timeText` shows a relative time while `datetime` keeps the exact
|
|
26859
|
+
* one, and the `end` slot holds a Show diff button: at the inline end while the timeline is wide,
|
|
26860
|
+
* under the text in a narrow panel.
|
|
26861
|
+
*/
|
|
26862
|
+
@Component({
|
|
26863
|
+
selector: 'app-example-timeline-audit',
|
|
26864
|
+
imports: [BfButtonComponent, BfTimelineComponent, BfTimelineEventComponent],
|
|
26865
|
+
template: `
|
|
26866
|
+
<div class="flex max-w-xl flex-col gap-3">
|
|
26867
|
+
<bf-timeline label="Audit trail">
|
|
26868
|
+
@for (entry of entries; track entry.id) {
|
|
26869
|
+
<bf-timeline-event [actor]="entry.actor" [time]="entry.time" [timeText]="entry.ago">
|
|
26870
|
+
{{ entry.action }}
|
|
26871
|
+
@if (entry.diff) {
|
|
26872
|
+
<bf-button bfSlot="end" variant="outline" size="sm" (clicked)="showDiff(entry)">
|
|
26873
|
+
Show diff
|
|
26874
|
+
</bf-button>
|
|
26875
|
+
}
|
|
26876
|
+
</bf-timeline-event>
|
|
26877
|
+
}
|
|
26878
|
+
</bf-timeline>
|
|
26879
|
+
<p data-status aria-live="polite" class="text-caption text-text-muted">{{ status() }}</p>
|
|
26880
|
+
</div>
|
|
26881
|
+
`,
|
|
26882
|
+
})
|
|
26883
|
+
export class TimelineAuditExampleComponent {
|
|
26884
|
+
readonly entries = ENTRIES;
|
|
26885
|
+
readonly status = signal('No diff open.');
|
|
26886
|
+
|
|
26887
|
+
/** A real app would open the change in a side panel. */
|
|
26888
|
+
showDiff(entry: AuditEntry): void {
|
|
26889
|
+
this.status.set(`Diff of "${entry.action}" by ${entry.actor}.`);
|
|
26890
|
+
}
|
|
26891
|
+
}
|
|
26892
|
+
```
|
|
26893
|
+
|
|
26894
|
+
## Desktop
|
|
26895
|
+
|
|
26896
|
+
The timeline itself is not interactive: no hover, no pointer cursor, no focus stop. Only the links in the event text and the controls in an `end` slot take focus, with their own hover and focus ring. Its spacing does not follow `provideBfDefaults()`: the events keep one rhythm at every density, and it has no `size`. Inside `provideBfShell()` it renders and behaves the same; the `end` slot's buttons bring their own 44 px touch height.
|
|
26897
|
+
|
|
26898
|
+
## Theming
|
|
26899
|
+
|
|
26900
|
+
- Marker: a 10 px dot (`rounded-control`) in `text-subtle` (neutral), `primary`, `success`, `warning`, `danger` or `info`; `CanvasText` under forced colours.
|
|
26901
|
+
- Line: a 1 px `border` line from marker to marker.
|
|
26902
|
+
- Text: `text-body` in `text`; links `primary-text`, underlined, `ring` on keyboard focus. Meta line: `text-caption` in `text-muted`.
|
|
26903
|
+
- Spacing: 12 px between the marker and the text, 20 px between events.
|
|
26904
|
+
|
|
26905
|
+
## Accessibility
|
|
26906
|
+
|
|
26907
|
+
The timeline is a list (`role="list"`, named by `label` through `aria-label`) and each event inside it a `listitem`, so a screen reader announces the number of events and the position of each. An event outside a `bf-timeline` claims no role. The marker and the line are `aria-hidden`; the tone is decoration, so the text must say what happened. The time is a `time` element whose `datetime` is the ISO value, and the separator between actor and time is hidden from assistive technology. Links and `end` slot controls are native elements in reading order.
|
|
26908
|
+
|
|
26909
|
+
## Inputs
|
|
26910
|
+
|
|
26911
|
+
| Name | Type | Default | Description |
|
|
26912
|
+
| --- | --- | --- | --- |
|
|
26913
|
+
| `label` | `string` | `''` | The list's accessible name, such as "History"; empty leaves the list unnamed (a visible heading above it already names the section). |
|
|
26914
|
+
| `timeFormat` | `Intl.DateTimeFormatOptions` | `TIMELINE_TIME_FORMAT` | `Intl.DateTimeFormat` options of every event's time; by default a medium date and a short time (`dateStyle: 'medium'`, `timeStyle: 'short'`). |
|
|
26915
|
+
| `locale` | `string` | `''` | BCP 47 locale of the times, such as `de-CH`; empty follows the app's `LOCALE_ID`. |
|
|
26916
|
+
|
|
26917
|
+
## Slots
|
|
26918
|
+
|
|
26919
|
+
- `default`: The events, each a `bf-timeline-event`, in the order to show them.
|
|
26920
|
+
|
|
26921
|
+
## Notes
|
|
26922
|
+
|
|
26923
|
+
### Do
|
|
26924
|
+
|
|
26925
|
+
- Give the timeline a `label` when no visible heading names it, and keep one order (newest first) across the app.
|
|
26926
|
+
- Name the actor and the object in every event; link the object.
|
|
26927
|
+
|
|
26928
|
+
### Don't
|
|
26929
|
+
|
|
26930
|
+
- Don't use a timeline for navigation or for steps the user still has to take.
|
|
26931
|
+
- Don't carry meaning in the tone alone; say "CI failed", not just a red dot.
|
|
26932
|
+
|
|
26933
|
+
## Migration notes
|
|
26934
|
+
|
|
26935
|
+
### 0.4.0
|
|
26936
|
+
|
|
26937
|
+
New: `bf-timeline`, a dated history of events (who did what, and when) for a record's history
|
|
26938
|
+
or an audit trail, in both shells. A `role="list"` named by `label`, in the order the consumer
|
|
26939
|
+
gives (it never sorts); each event's time is formatted with `Intl.DateTimeFormat` in the app's
|
|
26940
|
+
`LOCALE_ID` (`timeFormat`, default a medium date and a short time; `locale` overrides it).
|
|
26941
|
+
|
|
26942
|
+
---
|
|
26943
|
+
|
|
26944
|
+
# bf-timeline-event
|
|
26945
|
+
|
|
26946
|
+
One timeline event with a coloured marker, its text, actor and time
|
|
26947
|
+
|
|
26948
|
+
`BfTimelineEventComponent` from `@bitforgehq/ui` · Data display · since 0.4.0
|
|
26949
|
+
|
|
26950
|
+
## Example
|
|
26951
|
+
|
|
26952
|
+
```ts
|
|
26953
|
+
import { Component } from '@angular/core';
|
|
26954
|
+
import { RouterLink } from '@angular/router';
|
|
26955
|
+
import { BfTimelineComponent, BfTimelineEventComponent } from '@bitforgehq/ui';
|
|
26956
|
+
|
|
26957
|
+
/**
|
|
26958
|
+
* The bf-timeline-event overview.
|
|
26959
|
+
*
|
|
26960
|
+
* Live demo of `bf-timeline-event`: one event per tone in a `bf-timeline`, with and without an
|
|
26961
|
+
* actor, one with a link in its text and one with a relative `timeText`.
|
|
26962
|
+
*/
|
|
26963
|
+
@Component({
|
|
26964
|
+
selector: 'app-example-timeline-event-overview',
|
|
26965
|
+
imports: [RouterLink, BfTimelineComponent, BfTimelineEventComponent],
|
|
26966
|
+
template: `
|
|
26967
|
+
<bf-timeline label="Event tones" class="max-w-xl">
|
|
26968
|
+
<bf-timeline-event actor="Lena Meier" time="2026-10-28T15:40:00Z" tone="primary">
|
|
26969
|
+
Opened
|
|
26970
|
+
<a routerLink="/components/timeline" fragment="links-in-events">CVE-2026-1234</a>
|
|
26971
|
+
</bf-timeline-event>
|
|
26972
|
+
<bf-timeline-event actor="CI" time="2026-10-28T15:10:00Z" tone="success">
|
|
26973
|
+
All checks passed
|
|
26974
|
+
</bf-timeline-event>
|
|
26975
|
+
<bf-timeline-event actor="Dependency bot" time="2026-10-28T14:00:00Z" tone="warning">
|
|
26976
|
+
Found an outdated base image
|
|
26977
|
+
</bf-timeline-event>
|
|
26978
|
+
<bf-timeline-event actor="CI" time="2026-10-28T13:05:00Z" tone="danger">
|
|
26979
|
+
CI failed on the security scan
|
|
26980
|
+
</bf-timeline-event>
|
|
26981
|
+
<bf-timeline-event time="2026-10-28T12:00:00Z" timeText="4 hours ago" tone="info">
|
|
26982
|
+
A new advisory was published
|
|
26983
|
+
</bf-timeline-event>
|
|
26984
|
+
<bf-timeline-event actor="Jonas Keller" time="2026-10-27T16:02:00Z">
|
|
26985
|
+
Assigned the finding to Lena Meier
|
|
26986
|
+
</bf-timeline-event>
|
|
26987
|
+
</bf-timeline>
|
|
26988
|
+
`,
|
|
26989
|
+
})
|
|
26990
|
+
export class TimelineEventOverviewExampleComponent {}
|
|
26991
|
+
```
|
|
26992
|
+
|
|
26993
|
+
## Overview
|
|
26994
|
+
|
|
26995
|
+
One event of a `bf-timeline`: a marker coloured by `tone`, the event text (the default slot,
|
|
26996
|
+
which may hold links), then who did it (`actor`) and when (`time`, in a `time` element).
|
|
26997
|
+
|
|
26998
|
+
One event of a [`bf-timeline`](https://bitforge-ui.web.app/components/timeline): a marker coloured by `tone`, the event text from the default slot, then a meta line with `actor` and `time`. Place events in a `bf-timeline`, which gives them the list semantics and the time format; the line between the markers ends at the last event.
|
|
26999
|
+
|
|
27000
|
+
## When to use
|
|
27001
|
+
|
|
27002
|
+
Use `bf-timeline-event` for each dated entry of a `bf-timeline`: a change, a comment, a CI run. Use [bf-list-item](https://bitforge-ui.web.app/components/list-item) instead for a row the user opens or acts on.
|
|
27003
|
+
|
|
27004
|
+
## Basic usage
|
|
27005
|
+
|
|
27006
|
+
`actor`, `time` (a `Date` or an ISO 8601 string) and `tone` are inputs; the text is the content and may hold links, which take the link style. `timeText` replaces the formatted time with your own text while the `datetime` keeps the exact value. `bfSlot="end"` holds a small action, at the inline end on a wide timeline and below the text on a narrow one.
|
|
27007
|
+
|
|
27008
|
+
```ts
|
|
27009
|
+
import { Component } from '@angular/core';
|
|
27010
|
+
import { BfTimelineComponent, BfTimelineEventComponent } from '@bitforgehq/ui';
|
|
27011
|
+
|
|
27012
|
+
/**
|
|
27013
|
+
* An event's actor, time and tone.
|
|
27014
|
+
*
|
|
27015
|
+
* Two events of a CVE side panel: one by a person with an exact time, one by a bot with a relative
|
|
27016
|
+
* `timeText` whose `datetime` keeps the exact value.
|
|
27017
|
+
*/
|
|
27018
|
+
@Component({
|
|
27019
|
+
selector: 'app-example-timeline-event-basic',
|
|
27020
|
+
imports: [BfTimelineComponent, BfTimelineEventComponent],
|
|
27021
|
+
template: `
|
|
27022
|
+
<bf-timeline label="CVE history" class="max-w-sm">
|
|
27023
|
+
<bf-timeline-event actor="Lena Meier" time="2026-10-28T15:40:00Z" tone="warning">
|
|
27024
|
+
Accepted the risk until the next release
|
|
27025
|
+
</bf-timeline-event>
|
|
27026
|
+
<bf-timeline-event
|
|
27027
|
+
actor="Advisory bot"
|
|
27028
|
+
time="2026-10-28T10:00:00Z"
|
|
27029
|
+
timeText="6 hours ago"
|
|
27030
|
+
tone="info"
|
|
27031
|
+
>
|
|
27032
|
+
Imported the advisory
|
|
27033
|
+
</bf-timeline-event>
|
|
27034
|
+
</bf-timeline>
|
|
27035
|
+
`,
|
|
27036
|
+
})
|
|
27037
|
+
export class TimelineEventBasicExampleComponent {}
|
|
27038
|
+
```
|
|
27039
|
+
|
|
27040
|
+
## Desktop
|
|
27041
|
+
|
|
27042
|
+
An event has no hover and no focus stop of its own; only the links in its text and the controls in its `end` slot are interactive. It renders the same inside `provideBfShell()`.
|
|
27043
|
+
|
|
27044
|
+
## Theming
|
|
27045
|
+
|
|
27046
|
+
- Marker: `text-subtle`, `primary`, `success`, `warning`, `danger` or `info`; `CanvasText` under forced colours. Line: `border`.
|
|
27047
|
+
- Text `text-body` in `text`, links `primary-text`; meta line `text-caption` in `text-muted`.
|
|
27048
|
+
|
|
27049
|
+
## Accessibility
|
|
27050
|
+
|
|
27051
|
+
Inside a `bf-timeline` the event is a `listitem`; on its own it has no role. The marker is `aria-hidden`; the time is a `time` element with an ISO `datetime`, and the separator between actor and time is hidden from assistive technology.
|
|
27052
|
+
|
|
27053
|
+
## Inputs
|
|
27054
|
+
|
|
27055
|
+
| Name | Type | Default | Description |
|
|
27056
|
+
| --- | --- | --- | --- |
|
|
27057
|
+
| `actor` | `string` | `''` | Who did it, such as a person or a bot; empty for a system event. |
|
|
27058
|
+
| `time` | `Date \| string \| null` | `null` | When it happened: a Date or an ISO 8601 string; empty or invalid shows no time. |
|
|
27059
|
+
| `timeText` | `string` | `''` | Shown in place of the formatted time, such as "vor 2 Std."; the `time` element's `datetime` keeps the exact value. |
|
|
27060
|
+
| `tone` | `BfTimelineTone` (`'neutral' \| 'primary' \| 'success' \| 'warning' \| 'danger' \| 'info'`) | `'neutral'` | The marker's colour. |
|
|
27061
|
+
|
|
27062
|
+
## Slots
|
|
27063
|
+
|
|
27064
|
+
- `default`: The event text; links in it take the link style.
|
|
27065
|
+
- `end`: Content at the inline end on a wide timeline and below the text on a narrow one, such as a button.
|
|
27066
|
+
|
|
27067
|
+
## Notes
|
|
27068
|
+
|
|
27069
|
+
### Do
|
|
27070
|
+
|
|
27071
|
+
- Write the text as what happened ("Assigned to Lena Meier"), and link the object it names.
|
|
27072
|
+
|
|
27073
|
+
### Don't
|
|
27074
|
+
|
|
27075
|
+
- Don't put more than one small action in the `end` slot; open the details elsewhere.
|
|
27076
|
+
|
|
27077
|
+
## Migration notes
|
|
27078
|
+
|
|
27079
|
+
### 0.4.0
|
|
27080
|
+
|
|
27081
|
+
New: `bf-timeline-event`, one event of a `bf-timeline`: a 10 px marker coloured by `tone`
|
|
27082
|
+
(`neutral`, `primary`, `success`, `warning`, `danger`, `info`; new type `BfTimelineTone`) on a
|
|
27083
|
+
`border` line that ends at the last event, the event text in the default slot (links in it take
|
|
27084
|
+
the link style), then `actor` and `time` (a `Date` or an ISO 8601 string, in a `time` element;
|
|
27085
|
+
`timeText` shows a relative text while `datetime` keeps the exact value; an invalid time shows
|
|
27086
|
+
nothing). A `bfSlot="end"` action sits at the inline end, or under the text once the event is
|
|
27087
|
+
narrow.
|
|
27088
|
+
|
|
27089
|
+
---
|
|
27090
|
+
|
|
26248
27091
|
# bf-toast
|
|
26249
27092
|
|
|
26250
27093
|
Passive status pill with an optional action that never steals focus
|
|
@@ -26902,9 +27745,11 @@ export class ToggleListRowExampleComponent {
|
|
|
26902
27745
|
}
|
|
26903
27746
|
```
|
|
26904
27747
|
|
|
27748
|
+
In a table of switches (a settings matrix: alert kinds by channel), each cell's toggle is named after its column and row with `ariaLabel`; see [bf-table](https://bitforge-ui.web.app/components/table)'s Toggle cells.
|
|
27749
|
+
|
|
26905
27750
|
## Sizes
|
|
26906
27751
|
|
|
26907
|
-
`sm` (32 px row, 24×40 track), `md` (default, 40 px row, 28×48 track), `lg` (48 px row, 32×56 track). Unset, `size` follows `provideBfDefaults()`'s `controlSize`, `md` by default (`provideBfDefaults({ size: 'lg' })` enlarges every control of a Capacitor app; `{ size: 'sm' }` in a component's `providers` makes a dense sub-tree). Under a fine pointer the row is the hit area (32 px and up, above the 24 px of WCAG 2.5.8); under a coarse pointer (touch) `sm` and `md` rows grow to 44 px. The knob travels to the inline end, so it moves left under `dir="rtl"`.
|
|
27752
|
+
`sm` (32 px row, 24×40 track), `md` (default, 40 px row, 28×48 track), `lg` (48 px row, 32×56 track). Unset, `size` follows `provideBfDefaults()`'s `controlSize`, `md` by default (`provideBfDefaults({ size: 'lg' })` enlarges every control of a Capacitor app; `{ size: 'sm' }` in a component's `providers` makes a dense sub-tree). Under a fine pointer the row is the hit area (32 px and up, above the 24 px of WCAG 2.5.8); under a coarse pointer (touch) `sm` and `md` rows grow to 44 px, and a label-less `sm` switch (40 px wide) also takes a 44 px width, its track centred. The knob travels to the inline end, so it moves left under `dir="rtl"`.
|
|
26908
27753
|
|
|
26909
27754
|
```ts
|
|
26910
27755
|
import { Component, signal } from '@angular/core';
|
|
@@ -27097,6 +27942,14 @@ Focuses the native switch; Signal Forms calls it from `focusBoundControl()`.
|
|
|
27097
27942
|
|
|
27098
27943
|
## Migration notes
|
|
27099
27944
|
|
|
27945
|
+
### 0.4.0
|
|
27946
|
+
|
|
27947
|
+
A label-less `sm` toggle (a table cell) takes a 44 px min-width under a coarse pointer, its track
|
|
27948
|
+
centred, so its touch target is 44 × 44 px (it was 40 px wide). Nothing changes under a fine
|
|
27949
|
+
pointer or for `md` and `lg`. `@bitforgehq/ui/testing`: new `BfToggleHarness` (`with({ label })`
|
|
27950
|
+
by the switch's computed name, `getLabel()`, `isChecked()`, `isDisabled()`, `isReadonly()`,
|
|
27951
|
+
`toggle()`, `check()`, `uncheck()`, `getErrorText()`).
|
|
27952
|
+
|
|
27100
27953
|
### 0.3.0
|
|
27101
27954
|
|
|
27102
27955
|
New `ariaLabelledby` input: the id of the element that names the switch when no visible `label`
|
|
@@ -28140,7 +28993,9 @@ exposed: the heading stays a heading and the accessible name is the title alone.
|
|
|
28140
28993
|
with the nearest card or row, which then draws the pointer, the hover and, while the action has
|
|
28141
28994
|
keyboard focus, the focus ring; a card is never lit by the actions of rows nested in it. Give
|
|
28142
28995
|
secondary controls inside the surface `class="relative z-1"` so they stay clickable above the
|
|
28143
|
-
stretched area.
|
|
28996
|
+
stretched area. When the surface marks a state that belongs in the name (an `unread` list
|
|
28997
|
+
row), the directive names the element `aria-labelledby="<state id> <own id>"`, so the link reads
|
|
28998
|
+
"Unread, Account", and restores the element's own `aria-labelledby` when the state goes.
|
|
28144
28999
|
|
|
28145
29000
|
```ts
|
|
28146
29001
|
import { BfActionDirective } from '@bitforgehq/ui';
|
|
@@ -28376,6 +29231,36 @@ type BfBadgeAppearance = BfBadgeVariant | 'info'
|
|
|
28376
29231
|
|
|
28377
29232
|
---
|
|
28378
29233
|
|
|
29234
|
+
# BfBadgeEmphasis
|
|
29235
|
+
|
|
29236
|
+
The two badge emphases, the soft tint or the solid strong fill
|
|
29237
|
+
|
|
29238
|
+
Type from `@bitforgehq/ui` · since 0.4.0
|
|
29239
|
+
|
|
29240
|
+
How loud a `bf-badge` is: `soft`, a pale tint with tinted text (the default), or `strong`, a
|
|
29241
|
+
solid fill with contrasting text for the one state that must stand out, such as "Critical".
|
|
29242
|
+
|
|
29243
|
+
```ts
|
|
29244
|
+
import { type BfBadgeEmphasis } from '@bitforgehq/ui';
|
|
29245
|
+
```
|
|
29246
|
+
|
|
29247
|
+
## Signature
|
|
29248
|
+
|
|
29249
|
+
```ts
|
|
29250
|
+
type BfBadgeEmphasis = 'soft' | 'strong'
|
|
29251
|
+
```
|
|
29252
|
+
|
|
29253
|
+
## Values
|
|
29254
|
+
|
|
29255
|
+
- `soft`
|
|
29256
|
+
- `strong`
|
|
29257
|
+
|
|
29258
|
+
## Used by
|
|
29259
|
+
|
|
29260
|
+
- [bf-badge](../components/badge.md)
|
|
29261
|
+
|
|
29262
|
+
---
|
|
29263
|
+
|
|
28379
29264
|
# BfBadgeVariant
|
|
28380
29265
|
|
|
28381
29266
|
The five tones of a badge, from neutral counts to danger states
|
|
@@ -29421,6 +30306,7 @@ import { type BfLabels } from '@bitforgehq/ui';
|
|
|
29421
30306
|
| `chartValue` | `string` | `'Value'` | The value column header of a bf-donut-chart's data table. |
|
|
29422
30307
|
| `chartEmpty` | `string` | `'No data to show'` | bf-chart-card's text when it has no data and no `empty` slot. |
|
|
29423
30308
|
| `chartError` | `string` | `'The data could not be loaded'` | bf-chart-card's text when its data failed to load and it has no `error` slot. |
|
|
30309
|
+
| `listItemUnread` | `string` | `'Unread'` | bf-list-item's visually hidden state text before the title of an `unread` row. |
|
|
29424
30310
|
| `validation` | `BfValidationMessages` | required | Default error text per validator kind (see `BfValidationMessages`). |
|
|
29425
30311
|
|
|
29426
30312
|
## Uses
|
|
@@ -29982,6 +30868,37 @@ type BfStatVariant = 'plain' | 'card'
|
|
|
29982
30868
|
|
|
29983
30869
|
---
|
|
29984
30870
|
|
|
30871
|
+
# BfStepHeadingLevel
|
|
30872
|
+
|
|
30873
|
+
The heading level a step title can take, two, three or four
|
|
30874
|
+
|
|
30875
|
+
Type from `@bitforgehq/ui` · since 0.4.0
|
|
30876
|
+
|
|
30877
|
+
The heading level of a `bf-step` title, for a guide whose steps hold enough content (screenshots,
|
|
30878
|
+
code) that a screen-reader user moves between them by heading.
|
|
30879
|
+
|
|
30880
|
+
```ts
|
|
30881
|
+
import { type BfStepHeadingLevel } from '@bitforgehq/ui';
|
|
30882
|
+
```
|
|
30883
|
+
|
|
30884
|
+
## Signature
|
|
30885
|
+
|
|
30886
|
+
```ts
|
|
30887
|
+
type BfStepHeadingLevel = 2 | 3 | 4
|
|
30888
|
+
```
|
|
30889
|
+
|
|
30890
|
+
## Values
|
|
30891
|
+
|
|
30892
|
+
- `2`
|
|
30893
|
+
- `3`
|
|
30894
|
+
- `4`
|
|
30895
|
+
|
|
30896
|
+
## Used by
|
|
30897
|
+
|
|
30898
|
+
- [bf-step](../components/step.md)
|
|
30899
|
+
|
|
30900
|
+
---
|
|
30901
|
+
|
|
29985
30902
|
# BfTabBarController
|
|
29986
30903
|
|
|
29987
30904
|
The state a parent that drives a projected tab bar gives it to derive from
|
|
@@ -30116,7 +31033,7 @@ type BfTableAlign = 'start' | 'end'
|
|
|
30116
31033
|
|
|
30117
31034
|
## Used by
|
|
30118
31035
|
|
|
30119
|
-
- [
|
|
31036
|
+
- [BfTableColumnAlign](bf-table-column-align.md)
|
|
30120
31037
|
|
|
30121
31038
|
---
|
|
30122
31039
|
|
|
@@ -30191,11 +31108,11 @@ import { type BfTableColumn } from '@bitforgehq/ui';
|
|
|
30191
31108
|
| `key` | `string` | required | The row property the default cell shows; also the key a `bfTableCell` template names. |
|
|
30192
31109
|
| `label` | `string` | required | The header text. |
|
|
30193
31110
|
| `sortable` | `boolean` | `false` | Whether the header is a button that sets the table's `sort`. |
|
|
30194
|
-
| `align` | `
|
|
31111
|
+
| `align` | `BfTableColumnAlign` (`'start' \| 'end' \| 'center'`) | `'start'` | The inline alignment of the header and cells; `end` also sets tabular figures, `center` centres a cell's control (a toggle, a checkbox) in the column. |
|
|
30195
31112
|
|
|
30196
31113
|
## Uses
|
|
30197
31114
|
|
|
30198
|
-
- [
|
|
31115
|
+
- [BfTableColumnAlign](bf-table-column-align.md)
|
|
30199
31116
|
|
|
30200
31117
|
## Used by
|
|
30201
31118
|
|
|
@@ -30203,6 +31120,42 @@ import { type BfTableColumn } from '@bitforgehq/ui';
|
|
|
30203
31120
|
|
|
30204
31121
|
---
|
|
30205
31122
|
|
|
31123
|
+
# BfTableColumnAlign
|
|
31124
|
+
|
|
31125
|
+
The inline alignment of a table column: start, end, or centred for controls
|
|
31126
|
+
|
|
31127
|
+
Type from `@bitforgehq/ui` · since 0.4.0
|
|
31128
|
+
|
|
31129
|
+
Where a `bf-table` column lines up its header and cells: a `BfTableAlign`, or `center` for a
|
|
31130
|
+
column of controls such as the toggles of a settings matrix. A new type, so `Record`s over the
|
|
31131
|
+
released `BfTableAlign` keep compiling.
|
|
31132
|
+
|
|
31133
|
+
```ts
|
|
31134
|
+
import { type BfTableColumnAlign } from '@bitforgehq/ui';
|
|
31135
|
+
```
|
|
31136
|
+
|
|
31137
|
+
## Signature
|
|
31138
|
+
|
|
31139
|
+
```ts
|
|
31140
|
+
type BfTableColumnAlign = BfTableAlign | 'center'
|
|
31141
|
+
```
|
|
31142
|
+
|
|
31143
|
+
## Values
|
|
31144
|
+
|
|
31145
|
+
- `start`
|
|
31146
|
+
- `end`
|
|
31147
|
+
- `center`
|
|
31148
|
+
|
|
31149
|
+
## Uses
|
|
31150
|
+
|
|
31151
|
+
- [BfTableAlign](bf-table-align.md)
|
|
31152
|
+
|
|
31153
|
+
## Used by
|
|
31154
|
+
|
|
31155
|
+
- [BfTableColumn](bf-table-column.md)
|
|
31156
|
+
|
|
31157
|
+
---
|
|
31158
|
+
|
|
30206
31159
|
# BfTableRowKey
|
|
30207
31160
|
|
|
30208
31161
|
Function that returns the unique string key of one table row
|
|
@@ -30358,6 +31311,40 @@ with signals.
|
|
|
30358
31311
|
|
|
30359
31312
|
---
|
|
30360
31313
|
|
|
31314
|
+
# BfTimelineTone
|
|
31315
|
+
|
|
31316
|
+
The marker colour of a timeline event, neutral, primary or a status
|
|
31317
|
+
|
|
31318
|
+
Type from `@bitforgehq/ui` · since 0.4.0
|
|
31319
|
+
|
|
31320
|
+
The colour of a `bf-timeline-event`'s marker: `neutral` (the default), `primary`, or a status
|
|
31321
|
+
(`success`, `warning`, `danger`, `info`), such as danger for a failed CI run.
|
|
31322
|
+
|
|
31323
|
+
```ts
|
|
31324
|
+
import { type BfTimelineTone } from '@bitforgehq/ui';
|
|
31325
|
+
```
|
|
31326
|
+
|
|
31327
|
+
## Signature
|
|
31328
|
+
|
|
31329
|
+
```ts
|
|
31330
|
+
type BfTimelineTone = 'neutral' | 'primary' | 'success' | 'warning' | 'danger' | 'info'
|
|
31331
|
+
```
|
|
31332
|
+
|
|
31333
|
+
## Values
|
|
31334
|
+
|
|
31335
|
+
- `neutral`
|
|
31336
|
+
- `primary`
|
|
31337
|
+
- `success`
|
|
31338
|
+
- `warning`
|
|
31339
|
+
- `danger`
|
|
31340
|
+
- `info`
|
|
31341
|
+
|
|
31342
|
+
## Used by
|
|
31343
|
+
|
|
31344
|
+
- [bf-timeline-event](../components/timeline-event.md)
|
|
31345
|
+
|
|
31346
|
+
---
|
|
31347
|
+
|
|
30361
31348
|
# BfToggleLabelPosition
|
|
30362
31349
|
|
|
30363
31350
|
Whether a toggle's label sits after or before its switch
|
|
@@ -30535,7 +31522,7 @@ every string. In a component's `providers` it covers that sub-tree's widgets and
|
|
|
30535
31522
|
`dateInputUnavailable`, `timeInputHour`, `timeInputMinute`, `timeInputSecond`,
|
|
30536
31523
|
`timeInputDayPeriod`, `timeInputOpenList`, `timeInputInvalid`, `timeInputMin`, `timeInputMax`,
|
|
30537
31524
|
`chart`, `chartLegend`, `chartValues`, `chartShowData`, `chartHideData`, `chartCategory`,
|
|
30538
|
-
`chartValue`, `chartEmpty`, `chartError`, `validation`); the overlay services (`ok`, `cancel`,
|
|
31525
|
+
`chartValue`, `chartEmpty`, `chartError`, `listItemUnread`, `validation`); the overlay services (`ok`, `cancel`,
|
|
30539
31526
|
`actions`, `sheet`, `modal`, `close`, `expand`, `collapse`, `sheetPosition`, `dialog`,
|
|
30540
31527
|
`notifications`) are root singletons and pick it up only when the caller passes its injector:
|
|
30541
31528
|
`open(…, { injector: inject(Injector) })`.
|
|
@@ -37477,6 +38464,18 @@ The text of one cell.
|
|
|
37477
38464
|
| `row` | `number` | The row's position, from 0. |
|
|
37478
38465
|
| `column` | `string` | The column's header text. |
|
|
37479
38466
|
|
|
38467
|
+
### `getCellHarness<T extends ComponentHarness>(row: number, column: string, query: HarnessQuery<T>): Promise<T>`
|
|
38468
|
+
|
|
38469
|
+
A harness for a control in one cell, such as a `bf-toggle` of a settings matrix or a
|
|
38470
|
+
`bf-select` in a custom cell. Throws for an unknown row or column, or when the cell holds no
|
|
38471
|
+
matching control.
|
|
38472
|
+
|
|
38473
|
+
| Parameter | Type | Description |
|
|
38474
|
+
| --- | --- | --- |
|
|
38475
|
+
| `row` | `number` | The row's position, from 0. |
|
|
38476
|
+
| `column` | `string` | The column's header text. |
|
|
38477
|
+
| `query` | `HarnessQuery<T>` | The harness type, or a predicate from its `with()`. |
|
|
38478
|
+
|
|
37480
38479
|
### `sortBy(column: string): Promise<void>`
|
|
37481
38480
|
|
|
37482
38481
|
Clicks a sortable column's header, as a user would: ascending first, then descending.
|
|
@@ -37620,6 +38619,64 @@ time, which closes it. Throws for a time the list does not hold (off the `step`)
|
|
|
37620
38619
|
|
|
37621
38620
|
---
|
|
37622
38621
|
|
|
38622
|
+
# BfToggleHarness
|
|
38623
|
+
|
|
38624
|
+
Test harness for the toggle: reads its name and state and switches it
|
|
38625
|
+
|
|
38626
|
+
Class from `@bitforgehq/ui/testing` · since 0.4.0
|
|
38627
|
+
|
|
38628
|
+
Harness for `bf-toggle`. Its `label` filter matches the switch's name: the text of the elements
|
|
38629
|
+
`ariaLabelledby` names, else `ariaLabel`, else the visible label, so a label-less switch in a
|
|
38630
|
+
table cell or a list row is found the same way.
|
|
38631
|
+
|
|
38632
|
+
```ts
|
|
38633
|
+
import { BfToggleHarness } from '@bitforgehq/ui/testing';
|
|
38634
|
+
```
|
|
38635
|
+
|
|
38636
|
+
## Signature
|
|
38637
|
+
|
|
38638
|
+
```ts
|
|
38639
|
+
class BfToggleHarness extends ComponentHarness
|
|
38640
|
+
```
|
|
38641
|
+
|
|
38642
|
+
## Methods
|
|
38643
|
+
|
|
38644
|
+
### `getLabel(): Promise<string>`
|
|
38645
|
+
|
|
38646
|
+
The switch's name, as the browser computes it: the text of the elements `ariaLabelledby`
|
|
38647
|
+
names, else `ariaLabel`, else the visible label (the `label` text and the default slot).
|
|
38648
|
+
|
|
38649
|
+
### `isChecked(): Promise<boolean>`
|
|
38650
|
+
|
|
38651
|
+
Whether the switch is on.
|
|
38652
|
+
|
|
38653
|
+
### `isDisabled(): Promise<boolean>`
|
|
38654
|
+
|
|
38655
|
+
Whether the switch is disabled.
|
|
38656
|
+
|
|
38657
|
+
### `isReadonly(): Promise<boolean>`
|
|
38658
|
+
|
|
38659
|
+
Whether the switch is read-only (`aria-readonly`): it shows its state but a click does nothing.
|
|
38660
|
+
|
|
38661
|
+
### `toggle(): Promise<void>`
|
|
38662
|
+
|
|
38663
|
+
Clicks the switch, as a user would, so it turns on or off. Throws while it is disabled (a
|
|
38664
|
+
user's click would do nothing); a read-only switch takes the click and stays as it is.
|
|
38665
|
+
|
|
38666
|
+
### `check(): Promise<void>`
|
|
38667
|
+
|
|
38668
|
+
Turns the switch on with a click; an on switch stays on. Throws while it is disabled.
|
|
38669
|
+
|
|
38670
|
+
### `uncheck(): Promise<void>`
|
|
38671
|
+
|
|
38672
|
+
Turns the switch off with a click; an off switch stays off. Throws while it is disabled.
|
|
38673
|
+
|
|
38674
|
+
### `getErrorText(): Promise<string>`
|
|
38675
|
+
|
|
38676
|
+
The error text under the switch.
|
|
38677
|
+
|
|
38678
|
+
---
|
|
38679
|
+
|
|
37623
38680
|
# BfTooltipHarness
|
|
37624
38681
|
|
|
37625
38682
|
Test harness for a tooltip: shows it, reads its text and whether it shows
|