@bitforgehq/ui 0.4.0 → 0.5.0-next.3

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 (80) hide show
  1. package/CHANGELOG.md +303 -0
  2. package/README.md +12 -12
  3. package/ai/MANIFEST.index.json +65 -2
  4. package/ai/MANIFEST.json +2221 -737
  5. package/ai/REFERENCE.index.json +161 -0
  6. package/ai/REFERENCE.json +1336 -27
  7. package/ai/UI_GUIDE.md +61 -20
  8. package/ai/components/app-frame.md +1 -1
  9. package/ai/components/chat-composer.md +357 -0
  10. package/ai/components/chat-message.md +251 -0
  11. package/ai/components/chat-thread.md +521 -0
  12. package/ai/components/checkbox.md +7 -0
  13. package/ai/components/combobox.md +12 -0
  14. package/ai/components/date-input.md +9 -0
  15. package/ai/components/datetime-input.md +2 -0
  16. package/ai/components/field.md +10 -0
  17. package/ai/components/file-input.md +498 -0
  18. package/ai/components/header.md +1 -1
  19. package/ai/components/image-input.md +368 -0
  20. package/ai/components/image-viewer.md +309 -0
  21. package/ai/components/media-card.md +478 -0
  22. package/ai/components/menu-button.md +2 -0
  23. package/ai/components/menu.md +10 -0
  24. package/ai/components/multi-combobox.md +7 -0
  25. package/ai/components/nav-group.md +10 -3
  26. package/ai/components/nav-item.md +11 -2
  27. package/ai/components/number-input.md +2 -7
  28. package/ai/components/popover.md +13 -0
  29. package/ai/components/radio-group.md +6 -0
  30. package/ai/components/segmented.md +14 -2
  31. package/ai/components/select.md +100 -42
  32. package/ai/components/sidebar-toggle.md +16 -9
  33. package/ai/components/sidebar.md +41 -13
  34. package/ai/components/tab-group.md +18 -2
  35. package/ai/components/table.md +17 -2
  36. package/ai/components/theme-menu-button.md +1 -0
  37. package/ai/components/time-input.md +2 -0
  38. package/ai/components/toolbar.md +7 -18
  39. package/ai/reference/bf-chat-composer-harness.md +64 -0
  40. package/ai/reference/bf-chat-message-role.md +27 -0
  41. package/ai/reference/bf-chat-message-status.md +28 -0
  42. package/ai/reference/bf-fade-in-directive.md +18 -0
  43. package/ai/reference/bf-file-input-harness.md +67 -0
  44. package/ai/reference/bf-file-input-variant.md +27 -0
  45. package/ai/reference/bf-image-input-harness.md +67 -0
  46. package/ai/reference/bf-image-input-shape.md +27 -0
  47. package/ai/reference/bf-image-viewer-actions-context.md +29 -0
  48. package/ai/reference/bf-image-viewer-harness.md +87 -0
  49. package/ai/reference/bf-image-viewer-image.md +25 -0
  50. package/ai/reference/bf-image-viewer-options.md +33 -0
  51. package/ai/reference/bf-image-viewer-origin.md +23 -0
  52. package/ai/reference/bf-image-viewer-ref.md +55 -0
  53. package/ai/reference/bf-image-viewer-service.md +32 -0
  54. package/ai/reference/bf-labels.md +105 -75
  55. package/ai/reference/bf-media-card-aspect.md +28 -0
  56. package/ai/reference/bf-media-card-harness.md +66 -0
  57. package/ai/reference/bf-motion-list-directive.md +22 -0
  58. package/ai/reference/bf-prose-directive.md +16 -0
  59. package/ai/reference/bf-rejected-file-reason.md +28 -0
  60. package/ai/reference/bf-rejected-file.md +28 -0
  61. package/ai/reference/bf-select-harness.md +14 -5
  62. package/ai/reference/bf-select-option.md +2 -0
  63. package/ai/reference/bf-size.md +3 -0
  64. package/ai/reference/bf_table_sort_select.md +23 -0
  65. package/ai/reference/provide-bf-labels.md +10 -3
  66. package/ai/reference/provide-bf-select.md +20 -0
  67. package/bin/bf-ui.js +1 -0
  68. package/fesm2022/bitforgehq-ui-overlay.mjs +2649 -606
  69. package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
  70. package/fesm2022/bitforgehq-ui-testing.mjs +356 -10
  71. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
  72. package/fesm2022/bitforgehq-ui.mjs +7531 -3989
  73. package/fesm2022/bitforgehq-ui.mjs.map +1 -1
  74. package/llms-full.txt +4151 -130
  75. package/llms.txt +31 -1
  76. package/package.json +1 -1
  77. package/theme.css +60 -0
  78. package/types/bitforgehq-ui-overlay.d.ts +684 -7
  79. package/types/bitforgehq-ui-testing.d.ts +434 -6
  80. package/types/bitforgehq-ui.d.ts +1473 -182
@@ -148,6 +148,8 @@ export class TabGroupLazyExampleComponent {
148
148
 
149
149
  `[(selected)]` holds the shown panel's `value`; `(changed)` emits the new value after a user change, never for a write of `selected`. While `selected` matches no panel (unset, or a value that went away), the first enabled panel shows; `selected` itself keeps its value until the user picks a tab.
150
150
 
151
+ The underline slides to the newly selected tab, changing width as it goes (200 ms, `--bf-duration-layout`); it lands in place at once on the first render and after a resize, and always under `prefers-reduced-motion`. The panel a user switches to fades in over 200 ms (`animate-panel-in`); the first panel shown, and every panel under reduced motion, appears at once.
152
+
151
153
  ## Sizes and width
152
154
 
153
155
  `size` sets the tabs' height: `sm` 32 px, `md` 40 px, `lg` 48 px. Unset, it follows `provideBfDefaults()`'s `controlSize`, `md` by default. `fitted` stretches the tabs to share the group's width (two or three tabs on a phone). When the tabs do not fit, the row scrolls sideways; focusing a tab with the keyboard scrolls it into view.
@@ -159,7 +161,7 @@ Under a mouse an unselected tab takes a `surface-muted` fill and `text` on hover
159
161
  ## Theming
160
162
 
161
163
  - Tabs: `text-muted` at rest, hover `surface-muted` with `text`, pressed `surface-pressed`; top corners `rounded-tile`.
162
- - Selected tab: `primary-text` with a 2 px `primary` underline on its bottom edge, so the selection never rests on colour alone (`CanvasText` under forced colours; `text-disabled` on a disabled selected tab).
164
+ - Selected tab: `primary-text` with a 2 px `primary` underline on its bottom edge, so the selection never rests on colour alone (`CanvasText` under forced colours; `text-disabled` on a disabled selected tab). It slides over `--bf-duration-layout` with the `ease-md` curve.
163
165
  - Disabled tab: `text-disabled` (never opacity).
164
166
  - The row: a 1 px `border` line under the tabs, across the group's width.
165
167
  - Badge: `primary` with `on-primary` text, `rounded-control`, `text-micro`.
@@ -168,7 +170,7 @@ Under a mouse an unselected tab takes a `surface-muted` fill and `text` on hover
168
170
 
169
171
  ## Accessibility
170
172
 
171
- The row is a `role="tablist"` named by `label`, else `provideBfLabels()`'s `tabGroup` ("Tabs"); give each group on a page its own `label`. Each tab is a native `<button role="tab">` with `aria-selected` and `aria-controls` naming its panel; each `bf-tab-panel` is a `role="tabpanel"` with `aria-labelledby` naming its tab and `tabindex="0"`, and an unselected panel is `hidden`. Only the selected tab is in the tab order (a roving tab stop), so <kbd>Tab</kbd> moves from it into the panel. Selection follows focus (automatic activation): the arrow keys, <kbd>Home</kbd> and <kbd>End</kbd> move to a tab and show its panel at once, so keep a panel's first render quick. A disabled tab is native-disabled and skipped. A badge's pill is `aria-hidden`; its count is read after the label from visually hidden text (`tabBadge(n)`, "3 new").
173
+ The row is a `role="tablist"` named by `label`, else `provideBfLabels()`'s `tabGroup` ("Tabs"); give each group on a page its own `label`. Each tab is a native `<button role="tab">` with `aria-selected` and `aria-controls` naming its panel; each `bf-tab-panel` is a `role="tabpanel"` with `aria-labelledby` naming its tab and `tabindex="0"`, and an unselected panel is `hidden`. Only the selected tab is in the tab order (a roving tab stop), so <kbd>Tab</kbd> moves from it into the panel. Selection follows focus (automatic activation): the arrow keys, <kbd>Home</kbd> and <kbd>End</kbd> move to a tab and show its panel at once, so keep a panel's first render quick. A disabled tab is native-disabled and skipped. The sliding underline is one decorative `aria-hidden` element of the row. A badge's pill is `aria-hidden`; its count is read after the label from visually hidden text (`tabBadge(n)`, "3 new").
172
174
 
173
175
  ### Keyboard
174
176
 
@@ -213,6 +215,20 @@ The row is a `role="tablist"` named by `label`, else `provideBfLabels()`'s `tabG
213
215
 
214
216
  ## Migration notes
215
217
 
218
+ ### 0.5.0
219
+
220
+ The selected tab's underline is now one indicator element of the row that slides to the newly
221
+ selected tab, changing width as it goes (`--bf-duration-layout`, `ease-md`). The first placement
222
+ and a resize land at once, and so does everything under `prefers-reduced-motion`. It is measured
223
+ from the selected tab's inline-start offset, so it mirrors under `dir="rtl"`, and is re-measured
224
+ on resize and when labels, badges, size or `fitted` change. Until it has been measured (jsdom,
225
+ server render, a hidden group) the tab keeps drawing its own underline, so unit tests and the
226
+ first paint are unchanged. The indicator is `aria-hidden`; roles, keyboard and focus are
227
+ unchanged.
228
+
229
+ The panel a user switches to fades in (200 ms of opacity, new `--animate-panel-in`, behind
230
+ `motion-safe:`); the panel shown on the first render never does.
231
+
216
232
  ### 0.3.1
217
233
 
218
234
  New `bf-tab-group`: in-page tabs over the content they switch, in both shells. A `tablist` of
@@ -489,11 +489,12 @@ export class TablePagedExampleComponent {
489
489
 
490
490
  `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.
491
491
 
492
- 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, since the hidden header's buttons are not shown. Its first option, Not sorted, shows while `sort` is null and sets it back to null; then every sortable column, ascending and descending (`tableSortBy`, `tableSortNone`, `tableSortAscending`, `tableSortDescending` labels). Choosing a column option sets `sort`, as a header click does. In a test, `BfTableHarness.getSortSelect()` returns that select's `BfSelectHarness`.
492
+ 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, since the hidden header's buttons are not shown. Its first option, Not sorted, shows while `sort` is null and sets it back to null; then every sortable column, ascending and descending (`tableSortBy`, `tableSortNone`, `tableSortAscending`, `tableSortDescending` labels). Choosing a column option sets `sort`, as a header click does. The Sort by select is a native `<select>` unless the app adds `provideBfSelect()` from `@bitforgehq/ui/overlay` to its providers: then it is the styled [bf-select](https://bitforge-ui.web.app/components/select) (still native under touch), through the `BF_TABLE_SORT_SELECT` token, so `@bitforgehq/ui` itself never loads the CDK. In a test, `BfTableHarness.getSortSelect()` returns that select's `BfSelectHarness`, in either form.
493
493
 
494
494
  ```ts
495
495
  import { Component, computed, signal } from '@angular/core';
496
496
  import {
497
+ BF_TABLE_SORT_SELECT,
497
498
  BfBadgeComponent,
498
499
  BfSegmentedComponent,
499
500
  BfTableCellDirective,
@@ -502,6 +503,7 @@ import {
502
503
  type BfTableColumn,
503
504
  type BfTableSort,
504
505
  } from '@bitforgehq/ui';
506
+ import { BfSelectComponent } from '@bitforgehq/ui/overlay';
505
507
 
506
508
  interface Task {
507
509
  id: string;
@@ -526,10 +528,16 @@ type Width = 'phone' | 'full';
526
528
  * than 36rem: the selection checkbox and the first cell head the tile, and a bar above the tiles
527
529
  * holds Select all and a Sort by select, whose first option, Not sorted, shows while `sort` is
528
530
  * null and clears it. Switch the box between phone width and full width.
531
+ *
532
+ * The Sort by select is the styled `bf-select`. In an app, add `provideBfSelect()` from
533
+ * `@bitforgehq/ui/overlay` to `app.config.ts` once; this page provides `BF_TABLE_SORT_SELECT`
534
+ * on the example instead, so the docs site loads the select only with this example.
529
535
  */
530
536
  @Component({
531
537
  selector: 'app-example-table-stacked',
532
538
  imports: [BfTableComponent, BfTableCellDirective, BfBadgeComponent, BfSegmentedComponent],
539
+ // In an app: provideBfSelect() in app.config.ts (see the comment above).
540
+ providers: [{ provide: BF_TABLE_SORT_SELECT, useValue: BfSelectComponent }],
533
541
  template: `
534
542
  <!-- A stacking table is a size container: its width comes from its parent, never its columns. -->
535
543
  <div class="flex w-152 max-w-full flex-col gap-3">
@@ -684,7 +692,7 @@ A table that can stack (`stack` other than `never`) sets explicit `table`, `rowg
684
692
  | <kbd>Space</kbd> | Toggles the focused checkbox, or sorts by the focused header |
685
693
  | <kbd>Enter</kbd> | Sorts by the focused header |
686
694
 
687
- A stacked table's Sort by select is a native select with its own keys.
695
+ A stacked table's Sort by select has its own keys: the native select's, or with `provideBfSelect()` those of [bf-select](https://bitforge-ui.web.app/components/select#keyboard).
688
696
 
689
697
  Text fields, selects and composite widgets (radios, comboboxes, sliders) in a cell keep their own arrow keys.
690
698
 
@@ -751,6 +759,13 @@ Selects or clears one row.
751
759
 
752
760
  ## Migration notes
753
761
 
762
+ ### 0.5.0
763
+
764
+ New `BF_TABLE_SORT_SELECT` injection token: the component a stacked table renders as its "Sort
765
+ by" select (`null`, the default, keeps the native one). `provideBfSelect()` from
766
+ `@bitforgehq/ui/overlay` sets it to the styled `bf-select`, so the core entry still never imports
767
+ the CDK. `BfTableHarness.getSortSelect()` returns a working `BfSelectHarness` either way.
768
+
754
769
  ### 0.4.0
755
770
 
756
771
  New: toggle cells for a settings matrix (rows of alert kinds, columns of channels, a `bf-toggle`
@@ -127,6 +127,7 @@ The button consumes `bf-menu-button`'s tokens (`bf-button`'s, or `bf-icon-button
127
127
  - The three items are `role="menuitemradio"` with `aria-checked`, so a screen reader announces the current choice. The dot is drawn in CSS and adds nothing to the name.
128
128
  - Choosing an item closes the menu and returns focus to the button.
129
129
  - Hit area: at least 32 px, 44 px under a coarse pointer, as `bf-menu-button`.
130
+ - Motion: the menu fades and grows out of the button as it opens, and closes at once. Under `prefers-reduced-motion` it only fades in.
130
131
 
131
132
  ### Keyboard
132
133
 
@@ -138,6 +138,8 @@ The field shows the `primary` border and focus ring while any part has focus, th
138
138
 
139
139
  The parts are a `role="group"` named by `label` (else `ariaLabel` or `ariaLabelledby`); each part is a `role="spinbutton"` named from the `timeInputHour`, `timeInputMinute`, `timeInputSecond` and `timeInputDayPeriod` labels, with `aria-valuemin`, `aria-valuemax`, `aria-valuenow` and `aria-valuetext` (the AM or PM name), and the field's `aria-invalid`, `aria-errormessage`, `aria-required`, `aria-readonly` and `aria-disabled`. The clock button is named by `timeInputOpenList`, with `aria-haspopup="dialog"`, `aria-expanded` and `aria-controls`. The list is a `role="listbox"` named by the same label, its times `role="option"` with `aria-selected` and `aria-disabled`; focus stays on the list and `aria-activedescendant` names the active time.
140
140
 
141
+ Motion: the list grows out of the field as it opens (a fade, a slight scale and a 4 px slide, 180 ms) and fades back as it closes (130 ms). Focus returns at once and the closing list is inert. Under `prefers-reduced-motion` it only fades.
142
+
141
143
  ### Keyboard
142
144
 
143
145
  | Key | Where | Action |
@@ -12,11 +12,10 @@ import {
12
12
  BfButtonComponent,
13
13
  BfInputComponent,
14
14
  BfSegmentedComponent,
15
- BfSelectComponent,
16
15
  BfToolbarComponent,
17
16
  type BfSegmentOption,
18
- type BfSelectOption,
19
17
  } from '@bitforgehq/ui';
18
+ import { BfSelectComponent, type BfSelectOption } from '@bitforgehq/ui/overlay';
20
19
 
21
20
  type ProjectStatus = 'active' | 'paused' | 'done';
22
21
  type StatusFilter = ProjectStatus | 'all';
@@ -125,7 +124,7 @@ export class ToolbarOverviewExampleComponent {
125
124
  Row of search, filters, a view switch and trailing actions above a list or table. Every
126
125
  control projected into it is `sm` unless it sets `size` itself.
127
126
 
128
- A dense row above a list or table: the search field and filters, a view switch, a live result count and the trailing actions. `bf-toolbar` lays the row out, wraps it in a narrow column and makes every control in it `sm`; the controls themselves are ordinary `bf-input`, `bf-select`, `bf-chip-group`, `bf-segmented` and `bf-button`s.
127
+ A dense row above a list or table: the search field and filters, a view switch, a live result count and the trailing actions. `bf-toolbar` lays the row out, wraps it in a narrow column and makes every control in it `sm`; the controls themselves are ordinary `bf-input`, `bf-select` (from `@bitforgehq/ui/overlay`), `bf-chip-group`, `bf-segmented` and `bf-button`s.
129
128
 
130
129
  ## When to use
131
130
 
@@ -191,13 +190,8 @@ The row is a wrapping flex row with an 8 px gap between items and between rows.
191
190
 
192
191
  ```ts
193
192
  import { Component } from '@angular/core';
194
- import {
195
- BfButtonComponent,
196
- BfInputComponent,
197
- BfSelectComponent,
198
- BfToolbarComponent,
199
- type BfSelectOption,
200
- } from '@bitforgehq/ui';
193
+ import { BfButtonComponent, BfInputComponent, BfToolbarComponent } from '@bitforgehq/ui';
194
+ import { BfSelectComponent, type BfSelectOption } from '@bitforgehq/ui/overlay';
201
195
 
202
196
  /**
203
197
  * A toolbar that wraps.
@@ -238,13 +232,8 @@ At phone width (in a desktop web app's narrow window or a narrow column) the sea
238
232
 
239
233
  ```ts
240
234
  import { Component, signal } from '@angular/core';
241
- import {
242
- BfButtonComponent,
243
- BfInputComponent,
244
- BfSelectComponent,
245
- BfToolbarComponent,
246
- type BfSelectOption,
247
- } from '@bitforgehq/ui';
235
+ import { BfButtonComponent, BfInputComponent, BfToolbarComponent } from '@bitforgehq/ui';
236
+ import { BfSelectComponent, type BfSelectOption } from '@bitforgehq/ui/overlay';
248
237
 
249
238
  /**
250
239
  * A toolbar at phone width.
@@ -317,7 +306,7 @@ The `status` element is `role="status"` (an `aria-live="polite"` region), always
317
306
 
318
307
  ## Slots
319
308
 
320
- - `default`: The search field and the filters (bf-input, bf-select, bf-chip-group), in order.
309
+ - `default`: The search field and the filters (bf-input, bf-chip-group, bf-select from /overlay), in order.
321
310
  - `view`: A view switch after the filters, such as a bf-segmented of list and grid.
322
311
  - `actions`: The trailing actions, kept together at the inline end of the row, beside the status.
323
312
 
@@ -0,0 +1,64 @@
1
+ # BfChatComposerHarness
2
+
3
+ Test harness for the chat composer: types, sends, stops and reads its state
4
+
5
+ Class from `@bitforgehq/ui/testing` · since 0.5.0
6
+
7
+ Harness for `bf-chat-composer` (`@bitforgehq/ui/overlay`). Its `label` filter matches the text
8
+ field's name: the visible label, else its `aria-label` ("Message" by default).
9
+
10
+ ```ts
11
+ import { BfChatComposerHarness } from '@bitforgehq/ui/testing';
12
+ ```
13
+
14
+ ## Signature
15
+
16
+ ```ts
17
+ class BfChatComposerHarness extends ComponentHarness
18
+ ```
19
+
20
+ ## Methods
21
+
22
+ ### `getLabel(): Promise<string>`
23
+
24
+ The text field's name: the visible label, else its `aria-label`.
25
+
26
+ ### `getValue(): Promise<string>`
27
+
28
+ The text in the field.
29
+
30
+ ### `setValue(text: string): Promise<void>`
31
+
32
+ Replaces the text as the user would type it (`changed` and the value update).
33
+
34
+ | Parameter | Type | Description |
35
+ | --------- | -------- | ------------- |
36
+ | `text` | `string` | The new text. |
37
+
38
+ ### `send(): Promise<void>`
39
+
40
+ Sends the text with the send button, as a click does. Does nothing while it cannot send.
41
+
42
+ ### `pressEnter(): Promise<void>`
43
+
44
+ Sends the text with `Enter` in the field, as the keyboard does.
45
+
46
+ ### `stop(): Promise<void>`
47
+
48
+ Stops the running reply with the stop button. Does nothing unless a reply is running.
49
+
50
+ ### `isRunning(): Promise<boolean>`
51
+
52
+ Whether a reply is running, so the button stops instead of sending.
53
+
54
+ ### `isDisabled(): Promise<boolean>`
55
+
56
+ Whether the composer is disabled (its text field is).
57
+
58
+ ### `canAct(): Promise<boolean>`
59
+
60
+ Whether the button can send (or stop) now: not disabled and, to send, with text.
61
+
62
+ ### `getButtonLabel(): Promise<string>`
63
+
64
+ The button's name, "Send" or "Stop" by default.
@@ -0,0 +1,27 @@
1
+ # BfChatMessageRole
2
+
3
+ Who wrote a chat message, the user or the assistant
4
+
5
+ Type from `@bitforgehq/ui` · since 0.5.0
6
+
7
+ Who wrote a `bf-chat-message`: `user` (a tinted bubble at the inline end) or `assistant` (full
8
+ width, no bubble).
9
+
10
+ ```ts
11
+ import { type BfChatMessageRole } from '@bitforgehq/ui';
12
+ ```
13
+
14
+ ## Signature
15
+
16
+ ```ts
17
+ type BfChatMessageRole = 'user' | 'assistant'
18
+ ```
19
+
20
+ ## Values
21
+
22
+ - `user`
23
+ - `assistant`
24
+
25
+ ## Used by
26
+
27
+ - [bf-chat-message](../components/chat-message.md)
@@ -0,0 +1,28 @@
1
+ # BfChatMessageStatus
2
+
3
+ How a chat message ended: done, stopped by the user, or failed
4
+
5
+ Type from `@bitforgehq/ui` · since 0.5.0
6
+
7
+ How a `bf-chat-message` ended: `done` (the default, no status line), `stopped` (the user
8
+ stopped the reply) or `failed` (it did not arrive or was not sent).
9
+
10
+ ```ts
11
+ import { type BfChatMessageStatus } from '@bitforgehq/ui';
12
+ ```
13
+
14
+ ## Signature
15
+
16
+ ```ts
17
+ type BfChatMessageStatus = 'done' | 'stopped' | 'failed'
18
+ ```
19
+
20
+ ## Values
21
+
22
+ - `done`
23
+ - `stopped`
24
+ - `failed`
25
+
26
+ ## Used by
27
+
28
+ - [bf-chat-message](../components/chat-message.md)
@@ -0,0 +1,18 @@
1
+ # BfFadeInDirective
2
+
3
+ Fades an image in once it has loaded instead of popping in
4
+
5
+ Directive from `@bitforgehq/ui` · since 0.5.0
6
+
7
+ Fades an image in when it has loaded instead of letting it pop in line by line: put
8
+ `bfFadeIn` on the `<img>`. The image stays transparent until its `load` (or `error`) event,
9
+ then fades in over 260 ms (`duration-slow`), at once under `prefers-reduced-motion: reduce`. An
10
+ image that is already loaded when it renders (from the cache) shows straight away. Reserve its
11
+ space (`width`/`height` attributes or an aspect ratio) so the layout does not move when it
12
+ arrives; for a placeholder while it loads, put a `bf-skeleton` behind it.
13
+
14
+ ```ts
15
+ import { BfFadeInDirective } from '@bitforgehq/ui';
16
+ ```
17
+
18
+ Selector: `img[bfFadeIn]`
@@ -0,0 +1,67 @@
1
+ # BfFileInputHarness
2
+
3
+ Test harness for the file input: drops files and reads the list and rejections
4
+
5
+ Class from `@bitforgehq/ui/testing` · since 0.5.0
6
+
7
+ Harness for `bf-file-input`, in both looks. `addFiles()` drops files on the field, so they go
8
+ through the same `accept`, `maxSize` and `maxFiles` rules as a real drop; read the outcome with
9
+ `getFileNames()` and `getRejected()`. It works by file name, so a test never needs the rows.
10
+
11
+ ```ts
12
+ import { BfFileInputHarness } from '@bitforgehq/ui/testing';
13
+ ```
14
+
15
+ ## Signature
16
+
17
+ ```ts
18
+ class BfFileInputHarness extends ComponentHarness
19
+ ```
20
+
21
+ ## Methods
22
+
23
+ ### `getLabel(): Promise<string>`
24
+
25
+ The visible label without the required mark, else `ariaLabel`.
26
+
27
+ ### `getErrorText(): Promise<string>`
28
+
29
+ The error text under the field (an explicit message, or the first form error once touched).
30
+
31
+ ### `getVariant(): Promise<'field' | 'dropzone'>`
32
+
33
+ The look of the field.
34
+
35
+ ### `isDisabled(): Promise<boolean>`
36
+
37
+ Whether the field is disabled.
38
+
39
+ ### `isReadonly(): Promise<boolean>`
40
+
41
+ Whether the field is read-only: it has no pick target.
42
+
43
+ ### `addFiles(files: File[]): Promise<void>`
44
+
45
+ Drops files on the field, as a user would. On a disabled or read-only field it does nothing,
46
+ like the UI.
47
+
48
+ | Parameter | Type | Description |
49
+ | --------- | -------- | ------------------ |
50
+ | `files` | `File[]` | The files to drop. |
51
+
52
+ ### `getFileNames(): Promise<string[]>`
53
+
54
+ The names of the chosen files, in order (rejected files are not included).
55
+
56
+ ### `getRejected(): Promise<{ name: string; message: string }[]>`
57
+
58
+ The files the last pick or drop refused, each with its reason, until they are dismissed.
59
+
60
+ ### `removeFile(name: string): Promise<void>`
61
+
62
+ Removes the chosen file with this name, as the row's remove button does. Throws when no
63
+ chosen file has that name or the field cannot be edited.
64
+
65
+ | Parameter | Type | Description |
66
+ | --------- | -------- | ---------------- |
67
+ | `name` | `string` | The file's name. |
@@ -0,0 +1,27 @@
1
+ # BfFileInputVariant
2
+
3
+ The two looks of a file picker, a compact field or a drop zone
4
+
5
+ Type from `@bitforgehq/ui` · since 0.5.0
6
+
7
+ The look of a `bf-file-input`: a compact field with a pick button (`field`), or a drop zone
8
+ (`dropzone`). Both have the same API and behaviour.
9
+
10
+ ```ts
11
+ import { type BfFileInputVariant } from '@bitforgehq/ui';
12
+ ```
13
+
14
+ ## Signature
15
+
16
+ ```ts
17
+ type BfFileInputVariant = 'field' | 'dropzone'
18
+ ```
19
+
20
+ ## Values
21
+
22
+ - `field`
23
+ - `dropzone`
24
+
25
+ ## Used by
26
+
27
+ - [bf-file-input](../components/file-input.md)
@@ -0,0 +1,67 @@
1
+ # BfImageInputHarness
2
+
3
+ Test harness for the image input: drops an image on it and reads the preview
4
+
5
+ Class from `@bitforgehq/ui/testing` · since 0.5.0
6
+
7
+ Harness for `bf-image-input`. `addFile()` drops the image on the tile, so it goes through the
8
+ same `accept` and `maxSize` rules as a real drop; read the outcome with `hasPreview()`,
9
+ `getPreviewSrc()` and `getRejectedMessage()`. jsdom has no `URL.createObjectURL`, so a picked
10
+ image shows no preview there: assert on the bound value, or stub `URL.createObjectURL` to read
11
+ the preview.
12
+
13
+ ```ts
14
+ import { BfImageInputHarness } from '@bitforgehq/ui/testing';
15
+ ```
16
+
17
+ ## Signature
18
+
19
+ ```ts
20
+ class BfImageInputHarness extends ComponentHarness
21
+ ```
22
+
23
+ ## Methods
24
+
25
+ ### `getLabel(): Promise<string>`
26
+
27
+ The visible label without the required mark, else the tile's `aria-label`.
28
+
29
+ ### `getErrorText(): Promise<string>`
30
+
31
+ The error text beside the tile (an explicit message, or the first form error once touched).
32
+
33
+ ### `isDisabled(): Promise<boolean>`
34
+
35
+ Whether the control is disabled.
36
+
37
+ ### `isReadonly(): Promise<boolean>`
38
+
39
+ Whether the control is read-only: its tile is not a button and there are no Upload or Remove
40
+ buttons.
41
+
42
+ ### `hasPreview(): Promise<boolean>`
43
+
44
+ Whether the tile shows an image, picked or from `src`. A picked image needs
45
+ `URL.createObjectURL`, which jsdom lacks: stub it to see one.
46
+
47
+ ### `getPreviewSrc(): Promise<string | null>`
48
+
49
+ The `src` of the shown image.
50
+
51
+ ### `addFile(file: File): Promise<void>`
52
+
53
+ Drops an image on the tile, as a user would. On a disabled or read-only control it does
54
+ nothing, like the UI. It waits on no timer, so it works under fake timers and `fakeAsync`.
55
+
56
+ | Parameter | Type | Description |
57
+ | --------- | ------ | ------------------ |
58
+ | `file` | `File` | The image to drop. |
59
+
60
+ ### `remove(): Promise<void>`
61
+
62
+ Presses Remove, which clears the picked and the existing image. Throws while there is no
63
+ image or the control cannot be edited.
64
+
65
+ ### `getRejectedMessage(): Promise<string>`
66
+
67
+ The reason the last pick was refused, until the next pick or Remove.
@@ -0,0 +1,27 @@
1
+ # BfImageInputShape
2
+
3
+ The two tile shapes of an image picker, a circle or a rounded square
4
+
5
+ Type from `@bitforgehq/ui` · since 0.5.0
6
+
7
+ The shape of a `bf-image-input` tile: a circle (`round`, for avatars) or a rounded square
8
+ (`square`, for logos and covers).
9
+
10
+ ```ts
11
+ import { type BfImageInputShape } from '@bitforgehq/ui';
12
+ ```
13
+
14
+ ## Signature
15
+
16
+ ```ts
17
+ type BfImageInputShape = 'round' | 'square'
18
+ ```
19
+
20
+ ## Values
21
+
22
+ - `round`
23
+ - `square`
24
+
25
+ ## Used by
26
+
27
+ - [bf-image-input](../components/image-input.md)
@@ -0,0 +1,29 @@
1
+ # BfImageViewerActionsContext
2
+
3
+ What the viewer's actions template receives: the shown image, its index and the ref
4
+
5
+ Interface from `@bitforgehq/ui/overlay` · since 0.5.0
6
+
7
+ Context of the `actions` template of `BfImageViewerService.open()`: `let-image`,
8
+ `let-index="index"` and `let-ref="ref"`.
9
+
10
+ ```ts
11
+ import { type BfImageViewerActionsContext } from '@bitforgehq/ui/overlay';
12
+ ```
13
+
14
+ ## Properties
15
+
16
+ | Name | Type | Default | Description |
17
+ | ----------- | -------------------- | -------- | -------------------------------------------------------- |
18
+ | `$implicit` | `BfImageViewerImage` | required | The image the viewer shows (`let-image`). |
19
+ | `index` | `number` | required | Its 0-based index in the set (`let-index="index"`). |
20
+ | `ref` | `BfImageViewerRef` | required | The viewer's ref (`let-ref="ref"`), to close it or step. |
21
+
22
+ ## Uses
23
+
24
+ - [BfImageViewerImage](bf-image-viewer-image.md)
25
+ - [BfImageViewerRef](bf-image-viewer-ref.md)
26
+
27
+ ## Used by
28
+
29
+ - [BfImageViewerOptions](bf-image-viewer-options.md)
@@ -0,0 +1,87 @@
1
+ # BfImageViewerHarness
2
+
3
+ Test harness for an image viewer: its image, index, caption, steps and close
4
+
5
+ Class from `@bitforgehq/ui/testing` · since 0.5.0
6
+
7
+ Harness for `bf-image-viewer`, the lightbox `BfImageViewerService.open()` renders. It renders
8
+ in the CDK overlay container outside the tested component, so get it through
9
+ `TestbedHarnessEnvironment.documentRootLoader(fixture)`. jsdom never loads images: call
10
+ `loadImage()` to fire the shown image's `load` event.
11
+
12
+ ```ts
13
+ import { BfImageViewerHarness } from '@bitforgehq/ui/testing';
14
+ ```
15
+
16
+ ## Signature
17
+
18
+ ```ts
19
+ class BfImageViewerHarness extends ComponentHarness
20
+ ```
21
+
22
+ ## Methods
23
+
24
+ ### `getLabel(): Promise<string>`
25
+
26
+ The viewer's accessible name (`ariaLabel`, else the `imageViewer` label).
27
+
28
+ ### `getIndex(): Promise<number>`
29
+
30
+ The 0-based index of the shown image.
31
+
32
+ ### `getCount(): Promise<number>`
33
+
34
+ How many images the viewer steps through.
35
+
36
+ ### `getCounterText(): Promise<string>`
37
+
38
+ The counter's text ("2 of 5"); a viewer of one image shows none.
39
+
40
+ ### `getSrc(): Promise<string>`
41
+
42
+ The URL of the shown image.
43
+
44
+ ### `getAlt(): Promise<string>`
45
+
46
+ The alternative text of the shown image.
47
+
48
+ ### `getCaption(): Promise<string>`
49
+
50
+ The caption under the shown image.
51
+
52
+ ### `isLoaded(): Promise<boolean>`
53
+
54
+ Whether the shown image has loaded (no spinner and no failure message).
55
+
56
+ ### `hasFailed(): Promise<boolean>`
57
+
58
+ Whether the shown image failed to load (the failure message shows).
59
+
60
+ ### `loadImage(): Promise<void>`
61
+
62
+ Fires the shown image's `load` event, as a browser does when it arrives.
63
+
64
+ ### `failImage(): Promise<void>`
65
+
66
+ Fires the shown image's `error` event, as a browser does when it fails.
67
+
68
+ ### `next(): Promise<void>`
69
+
70
+ Clicks the next button. Throws for a viewer of one image (it has none).
71
+
72
+ ### `previous(): Promise<void>`
73
+
74
+ Clicks the previous button. Throws for a viewer of one image (it has none).
75
+
76
+ ### `pressKey(key: 'ArrowLeft' | 'ArrowRight' | 'Home' | 'End' | 'Escape'): Promise<void>`
77
+
78
+ Presses a key inside the viewer: ArrowLeft and ArrowRight step, Home and End jump, Escape
79
+ closes.
80
+
81
+ | Parameter | Type | Description |
82
+ | --------- | ------------------------------------------------------------ | ----------------- |
83
+ | `key` | `'ArrowLeft' \| 'ArrowRight' \| 'Home' \| 'End' \| 'Escape'` | The key to press. |
84
+
85
+ ### `close(): Promise<void>`
86
+
87
+ Clicks the close button.
@@ -0,0 +1,25 @@
1
+ # BfImageViewerImage
2
+
3
+ One image the viewer shows: its URL, its name as alternative text and a caption
4
+
5
+ Interface from `@bitforgehq/ui/overlay` · since 0.5.0
6
+
7
+ One image of a `BfImageViewerService.open()` set.
8
+
9
+ ```ts
10
+ import { type BfImageViewerImage } from '@bitforgehq/ui/overlay';
11
+ ```
12
+
13
+ ## Properties
14
+
15
+ | Name | Type | Default | Description |
16
+ | --------- | -------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
17
+ | `src` | `string` | required | URL of the full-size image. |
18
+ | `label` | `string` | required | The image's name: its alternative text (`alt`), read when it shows and announced after a step (required: the viewer shows nothing else that names it). |
19
+ | `caption` | `string` | | Text shown under the image; none shows no caption. |
20
+
21
+ ## Used by
22
+
23
+ - [BfImageViewerActionsContext](bf-image-viewer-actions-context.md)
24
+ - [BfImageViewerOptions](bf-image-viewer-options.md)
25
+ - [BfImageViewerRef](bf-image-viewer-ref.md)