@bitforgehq/ui 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (281) hide show
  1. package/CHANGELOG.md +3665 -0
  2. package/LICENSE +21 -0
  3. package/README.md +175 -0
  4. package/ai/MANIFEST.index.json +383 -0
  5. package/ai/MANIFEST.json +7528 -0
  6. package/ai/REFERENCE.index.json +1461 -0
  7. package/ai/REFERENCE.json +7213 -0
  8. package/ai/UI_GUIDE.md +1159 -0
  9. package/ai/components/action-bar.md +209 -0
  10. package/ai/components/action-sheet.md +526 -0
  11. package/ai/components/alert-dialog.md +509 -0
  12. package/ai/components/alert.md +376 -0
  13. package/ai/components/avatar.md +146 -0
  14. package/ai/components/back-button.md +286 -0
  15. package/ai/components/badge.md +171 -0
  16. package/ai/components/button.md +431 -0
  17. package/ai/components/card.md +303 -0
  18. package/ai/components/checkbox.md +418 -0
  19. package/ai/components/chip-group.md +205 -0
  20. package/ai/components/chip.md +300 -0
  21. package/ai/components/content.md +474 -0
  22. package/ai/components/desktop-toast.md +420 -0
  23. package/ai/components/dialog.md +962 -0
  24. package/ai/components/empty-state.md +146 -0
  25. package/ai/components/field.md +319 -0
  26. package/ai/components/header.md +809 -0
  27. package/ai/components/icon-button.md +221 -0
  28. package/ai/components/icon.md +176 -0
  29. package/ai/components/input.md +455 -0
  30. package/ai/components/list-item.md +326 -0
  31. package/ai/components/list.md +178 -0
  32. package/ai/components/menu-button.md +377 -0
  33. package/ai/components/menu.md +661 -0
  34. package/ai/components/modal.md +613 -0
  35. package/ai/components/number-input.md +423 -0
  36. package/ai/components/page.md +299 -0
  37. package/ai/components/progress.md +215 -0
  38. package/ai/components/radio-group.md +432 -0
  39. package/ai/components/refresher.md +377 -0
  40. package/ai/components/segmented.md +517 -0
  41. package/ai/components/select.md +510 -0
  42. package/ai/components/sheet.md +845 -0
  43. package/ai/components/spinner.md +171 -0
  44. package/ai/components/stack-outlet.md +661 -0
  45. package/ai/components/tab-bar.md +427 -0
  46. package/ai/components/tab.md +295 -0
  47. package/ai/components/tabs.md +408 -0
  48. package/ai/components/textarea.md +371 -0
  49. package/ai/components/toast.md +522 -0
  50. package/ai/components/toggle.md +387 -0
  51. package/ai/reference/bf-action-directive.md +21 -0
  52. package/ai/reference/bf-action-sheet-action-role.md +27 -0
  53. package/ai/reference/bf-action-sheet-action.md +28 -0
  54. package/ai/reference/bf-action-sheet-options.md +28 -0
  55. package/ai/reference/bf-action-sheet-service.md +33 -0
  56. package/ai/reference/bf-alert-dialog-button-role.md +27 -0
  57. package/ai/reference/bf-alert-dialog-button.md +27 -0
  58. package/ai/reference/bf-alert-dialog-options.md +29 -0
  59. package/ai/reference/bf-alert-dialog-service.md +34 -0
  60. package/ai/reference/bf-alert-variant.md +28 -0
  61. package/ai/reference/bf-autocapitalize.md +30 -0
  62. package/ai/reference/bf-avatar-size.md +27 -0
  63. package/ai/reference/bf-avatar-variant.md +28 -0
  64. package/ai/reference/bf-back-at-root.md +28 -0
  65. package/ai/reference/bf-back-button-service.md +40 -0
  66. package/ai/reference/bf-badge-variant.md +29 -0
  67. package/ai/reference/bf-button-size.md +29 -0
  68. package/ai/reference/bf-button-type.md +28 -0
  69. package/ai/reference/bf-button-variant.md +29 -0
  70. package/ai/reference/bf-card-padding.md +26 -0
  71. package/ai/reference/bf-card-variant.md +28 -0
  72. package/ai/reference/bf-chip-group-mode.md +27 -0
  73. package/ai/reference/bf-chip-variant.md +26 -0
  74. package/ai/reference/bf-compare-with.md +24 -0
  75. package/ai/reference/bf-component-overlay-ref.md +33 -0
  76. package/ai/reference/bf-confirm-button-role.md +26 -0
  77. package/ai/reference/bf-confirm-button.md +27 -0
  78. package/ai/reference/bf-confirm-options.md +31 -0
  79. package/ai/reference/bf-confirm-size.md +26 -0
  80. package/ai/reference/bf-content-scroll-event.md +21 -0
  81. package/ai/reference/bf-defaults-options.md +32 -0
  82. package/ai/reference/bf-defaults.md +28 -0
  83. package/ai/reference/bf-desktop-toast-config.md +28 -0
  84. package/ai/reference/bf-desktop-toast-harness.md +33 -0
  85. package/ai/reference/bf-desktop-toast-options.md +28 -0
  86. package/ai/reference/bf-desktop-toast-position.md +28 -0
  87. package/ai/reference/bf-desktop-toast-service.md +42 -0
  88. package/ai/reference/bf-dialog-config.md +44 -0
  89. package/ai/reference/bf-dialog-harness.md +52 -0
  90. package/ai/reference/bf-dialog-ref.md +44 -0
  91. package/ai/reference/bf-dialog-role.md +26 -0
  92. package/ai/reference/bf-dialog-service.md +55 -0
  93. package/ai/reference/bf-dialog-size.md +31 -0
  94. package/ai/reference/bf-dialog-template-context.md +32 -0
  95. package/ai/reference/bf-empty-state-heading-level.md +26 -0
  96. package/ai/reference/bf-enter-key-hint.md +31 -0
  97. package/ai/reference/bf-field-control-class.md +32 -0
  98. package/ai/reference/bf-field-control-state.md +28 -0
  99. package/ai/reference/bf-field-size.md +29 -0
  100. package/ai/reference/bf-haptics-impact-style.md +27 -0
  101. package/ai/reference/bf-haptics-notification-type.md +27 -0
  102. package/ai/reference/bf-haptics-service.md +41 -0
  103. package/ai/reference/bf-harness-filters.md +29 -0
  104. package/ai/reference/bf-horizontal-scroll-directive.md +129 -0
  105. package/ai/reference/bf-icon-button-variant.md +28 -0
  106. package/ai/reference/bf-icon-size.md +27 -0
  107. package/ai/reference/bf-input-autocapitalize.md +36 -0
  108. package/ai/reference/bf-input-enter-key-hint.md +38 -0
  109. package/ai/reference/bf-input-input-mode.md +38 -0
  110. package/ai/reference/bf-input-mode.md +32 -0
  111. package/ai/reference/bf-input-type.md +35 -0
  112. package/ai/reference/bf-jsdom-shim-options.md +22 -0
  113. package/ai/reference/bf-keyboard-assist-behavior.md +26 -0
  114. package/ai/reference/bf-keyboard-assist-directive.md +185 -0
  115. package/ai/reference/bf-keyboard-phase.md +30 -0
  116. package/ai/reference/bf-keyboard-service.md +50 -0
  117. package/ai/reference/bf-labels-overrides.md +26 -0
  118. package/ai/reference/bf-labels.md +44 -0
  119. package/ai/reference/bf-menu-button-harness.md +40 -0
  120. package/ai/reference/bf-menu-button-variant.md +27 -0
  121. package/ai/reference/bf-menu-divider-directive.md +13 -0
  122. package/ai/reference/bf-menu-group-directive.md +14 -0
  123. package/ai/reference/bf-menu-harness.md +55 -0
  124. package/ai/reference/bf-menu-item-checkbox-directive.md +31 -0
  125. package/ai/reference/bf-menu-item-directive.md +31 -0
  126. package/ai/reference/bf-menu-item-harness.md +52 -0
  127. package/ai/reference/bf-menu-item-radio-directive.md +29 -0
  128. package/ai/reference/bf-menu-placement.md +29 -0
  129. package/ai/reference/bf-menu-trigger-directive.md +46 -0
  130. package/ai/reference/bf-modal-options.md +30 -0
  131. package/ai/reference/bf-modal-presentation.md +26 -0
  132. package/ai/reference/bf-modal-service.md +38 -0
  133. package/ai/reference/bf-nav-controller.md +59 -0
  134. package/ai/reference/bf-nav-direction.md +23 -0
  135. package/ai/reference/bf-nav-target.md +21 -0
  136. package/ai/reference/bf-number-input-mode.md +28 -0
  137. package/ai/reference/bf-number-input-step.md +25 -0
  138. package/ai/reference/bf-overlay-auto-focus.md +29 -0
  139. package/ai/reference/bf-overlay-controller.md +22 -0
  140. package/ai/reference/bf-overlay-host.md +36 -0
  141. package/ai/reference/bf-overlay-options.md +53 -0
  142. package/ai/reference/bf-overlay-position.md +30 -0
  143. package/ai/reference/bf-overlay-ref.md +53 -0
  144. package/ai/reference/bf-overlay-role.md +27 -0
  145. package/ai/reference/bf-overlay-service.md +53 -0
  146. package/ai/reference/bf-overlay-stack-options.md +24 -0
  147. package/ai/reference/bf-overlay-stack.md +81 -0
  148. package/ai/reference/bf-overlay-template-context.md +24 -0
  149. package/ai/reference/bf-overscroll-stretch-directive.md +163 -0
  150. package/ai/reference/bf-page-context.md +24 -0
  151. package/ai/reference/bf-platform-service.md +53 -0
  152. package/ai/reference/bf-platform.md +28 -0
  153. package/ai/reference/bf-progress-size.md +26 -0
  154. package/ai/reference/bf-progress-tone.md +28 -0
  155. package/ai/reference/bf-radio-group-harness.md +49 -0
  156. package/ai/reference/bf-radio-group-orientation.md +26 -0
  157. package/ai/reference/bf-radio-option.md +30 -0
  158. package/ai/reference/bf-refresher-refresh-event.md +22 -0
  159. package/ai/reference/bf-segment-option.md +29 -0
  160. package/ai/reference/bf-segmented-harness.md +48 -0
  161. package/ai/reference/bf-segmented-size.md +29 -0
  162. package/ai/reference/bf-select-harness.md +70 -0
  163. package/ai/reference/bf-select-option.md +29 -0
  164. package/ai/reference/bf-sheet-auto-focus.md +29 -0
  165. package/ai/reference/bf-sheet-options.md +32 -0
  166. package/ai/reference/bf-sheet-ref.md +45 -0
  167. package/ai/reference/bf-sheet-service.md +34 -0
  168. package/ai/reference/bf-shell-config-mode.md +28 -0
  169. package/ai/reference/bf-shell-config.md +38 -0
  170. package/ai/reference/bf-shell-dynamic-type-limit.md +21 -0
  171. package/ai/reference/bf-shell-dynamic-type.md +25 -0
  172. package/ai/reference/bf-shell-mode.md +28 -0
  173. package/ai/reference/bf-shell-testing-options.md +26 -0
  174. package/ai/reference/bf-size.md +45 -0
  175. package/ai/reference/bf-spinner-size.md +27 -0
  176. package/ai/reference/bf-stack-change.md +22 -0
  177. package/ai/reference/bf-stack-reuse-strategy.md +32 -0
  178. package/ai/reference/bf-stack-transition-event.md +26 -0
  179. package/ai/reference/bf-stack-transition.md +26 -0
  180. package/ai/reference/bf-stacked-overlay.md +23 -0
  181. package/ai/reference/bf-system-bars-style.md +38 -0
  182. package/ai/reference/bf-tab-bar-controller.md +51 -0
  183. package/ai/reference/bf-tab-bar-host.md +52 -0
  184. package/ai/reference/bf-tab-context.md +32 -0
  185. package/ai/reference/bf-tab-links.md +37 -0
  186. package/ai/reference/bf-testing-options.md +27 -0
  187. package/ai/reference/bf-text-scale-service.md +35 -0
  188. package/ai/reference/bf-theme.md +27 -0
  189. package/ai/reference/bf-toast-action.md +25 -0
  190. package/ai/reference/bf-toast-controller.md +17 -0
  191. package/ai/reference/bf-toast-dismiss-reason.md +29 -0
  192. package/ai/reference/bf-toast-options.md +29 -0
  193. package/ai/reference/bf-toast-position.md +26 -0
  194. package/ai/reference/bf-toast-ref.md +41 -0
  195. package/ai/reference/bf-toast-service.md +39 -0
  196. package/ai/reference/bf-toggle-label-position.md +26 -0
  197. package/ai/reference/bf-transition-kind.md +28 -0
  198. package/ai/reference/bf-validation-message.md +31 -0
  199. package/ai/reference/bf-validation-messages.md +33 -0
  200. package/ai/reference/bf-view-event.md +28 -0
  201. package/ai/reference/bf-view-lifecycle.md +41 -0
  202. package/ai/reference/bf-view-state.md +28 -0
  203. package/ai/reference/bf_default_labels.md +21 -0
  204. package/ai/reference/bf_default_values.md +21 -0
  205. package/ai/reference/bf_defaults.md +21 -0
  206. package/ai/reference/bf_desktop_toast_defaults.md +21 -0
  207. package/ai/reference/bf_dialog_data.md +17 -0
  208. package/ai/reference/bf_labels.md +21 -0
  209. package/ai/reference/bf_overlay_data.md +19 -0
  210. package/ai/reference/bf_overlay_host.md +21 -0
  211. package/ai/reference/bf_sheet_default_snap_points.md +17 -0
  212. package/ai/reference/bf_shell_config.md +21 -0
  213. package/ai/reference/bf_shell_defaults.md +21 -0
  214. package/ai/reference/bf_tab_bar.md +21 -0
  215. package/ai/reference/bf_tab_bar_controller.md +21 -0
  216. package/ai/reference/bf_tab_context.md +21 -0
  217. package/ai/reference/bf_tab_links.md +21 -0
  218. package/ai/reference/bf_theme_storage.md +19 -0
  219. package/ai/reference/create-transition.md +36 -0
  220. package/ai/reference/duration_fast.md +17 -0
  221. package/ai/reference/duration_md.md +17 -0
  222. package/ai/reference/duration_overlay.md +17 -0
  223. package/ai/reference/duration_push.md +17 -0
  224. package/ai/reference/fade-down.md +26 -0
  225. package/ai/reference/fade-in.md +25 -0
  226. package/ai/reference/fade-out.md +25 -0
  227. package/ai/reference/fade-up.md +26 -0
  228. package/ai/reference/inject-shell-mode.md +23 -0
  229. package/ai/reference/install-bf-jsdom-shims.md +31 -0
  230. package/ai/reference/ios_duration.md +17 -0
  231. package/ai/reference/ios_easing.md +17 -0
  232. package/ai/reference/is-text-entry.md +25 -0
  233. package/ai/reference/max_complete_ms.md +17 -0
  234. package/ai/reference/md-transition.md +31 -0
  235. package/ai/reference/md_duration.md +17 -0
  236. package/ai/reference/md_easing.md +17 -0
  237. package/ai/reference/overlay_duration.md +21 -0
  238. package/ai/reference/overlay_easing.md +19 -0
  239. package/ai/reference/overlay_reduced_duration.md +17 -0
  240. package/ai/reference/pop-frames-at.md +25 -0
  241. package/ai/reference/prefers-reduced-motion.md +25 -0
  242. package/ai/reference/provide-bf-defaults.md +33 -0
  243. package/ai/reference/provide-bf-desktop-toast.md +28 -0
  244. package/ai/reference/provide-bf-labels.md +38 -0
  245. package/ai/reference/provide-bf-shell-testing.md +34 -0
  246. package/ai/reference/provide-bf-shell.md +41 -0
  247. package/ai/reference/provide-bf-testing.md +33 -0
  248. package/ai/reference/reduced-transition.md +28 -0
  249. package/ai/reference/reduced_duration.md +17 -0
  250. package/ai/reference/resolve-shell-mode.md +33 -0
  251. package/ai/reference/scale-in.md +25 -0
  252. package/ai/reference/settle-duration.md +25 -0
  253. package/ai/reference/settle-pop.md +33 -0
  254. package/ai/reference/settle_easing.md +17 -0
  255. package/ai/reference/should-complete-pop.md +26 -0
  256. package/ai/reference/slide-down.md +26 -0
  257. package/ai/reference/slide-up.md +26 -0
  258. package/ai/reference/with-bf-shell-routing.md +19 -0
  259. package/bin/bf-ui.js +81 -0
  260. package/fesm2022/bitforgehq-ui-icons.mjs +230 -0
  261. package/fesm2022/bitforgehq-ui-icons.mjs.map +1 -0
  262. package/fesm2022/bitforgehq-ui-mobile.mjs +5530 -0
  263. package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -0
  264. package/fesm2022/bitforgehq-ui-number-input.mjs +680 -0
  265. package/fesm2022/bitforgehq-ui-number-input.mjs.map +1 -0
  266. package/fesm2022/bitforgehq-ui-overlay.mjs +2675 -0
  267. package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -0
  268. package/fesm2022/bitforgehq-ui-testing.mjs +402 -0
  269. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -0
  270. package/fesm2022/bitforgehq-ui.mjs +7765 -0
  271. package/fesm2022/bitforgehq-ui.mjs.map +1 -0
  272. package/llms-full.txt +25394 -0
  273. package/llms.txt +329 -0
  274. package/package.json +94 -0
  275. package/theme.css +253 -0
  276. package/types/bitforgehq-ui-icons.d.ts +50 -0
  277. package/types/bitforgehq-ui-mobile.d.ts +2914 -0
  278. package/types/bitforgehq-ui-number-input.d.ts +282 -0
  279. package/types/bitforgehq-ui-overlay.d.ts +1514 -0
  280. package/types/bitforgehq-ui-testing.d.ts +495 -0
  281. package/types/bitforgehq-ui.d.ts +3499 -0
@@ -0,0 +1,295 @@
1
+ # bf-tab
2
+
3
+ One tab bar destination with an icon, a label and an optional count badge
4
+
5
+ `BfTabComponent` from `@bitforgehq/ui` · Navigation · since 0.1.0
6
+
7
+ ## Example
8
+
9
+ ```ts
10
+ import { Component, signal } from '@angular/core';
11
+ import { BfTabBarComponent, BfTabComponent } from '@bitforgehq/ui';
12
+ import { BfIconComponent } from '@bitforgehq/ui/icons';
13
+ import { Inbox, Sun } from 'lucide';
14
+
15
+ /**
16
+ * The bf-tab overview.
17
+ *
18
+ * Live demo of `bf-tab`: two tabs inside a `bf-tab-bar`, one with a badge; click to switch.
19
+ */
20
+ @Component({
21
+ selector: 'app-example-tab-overview',
22
+ imports: [BfTabBarComponent, BfTabComponent, BfIconComponent],
23
+ template: `
24
+ <bf-tab-bar [(active)]="active" [floating]="false" label="Sections">
25
+ <bf-tab id="today" label="Today"><bf-icon [icon]="sun" /></bf-tab>
26
+ <bf-tab id="inbox" label="Inbox" [badge]="2"><bf-icon [icon]="inbox" /></bf-tab>
27
+ </bf-tab-bar>
28
+ <p data-status aria-live="polite" class="text-caption text-text-muted mt-3">
29
+ Active tab: {{ active() }}
30
+ </p>
31
+ `,
32
+ })
33
+ export class TabOverviewExampleComponent {
34
+ readonly active = signal('today');
35
+ readonly sun = Sun;
36
+ readonly inbox = Inbox;
37
+ }
38
+ ```
39
+
40
+ ## Overview
41
+
42
+ One destination inside `bf-tab-bar`: icon in the default slot, `label` under it, optional count
43
+ `badge`. A `button role="tab"` in a standalone bar; inside `bf-tabs`, a link to the tab's URL
44
+ with `aria-current` while active: `page` on the tab's root page, `true` on a child page of it
45
+ (the current section, not the current page).
46
+
47
+ One destination of a [`bf-tab-bar`](https://bitforge-ui.web.app/components/tab-bar): an icon in the default slot with a `label` underneath. A `bf-tab` lives only inside a bar, which owns the selection (`active`), the keyboard navigation and the floating layout; this page covers what a single tab adds: its id, its badge and its disabled state.
48
+
49
+ ## When to use
50
+
51
+ Use `bf-tab` for each destination of a [bf-tab-bar](https://bitforge-ui.web.app/components/tab-bar), and only there. Use [bf-segmented](https://bitforge-ui.web.app/components/segmented) instead for options that switch a view inside a page, and [bf-button](https://bitforge-ui.web.app/components/button) for an action.
52
+
53
+ ## Basic usage
54
+
55
+ Give every tab an `id` (the selection key the bar's `active` holds and `changed` emits) and a short `label`, and put a `bf-icon` in its default slot. The `id` is not a host DOM id: the host drops its own `id` attribute, and the id lands once, on the tab's inner `<button>` (or `<a>` inside `bf-tabs`).
56
+
57
+ ```ts
58
+ import { Component, signal } from '@angular/core';
59
+ import { BfTabBarComponent, BfTabComponent } from '@bitforgehq/ui';
60
+ import { BfIconComponent } from '@bitforgehq/ui/icons';
61
+ import { FileText, FolderOpen, Users } from 'lucide';
62
+
63
+ /**
64
+ * Tabs with an icon and a label.
65
+ *
66
+ * Each `bf-tab` is one destination: its `id` is the selection key the bar's `active` holds.
67
+ */
68
+ @Component({
69
+ selector: 'app-example-tab-basic',
70
+ imports: [BfTabBarComponent, BfTabComponent, BfIconComponent],
71
+ template: `
72
+ <div class="flex flex-col items-center gap-3">
73
+ <bf-tab-bar [(active)]="active" [floating]="false" label="Workspace">
74
+ <bf-tab id="notes" label="Notes"><bf-icon [icon]="fileText" /></bf-tab>
75
+ <bf-tab id="files" label="Files"><bf-icon [icon]="folderOpen" /></bf-tab>
76
+ <bf-tab id="people" label="People"><bf-icon [icon]="users" /></bf-tab>
77
+ </bf-tab-bar>
78
+ <p class="text-caption text-text-muted">active: {{ active() }}</p>
79
+ </div>
80
+ `,
81
+ })
82
+ export class TabBasicExampleComponent {
83
+ protected readonly fileText = FileText;
84
+ protected readonly folderOpen = FolderOpen;
85
+ protected readonly users = Users;
86
+ protected readonly active = signal('notes');
87
+ }
88
+ ```
89
+
90
+ ## Badges
91
+
92
+ Give a tab a `badge` for an unread or pending count, or a short text. The badge sits at the inline end of the icon (its left under `dir="rtl"`). A number is announced through `provideBfLabels()`'s `tabBadge(n)` ("3 new"); a string is announced as written.
93
+
94
+ ```ts
95
+ import { Component, signal } from '@angular/core';
96
+ import { BfTabBarComponent, BfTabComponent } from '@bitforgehq/ui';
97
+ import { BfIconComponent } from '@bitforgehq/ui/icons';
98
+ import { Bell, MessageCircle } from 'lucide';
99
+
100
+ /**
101
+ * Tabs with badges.
102
+ *
103
+ * A number badge is announced as "Messages, 3 new"; a text badge is announced as written.
104
+ */
105
+ @Component({
106
+ selector: 'app-example-tab-badges',
107
+ imports: [BfTabBarComponent, BfTabComponent, BfIconComponent],
108
+ template: `
109
+ <bf-tab-bar [(active)]="active" [floating]="false" label="Updates">
110
+ <bf-tab id="messages" label="Messages" [badge]="3"><bf-icon [icon]="messageCircle" /></bf-tab>
111
+ <bf-tab id="alerts" label="Alerts" badge="!"><bf-icon [icon]="bell" /></bf-tab>
112
+ </bf-tab-bar>
113
+ `,
114
+ })
115
+ export class TabBadgesExampleComponent {
116
+ protected readonly messageCircle = MessageCircle;
117
+ protected readonly bell = Bell;
118
+ protected readonly active = signal('messages');
119
+ }
120
+ ```
121
+
122
+ ## Disabled
123
+
124
+ `disabled` greys the tab out and takes it out of the keyboard navigation; it cannot be clicked. Inside `bf-tabs` a disabled tab is a link without an `href`.
125
+
126
+ ```ts
127
+ import { Component, signal } from '@angular/core';
128
+ import { BfTabBarComponent, BfTabComponent } from '@bitforgehq/ui';
129
+ import { BfIconComponent } from '@bitforgehq/ui/icons';
130
+ import { Archive, PenLine } from 'lucide';
131
+
132
+ /** A disabled tab: skipped by the arrow keys and not clickable. */
133
+ @Component({
134
+ selector: 'app-example-tab-disabled',
135
+ imports: [BfTabBarComponent, BfTabComponent, BfIconComponent],
136
+ template: `
137
+ <bf-tab-bar [(active)]="active" [floating]="false" label="Mail">
138
+ <bf-tab id="drafts" label="Drafts"><bf-icon [icon]="penLine" /></bf-tab>
139
+ <bf-tab id="archive" label="Archive" [disabled]="true"><bf-icon [icon]="archive" /></bf-tab>
140
+ </bf-tab-bar>
141
+ `,
142
+ })
143
+ export class TabDisabledExampleComponent {
144
+ protected readonly penLine = PenLine;
145
+ protected readonly archive = Archive;
146
+ protected readonly active = signal('drafts');
147
+ }
148
+ ```
149
+
150
+ ## Desktop
151
+
152
+ A tab lives in a phone tab bar; see the [bf-tab-bar](https://bitforge-ui.web.app/components/tab-bar) page for what to use on desktop. Under a mouse an inactive tab takes a `surface-muted` fill and a `text` icon on hover, the active capsule `primary-soft-hover`, with the pointer cursor; a disabled tab shows `not-allowed`. The focus ring shows on keyboard focus only.
153
+
154
+ ## Theming
155
+
156
+ - Active tab capsule: `primary-soft` background, `primary-strong` icon/label and a 1.5 px inset
157
+ `primary-strong` outline, so the active tab does not rest on the fill alone. Inactive: `text-muted`.
158
+ - Hover (pointer cursor): the active capsule goes to `primary-soft-hover`, an inactive one takes a
159
+ `surface-muted` fill and `text` icon.
160
+ - Pressed: the capsule takes `primary-soft-pressed` (an inactive one with a `text` icon); none
161
+ while disabled.
162
+ - Disabled tab (`disabled` button, or `aria-disabled` link inside `bf-tabs`): `surface-sunken`
163
+ capsule, `text-disabled` icon and label (never opacity).
164
+ - A label longer than the tab's width wraps to at most two lines; a long word is hyphenated where the page's `lang` allows it (`hyphens-auto`), else broken where it must be.
165
+ - Label: `text-nano` (11/14 px), capped at 200 % (22/28 px, `min(var(--text-nano), 22px)`, in px
166
+ because iOS Dynamic Type scales the root); the capsule (30 × 52 px), its icon, the badge
167
+ (18 px, its count capped at 13 px), the padding and the gaps are px, so they keep their size at
168
+ every text size. The label
169
+ never clips vertically: the bar grows with a two-line label. At compact heights
170
+ (`(max-height: 500px)`, phone landscape) the icon and the label sit side by side
171
+ (`flex-row gap-1.5`).
172
+ - Badge: `primary` background, `on-primary` text; always a circle (`rounded-full`).
173
+ - Shape (tab and capsule): `rounded-control` (`--radius-control`, `9999px` by default).
174
+ - Focus ring: `ring`.
175
+
176
+ ## Accessibility
177
+
178
+ In a standalone bar a tab is a native `<button role="tab">` with `aria-selected`, one of a
179
+ roving-`tabindex` tablist; inside `bf-tabs` it is an `<a href>` link to the tab's root URL, with
180
+ `aria-current` while active. The bar decides which form it takes; the
181
+ [`bf-tab-bar` page](https://bitforge-ui.web.app/components/tab-bar#accessibility) describes both,
182
+ with their keyboard behaviour.
183
+
184
+ The visible `label` is the tab's name. With a `badge`, the badge text is `aria-hidden` and the
185
+ name becomes the label, a comma and the announcement ("Inbox, 3 new", one string with no pause
186
+ before the comma), so it still starts with the visible label. A `disabled` tab is native-disabled
187
+ (a button) or `aria-disabled="true"` without an `href` (a link), so it is skipped by Tab and inert.
188
+ The active capsule stays visible under `forced-colors` (`Highlight`/`HighlightText`).
189
+
190
+ ### Keyboard
191
+
192
+ The bar owns the tab stop and the arrow keys; its [Accessibility section](https://bitforge-ui.web.app/components/tab-bar#keyboard) has the full table.
193
+
194
+ | Key | Action |
195
+ | ----------------------------------- | -------------------------------------------------------------------------------------- |
196
+ | <kbd>Enter</kbd> / <kbd>Space</kbd> | Standalone bar: selects the focused tab; on the active tab, the bar emits `reselected` |
197
+ | <kbd>Enter</kbd> | Inside `bf-tabs`: follows the tab's link |
198
+
199
+ ## Inputs
200
+
201
+ | Name | Type | Default | Description |
202
+ | ---------- | -------------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
203
+ | `id` | `string` | required | Stable identifier; matches `bf-tab-bar`'s `active` when this tab is selected. It is a selection key only, never reflected as the DOM `id` of more than the inner `<button>` (or `<a>` inside `bf-tabs`). |
204
+ | `label` | `string` | required | Visible label under the icon. |
205
+ | `badge` | `string \| number \| null` | `null` | Optional count shown as a badge on the icon capsule; announced to screen readers as part of the tab's accessible name (`aria-label` "{label}, {announcement}", with `provideBfLabels()`'s `tabBadge(n)`, `"{n} new"`, for a number, the string as-is otherwise) since the badge itself is `aria-hidden`. |
206
+ | `disabled` | `boolean` | `false` | Disables the tab: skipped by keyboard navigation, cannot be clicked. |
207
+
208
+ ## Slots
209
+
210
+ - `default`: The tab icon, a `bf-icon` above the label.
211
+
212
+ ## Methods
213
+
214
+ ### `focus(): void`
215
+
216
+ Moves keyboard focus to this tab's button (or link); called by `bf-tab-bar` after arrow-key
217
+ selection.
218
+
219
+ ## Notes
220
+
221
+ ### Do
222
+
223
+ - Give each tab a short, one-word label ("Benachrichtigungen" wraps in a quarter-width tab).
224
+ - Keep ids stable and meaningful (`today`, `inbox`): they are what `active` stores and routes map to.
225
+
226
+ ### Don't
227
+
228
+ - Don't use a `bf-tab` outside a `bf-tab-bar`.
229
+ - Don't rely on the badge alone for important information; it is a count, not a message.
230
+
231
+ ## Migration notes
232
+
233
+ ### 0.3.0
234
+
235
+ **Breaking:** (ARIA contract) inside `bf-tabs` a tab is `<a href>` with `aria-current` while
236
+ active: `page` on the tab's root page, `true` on a child page of it (no `role="tab"` or
237
+ `aria-selected`); a disabled one is `<a role="link" aria-disabled="true">` without `href`. A plain
238
+ primary click selects the tab through the bar (default prevented); Ctrl/Cmd, Shift, Alt and middle
239
+ clicks open the link in a new tab or window. The link's underline is removed with an important
240
+ utility (`no-underline!`), so an unlayered global link rule cannot underline it. See Migration 11.
241
+
242
+ **Behaviour:** a badged tab is named by `aria-label` = label, comma, announcement ("Projects, 3
243
+ new"; was "Projects , 3 new", with a pause, from a visually hidden span that browsers joined with a
244
+ space), in both forms; the `sr-only` announcement span is gone. Without a badge the visible label
245
+ is the name, as before.
246
+
247
+ **Behaviour:** the badge is placed with a logical inset (`-end-2`), so it sits at the icon's
248
+ inline end under `dir="rtl"`.
249
+
250
+ **Behaviour:** a numeric `badge` is announced through `provideBfLabels()`'s `tabBadge(count)`
251
+ (`"{n} new"` by default, now translatable); a string badge is announced as given.
252
+
253
+ **Behaviour:** the active capsule carries a 1.5 px inset `primary-strong` outline (≥ 3:1 on its
254
+ `primary-soft` fill and the bar), so the active tab no longer rests on a fill 1.23:1 from the bar;
255
+ a disabled active capsule is outlined in `text-disabled`. The tab and its capsule use
256
+ `rounded-control` (`--radius-control`); the count badge stays a circle.
257
+
258
+ **Docs:** `bf-tab` has a page of its own (`tab-bar/tab.docs.md`): its id, its badges (moved from
259
+ the `bf-tab-bar` page) and a disabled tab, with the tab's own theming and accessibility; the
260
+ `bf-tab-bar` page links to it.
261
+
262
+ JSDoc of `tab.component.ts` for the API reference: `@slot` docs for `default`; template handlers and
263
+ framework hooks marked `@internal`, so the reference leaves them out. No behaviour change.
264
+
265
+ **Behaviour:** a pressed state (F-045): the capsule of an enabled tab takes `primary-soft-pressed` (an inactive one with the `text` icon) while the tab is held down. None while disabled; under forced colours the system colours win.
266
+
267
+ **Behaviour:** large text (F-051): the label's size and line height are capped at 200 %
268
+ (`min(var(--text-nano), 22px)`, `min(var(--text-nano--line-height), 28px)`, in px because iOS
269
+ Dynamic Type scales the root); it still wraps to at most two lines and never clips vertically. The
270
+ tab has 4 px of vertical padding, so a grown tab keeps off the bar's edge. The capsule (30 × 52
271
+ px), the badge (18 px, its count capped at 13 px), the padding and the gaps are px, so they keep
272
+ their size at every text size. The label hyphenates a long word where the engine has
273
+ hyphenation for the page's `lang` (`hyphens-auto wrap-break-word`, was `wrap-anywhere`), and
274
+ otherwise still breaks it rather than overflowing (WKWebView on the iOS 18 simulator does not
275
+ hyphenate "Projects", so it still reads "Projec/ts" at AX5). At
276
+ compact heights (`(max-height: 500px)`, F-054) the icon and the label sit side by side
277
+ (`flex-row gap-[6px]`).
278
+
279
+ ### 0.2.0
280
+
281
+ The label is `text-nano` (11/14; the line was 16.5 px). Dropped the `[&>svg]:h-5 [&>svg]:w-5`
282
+ selector, which never matched (icons render inside the `bf-icon` host). A disabled tab uses tokens
283
+ instead of `opacity-40`: `surface-sunken` capsule, `text-disabled` icon and label. The tab can
284
+ shrink (`min-w-0`) and its label is capped at `max-w-full px-1` (it wraps, see "Changed" below), so
285
+ a long label no longer overflows its quarter of the bar.
286
+
287
+ Fixed: the tab shows a pointer cursor and its capsule a hover (`primary-soft-hover` when active,
288
+ `surface-muted` fill and `text` icon when inactive); a disabled tab keeps its sunken capsule.
289
+
290
+ Changed: a long label wraps to at most two lines (`line-clamp-2 wrap-anywhere text-center`) instead
291
+ of truncating to one, so "Benachrichtigungen" stays readable in a quarter-width tab.
292
+
293
+ ### 0.1.0
294
+
295
+ New `bf-tab`: one destination inside `bf-tab-bar` — an icon in the default slot, `label` under it, and an optional `badge` count. `id` and `label` are required; `disabled` removes it from keyboard navigation and blocks clicks. Renders a native `<button role="tab">` with `aria-selected` and a roving `tabindex` driven by the bar's `tabStop`; the active tab's icon sits on a `primary-soft` capsule (`forced-colors:bg-[Highlight]`) with a `primary-strong` label, inactive tabs are `text-muted`. The host no longer reflects `id` as a DOM attribute (`bf-tab id="today"` previously duplicated `id="today"` onto both the host and the inner `<button>`); the id now lands once, on the button. The badge is `aria-hidden`; a visually hidden `sr-only` span after the label announces it instead (`"{n} new"` for a numeric badge, the string as-is otherwise), so the tab's accessible name carries meaning instead of a bare number.