@bitforgehq/ui 0.3.1 → 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 +116 -0
- package/README.md +9 -8
- package/ai/MANIFEST.index.json +18 -0
- package/ai/MANIFEST.json +368 -31
- package/ai/REFERENCE.index.json +63 -0
- package/ai/REFERENCE.json +247 -5
- package/ai/UI_GUIDE.md +59 -33
- package/ai/components/app-frame.md +328 -0
- package/ai/components/card.md +56 -2
- package/ai/components/empty-state.md +99 -6
- package/ai/components/header.md +5 -1
- package/ai/components/sidebar-toggle.md +287 -0
- package/ai/components/sidebar.md +188 -10
- package/ai/components/stat.md +74 -10
- package/ai/components/table.md +134 -5
- package/ai/components/tabs.md +5 -1
- package/ai/components/toolbar.md +69 -4
- 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-empty-state-heading-level.md +1 -1
- package/ai/reference/bf-empty-state-heading.md +33 -0
- package/ai/reference/bf-labels.md +6 -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 +1 -0
- package/ai/reference/bf-stat-appearance.md +33 -0
- package/ai/reference/bf-stat-variant.md +1 -1
- package/ai/reference/bf-table-harness.md +1 -1
- package/ai/reference/bf-table-stack.md +29 -0
- package/ai/reference/bf_sidebar_state_storage.md +20 -0
- package/ai/reference/provide-bf-labels.md +4 -3
- package/ai/reference/provide-bf-sidebar-state.md +20 -0
- package/bin/bf-ui.js +433 -3
- package/fesm2022/bitforgehq-ui-overlay.mjs +571 -446
- package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui-testing.mjs +18 -2
- package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
- package/fesm2022/bitforgehq-ui.mjs +759 -127
- package/fesm2022/bitforgehq-ui.mjs.map +1 -1
- package/llms-full.txt +1560 -43
- package/llms.txt +11 -0
- package/package.json +1 -1
- package/types/bitforgehq-ui-overlay.d.ts +51 -0
- package/types/bitforgehq-ui-testing.d.ts +35 -1
- package/types/bitforgehq-ui.d.ts +276 -20
package/ai/components/stat.md
CHANGED
|
@@ -61,7 +61,7 @@ Use `bf-stat` for a few headline figures the reader should take in at a glance,
|
|
|
61
61
|
|
|
62
62
|
## Cards
|
|
63
63
|
|
|
64
|
-
`variant="card"` gives each stat its own outlined tile, the `flat` card surface. In a grid the cards stretch to the row's height, so a row of stats lines up even when one has a supporting line and another has none. Put an icon in the `icon` slot (`bfSlot="icon"`, a `bf-icon`) to show what the figure is about.
|
|
64
|
+
`variant="card"` gives each stat its own outlined tile, the `flat` card surface, for stats that sit on the page itself; inside a raised card use `tile` instead. In a grid the cards stretch to the row's height, so a row of stats lines up even when one has a supporting line and another has none. Put an icon in the `icon` slot (`bfSlot="icon"`, a `bf-icon`) to show what the figure is about.
|
|
65
65
|
|
|
66
66
|
```ts
|
|
67
67
|
import { Component } from '@angular/core';
|
|
@@ -103,6 +103,60 @@ export class StatOverviewExampleComponent {
|
|
|
103
103
|
}
|
|
104
104
|
```
|
|
105
105
|
|
|
106
|
+
## Tiles
|
|
107
|
+
|
|
108
|
+
`variant="tile"` is a sunken, borderless tile (`surface-sunken`, the `card` radius and padding) for a row of stats inside a raised [bf-card](https://bitforge-ui.web.app/components/card): a raised card holds sunken tiles, never outlined ones. On a tile the icon tile turns `surface`, so it still shows. Keep one surface style per level of a dashboard: raised cards on the page, tiles in each card.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { Component } from '@angular/core';
|
|
112
|
+
import { BfCardComponent, BfStatComponent } from '@bitforgehq/ui';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A dashboard with one surface per level.
|
|
116
|
+
*
|
|
117
|
+
* The page holds raised cards, and every card holds sunken stat tiles: each level has one surface
|
|
118
|
+
* style, so the eye reads the cards as the groups and the tiles as their figures.
|
|
119
|
+
*/
|
|
120
|
+
@Component({
|
|
121
|
+
selector: 'app-example-stat-dashboard',
|
|
122
|
+
imports: [BfCardComponent, BfStatComponent],
|
|
123
|
+
template: `
|
|
124
|
+
<div class="grid gap-4 @lg:grid-cols-2">
|
|
125
|
+
<bf-card>
|
|
126
|
+
<h3 class="text-heading">Sales</h3>
|
|
127
|
+
<div class="grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-3">
|
|
128
|
+
<bf-stat label="Revenue" value="€48,200" variant="tile" delta="+12%" trend="up">
|
|
129
|
+
vs. last month
|
|
130
|
+
</bf-stat>
|
|
131
|
+
<bf-stat label="Orders" value="1,204" variant="tile" delta="+3%" trend="up">
|
|
132
|
+
vs. last month
|
|
133
|
+
</bf-stat>
|
|
134
|
+
</div>
|
|
135
|
+
</bf-card>
|
|
136
|
+
<bf-card>
|
|
137
|
+
<h3 class="text-heading">Support</h3>
|
|
138
|
+
<div class="grid grid-cols-[repeat(auto-fit,minmax(9rem,1fr))] gap-3">
|
|
139
|
+
<bf-stat
|
|
140
|
+
label="Open tickets"
|
|
141
|
+
value="18"
|
|
142
|
+
variant="tile"
|
|
143
|
+
delta="-4"
|
|
144
|
+
trend="down"
|
|
145
|
+
trendIntent="negative"
|
|
146
|
+
>
|
|
147
|
+
vs. last week
|
|
148
|
+
</bf-stat>
|
|
149
|
+
<bf-stat label="First reply" value="2 h" variant="tile" delta="0" trend="flat">
|
|
150
|
+
vs. last week
|
|
151
|
+
</bf-stat>
|
|
152
|
+
</div>
|
|
153
|
+
</bf-card>
|
|
154
|
+
</div>
|
|
155
|
+
`,
|
|
156
|
+
})
|
|
157
|
+
export class StatDashboardExampleComponent {}
|
|
158
|
+
```
|
|
159
|
+
|
|
106
160
|
## Plain
|
|
107
161
|
|
|
108
162
|
`variant="plain"` (the default) draws no surface, for stats that sit on a card or a page section of their own. The default slot is the supporting line under the value: a short trend ("+12% this week") or a `bf-badge`.
|
|
@@ -182,8 +236,9 @@ A stat is not interactive: no hover, no pointer cursor, no focus stop. Its size
|
|
|
182
236
|
- Label (`dt`): `text-caption` in `text-muted`. Value (`dd`): `text-title` in `text`, with tabular figures (`tabular-nums`) so numbers line up across stats.
|
|
183
237
|
- Supporting line: `text-caption` in `text-muted`.
|
|
184
238
|
- Delta pill: the badge's label shape (`control` radius, `text-micro` bold, tabular figures); good changes `success-soft` with `success` text, bad ones `danger-soft` with `danger` text, flat or no trend `neutral-soft` with `neutral` text. The arrow mark is drawn with borders in `currentColor`, so it takes the pill's text colour.
|
|
185
|
-
- Icon tile: `surface-sunken` background, `text-muted` icon, `tile` radius, 40 px.
|
|
239
|
+
- Icon tile: `surface-sunken` background (`surface` on a `tile` stat), `text-muted` icon, `tile` radius, 40 px.
|
|
186
240
|
- `card`: `surface`, the `card` radius, `--spacing-card` padding (`p-card`) and a 1.5 px `border-strong` edge, as the `flat` `bf-card`.
|
|
241
|
+
- `tile`: `surface-sunken`, the `card` radius and `--spacing-card` padding, no border.
|
|
187
242
|
|
|
188
243
|
## Accessibility
|
|
189
244
|
|
|
@@ -191,14 +246,14 @@ A stat is not interactive: no hover, no pointer cursor, no focus stop. Its size
|
|
|
191
246
|
|
|
192
247
|
## Inputs
|
|
193
248
|
|
|
194
|
-
| Name | Type | Default | Description
|
|
195
|
-
| ------------- | -------------------------------------------------------------------- | ------------ |
|
|
196
|
-
| `label` | `string` | required | What the figure measures, shown above it.
|
|
197
|
-
| `value` | `string` | required | The figure, already formatted (`45 min`, `1,204`, `98%`).
|
|
198
|
-
| `variant` | `
|
|
199
|
-
| `delta` | `string` | `''` | A change shown in a pill beside the value, already formatted (`+12%`); empty shows none.
|
|
200
|
-
| `trend` | `BfStatTrend \| undefined` (`'up' \| 'down' \| 'flat' \| undefined`) | `undefined` | The delta's direction: an arrow mark and a hidden word; left unset, the pill is neutral.
|
|
201
|
-
| `trendIntent` | `BfStatTrendIntent` (`'positive' \| 'negative'`) | `'positive'` | Whether up is good (positive, default) or down is good (negative, such as costs).
|
|
249
|
+
| Name | Type | Default | Description |
|
|
250
|
+
| ------------- | -------------------------------------------------------------------- | ------------ | ----------------------------------------------------------------------------------------------- |
|
|
251
|
+
| `label` | `string` | required | What the figure measures, shown above it. |
|
|
252
|
+
| `value` | `string` | required | The figure, already formatted (`45 min`, `1,204`, `98%`). |
|
|
253
|
+
| `variant` | `BfStatAppearance` (`'plain' \| 'card' \| 'tile'`) | `'plain'` | Surface: plain (default) on its container, card (an outlined tile) or tile (sunken, no border). |
|
|
254
|
+
| `delta` | `string` | `''` | A change shown in a pill beside the value, already formatted (`+12%`); empty shows none. |
|
|
255
|
+
| `trend` | `BfStatTrend \| undefined` (`'up' \| 'down' \| 'flat' \| undefined`) | `undefined` | The delta's direction: an arrow mark and a hidden word; left unset, the pill is neutral. |
|
|
256
|
+
| `trendIntent` | `BfStatTrendIntent` (`'positive' \| 'negative'`) | `'positive'` | Whether up is good (positive, default) or down is good (negative, such as costs). |
|
|
202
257
|
|
|
203
258
|
## Slots
|
|
204
259
|
|
|
@@ -215,12 +270,21 @@ A stat is not interactive: no hover, no pointer cursor, no focus stop. Its size
|
|
|
215
270
|
|
|
216
271
|
### Don't
|
|
217
272
|
|
|
273
|
+
- Don't put `card` stats (outlined) inside a raised `bf-card`; use `tile`.
|
|
218
274
|
- Don't use a stat for a value the user edits or acts on; give it its own control.
|
|
219
275
|
- Don't put long text in `value`; it is set at the `title` size for a short figure.
|
|
220
276
|
- Don't put the comparison period in `delta`; keep it to the change (`+12%`) and say "vs. last month" in the supporting line.
|
|
221
277
|
|
|
222
278
|
## Migration notes
|
|
223
279
|
|
|
280
|
+
### 0.3.2
|
|
281
|
+
|
|
282
|
+
New `variant="tile"`: a sunken, borderless tile (`surface-sunken`, the `card` radius and
|
|
283
|
+
padding) for a row of stats inside a raised `bf-card`; on it the icon tile turns `surface`.
|
|
284
|
+
`variant` now takes the new named type `BfStatAppearance` (`BfStatVariant | 'tile'`); the
|
|
285
|
+
released `BfStatVariant` keeps its two members, so `Record`s over it keep compiling. New
|
|
286
|
+
`stat/dashboard` example with one surface per level.
|
|
287
|
+
|
|
224
288
|
### 0.3.1
|
|
225
289
|
|
|
226
290
|
New: `bf-stat`, one labelled figure in its own `dl`, with the value at the `title` size in
|
package/ai/components/table.md
CHANGED
|
@@ -103,13 +103,14 @@ export class TableOverviewExampleComponent {
|
|
|
103
103
|
|
|
104
104
|
Data table for desktop: column headers that set a sort, optional row selection with
|
|
105
105
|
checkboxes, custom cells from `bfTableCell` templates and an empty slot. It never sorts or
|
|
106
|
-
filters itself; the consumer sorts the rows in a `computed()` from `sort`.
|
|
106
|
+
filters itself; the consumer sorts the rows in a `computed()` from `sort`. With `stack` it
|
|
107
|
+
renders each row as a tile of label/value pairs in a narrow space or under touch.
|
|
107
108
|
|
|
108
109
|
A data table for desktop pages: rows of records the user compares across columns, with headers that sort, an optional checkbox column that selects rows, custom cells and an empty state. `bf-table` is data-driven: you pass `rows` and `columns`, and it never sorts or filters the rows itself. Its headers set the `sort` model and you sort the rows in a `computed()`, on the client or on the server.
|
|
109
110
|
|
|
110
111
|
## When to use
|
|
111
112
|
|
|
112
|
-
Use `bf-table` on a desktop page for records the user scans and compares column by column: tasks, invoices, members. On a phone or in the Capacitor shell use [bf-list](https://bitforge-ui.web.app/components/list) rows instead. Use a [bf-list](https://bitforge-ui.web.app/components/list) on desktop too when each record is one line of text with a status, and a description list for the fields of a single record.
|
|
113
|
+
Use `bf-table` on a desktop page for records the user scans and compares column by column: tasks, invoices, members. On a phone or in the Capacitor shell use [bf-list](https://bitforge-ui.web.app/components/list) rows instead, or let the table stack its rows into tiles with `stack` (see Stacked rows). Use a [bf-list](https://bitforge-ui.web.app/components/list) on desktop too when each record is one line of text with a status, and a description list for the fields of a single record.
|
|
113
114
|
|
|
114
115
|
## Columns and rows
|
|
115
116
|
|
|
@@ -400,9 +401,115 @@ export class TablePagedExampleComponent {
|
|
|
400
401
|
|
|
401
402
|
`size` sets the row height: `sm` 40 px, `md` 48 px (default), `lg` 56 px, with a 32, 40 or 48 px header. Unset, it follows `provideBfDefaults()`'s `controlSize`, so `{ size: 'sm' }` in a page's `providers` makes a dense table. The checkboxes take the same step. Under a coarse pointer every row is at least 44 px tall, and the sortable header buttons are 44 px targets; a cell grows to fit its content and is never covered by a hit-area extension.
|
|
402
403
|
|
|
404
|
+
## Stacked rows
|
|
405
|
+
|
|
406
|
+
`stack` lets the table itself fit a narrow space. With `stack="narrow"` it stacks while the table is narrower than 36rem (576 px at the default root size, Tailwind's `xl` container size): a container query on the table's own width, so a table in a narrow column or a side panel stacks even on a wide screen. The host is then a size container (`container-type: inline-size`), so give the table its width from its parent (a block or `w-full` / `flex-1`), not from its columns. With `stack="coarse"` it stacks under a coarse pointer at any width (phones, tablets, the Capacitor shell). The default `never` keeps the table as it is.
|
|
407
|
+
|
|
408
|
+
Stacked, each row is a sunken tile (`surface-sunken`, `rounded-tile`, the tile a raised card holds; a selected row keeps `primary-soft`). Its checkbox and first cell head the tile in bold; every other cell shows its column label at the start and its value at the end. The header row is visually hidden, and a bar above the tiles holds a labelled Select all checkbox (with `selectable`) and a Sort by select of every sortable column, ascending and descending (`tableSortBy`, `tableSortAscending`, `tableSortDescending` labels), since the hidden header's buttons are not shown. Choosing an option sets `sort`, as a header click does.
|
|
409
|
+
|
|
410
|
+
```ts
|
|
411
|
+
import { Component, computed, signal } from '@angular/core';
|
|
412
|
+
import {
|
|
413
|
+
BfBadgeComponent,
|
|
414
|
+
BfSegmentedComponent,
|
|
415
|
+
BfTableCellDirective,
|
|
416
|
+
BfTableComponent,
|
|
417
|
+
type BfSegmentOption,
|
|
418
|
+
type BfTableColumn,
|
|
419
|
+
type BfTableSort,
|
|
420
|
+
} from '@bitforgehq/ui';
|
|
421
|
+
|
|
422
|
+
interface Task {
|
|
423
|
+
id: string;
|
|
424
|
+
title: string;
|
|
425
|
+
project: string;
|
|
426
|
+
status: 'Open' | 'Done';
|
|
427
|
+
hours: number;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const TASKS: readonly Task[] = [
|
|
431
|
+
{ id: 'brief', title: 'Write the brief', project: 'Atlas', status: 'Done', hours: 3 },
|
|
432
|
+
{ id: 'moodboard', title: 'Bloom moodboard', project: 'Bloom', status: 'Open', hours: 6 },
|
|
433
|
+
{ id: 'deck', title: 'Pitch deck', project: 'Atlas', status: 'Open', hours: 9 },
|
|
434
|
+
];
|
|
435
|
+
|
|
436
|
+
type Width = 'phone' | 'full';
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Stacked rows on a narrow table.
|
|
440
|
+
*
|
|
441
|
+
* `stack="narrow"` turns each row into a tile of label/value pairs while the table is narrower
|
|
442
|
+
* than 36rem: the selection checkbox and the first cell head the tile, and a bar above the tiles
|
|
443
|
+
* holds Select all and a Sort by select. Switch the box between phone width and full width.
|
|
444
|
+
*/
|
|
445
|
+
@Component({
|
|
446
|
+
selector: 'app-example-table-stacked',
|
|
447
|
+
imports: [BfTableComponent, BfTableCellDirective, BfBadgeComponent, BfSegmentedComponent],
|
|
448
|
+
template: `
|
|
449
|
+
<!-- A stacking table is a size container: its width comes from its parent, never its columns. -->
|
|
450
|
+
<div class="flex w-152 max-w-full flex-col gap-3">
|
|
451
|
+
<bf-segmented label="Box width" [options]="widths" [(value)]="width" />
|
|
452
|
+
<div [class]="width() === 'phone' ? 'w-full max-w-sm' : 'w-full'">
|
|
453
|
+
<bf-table
|
|
454
|
+
label="Stacked tasks"
|
|
455
|
+
stack="narrow"
|
|
456
|
+
selectable
|
|
457
|
+
[rows]="rows()"
|
|
458
|
+
[columns]="columns"
|
|
459
|
+
[(sort)]="sort"
|
|
460
|
+
[(selection)]="selection"
|
|
461
|
+
>
|
|
462
|
+
<ng-template bfTableCell="status" [bfTableCellOf]="rows()" let-task>
|
|
463
|
+
<bf-badge [variant]="task.status === 'Done' ? 'success' : 'neutral'">
|
|
464
|
+
{{ task.status }}
|
|
465
|
+
</bf-badge>
|
|
466
|
+
</ng-template>
|
|
467
|
+
</bf-table>
|
|
468
|
+
</div>
|
|
469
|
+
<p data-status aria-live="polite" class="text-caption text-text-muted">{{ status() }}</p>
|
|
470
|
+
</div>
|
|
471
|
+
`,
|
|
472
|
+
})
|
|
473
|
+
export class TableStackedExampleComponent {
|
|
474
|
+
readonly widths: BfSegmentOption<Width>[] = [
|
|
475
|
+
{ value: 'phone', label: 'Phone' },
|
|
476
|
+
{ value: 'full', label: 'Full width' },
|
|
477
|
+
];
|
|
478
|
+
readonly width = signal<Width | null>('phone');
|
|
479
|
+
readonly columns: readonly BfTableColumn[] = [
|
|
480
|
+
{ key: 'title', label: 'Task', sortable: true },
|
|
481
|
+
{ key: 'project', label: 'Project' },
|
|
482
|
+
{ key: 'status', label: 'Status' },
|
|
483
|
+
{ key: 'hours', label: 'Hours', sortable: true, align: 'end' },
|
|
484
|
+
];
|
|
485
|
+
readonly sort = signal<BfTableSort | null>(null);
|
|
486
|
+
readonly selection = signal<readonly string[]>([]);
|
|
487
|
+
|
|
488
|
+
/** The table never sorts: the page sorts its rows from `sort`. */
|
|
489
|
+
readonly rows = computed(() => {
|
|
490
|
+
const sort = this.sort();
|
|
491
|
+
if (!sort) {
|
|
492
|
+
return TASKS;
|
|
493
|
+
}
|
|
494
|
+
const factor = sort.direction === 'ascending' ? 1 : -1;
|
|
495
|
+
return [...TASKS].sort((a, b) =>
|
|
496
|
+
sort.column === 'hours'
|
|
497
|
+
? (a.hours - b.hours) * factor
|
|
498
|
+
: a.title.localeCompare(b.title) * factor,
|
|
499
|
+
);
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
readonly status = computed(() => {
|
|
503
|
+
const sort = this.sort();
|
|
504
|
+
const sorted = sort ? `Sorted by ${sort.column}, ${sort.direction}` : 'Unsorted';
|
|
505
|
+
return `${sorted} · ${this.selection().length} selected.`;
|
|
506
|
+
});
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
403
510
|
## Narrow screens and touch
|
|
404
511
|
|
|
405
|
-
A table needs width.
|
|
512
|
+
A table needs width. When stacked tiles are not what a phone should show (long records, a summary per row), render the same rows as a divided `bf-list` of `bf-list-item`s below the `md` breakpoint (a `md:hidden` wrapper) and the table only from `md` up (a `hidden md:block` wrapper), from the one `rows` array. Inside the Capacitor shell use the list alone, or a table with `stack="coarse"`. The table's wrapper scrolls sideways when its columns cannot fit, but that is a last resort, not a layout for phones.
|
|
406
513
|
|
|
407
514
|
```ts
|
|
408
515
|
import { Component } from '@angular/core';
|
|
@@ -471,6 +578,7 @@ A selectable table tints a row `surface-muted` while hovered (a selected row `pr
|
|
|
471
578
|
- Rows: `text` on the page's surface, divided by `border` lines; hover (selectable only) `surface-muted`; selected `primary-soft`, hover `primary-soft-hover`.
|
|
472
579
|
- Sort arrow: a 1.5 px CSS chevron in the header's text colour.
|
|
473
580
|
- Focus ring: `ring`. Header buttons: `rounded-field`.
|
|
581
|
+
- Stacked rows: tiles on `surface-sunken` with `rounded-tile`, labels `text-label-xs` bold in `text-muted`.
|
|
474
582
|
- Text: `text-body` (`text-label-sm` at `sm`), `tabular-nums` in `end` columns.
|
|
475
583
|
|
|
476
584
|
Put the table on a `bf-card` (or another surface) yourself; it has no background or border of its own.
|
|
@@ -479,6 +587,8 @@ Put the table on a `bf-card` (or another surface) yourself; it has no background
|
|
|
479
587
|
|
|
480
588
|
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.
|
|
481
589
|
|
|
590
|
+
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) / ""`), so a screen reader reads the column header once, not the label as well.
|
|
591
|
+
|
|
482
592
|
### Keyboard
|
|
483
593
|
|
|
484
594
|
| Key | Action |
|
|
@@ -489,6 +599,8 @@ A native `table` with a visually hidden `caption` from `label`, `th scope="col"`
|
|
|
489
599
|
| <kbd>Space</kbd> | Toggles the focused checkbox, or sorts by the focused header |
|
|
490
600
|
| <kbd>Enter</kbd> | Sorts by the focused header |
|
|
491
601
|
|
|
602
|
+
A stacked table's Sort by select is a native select with its own keys.
|
|
603
|
+
|
|
492
604
|
Text fields, selects and composite widgets (radios, comboboxes, sliders) in a cell keep their own arrow keys.
|
|
493
605
|
|
|
494
606
|
## Inputs
|
|
@@ -502,6 +614,7 @@ Text fields, selects and composite widgets (radios, comboboxes, sliders) in a ce
|
|
|
502
614
|
| `selectable` | `boolean` | `false` | Adds a first column of checkboxes that select rows. |
|
|
503
615
|
| `selectAllLabel` | `string` | `''` | Accessible name of the header checkbox; empty falls back to `provideBfLabels()`'s `tableSelectAll` ("Select all rows"). |
|
|
504
616
|
| `size` | `BfSize \| undefined` (`'sm' \| 'md' \| 'lg' \| undefined`) | `undefined` | Row height step: sm 40, md 48, lg 56 px (the header 32/40/48; at least 44 px under a coarse pointer); unset follows `provideBfDefaults()` (`controlSize`, `md` by default). |
|
|
617
|
+
| `stack` | `BfTableStack` (`'never' \| 'narrow' \| 'coarse'`) | `'never'` | When the rows render as cards of label/value pairs: `never`, `narrow` (the table is narrower than 36rem) or `coarse` (under a coarse pointer, at any width). |
|
|
505
618
|
| `sort` | `BfTableSort \| null` | `null` | The sorted column and direction, `null` while unsorted; two-way bindable. A sortable header sets it, and the consumer sorts `rows` from it. Two-way: `[(sort)]`. |
|
|
506
619
|
| `selection` | `readonly string[]` | `[]` | The keys (`rowKey`) of the selected rows; two-way bindable. Two-way: `[(selection)]`. |
|
|
507
620
|
|
|
@@ -542,15 +655,31 @@ Selects or clears one row.
|
|
|
542
655
|
|
|
543
656
|
- Give every table a `label`, and every sortable column a short header.
|
|
544
657
|
- Sort and filter the rows in a `computed()` from `sort` and your filters.
|
|
545
|
-
-
|
|
658
|
+
- 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`.
|
|
546
659
|
|
|
547
660
|
### Don't
|
|
548
661
|
|
|
549
|
-
- Don't put a table on a phone screen that scrolls sideways; use the list.
|
|
662
|
+
- Don't put a table on a phone screen that scrolls sideways; stack it or use the list.
|
|
663
|
+
- Don't put a stacking table in a parent that sizes it from its content: the container query needs a width from outside.
|
|
550
664
|
- Don't make a whole row clickable; put a link or button in a custom cell.
|
|
551
665
|
|
|
552
666
|
## Migration notes
|
|
553
667
|
|
|
668
|
+
### 0.3.2
|
|
669
|
+
|
|
670
|
+
New opt-in `stack` input (`BfTableStack`: `'never'` by default, so existing tables do not
|
|
671
|
+
change, `'narrow'` or `'coarse'`): while the table is narrower than 36rem (a container query on
|
|
672
|
+
the host, which then gets `@container`) or, for `'coarse'`, under a coarse pointer at any width,
|
|
673
|
+
each body row renders as a sunken tile of label/value pairs. The markup stays a `table` with
|
|
674
|
+
explicit `table`, `rowgroup`, `row`, `columnheader` and `cell` roles (some browsers drop a
|
|
675
|
+
table's semantics once its display changes), the header row is visually hidden but still read,
|
|
676
|
+
the selection checkbox and the first cell head each tile, and every other cell shows its column
|
|
677
|
+
label (`data-label`, a `::before` with empty alternative text, so it is not read twice). A bar
|
|
678
|
+
above the tiles holds a labelled Select all checkbox and a Sort by `bf-select`, since the hidden
|
|
679
|
+
header's controls are not shown. New label keys `tableSortBy` ("Sort by"), `tableSortAscending`
|
|
680
|
+
and `tableSortDescending` (`"Hours, ascending"`). `BfTableHarness` reads and drives a stacked
|
|
681
|
+
table the same way. New `table/stacked` example and a Stacked rows docs section.
|
|
682
|
+
|
|
554
683
|
### 0.3.1
|
|
555
684
|
|
|
556
685
|
New `bf-table` and `ng-template[bfTableCell]` (`BfTableCellDirective`) in `@bitforgehq/ui`, a
|
package/ai/components/tabs.md
CHANGED
|
@@ -194,7 +194,7 @@ fires no keyboard event).
|
|
|
194
194
|
|
|
195
195
|
## Desktop
|
|
196
196
|
|
|
197
|
-
`bf-tabs` is part of the Capacitor shell (`provideBfShell()`). On a desktop web app, put the top-level destinations in a [bf-top-nav](https://bitforge-ui.web.app/components/top-nav) (a few sections) or a [bf-sidebar](https://bitforge-ui.web.app/components/sidebar) (more, in groups, collapsible to an icon rail) of `a[bfNavItem]` links, each with `routerLink`, `routerLinkActive` and `ariaCurrentWhenActive="page"`, above a plain `router-outlet`. The router sets `aria-current="page"` on the link of the current route and the item shows it. Drive both from one array of destinations: inside the shell the same array feeds the `bf-tab`s of a [bf-tab-bar](https://bitforge-ui.web.app/components/tab-bar), and below a breakpoint a [bf-menu-button](https://bitforge-ui.web.app/components/menu-button) of `a[bfMenuItem]` links (see bf-sidebar, Responsive). Inside the shell under a mouse, the tab links take the `bf-tab` hover and focus styles.
|
|
197
|
+
`bf-tabs` is part of the Capacitor shell (`provideBfShell()`). On a desktop web app, put the top-level destinations in a [bf-top-nav](https://bitforge-ui.web.app/components/top-nav) (a few sections) or a [bf-sidebar](https://bitforge-ui.web.app/components/sidebar) (more, in groups, collapsible to an icon rail) of `a[bfNavItem]` links, each with `routerLink`, `routerLinkActive` and `ariaCurrentWhenActive="page"`, above a plain `router-outlet`. The router sets `aria-current="page"` on the link of the current route and the item shows it. Drive both from one array of destinations: inside the shell the same array feeds the `bf-tab`s of a [bf-tab-bar](https://bitforge-ui.web.app/components/tab-bar), and below a breakpoint a [bf-menu-button](https://bitforge-ui.web.app/components/menu-button) of `a[bfMenuItem]` links (see bf-sidebar, Responsive). Wrap the desktop app in a [bf-app-frame](https://bitforge-ui.web.app/components/app-frame): it holds the sidebar from `md` up and, below it, a header bar with that menu button. Inside the shell under a mouse, the tab links take the `bf-tab` hover and focus styles.
|
|
198
198
|
|
|
199
199
|
```ts
|
|
200
200
|
import { Component } from '@angular/core';
|
|
@@ -365,6 +365,10 @@ content to the top.
|
|
|
365
365
|
|
|
366
366
|
## Migration notes
|
|
367
367
|
|
|
368
|
+
### 0.3.2
|
|
369
|
+
|
|
370
|
+
The `## Desktop` docs point at `bf-app-frame` for the frame around the desktop navigation.
|
|
371
|
+
|
|
368
372
|
### 0.3.1
|
|
369
373
|
|
|
370
374
|
The `## Desktop` docs name the desktop replacement: a `bf-top-nav` or `bf-sidebar` of
|
package/ai/components/toolbar.md
CHANGED
|
@@ -187,7 +187,7 @@ export class ToolbarStatusExampleComponent {
|
|
|
187
187
|
|
|
188
188
|
## Wrapping
|
|
189
189
|
|
|
190
|
-
The row is a wrapping flex row with an 8 px gap between items and between rows.
|
|
190
|
+
The row is a wrapping flex row with an 8 px gap between items and between rows. The status and the actions are one group that takes the rest of the last row: on a wide row the status follows the view switch and the actions sit at the inline end; when the group no longer fits beside the filters, it wraps onto a row of its own as a whole, with the status at the start and the actions at the end. So the actions never end up alone on a row, and they stay on the last filter row whenever the group fits there. Give a search field a width (`class="w-full sm:w-56"`) so it fills a phone-wide row and stays compact on a wide one.
|
|
191
191
|
|
|
192
192
|
```ts
|
|
193
193
|
import { Component } from '@angular/core';
|
|
@@ -202,8 +202,8 @@ import {
|
|
|
202
202
|
/**
|
|
203
203
|
* A toolbar that wraps.
|
|
204
204
|
*
|
|
205
|
-
* In a narrow column the filters wrap onto new rows 8 px apart, and the
|
|
206
|
-
* together,
|
|
205
|
+
* In a narrow column the filters wrap onto new rows 8 px apart, and the status and the actions
|
|
206
|
+
* move down together: the count at the start of the last row, the actions at the inline end.
|
|
207
207
|
*/
|
|
208
208
|
@Component({
|
|
209
209
|
selector: 'app-example-toolbar-wrapping',
|
|
@@ -232,6 +232,63 @@ export class ToolbarWrappingExampleComponent {
|
|
|
232
232
|
}
|
|
233
233
|
```
|
|
234
234
|
|
|
235
|
+
## Phone width
|
|
236
|
+
|
|
237
|
+
At phone width (in a desktop web app's narrow window or a narrow column) the search takes a row, the filters share the next, and the status and actions share the last row. A toolbar without actions keeps the status as a plain item after the filters.
|
|
238
|
+
|
|
239
|
+
```ts
|
|
240
|
+
import { Component, signal } from '@angular/core';
|
|
241
|
+
import {
|
|
242
|
+
BfButtonComponent,
|
|
243
|
+
BfInputComponent,
|
|
244
|
+
BfSelectComponent,
|
|
245
|
+
BfToolbarComponent,
|
|
246
|
+
type BfSelectOption,
|
|
247
|
+
} from '@bitforgehq/ui';
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* A toolbar at phone width.
|
|
251
|
+
*
|
|
252
|
+
* In a phone-wide column the search fills its own row, the two filters share the next one, and
|
|
253
|
+
* the status and the Refresh action share the last row: the count at the start, the action at the
|
|
254
|
+
* end, never alone on a row of its own.
|
|
255
|
+
*/
|
|
256
|
+
@Component({
|
|
257
|
+
selector: 'app-example-toolbar-narrow',
|
|
258
|
+
imports: [BfButtonComponent, BfInputComponent, BfSelectComponent, BfToolbarComponent],
|
|
259
|
+
template: `
|
|
260
|
+
<div class="max-w-xs">
|
|
261
|
+
<bf-toolbar label="Order filters" [status]="count()">
|
|
262
|
+
<bf-input
|
|
263
|
+
type="search"
|
|
264
|
+
ariaLabel="Search orders"
|
|
265
|
+
placeholder="Search orders"
|
|
266
|
+
class="w-full"
|
|
267
|
+
/>
|
|
268
|
+
<bf-select ariaLabel="Status" [options]="statuses" value="open" />
|
|
269
|
+
<bf-select ariaLabel="Period" [options]="periods" value="week" />
|
|
270
|
+
<bf-button bfSlot="actions" variant="outline" (clicked)="refresh()">Refresh</bf-button>
|
|
271
|
+
</bf-toolbar>
|
|
272
|
+
</div>
|
|
273
|
+
`,
|
|
274
|
+
})
|
|
275
|
+
export class ToolbarNarrowExampleComponent {
|
|
276
|
+
protected readonly count = signal('12 orders');
|
|
277
|
+
protected readonly statuses: BfSelectOption[] = [
|
|
278
|
+
{ value: 'open', label: 'Open' },
|
|
279
|
+
{ value: 'shipped', label: 'Shipped' },
|
|
280
|
+
];
|
|
281
|
+
protected readonly periods: BfSelectOption[] = [
|
|
282
|
+
{ value: 'week', label: 'This week' },
|
|
283
|
+
{ value: 'month', label: 'This month' },
|
|
284
|
+
];
|
|
285
|
+
|
|
286
|
+
protected refresh(): void {
|
|
287
|
+
this.count.set('12 orders, updated');
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
```
|
|
291
|
+
|
|
235
292
|
## Desktop
|
|
236
293
|
|
|
237
294
|
`bf-toolbar` is a desktop pattern. Every control and field projected into it resolves its unset `size` to `sm` (32 px tall), because its `providers` set `provideBfDefaults({ size: 'sm' })` for its content; a control that sets `size` itself keeps it, and nothing outside the toolbar changes ([density guide](https://bitforge-ui.web.app/density)). Hover, the pointer cursor and the `focus-visible` ring come from each control; the row adds none of its own. Under a fine pointer each control's visual box is its hit area; under a coarse pointer the `sm` touch extensions reach up to 7.5 px past the visual edge, which the 8 px gap keeps off the neighbouring row.
|
|
@@ -262,7 +319,7 @@ The `status` element is `role="status"` (an `aria-live="polite"` region), always
|
|
|
262
319
|
|
|
263
320
|
- `default`: The search field and the filters (bf-input, bf-select, bf-chip-group), in order.
|
|
264
321
|
- `view`: A view switch after the filters, such as a bf-segmented of list and grid.
|
|
265
|
-
- `actions`: The trailing actions, kept together at the inline end of the row.
|
|
322
|
+
- `actions`: The trailing actions, kept together at the inline end of the row, beside the status.
|
|
266
323
|
|
|
267
324
|
## Notes
|
|
268
325
|
|
|
@@ -278,6 +335,14 @@ The `status` element is `role="status"` (an `aria-live="polite"` region), always
|
|
|
278
335
|
|
|
279
336
|
## Migration notes
|
|
280
337
|
|
|
338
|
+
### 0.3.2
|
|
339
|
+
|
|
340
|
+
On a narrow row the actions no longer end up alone on a row of their own: the status and the
|
|
341
|
+
actions are now one group that takes the rest of the last row and wraps as a whole, with the
|
|
342
|
+
status at the start and the actions at the inline end. The wide layout is unchanged, and a
|
|
343
|
+
toolbar without actions keeps the status as a plain item of the row. New `toolbar/narrow`
|
|
344
|
+
example at phone width.
|
|
345
|
+
|
|
281
346
|
### 0.3.1
|
|
282
347
|
|
|
283
348
|
New `bf-toolbar` in `@bitforgehq/ui`: a wrapping `role="group"` row for the search field and
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# BfAppFrameBreakpoint
|
|
2
|
+
|
|
3
|
+
The breakpoint where an app frame switches from its header bar to the sidebar
|
|
4
|
+
|
|
5
|
+
Type from `@bitforgehq/ui` · since 0.3.2
|
|
6
|
+
|
|
7
|
+
The viewport width from which `bf-app-frame` shows its sidebar column instead of the narrow
|
|
8
|
+
header bar: Tailwind's `md` (768 px) or `lg` (1024 px).
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { type BfAppFrameBreakpoint } from '@bitforgehq/ui';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Signature
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
type BfAppFrameBreakpoint = 'md' | 'lg'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Values
|
|
21
|
+
|
|
22
|
+
- `md`
|
|
23
|
+
- `lg`
|
|
24
|
+
|
|
25
|
+
## Used by
|
|
26
|
+
|
|
27
|
+
- [bf-app-frame](../components/app-frame.md)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# BfAppFrameContentWidth
|
|
2
|
+
|
|
3
|
+
The maximum width of an app frame's content column, from medium to full
|
|
4
|
+
|
|
5
|
+
Type from `@bitforgehq/ui` · since 0.3.2
|
|
6
|
+
|
|
7
|
+
The maximum width of `bf-app-frame`'s content column: `md` 48rem, `lg` 64rem, `xl` 80rem, or
|
|
8
|
+
`full` for no limit.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { type BfAppFrameContentWidth } from '@bitforgehq/ui';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Signature
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
type BfAppFrameContentWidth = 'md' | 'lg' | 'xl' | 'full'
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Values
|
|
21
|
+
|
|
22
|
+
- `md`
|
|
23
|
+
- `lg`
|
|
24
|
+
- `xl`
|
|
25
|
+
- `full`
|
|
26
|
+
|
|
27
|
+
## Used by
|
|
28
|
+
|
|
29
|
+
- [bf-app-frame](../components/app-frame.md)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# BfEmptyStateHeading
|
|
2
|
+
|
|
3
|
+
The heading level of an empty state title, one for a whole page
|
|
4
|
+
|
|
5
|
+
Type from `@bitforgehq/ui` · since 0.3.2
|
|
6
|
+
|
|
7
|
+
The heading level a `bf-empty-state` title takes: a `BfEmptyStateHeadingLevel`, or `1` when the
|
|
8
|
+
empty state is the page itself (a not-found or no-access page). A new type, so `Record`s over
|
|
9
|
+
the released `BfEmptyStateHeadingLevel` keep compiling.
|
|
10
|
+
|
|
11
|
+
```ts
|
|
12
|
+
import { type BfEmptyStateHeading } from '@bitforgehq/ui';
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Signature
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
type BfEmptyStateHeading = BfEmptyStateHeadingLevel | 1
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Values
|
|
22
|
+
|
|
23
|
+
- `2`
|
|
24
|
+
- `3`
|
|
25
|
+
- `1`
|
|
26
|
+
|
|
27
|
+
## Uses
|
|
28
|
+
|
|
29
|
+
- [BfEmptyStateHeadingLevel](bf-empty-state-heading-level.md)
|
|
30
|
+
|
|
31
|
+
## Used by
|
|
32
|
+
|
|
33
|
+
- [bf-empty-state](../components/empty-state.md)
|
|
@@ -32,6 +32,9 @@ import { type BfLabels } from '@bitforgehq/ui';
|
|
|
32
32
|
| `dialog` | `string` | `'Dialog'` | A dialog's or side panel's name without an ariaLabel, a title or a heading. |
|
|
33
33
|
| `notifications` | `string` | `'Notifications'` | The desktop toast stack's region name. |
|
|
34
34
|
| `tableSelectAll` | `string` | `'Select all rows'` | bf-table's header checkbox, which selects or clears every row. |
|
|
35
|
+
| `tableSortBy` | `string` | `'Sort by'` | The label of a stacked bf-table's sort select. |
|
|
36
|
+
| `tableSortAscending` | `(column: string) => string` | `` (column) => `${column}, ascending` `` | A stacked bf-table's sort option for a column in ascending order. |
|
|
37
|
+
| `tableSortDescending` | `(column: string) => string` | `` (column) => `${column}, descending` `` | A stacked bf-table's sort option for a column in descending order. |
|
|
35
38
|
| `theme` | `string` | `'Theme'` | bf-theme-switch's and bf-theme-menu-button's name without a label. |
|
|
36
39
|
| `themeSystem` | `string` | `'System'` | The theme choice that follows the system's colour scheme. |
|
|
37
40
|
| `themeLight` | `string` | `'Light'` | The theme choice that forces the light colour scheme. |
|
|
@@ -40,6 +43,9 @@ import { type BfLabels } from '@bitforgehq/ui';
|
|
|
40
43
|
| `breadcrumbExpand` | `(count: number) => string` | ``(count) => (count === 1 ? 'Show 1 more level' : `Show ${count} more levels`)`` | bf-breadcrumb's ellipsis button, which shows the levels a `maxItems` trail hides. |
|
|
41
44
|
| `navigation` | `string` | `'Main'` | bf-sidebar's and bf-top-nav's navigation name. |
|
|
42
45
|
| `navBadge` | `(count: number) => string` | `` (count) => `${count} new` `` | a[bfNavItem]'s announcement of its count badge. |
|
|
46
|
+
| `sidebarCollapse` | `string` | `'Collapse sidebar'` | bf-sidebar-toggle's name and tooltip while the sidebar is expanded. |
|
|
47
|
+
| `sidebarExpand` | `string` | `'Expand sidebar'` | bf-sidebar-toggle's name and tooltip while the sidebar is an icon rail. |
|
|
48
|
+
| `skipToContent` | `string` | `'Skip to main content'` | bf-app-frame's skip link, the first stop of the tab order, which moves focus to the content. |
|
|
43
49
|
| `pagination` | `string` | `'Pagination'` | bf-pagination's navigation name. |
|
|
44
50
|
| `previousPage` | `string` | `'Previous page'` | bf-pagination's button to the previous page. |
|
|
45
51
|
| `nextPage` | `string` | `'Next page'` | bf-pagination's button to the next page. |
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# BfSidebarStateService
|
|
2
|
+
|
|
3
|
+
The sidebar's collapsed state, kept in storage between visits of the app
|
|
4
|
+
|
|
5
|
+
Service from `@bitforgehq/ui` · since 0.3.2
|
|
6
|
+
|
|
7
|
+
Whether the app's `bf-sidebar` is collapsed to an icon rail, remembered between visits: the app
|
|
8
|
+
binds the sidebar's `[(collapsed)]` to `sidebarState.collapsed`. With `provideBfSidebarState()`
|
|
9
|
+
every change is stored in `BF_SIDEBAR_STATE_STORAGE` under `bf-sidebar-collapsed`; without it
|
|
10
|
+
the signal still holds the state but nothing is written. Storage is read in the browser only, so a
|
|
11
|
+
server render starts expanded and writes nothing. The widgets never inject it.
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { BfSidebarStateService } from '@bitforgehq/ui';
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Properties
|
|
18
|
+
|
|
19
|
+
| Name | Type | Default | Description |
|
|
20
|
+
| ----------- | ------------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
21
|
+
| `collapsed` | `WritableSignal<boolean>` | | Whether the sidebar is collapsed: the stored state in the browser, else false. Bind it two-way to `bf-sidebar`'s `collapsed`. |
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# BfSidebarToggleHarness
|
|
2
|
+
|
|
3
|
+
Test harness for a sidebar toggle: reads and flips the collapsed sidebar
|
|
4
|
+
|
|
5
|
+
Class from `@bitforgehq/ui/testing` · since 0.3.2
|
|
6
|
+
|
|
7
|
+
Harness for `bf-sidebar-toggle`, the button that collapses a `bf-sidebar` to an icon rail. Its
|
|
8
|
+
`label` filter matches the button's name ("Collapse sidebar" or "Expand sidebar").
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import { BfSidebarToggleHarness } from '@bitforgehq/ui/testing';
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Signature
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
class BfSidebarToggleHarness extends ComponentHarness
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Methods
|
|
21
|
+
|
|
22
|
+
### `getLabel(): Promise<string>`
|
|
23
|
+
|
|
24
|
+
The button's name, which says what the next press does.
|
|
25
|
+
|
|
26
|
+
### `isExpanded(): Promise<boolean>`
|
|
27
|
+
|
|
28
|
+
Whether the sidebar is at full width (`aria-expanded`).
|
|
29
|
+
|
|
30
|
+
### `toggle(): Promise<void>`
|
|
31
|
+
|
|
32
|
+
Flips the sidebar with a click.
|