@bitforgehq/ui 0.3.0 → 0.3.1

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.
Files changed (144) hide show
  1. package/CHANGELOG.md +482 -0
  2. package/README.md +17 -11
  3. package/ai/MANIFEST.index.json +288 -0
  4. package/ai/MANIFEST.json +8716 -3926
  5. package/ai/REFERENCE.index.json +413 -0
  6. package/ai/REFERENCE.json +4710 -2047
  7. package/ai/UI_GUIDE.md +185 -57
  8. package/ai/components/back-button.md +42 -2
  9. package/ai/components/badge.md +17 -7
  10. package/ai/components/bar-chart.md +188 -0
  11. package/ai/components/breadcrumb-item.md +121 -0
  12. package/ai/components/breadcrumb.md +277 -0
  13. package/ai/components/button.md +82 -15
  14. package/ai/components/calendar.md +300 -0
  15. package/ai/components/card.md +63 -2
  16. package/ai/components/chart-card.md +283 -0
  17. package/ai/components/combobox.md +411 -0
  18. package/ai/components/date-input.md +396 -0
  19. package/ai/components/datetime-input.md +215 -0
  20. package/ai/components/description-item.md +111 -0
  21. package/ai/components/description-list.md +160 -0
  22. package/ai/components/donut-chart.md +169 -0
  23. package/ai/components/header.md +67 -2
  24. package/ai/components/icon-button.md +74 -16
  25. package/ai/components/icon.md +63 -7
  26. package/ai/components/line-chart.md +234 -0
  27. package/ai/components/list.md +70 -6
  28. package/ai/components/menu.md +5 -0
  29. package/ai/components/multi-combobox.md +257 -0
  30. package/ai/components/nav-group.md +178 -0
  31. package/ai/components/nav-item.md +210 -0
  32. package/ai/components/page-header.md +237 -0
  33. package/ai/components/pagination.md +173 -0
  34. package/ai/components/popover.md +250 -0
  35. package/ai/components/side-panel.md +391 -0
  36. package/ai/components/sidebar.md +363 -0
  37. package/ai/components/skeleton.md +215 -0
  38. package/ai/components/sparkline.md +188 -0
  39. package/ai/components/stat.md +233 -0
  40. package/ai/components/tab-group.md +226 -0
  41. package/ai/components/tab-panel.md +163 -0
  42. package/ai/components/table.md +568 -0
  43. package/ai/components/tabs.md +42 -2
  44. package/ai/components/theme-menu-button.md +182 -0
  45. package/ai/components/theme-switch.md +170 -0
  46. package/ai/components/time-input.md +240 -0
  47. package/ai/components/toolbar.md +289 -0
  48. package/ai/components/tooltip.md +230 -0
  49. package/ai/components/top-nav.md +159 -0
  50. package/ai/reference/bf-badge-appearance.md +36 -0
  51. package/ai/reference/bf-badge-variant.md +1 -1
  52. package/ai/reference/bf-bar-chart-orientation.md +27 -0
  53. package/ai/reference/bf-button-appearance.md +36 -0
  54. package/ai/reference/bf-button-variant.md +1 -1
  55. package/ai/reference/bf-calendar-disabled-date.md +23 -0
  56. package/ai/reference/bf-calendar-harness.md +51 -0
  57. package/ai/reference/bf-calendar-weekday.md +31 -0
  58. package/ai/reference/bf-chart-card-heading-level.md +26 -0
  59. package/ai/reference/bf-chart-curve.md +28 -0
  60. package/ai/reference/bf-chart-harness.md +51 -0
  61. package/ai/reference/bf-chart-legend-position.md +30 -0
  62. package/ai/reference/bf-chart-series.md +23 -0
  63. package/ai/reference/bf-chart-value-format.md +23 -0
  64. package/ai/reference/bf-color-scheme-service.md +30 -0
  65. package/ai/reference/bf-color-scheme.md +31 -0
  66. package/ai/reference/bf-combobox-filter.md +27 -0
  67. package/ai/reference/bf-combobox-harness.md +89 -0
  68. package/ai/reference/bf-combobox-option.md +33 -0
  69. package/ai/reference/bf-compare-with.md +2 -0
  70. package/ai/reference/bf-date-input-harness.md +67 -0
  71. package/ai/reference/bf-date-input-picker.md +27 -0
  72. package/ai/reference/bf-date-time-input-harness.md +76 -0
  73. package/ai/reference/bf-date-time-input-picker.md +27 -0
  74. package/ai/reference/bf-description-list-layout.md +26 -0
  75. package/ai/reference/bf-donut-slice.md +22 -0
  76. package/ai/reference/bf-labels.md +67 -20
  77. package/ai/reference/bf-menu-button-variant.md +1 -0
  78. package/ai/reference/bf-menu-placement.md +1 -0
  79. package/ai/reference/bf-overlay-options.md +28 -27
  80. package/ai/reference/bf-overlay-placement.md +34 -0
  81. package/ai/reference/bf-overlay-position.md +1 -1
  82. package/ai/reference/bf-overlay-service.md +5 -3
  83. package/ai/reference/bf-page-header-heading-level.md +26 -0
  84. package/ai/reference/bf-pagination-harness.md +61 -0
  85. package/ai/reference/bf-platform-service.md +17 -15
  86. package/ai/reference/bf-popover-harness.md +42 -0
  87. package/ai/reference/bf-popover-placement.md +28 -0
  88. package/ai/reference/bf-popover-trigger-directive.md +56 -0
  89. package/ai/reference/bf-side-panel-config.md +35 -0
  90. package/ai/reference/bf-side-panel-harness.md +34 -0
  91. package/ai/reference/bf-side-panel-ref.md +44 -0
  92. package/ai/reference/bf-side-panel-service.md +43 -0
  93. package/ai/reference/bf-side-panel-template-context.md +32 -0
  94. package/ai/reference/bf-side-panel-width.md +28 -0
  95. package/ai/reference/bf-size.md +12 -0
  96. package/ai/reference/bf-skeleton-shape.md +28 -0
  97. package/ai/reference/bf-stat-trend-intent.md +27 -0
  98. package/ai/reference/bf-stat-trend.md +27 -0
  99. package/ai/reference/bf-stat-variant.md +26 -0
  100. package/ai/reference/bf-tab-group-harness.md +44 -0
  101. package/ai/reference/bf-table-align.md +26 -0
  102. package/ai/reference/bf-table-cell-context.md +24 -0
  103. package/ai/reference/bf-table-cell-directive.md +22 -0
  104. package/ai/reference/bf-table-column.md +28 -0
  105. package/ai/reference/bf-table-harness.md +77 -0
  106. package/ai/reference/bf-table-row-key.md +21 -0
  107. package/ai/reference/bf-table-sort-direction.md +26 -0
  108. package/ai/reference/bf-table-sort.md +27 -0
  109. package/ai/reference/bf-theme.md +5 -4
  110. package/ai/reference/bf-time-input-harness.md +67 -0
  111. package/ai/reference/bf-time-input-hour-cycle.md +27 -0
  112. package/ai/reference/bf-time-input-picker.md +27 -0
  113. package/ai/reference/bf-tooltip-directive.md +43 -0
  114. package/ai/reference/bf-tooltip-harness.md +43 -0
  115. package/ai/reference/bf-tooltip-placement.md +28 -0
  116. package/ai/reference/bf_color_scheme_storage.md +20 -0
  117. package/ai/reference/bf_side_panel_data.md +17 -0
  118. package/ai/reference/bf_theme_storage.md +3 -1
  119. package/ai/reference/provide-bf-color-scheme.md +20 -0
  120. package/ai/reference/provide-bf-labels.md +12 -4
  121. package/ai/reference/slide-in-from-end.md +24 -0
  122. package/ai/reference/slide-out-to-end.md +24 -0
  123. package/fesm2022/bitforgehq-ui-charts.mjs +3045 -0
  124. package/fesm2022/bitforgehq-ui-charts.mjs.map +1 -0
  125. package/fesm2022/bitforgehq-ui-icons.mjs +107 -3
  126. package/fesm2022/bitforgehq-ui-icons.mjs.map +1 -1
  127. package/fesm2022/bitforgehq-ui-mobile.mjs +14 -59
  128. package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -1
  129. package/fesm2022/bitforgehq-ui-overlay.mjs +6436 -33
  130. package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
  131. package/fesm2022/bitforgehq-ui-testing.mjs +618 -1
  132. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
  133. package/fesm2022/bitforgehq-ui.mjs +5092 -153
  134. package/fesm2022/bitforgehq-ui.mjs.map +1 -1
  135. package/llms-full.txt +25177 -14398
  136. package/llms.txt +95 -1
  137. package/package.json +7 -3
  138. package/theme.css +101 -0
  139. package/types/bitforgehq-ui-charts.d.ts +967 -0
  140. package/types/bitforgehq-ui-icons.d.ts +13 -1
  141. package/types/bitforgehq-ui-mobile.d.ts +25 -18
  142. package/types/bitforgehq-ui-overlay.d.ts +1844 -7
  143. package/types/bitforgehq-ui-testing.d.ts +748 -1
  144. package/types/bitforgehq-ui.d.ts +2136 -44
package/ai/UI_GUIDE.md 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.
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.
76
76
 
77
77
  ```html
78
78
  <html lang="en" class="dark">
@@ -138,15 +138,16 @@ Render library components only in the browser, for example in a `@defer` block o
138
138
  route. Support will be decided before 1.0.
139
139
 
140
140
  The one server-side check is a render smoke, not a support test: the library repository's
141
- `tools/ssr-smoke.ts` renders 28 fixtures with `renderApplication()` (every root widget, `bf-icon`,
142
- `bf-number-input`, a `/mobile` page with `provideBfShell()`, `bf-page`, `bf-header` and
143
- `bf-content`, `bf-tabs` with `bf-stack-outlet` under the router, and an `/overlay` dialog), and all
144
- of them render without an error. 19 of them render identically twice. The other 9 number their ids
145
- differently on every render, from a module-level counter, so they could not hydrate: `bf-checkbox`,
146
- `bf-input`, `bf-radio-group`, `bf-segmented`, `bf-select`, `bf-textarea`, `bf-toggle`,
147
- `bf-number-input` and the `/overlay` dialog. Hydration itself is still not supported or tested, and
148
- more stands in its way: `/mobile` writes to `<html>` and adds a keyboard probe to `<body>`, and an
149
- `/overlay` dialog renders outside the app root and marks it inert.
141
+ `tools/ssr-smoke.ts` renders 42 fixtures with `renderApplication()` (every root widget, `bf-icon`,
142
+ `bf-number-input`, a `/charts` line chart, a `/mobile` page with `provideBfShell()`, `bf-page`,
143
+ `bf-header` and `bf-content`, `bf-tabs` with `bf-stack-outlet` under the router, and an `/overlay`
144
+ dialog), and all of them render without an error. 27 of them render identically twice. The other 15
145
+ number their ids differently on every render, from a module-level counter, so they could not
146
+ hydrate: `bf-calendar`, `bf-checkbox`, `bf-input`, `bf-radio-group`, `bf-segmented`, `bf-select`,
147
+ `bf-sidebar`, `bf-tab-group`, `bf-table`, `bf-textarea`, `bf-theme-switch`, `bf-toggle`,
148
+ `bf-line-chart`, `bf-number-input` and the `/overlay` dialog. Hydration itself is still not
149
+ supported or tested, and more stands in its way: `/mobile` writes to `<html>` and adds a keyboard
150
+ probe to `<body>`, and an `/overlay` dialog renders outside the app root and marks it inert.
150
151
 
151
152
  ## Keeping this guide in sync
152
153
 
@@ -165,6 +166,11 @@ or out of date — wire it into CI so agent guidance never drifts from the insta
165
166
  - Number field: `import { BfNumberInputComponent } from '@bitforgehq/ui/number-input';`. It is
166
167
  the one widget in its own entry point, because it loads Angular Forms (`@angular/forms`, a
167
168
  required peer); `@bitforgehq/ui` itself loads no forms code, so an app without forms ships none.
169
+ - Charts: `import { BfLineChartComponent } from '@bitforgehq/ui/charts';` (also `BfBarChartComponent`,
170
+ `BfDonutChartComponent`, `BfSparklineComponent`, `BfChartCardComponent`). Our own SVG charts,
171
+ themed with the `--color-chart-1` … `--color-chart-8` tokens; pass `series` (`{ name, values }`) and
172
+ `categories`, and a `label` that names the figure. Prefer them to a chart library unless you need a
173
+ chart form they do not draw.
168
174
  - Layout classes go on the element (`<bf-button class="mt-4">`); never restyle a widget's internals.
169
175
  - Colors: use only the semantic tokens (`bg-primary`, `text-text-muted`, `bg-surface`,
170
176
  `border-border`, `rounded-field`, `shadow-raised`, `text-body`). Never raw palette classes and
@@ -260,7 +266,7 @@ toolbar or a German settings page); a key you leave out keeps the parent's value
260
266
  (hence `fieldSize: 'lg'` for touch). Keep `gap-2` or more between wrapping rows of `sm` controls.
261
267
  - `provideBfLabels({ ... })` replaces the built-in English strings (`loading`, `dismiss`, `tabBar`,
262
268
  `tabBadge(count)`, `back`, `ok`, `cancel`, `actions`, `sheet`, `modal`, `refreshing`, `close`,
263
- `dialog`) and the
269
+ `dialog`, `theme`, `themeSystem`, `themeLight`, `themeDark`) and the
264
270
  default error text per validator kind (`validation`: `required`, `email`, `pattern`, `parse`,
265
271
  `min(n)`, `max(n)`, `minLength(n)`, `maxLength(n)`, `minDate(d)`, `maxDate(d)`, `fallback`),
266
272
  merged key by key; a key set to `undefined` also keeps the parent's string. Use it for any
@@ -272,7 +278,7 @@ toolbar or a German settings page); a key you leave out keeps the parent's value
272
278
  fall back to `sheet`/`modal`.
273
279
  - What a component-level `provideBfLabels()` covers: the widgets, form controls and
274
280
  `bf-back-button`/`bf-refresher` rendered inside that component (`loading`, `dismiss`, `tabBar`,
275
- `tabBadge`, `back`, `refreshing`, `validation`). The overlay services (`BfAlertDialogService`
281
+ `tabBadge`, `back`, `refreshing`, the `theme…` keys, `validation`). The overlay services (`BfAlertDialogService`
276
282
  `ok`, `BfActionSheetService` `cancel`/`actions`, `BfSheetService` `sheet`, `BfModalService`
277
283
  `modal`, `BfDialogService` `close`/`dialog`/`ok`/`cancel`, `BfDesktopToastService`
278
284
  `notifications`) are root singletons: they read the app-level labels unless the call passes the
@@ -302,6 +308,83 @@ export const appConfig: ApplicationConfig = {
302
308
  };
303
309
  ```
304
310
 
311
+ ### Colour scheme
312
+
313
+ A System / Light / Dark choice needs no code of your own. In a desktop web app add
314
+ `provideBfColorScheme()` to `ApplicationConfig.providers`; `BfColorSchemeService` (both from
315
+ `@bitforgehq/ui`, no Capacitor) then toggles `dark` on `<html>`, follows `prefers-color-scheme`
316
+ while the choice is `system`, and stores the choice in `localStorage` under `bf-theme`
317
+ (`BF_COLOR_SCHEME_STORAGE` moves it elsewhere). Read `dark()`, and switch with
318
+ `scheme.set('dark')`. For the control, bind `bf-theme-switch` (three segments, for a settings page
319
+ or a header row with room) or `bf-theme-menu-button` (`@bitforgehq/ui/overlay`, a menu for a
320
+ crowded top bar, icon in `bfSlot="icon"`) two-way: `[(value)]="colorScheme.scheme"`. Storage and
321
+ the media query are read in the browser only, so a server render starts light and writes nothing.
322
+ A Capacitor app gets the same service from `provideBfShell()`: `BfPlatformService.theme` and
323
+ `dark` are the same signals, and the system bars follow them. Never write your own `matchMedia`
324
+ listener, storage key or `<html>` class toggle.
325
+
326
+ ```ts
327
+ export const appConfig: ApplicationConfig = { providers: [provideBfColorScheme()] };
328
+ // In a settings component:
329
+ protected readonly colorScheme = inject(BfColorSchemeService);
330
+ // <bf-theme-switch [(value)]="colorScheme.scheme" />
331
+ ```
332
+
333
+ ## Desktop layout
334
+
335
+ `bf-tabs`, `bf-back-button` and `bf-header` are Capacitor shell parts. A desktop web app (no
336
+ `provideBfShell()`) uses their desktop counterparts from `@bitforgehq/ui`:
337
+
338
+ - **Navigation:** `bf-sidebar` (groups in `bf-nav-group`, `[(collapsed)]` for an icon rail; the
339
+ app owns the toggle button) or `bf-top-nav` for a few sections, holding
340
+ `<a bfNavItem routerLink="…" routerLinkActive ariaCurrentWhenActive="page">` links with an icon
341
+ in `bfSlot="icon"` and an optional `[badge]` count. The router sets `aria-current="page"` and
342
+ the item shows it. Drive the sidebar, a below-`md` `bf-menu-button` of `a[bfMenuItem]` links and,
343
+ in the shell, the `bf-tab`s of a `bf-tab-bar` from one array of destinations.
344
+ - **Breadcrumb:** `<bf-breadcrumb>` of `<li bfBreadcrumbItem><a routerLink>…</a></li>`, the
345
+ current page last as plain text (marked `aria-current="page"`); `maxItems` collapses a long
346
+ trail, and a `bfSlot="overflow"` `bf-menu-button` turns the collapse into a menu. On mobile it is
347
+ `bf-back-button` in `bf-header`.
348
+ - **Page header:** `<bf-page-header title="…" subtitle="…">` with the breadcrumb in
349
+ `bfSlot="breadcrumb"`, badges in `bfSlot="meta"` and the actions in `bfSlot="actions"` (the main
350
+ action a primary `bf-button`, secondary ones `ghost`, the rest in an icon-only `bf-menu-button`).
351
+ An icon-only link (back, open, edit) is `a[bfIconButton]`.
352
+ - **Toolbar:** `<bf-toolbar label="…" [status]="count">` under the page header: search and filters
353
+ in the default slot, a view switch in `bfSlot="view"`, actions in `bfSlot="actions"`; its
354
+ controls default to `sm`, and `status` is a polite live region for the result count.
355
+ - **Table:** `<bf-table [rows] [columns] [(sort)] selectable [(selection)]>` with
356
+ `ng-template[bfTableCell]` for rich cells and `bfSlot="empty"` for the empty state; the app
357
+ sorts the rows in a `computed()`, and a selection shows a `bf-action-bar`. Below `md` or on a
358
+ coarse pointer render the same rows as `bf-list-item`s.
359
+ - **Details:** `bf-description-list` of `div[bfDescriptionItem]` label/value pairs, and `bf-stat`
360
+ figure tiles in a grid; both work in both shells.
361
+ - **Cards in a grid:** the grid stretches each `bf-card` and its `bfSlot="footer"` sits on the
362
+ bottom edge, so footers line up; put a footer's parts in one element.
363
+ - **Rows on a card:** `<bf-list [inset]="false" divided class="-mx-card">`, flush to the card's
364
+ edges with lines between the rows.
365
+ - **Theme switch:** `<bf-theme-switch [(value)]="colorScheme.scheme" />` (or
366
+ `bf-theme-menu-button` from `/overlay` in a crowded top bar) with `provideBfColorScheme()` (see
367
+ "Colour scheme").
368
+ - **Tabs in a page:** `<bf-tab-group [(selected)]="tab">` of `<bf-tab-panel value="…" label="…">`
369
+ (content in an `ng-template` inside renders only while shown). Not `bf-tabs`/`bf-tab-bar` (the
370
+ shell's bottom tabs), and not for routes (use `bf-top-nav` links).
371
+ - **Paging and loading:** `<bf-pagination [(page)]="page" [total]="count" [pageSize]="20">` under a
372
+ `bf-table` (the app slices its rows); `bf-skeleton` (`shape` text/rect/circle, `lines`) as the
373
+ placeholder while data loads, inside a region with `aria-busy="true"`.
374
+ - **Dates and times:** `<bf-calendar [(value)]="date">` for an inline month view;
375
+ `bf-date-input`, `bf-time-input` and `bf-datetime-input` (`/overlay`) for a field: typed parts
376
+ in locale order plus a calendar or time-list popover (`picker="none"` for typed only, `native`
377
+ for the platform picker on touch). Values are ISO strings (`'2026-10-28'`, `'14:30'`,
378
+ `'2026-10-28T14:30'`); month and day names come from `Intl` in the document's language.
379
+ - **Picking from many options:** `bf-combobox` (`/overlay`) for one value with search, groups and
380
+ server search (`queried`, `loading`); `bf-multi-combobox` for tags. `bf-select` stays the choice
381
+ for a short fixed list.
382
+ - **Dashboards:** `bf-stat` with `delta`, `trend` and `trendIntent` for a figure and its change;
383
+ `@bitforgehq/ui/charts` for `bf-line-chart`, `bf-bar-chart`, `bf-donut-chart` and
384
+ `bf-sparkline` inside a `bf-chart-card` (title, period slot, loading, empty and error states),
385
+ themed by the `chart-1`…`chart-8` tokens. Every chart takes a `label` and offers its data as a
386
+ table.
387
+
305
388
  ## Overlays (`@bitforgehq/ui/overlay`)
306
389
 
307
390
  A desktop or plain web app (no Capacitor, no router required) installs `@angular/cdk` and `rxjs`
@@ -331,6 +414,13 @@ injector? })` stacks up to three cards bottom-right (configurable with
331
414
  keys, arrow navigation with wrap, Home/End, type-ahead, `Escape`/`Tab` close with focus back on
332
415
  the trigger, `ArrowRight`/`ArrowLeft` for submenus. A menu opened from inside a `bf-dialog`:
333
416
  `Escape` closes only the menu, never the dialog underneath.
417
+ - **Tooltip and popover:** `[bfTooltip]="'Text'"` on a focusable element shows a short hint on
418
+ hover and keyboard focus (never on touch, never the only place the information lives).
419
+ `[bfPopoverTriggerFor]="panel"` opens a non-modal `bf-popover` panel anchored to its button
420
+ (filters, details); focus moves in, `Escape` and an outside click close it.
421
+ - **Side panel:** `BfSidePanelService.open(component | template, { width, modal, data })` slides a
422
+ full-height `bf-side-panel` in from the inline end: a record's details or edit form beside the
423
+ list. `modal: false` keeps the page usable. In the Capacitor shell use `bf-sheet`/`bf-modal`.
334
424
  - **`closeOnNavigation`:** every overlay (`BfDialogConfig`, `confirm()`, and the `/mobile` sheet,
335
425
  modal, action sheet and alert options) closes when the URL path changes by default (`true`);
336
426
  pass `closeOnNavigation: false` to keep one open across a navigation (e.g. a draft that must
@@ -862,7 +952,7 @@ describe('bf-button in a consumer app (Vitest)', () => {
862
952
 
863
953
  ### 6. Drive a form widget through its harness
864
954
 
865
- The entry ships CDK harnesses for the widgets whose markup is not obvious to drive: `BfSelectHarness`, `BfRadioGroupHarness`, `BfSegmentedHarness`, `BfDialogHarness`, `BfMenuHarness`, `BfMenuItemHarness`, `BfMenuButtonHarness` and `BfDesktopToastHarness`. `with({ label })` finds a widget by its label. Load an in-page widget with `TestbedHarnessEnvironment.loader(fixture)`.
955
+ 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)`.
866
956
 
867
957
  `select-harness.spec.ts`:
868
958
 
@@ -1048,10 +1138,16 @@ Don't assert on the library's CSS classes or internal markup. They are styling d
1048
1138
 
1049
1139
  ## Design foundations (Meadow Sage)
1050
1140
 
1051
- Warm off-white canvas (`bg-bg`), white surfaces, sage green primary, pill-shaped controls,
1141
+ Warm off-white canvas (`bg-bg`), white surfaces, a neutral indigo default primary
1142
+ (`#2b26ba`), pill-shaped controls,
1052
1143
  radii 12/16/24 px (`rounded-tile/field/card`), 1.5 px control borders, soft layered shadows
1053
1144
  (`shadow-raised`, `shadow-floating`), Manrope type (`text-display/title/heading/body/caption`).
1054
1145
 
1146
+ The palette is Meadow Sage, but the primary is not its sage green: the indigo default is neutral
1147
+ on purpose and meant to be overridden with the app's brand colour (`--color-primary` and the rest
1148
+ of its set, in `@theme` and `.dark`). An indigo primary right after install is expected; it does
1149
+ not mean the theme failed to load.
1150
+
1055
1151
  ### Type and spacing scale
1056
1152
 
1057
1153
  - Type (rem tokens; px at a 16 px root): `text-display` 40, `text-title` 28, `text-heading` 18,
@@ -1076,33 +1172,50 @@ notes.
1076
1172
  | `bf-action-bar` | `@bitforgehq/ui` | Floating pill of contextual actions that appears while items are selected |
1077
1173
  | `bf-button` | `@bitforgehq/ui` | Pill-shaped action button with five variants, three sizes and a loading state |
1078
1174
  | `bf-icon-button` | `@bitforgehq/ui` | Round icon-only button for toolbars and rows, with a required accessible label |
1175
+ | `bf-toolbar` | `@bitforgehq/ui` | Dense row of search, filters, view switch, result count and actions |
1079
1176
 
1080
1177
  ### Forms
1081
1178
 
1082
- | Component | Entry point | Purpose |
1083
- | ----------------- | ----------------------------- | ------------------------------------------------------------------------------------------- |
1084
- | `bf-checkbox` | `@bitforgehq/ui` | Rounded checkbox with an optional label that binds to Signal Forms |
1085
- | `bf-chip` | `@bitforgehq/ui` | Toggleable filter chip with a check mark when selected, in tonal or ink style |
1086
- | `bf-chip-group` | `@bitforgehq/ui` | Named row of chips that picks one like radios, or groups independent toggles |
1087
- | `bf-field` | `@bitforgehq/ui` | Label, help text and error text wrapper that wires ids for assistive tech |
1088
- | `bf-input` | `@bitforgehq/ui` | Single-line text field with label, help and error text, icon slots and Signal Forms binding |
1089
- | `bf-number-input` | `@bitforgehq/ui/number-input` | Number field that binds number or null, with native min, max and step |
1090
- | `bf-radio-group` | `@bitforgehq/ui` | Group of radio buttons for choosing one option, with optional per-option descriptions |
1091
- | `bf-segmented` | `@bitforgehq/ui` | Segmented control for switching between two to four views, keyboard-navigable like radios |
1092
- | `bf-select` | `@bitforgehq/ui` | Native single-choice dropdown styled like the text field, with Signal Forms binding |
1093
- | `bf-textarea` | `@bitforgehq/ui` | Multi-line text field with label, help and error text, and Signal Forms binding |
1094
- | `bf-toggle` | `@bitforgehq/ui` | On/off switch for settings that apply immediately, with Signal Forms binding |
1179
+ | Component | Entry point | Purpose |
1180
+ | ------------------- | ----------------------------- | ------------------------------------------------------------------------------------------- |
1181
+ | `bf-calendar` | `@bitforgehq/ui` | Inline month calendar for picking one date, with month and year jumps |
1182
+ | `bf-checkbox` | `@bitforgehq/ui` | Rounded checkbox with an optional label that binds to Signal Forms |
1183
+ | `bf-chip` | `@bitforgehq/ui` | Toggleable filter chip with a check mark when selected, in tonal or ink style |
1184
+ | `bf-chip-group` | `@bitforgehq/ui` | Named row of chips that picks one like radios, or groups independent toggles |
1185
+ | `bf-combobox` | `@bitforgehq/ui/overlay` | Text field that filters a list of options as you type and picks one |
1186
+ | `bf-date-input` | `@bitforgehq/ui/overlay` | Typed date field with a calendar popover, valued as an ISO date string |
1187
+ | `bf-datetime-input` | `@bitforgehq/ui/overlay` | Typed date and time field with a calendar and time list in one popover |
1188
+ | `bf-field` | `@bitforgehq/ui` | Label, help text and error text wrapper that wires ids for assistive tech |
1189
+ | `bf-input` | `@bitforgehq/ui` | Single-line text field with label, help and error text, icon slots and Signal Forms binding |
1190
+ | `bf-multi-combobox` | `@bitforgehq/ui/overlay` | Text field that filters options as you type and picks several as tags |
1191
+ | `bf-number-input` | `@bitforgehq/ui/number-input` | Number field that binds number or null, with native min, max and step |
1192
+ | `bf-radio-group` | `@bitforgehq/ui` | Group of radio buttons for choosing one option, with optional per-option descriptions |
1193
+ | `bf-segmented` | `@bitforgehq/ui` | Segmented control for switching between two to four views, keyboard-navigable like radios |
1194
+ | `bf-select` | `@bitforgehq/ui` | Native single-choice dropdown styled like the text field, with Signal Forms binding |
1195
+ | `bf-textarea` | `@bitforgehq/ui` | Multi-line text field with label, help and error text, and Signal Forms binding |
1196
+ | `bf-theme-switch` | `@bitforgehq/ui` | Segmented System, Light and Dark switch bound two-way to the app colour scheme |
1197
+ | `bf-time-input` | `@bitforgehq/ui/overlay` | Typed time-of-day field with a popover list of times, valued as an ISO string |
1198
+ | `bf-toggle` | `@bitforgehq/ui` | On/off switch for settings that apply immediately, with Signal Forms binding |
1095
1199
 
1096
1200
  ### Data display
1097
1201
 
1098
- | Component | Entry point | Purpose |
1099
- | -------------- | ---------------- | --------------------------------------------------------------------------------------- |
1100
- | `bf-avatar` | `@bitforgehq/ui` | Round avatar showing a photo or initials, in three sizes and four color variants |
1101
- | `bf-badge` | `@bitforgehq/ui` | Small status label in semantic tones, or a compact numeric pill for counts |
1102
- | `bf-card` | `@bitforgehq/ui` | Content surface with an optional header slot, in four visual styles from raised to flat |
1103
- | `bf-list` | `@bitforgehq/ui` | Container for list rows, inset by default with rounded corners on a warm background |
1104
- | `bf-list-item` | `@bitforgehq/ui` | List row with leading slot, title, subtitle, trailing slot and an optional chevron |
1105
- | `bf-progress` | `@bitforgehq/ui` | Progress bar in two sizes and four tones for completion, quotas and unknown waits |
1202
+ | Component | Entry point | Purpose |
1203
+ | ------------------------ | ----------------------- | --------------------------------------------------------------------------------------- |
1204
+ | `bf-avatar` | `@bitforgehq/ui` | Round avatar showing a photo or initials, in three sizes and four color variants |
1205
+ | `bf-badge` | `@bitforgehq/ui` | Small status label in semantic tones, or a compact numeric pill for counts |
1206
+ | `bf-bar-chart` | `@bitforgehq/ui/charts` | Bar chart of series over categories, grouped or stacked, vertical or horizontal |
1207
+ | `bf-card` | `@bitforgehq/ui` | Content surface with an optional header slot, in four visual styles from raised to flat |
1208
+ | `bf-chart-card` | `@bitforgehq/ui/charts` | Card around one chart with a title, period control and loading, empty and error states |
1209
+ | `div[bfDescriptionItem]` | `@bitforgehq/ui` | One label and value pair of a description list, label as term, content as value |
1210
+ | `bf-description-list` | `@bitforgehq/ui` | Native description list of label-value pairs, as divided rows or a tile grid |
1211
+ | `bf-donut-chart` | `@bitforgehq/ui/charts` | Donut chart of the parts of a whole, with a legend, tooltip and centre slot |
1212
+ | `bf-line-chart` | `@bitforgehq/ui/charts` | Line chart of series over categories, with tooltip, legend and data table |
1213
+ | `bf-list` | `@bitforgehq/ui` | Container for list rows, inset by default with rounded corners on a warm background |
1214
+ | `bf-list-item` | `@bitforgehq/ui` | List row with leading slot, title, subtitle, trailing slot and an optional chevron |
1215
+ | `bf-progress` | `@bitforgehq/ui` | Progress bar in two sizes and four tones for completion, quotas and unknown waits |
1216
+ | `bf-sparkline` | `@bitforgehq/ui/charts` | Tiny trend line with no axes or legend, for stats and table cells |
1217
+ | `bf-stat` | `@bitforgehq/ui` | One labelled figure with an optional icon tile and a supporting line |
1218
+ | `bf-table` | `@bitforgehq/ui` | Desktop data table with sortable headers, row selection, custom cells and an empty slot |
1106
1219
 
1107
1220
  ### Feedback
1108
1221
 
@@ -1110,35 +1223,50 @@ notes.
1110
1223
  | ---------------- | ---------------- | ---------------------------------------------------------------------------------- |
1111
1224
  | `bf-alert` | `@bitforgehq/ui` | Inline status message in four tones with a title and an optional dismiss button |
1112
1225
  | `bf-empty-state` | `@bitforgehq/ui` | Placeholder for an empty screen or list with icon, title, message and action |
1226
+ | `bf-skeleton` | `@bitforgehq/ui` | Loading placeholder shaped as text lines, a rectangle or a circle, with a shimmer |
1113
1227
  | `bf-spinner` | `@bitforgehq/ui` | Indeterminate loading spinner in three sizes that inherits its parent's text color |
1114
1228
 
1115
1229
  ### Navigation
1116
1230
 
1117
- | Component | Entry point | Purpose |
1118
- | ----------------- | ----------------------- | ------------------------------------------------------------------------------------------- |
1119
- | `bf-back-button` | `@bitforgehq/ui/mobile` | Header back button that pops the page stack or falls back to a default route |
1120
- | `bf-content` | `@bitforgehq/ui/mobile` | Page's single scroll container that keeps focused fields clear of the soft keyboard |
1121
- | `bf-header` | `@bitforgehq/ui/mobile` | Page header toolbar with a large title that collapses into the toolbar on scroll |
1122
- | `bf-page` | `@bitforgehq/ui/mobile` | Frame for one stacked mobile screen that supplies lifecycle events and shared page state |
1123
- | `bf-refresher` | `@bitforgehq/ui/mobile` | Pull-to-refresh indicator with haptic feedback, native iOS bounce and an Android-style pull |
1124
- | `bf-stack-outlet` | `@bitforgehq/ui/mobile` | Router outlet keeping a live page stack with slide transitions and iOS swipe back |
1125
- | `bf-tab` | `@bitforgehq/ui` | One tab bar destination with an icon, a label and an optional count badge |
1126
- | `bf-tab-bar` | `@bitforgehq/ui` | Floating pill tab bar for mobile apps with arrow-key selection and count badges |
1127
- | `bf-tabs` | `@bitforgehq/ui/mobile` | Tabs page with one navigation stack per tab, wiring the tab bar to the router |
1231
+ | Component | Entry point | Purpose |
1232
+ | ---------------------- | ----------------------- | ------------------------------------------------------------------------------------------- |
1233
+ | `bf-back-button` | `@bitforgehq/ui/mobile` | Header back button that pops the page stack or falls back to a default route |
1234
+ | `bf-breadcrumb` | `@bitforgehq/ui` | Desktop breadcrumb trail of links to the current page, with optional collapsing |
1235
+ | `li[bfBreadcrumbItem]` | `@bitforgehq/ui` | One level of a breadcrumb trail: a link, or the current page as text |
1236
+ | `bf-content` | `@bitforgehq/ui/mobile` | Page's single scroll container that keeps focused fields clear of the soft keyboard |
1237
+ | `bf-header` | `@bitforgehq/ui/mobile` | Page header toolbar with a large title that collapses into the toolbar on scroll |
1238
+ | `bf-nav-group` | `@bitforgehq/ui` | A titled group of sidebar links with a small heading that names it |
1239
+ | `a[bfNavItem]` | `@bitforgehq/ui` | Navigation link for a sidebar or top nav, with icon, label and count |
1240
+ | `bf-page` | `@bitforgehq/ui/mobile` | Frame for one stacked mobile screen that supplies lifecycle events and shared page state |
1241
+ | `bf-page-header` | `@bitforgehq/ui` | Desktop page header with breadcrumb, title, subtitle, badges and a row of actions |
1242
+ | `bf-pagination` | `@bitforgehq/ui` | Previous, next and numbered page buttons for a long list or table |
1243
+ | `bf-refresher` | `@bitforgehq/ui/mobile` | Pull-to-refresh indicator with haptic feedback, native iOS bounce and an Android-style pull |
1244
+ | `bf-sidebar` | `@bitforgehq/ui` | Vertical app navigation with brand, grouped links, footer and an icon rail mode |
1245
+ | `bf-stack-outlet` | `@bitforgehq/ui/mobile` | Router outlet keeping a live page stack with slide transitions and iOS swipe back |
1246
+ | `bf-tab` | `@bitforgehq/ui` | One tab bar destination with an icon, a label and an optional count badge |
1247
+ | `bf-tab-bar` | `@bitforgehq/ui` | Floating pill tab bar for mobile apps with arrow-key selection and count badges |
1248
+ | `bf-tab-group` | `@bitforgehq/ui` | In-page tabs that switch between content panels, with keyboard navigation and badges |
1249
+ | `bf-tab-panel` | `@bitforgehq/ui` | One tab of a tab group with its label, badge, icon and lazy content |
1250
+ | `bf-tabs` | `@bitforgehq/ui/mobile` | Tabs page with one navigation stack per tab, wiring the tab bar to the router |
1251
+ | `bf-top-nav` | `@bitforgehq/ui` | Horizontal app navigation, a wrapping row of links for apps with few sections |
1128
1252
 
1129
1253
  ### Overlays
1130
1254
 
1131
- | Component | Entry point | Purpose |
1132
- | ------------------ | ------------------------ | --------------------------------------------------------------------------------------------- |
1133
- | `bf-action-sheet` | `@bitforgehq/ui/mobile` | Bottom panel of labelled actions with a separate cancel button, destructive ones shown in red |
1134
- | `bf-alert-dialog` | `@bitforgehq/ui/mobile` | Centred confirmation dialog with a title, message and a row of role-styled buttons |
1135
- | `bf-desktop-toast` | `@bitforgehq/ui/overlay` | Desktop notification card in a bottom corner stack of up to three |
1136
- | `bf-dialog` | `@bitforgehq/ui/overlay` | Desktop modal dialog with a title, scrolling body, footer actions and focus trap |
1137
- | `bf-menu` | `@bitforgehq/ui/overlay` | Keyboard-operable menu panel with items, checkbox and radio items, groups and submenus |
1138
- | `bf-menu-button` | `@bitforgehq/ui/overlay` | Styled button that opens a menu, with outline, text, tonal and icon-only looks |
1139
- | `bf-modal` | `@bitforgehq/ui/mobile` | Modal overlay shown as an inset card over the scaled-down page, or full screen |
1140
- | `bf-sheet` | `@bitforgehq/ui/mobile` | Bottom sheet with snap points, drag to dismiss and a backdrop |
1141
- | `bf-toast` | `@bitforgehq/ui/mobile` | Passive status pill with an optional action that never steals focus |
1255
+ | Component | Entry point | Purpose |
1256
+ | ---------------------- | ------------------------ | --------------------------------------------------------------------------------------------- |
1257
+ | `bf-action-sheet` | `@bitforgehq/ui/mobile` | Bottom panel of labelled actions with a separate cancel button, destructive ones shown in red |
1258
+ | `bf-alert-dialog` | `@bitforgehq/ui/mobile` | Centred confirmation dialog with a title, message and a row of role-styled buttons |
1259
+ | `bf-desktop-toast` | `@bitforgehq/ui/overlay` | Desktop notification card in a bottom corner stack of up to three |
1260
+ | `bf-dialog` | `@bitforgehq/ui/overlay` | Desktop modal dialog with a title, scrolling body, footer actions and focus trap |
1261
+ | `bf-menu` | `@bitforgehq/ui/overlay` | Keyboard-operable menu panel with items, checkbox and radio items, groups and submenus |
1262
+ | `bf-menu-button` | `@bitforgehq/ui/overlay` | Styled button that opens a menu, with outline, text, tonal and icon-only looks |
1263
+ | `bf-modal` | `@bitforgehq/ui/mobile` | Modal overlay shown as an inset card over the scaled-down page, or full screen |
1264
+ | `bf-popover` | `@bitforgehq/ui/overlay` | Anchored, non-modal panel for filters, details or a small form |
1265
+ | `bf-sheet` | `@bitforgehq/ui/mobile` | Bottom sheet with snap points, drag to dismiss and a backdrop |
1266
+ | `bf-side-panel` | `@bitforgehq/ui/overlay` | Desktop panel sliding in from the end edge, with a title, body and footer actions |
1267
+ | `bf-theme-menu-button` | `@bitforgehq/ui/overlay` | Menu button with System, Light and Dark radio items bound to the colour scheme |
1268
+ | `bf-toast` | `@bitforgehq/ui/mobile` | Passive status pill with an optional action that never steals focus |
1269
+ | `bf-tooltip` | `@bitforgehq/ui/overlay` | Short hint beside a control on hover or keyboard focus, for desktop |
1142
1270
 
1143
1271
  ### Icons
1144
1272
 
@@ -81,7 +81,7 @@ and its anatomy follows the shell mode (`provideBfShell({ mode })`, the platform
81
81
 
82
82
  ## When to use
83
83
 
84
- Use `bf-back-button` in the `start` slot of a pushed page's [bf-header](https://bitforge-ui.web.app/components/header) in the Capacitor shell. Use the browser's own back button and a breadcrumb instead on a desktop web page, and a [bf-button](https://bitforge-ui.web.app/components/button) link (`a[bfButton]`) for a named way back.
84
+ Use `bf-back-button` in the `start` slot of a pushed page's [bf-header](https://bitforge-ui.web.app/components/header) in the Capacitor shell. Use the browser's own back button and a [bf-breadcrumb](https://bitforge-ui.web.app/components/breadcrumb) instead on a desktop web page, and a [bf-button](https://bitforge-ui.web.app/components/button) link (`a[bfButton]`) for a named way back.
85
85
 
86
86
  ## Basic usage
87
87
 
@@ -171,7 +171,42 @@ export class BackButtonLabelExampleComponent {}
171
171
 
172
172
  ## Desktop
173
173
 
174
- `bf-back-button` is part of the Capacitor shell (`provideBfShell()`). On a desktop web page the browser's back button and history already go back; add a breadcrumb or a named link instead. Inside the shell under a mouse, the iOS form darkens to `primary-strong` on hover and the Material form is a `text` icon button; both show the pointer cursor and a focus ring on keyboard focus only.
174
+ `bf-back-button` is part of the Capacitor shell (`provideBfShell()`). On a desktop web page the browser's back button and history already go back; show where the page sits with a [bf-breadcrumb](https://bitforge-ui.web.app/components/breadcrumb) instead, or give a named way back with `a[bfButton]` (or an icon-only `a[bfIconButton]`, [bf-icon-button](https://bitforge-ui.web.app/components/icon-button)). Each level up is a `li[bfBreadcrumbItem]` holding the app's own `routerLink`; the breadcrumb draws the separators (never announced), marks the last item, the current page, with `aria-current="page"`, and collapses a long trail with `maxItems`. Put it in the `breadcrumb` slot of a [bf-page-header](https://bitforge-ui.web.app/components/page-header).
175
+
176
+ ```ts
177
+ import { Component } from '@angular/core';
178
+ import { RouterLink } from '@angular/router';
179
+ import { BfBreadcrumbComponent, BfBreadcrumbItemComponent } from '@bitforgehq/ui';
180
+
181
+ /**
182
+ * The desktop replacement for a back button: a bf-breadcrumb.
183
+ *
184
+ * Every level up is the app's own `routerLink`; the last item is the current page, which the
185
+ * breadcrumb marks with `aria-current="page"`.
186
+ */
187
+ @Component({
188
+ selector: 'app-example-back-button-breadcrumb',
189
+ imports: [RouterLink, BfBreadcrumbComponent, BfBreadcrumbItemComponent],
190
+ template: `
191
+ <bf-breadcrumb label="Back button breadcrumb">
192
+ @for (crumb of trail; track crumb.path) {
193
+ <li bfBreadcrumbItem>
194
+ <a [routerLink]="crumb.path">{{ crumb.label }}</a>
195
+ </li>
196
+ }
197
+ <li bfBreadcrumbItem>Back button</li>
198
+ </bf-breadcrumb>
199
+ `,
200
+ })
201
+ export class BackButtonBreadcrumbExampleComponent {
202
+ protected readonly trail: readonly { path: string; label: string }[] = [
203
+ { path: '/', label: 'Docs' },
204
+ { path: '/components', label: 'Components' },
205
+ ];
206
+ }
207
+ ```
208
+
209
+ Inside the shell under a mouse, the iOS form darkens to `primary-strong` on hover and the Material form is a `text` icon button; both show the pointer cursor and a focus ring on keyboard focus only.
175
210
 
176
211
  ## Theming
177
212
 
@@ -232,6 +267,11 @@ Goes back one page, or to `defaultHref` when the stack has none to go back to.
232
267
 
233
268
  ## Migration notes
234
269
 
270
+ ### 0.3.1
271
+
272
+ The `## Desktop` docs and When to use name the desktop replacement, `bf-breadcrumb`, with an
273
+ example. No code change.
274
+
235
275
  ### 0.3.0
236
276
 
237
277
  **Behaviour:** `label` defaults to `''` and falls back to `provideBfLabels()`'s `back` ("Back"),
@@ -43,13 +43,13 @@ Use `bf-badge` for a read-only status or count next to what it describes: "At ri
43
43
 
44
44
  ## Status labels
45
45
 
46
- The variant carries the meaning: `success`, `warning`, `danger`, `primary` or the default `neutral`.
46
+ The variant carries the meaning: `success`, `warning`, `danger`, `primary`, `info` or the default `neutral`. `info` is for an informational label that is not a status, such as a category ("Design", "Billing"); it is a calm blue, distinct from the brand `primary`, so a category never reads as the selected or main thing. `variant` takes a `BfBadgeAppearance` (the five `BfBadgeVariant` tones plus `info`).
47
47
 
48
48
  ```ts
49
49
  import { Component } from '@angular/core';
50
50
  import { BfBadgeComponent } from '@bitforgehq/ui';
51
51
 
52
- /** Status badges in the four tones. */
52
+ /** Status badges in the four status tones, and an informational info label. */
53
53
  @Component({
54
54
  selector: 'app-example-badge-status',
55
55
  imports: [BfBadgeComponent],
@@ -59,6 +59,7 @@ import { BfBadgeComponent } from '@bitforgehq/ui';
59
59
  <bf-badge variant="warning">At risk</bf-badge>
60
60
  <bf-badge variant="danger">Blocked</bf-badge>
61
61
  <bf-badge>Draft</bf-badge>
62
+ <bf-badge variant="info">Design</bf-badge>
62
63
  </div>
63
64
  `,
64
65
  })
@@ -125,6 +126,7 @@ Consumes tokens by variant, background then text:
125
126
  - `success`: `success-soft` / `success`
126
127
  - `warning`: `warning-soft` / `warning`
127
128
  - `danger`: `danger-soft` / `danger`
129
+ - `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)
128
130
  - Count pill (`count` set): `primary` / `on-primary`, ignoring `variant`
129
131
  - Shape (label and count pill): `rounded-control` (`--radius-control`, `9999px` by default).
130
132
 
@@ -134,11 +136,11 @@ A badge is a plain `<span>` with no role or ARIA attributes; its text is read as
134
136
 
135
137
  ## Inputs
136
138
 
137
- | Name | Type | Default | Description |
138
- | ------------ | --------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
139
- | `variant` | `BfBadgeVariant` (`'neutral' \| 'primary' \| 'success' \| 'warning' \| 'danger'`) | `'neutral'` | Tint for the label style. Ignored when `count` is set. |
140
- | `count` | `number \| undefined` | `undefined` | Switches to the count pill; values above 99 render as "99+". |
141
- | `countLabel` | `string` | `''` | What the count counts ("unread messages"), read by assistive tech after the number ("99+ unread messages"); visually hidden. Only used with `count`. |
139
+ | Name | Type | Default | Description |
140
+ | ------------ | ---------------------------------------------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
141
+ | `variant` | `BfBadgeAppearance` (`'neutral' \| 'primary' \| 'success' \| 'warning' \| 'danger' \| 'info'`) | `'neutral'` | Tint for the label style: neutral, primary, success, warning, danger or info. Ignored when `count` is set. |
142
+ | `count` | `number \| undefined` | `undefined` | Switches to the count pill; values above 99 render as "99+". |
143
+ | `countLabel` | `string` | `''` | What the count counts ("unread messages"), read by assistive tech after the number ("99+ unread messages"); visually hidden. Only used with `count`. |
142
144
 
143
145
  ## Slots
144
146
 
@@ -155,9 +157,17 @@ A badge is a plain `<span>` with no role or ARIA attributes; its text is read as
155
157
 
156
158
  - Don't use a badge as a button; it has no interactive states.
157
159
  - Don't invent new colors on it; pick the variant that matches the meaning.
160
+ - Don't use `primary` or `success` for a category; use `info`, so the status tones keep their meaning.
158
161
 
159
162
  ## Migration notes
160
163
 
164
+ ### 0.3.1
165
+
166
+ New `info` tone for informational labels such as a category, on the new `info` / `info-soft`
167
+ tokens (7.7:1 in light, 7.2:1 in dark; not derived from the primary). `variant` is now typed
168
+ `BfBadgeAppearance` (the five `BfBadgeVariant` tones plus `info`); `BfBadgeVariant` keeps its five
169
+ members, so code that maps over it keeps compiling.
170
+
161
171
  ### 0.3.0
162
172
 
163
173
  **Behaviour:** the label and the count pill use `rounded-control` (`--radius-control`, `9999px` by