@bitforgehq/ui 0.3.1 → 0.3.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 (49) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/README.md +9 -8
  3. package/ai/MANIFEST.index.json +18 -0
  4. package/ai/MANIFEST.json +380 -31
  5. package/ai/REFERENCE.index.json +63 -0
  6. package/ai/REFERENCE.json +265 -7
  7. package/ai/UI_GUIDE.md +59 -33
  8. package/ai/components/app-frame.md +335 -0
  9. package/ai/components/card.md +56 -2
  10. package/ai/components/empty-state.md +99 -6
  11. package/ai/components/header.md +14 -1
  12. package/ai/components/sidebar-toggle.md +287 -0
  13. package/ai/components/sidebar.md +188 -10
  14. package/ai/components/stat.md +74 -10
  15. package/ai/components/table.md +152 -5
  16. package/ai/components/tabs.md +5 -1
  17. package/ai/components/toolbar.md +69 -4
  18. package/ai/reference/bf-app-frame-breakpoint.md +27 -0
  19. package/ai/reference/bf-app-frame-content-width.md +29 -0
  20. package/ai/reference/bf-empty-state-heading-level.md +1 -1
  21. package/ai/reference/bf-empty-state-heading.md +33 -0
  22. package/ai/reference/bf-labels.md +7 -0
  23. package/ai/reference/bf-select-harness.md +4 -0
  24. package/ai/reference/bf-sidebar-state-service.md +21 -0
  25. package/ai/reference/bf-sidebar-toggle-harness.md +32 -0
  26. package/ai/reference/bf-size.md +1 -0
  27. package/ai/reference/bf-stat-appearance.md +33 -0
  28. package/ai/reference/bf-stat-variant.md +1 -1
  29. package/ai/reference/bf-table-harness.md +7 -1
  30. package/ai/reference/bf-table-stack.md +29 -0
  31. package/ai/reference/bf_sidebar_state_storage.md +20 -0
  32. package/ai/reference/provide-bf-labels.md +4 -3
  33. package/ai/reference/provide-bf-sidebar-state.md +20 -0
  34. package/bin/bf-ui.js +433 -3
  35. package/fesm2022/bitforgehq-ui-mobile.mjs +11 -2
  36. package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -1
  37. package/fesm2022/bitforgehq-ui-overlay.mjs +571 -446
  38. package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
  39. package/fesm2022/bitforgehq-ui-testing.mjs +22 -2
  40. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
  41. package/fesm2022/bitforgehq-ui.mjs +777 -127
  42. package/fesm2022/bitforgehq-ui.mjs.map +1 -1
  43. package/llms-full.txt +1605 -43
  44. package/llms.txt +11 -0
  45. package/package.json +1 -1
  46. package/theme.css +13 -0
  47. package/types/bitforgehq-ui-overlay.d.ts +51 -0
  48. package/types/bitforgehq-ui-testing.d.ts +49 -1
  49. package/types/bitforgehq-ui.d.ts +284 -20
@@ -236,6 +236,26 @@ interface BfLabels {
236
236
  * @default 'Select all rows'
237
237
  */
238
238
  readonly tableSelectAll: string;
239
+ /**
240
+ * The label of a stacked bf-table's sort select.
241
+ * @default 'Sort by'
242
+ */
243
+ readonly tableSortBy: string;
244
+ /**
245
+ * A stacked bf-table's first sort option: rows in the order given, no column sorted.
246
+ * @default 'Not sorted'
247
+ */
248
+ readonly tableSortNone: string;
249
+ /**
250
+ * A stacked bf-table's sort option for a column in ascending order.
251
+ * @default (column) => `${column}, ascending`
252
+ */
253
+ readonly tableSortAscending: (column: string) => string;
254
+ /**
255
+ * A stacked bf-table's sort option for a column in descending order.
256
+ * @default (column) => `${column}, descending`
257
+ */
258
+ readonly tableSortDescending: (column: string) => string;
239
259
  /**
240
260
  * bf-theme-switch's and bf-theme-menu-button's name without a label.
241
261
  * @default 'Theme'
@@ -276,6 +296,21 @@ interface BfLabels {
276
296
  * @default (count) => `${count} new`
277
297
  */
278
298
  readonly navBadge: (count: number) => string;
299
+ /**
300
+ * bf-sidebar-toggle's name and tooltip while the sidebar is expanded.
301
+ * @default 'Collapse sidebar'
302
+ */
303
+ readonly sidebarCollapse: string;
304
+ /**
305
+ * bf-sidebar-toggle's name and tooltip while the sidebar is an icon rail.
306
+ * @default 'Expand sidebar'
307
+ */
308
+ readonly sidebarExpand: string;
309
+ /**
310
+ * bf-app-frame's skip link, the first stop of the tab order, which moves focus to the content.
311
+ * @default 'Skip to main content'
312
+ */
313
+ readonly skipToContent: string;
279
314
  /**
280
315
  * bf-pagination's navigation name.
281
316
  * @default 'Pagination'
@@ -507,9 +542,10 @@ export declare const BF_LABELS: InjectionToken<BfLabels>;
507
542
  * Replaces built-in strings, merged over the parent's (validation merged key by key); a key left
508
543
  * out or set to `undefined` keeps the parent's string. In `ApplicationConfig.providers` it covers
509
544
  * every string. In a component's `providers` it covers that sub-tree's widgets and form controls
510
- * (`loading`, `dismiss`, `tabBar`, `tabBadge`, `back`, `refreshing`, `tableSelectAll`, `theme`,
511
- * `themeSystem`, `themeLight`, `themeDark`, `breadcrumb`, `breadcrumbExpand`, `navigation`,
512
- * `navBadge`, `pagination`, `previousPage`, `nextPage`, `pageOf`, `goToPage`, `tabGroup`,
545
+ * (`loading`, `dismiss`, `tabBar`, `tabBadge`, `back`, `refreshing`, `tableSelectAll`, `tableSortBy`,
546
+ * `tableSortNone`, `tableSortAscending`, `tableSortDescending`, `theme`, `themeSystem`, `themeLight`, `themeDark`,
547
+ * `breadcrumb`, `breadcrumbExpand`, `navigation`, `navBadge`, `sidebarCollapse`, `sidebarExpand`,
548
+ * `skipToContent`, `pagination`, `previousPage`, `nextPage`, `pageOf`, `goToPage`, `tabGroup`,
513
549
  * `calendarPreviousMonth`, `calendarNextMonth`, `calendarChooseMonth`, `calendarChooseYear`,
514
550
  * `statTrendUp`, `statTrendDown`, `statTrendFlat`, `comboboxEmpty`, `comboboxRemove`,
515
551
  * `dateInputDay`, `dateInputMonth`, `dateInputYear`, `dateInputOpenCalendar`, `dateInputInvalid`,
@@ -542,6 +578,9 @@ type BfColorSchemeStorage = Pick<Storage, 'getItem' | 'setItem'>;
542
578
  * `ɵcreateMemoryColorSchemeStorage`.
543
579
  */
544
580
  declare function createMemoryColorSchemeStorage(): BfColorSchemeStorage;
581
+ /** `localStorage`, or `null` where there is none or reading it throws (storage disabled, SSR).
582
+ * Internal: `BF_SIDEBAR_STATE_STORAGE` (`sidebar-state.ts`) falls back the same way. */
583
+ declare function browserStorage(): Storage | null;
545
584
  /**
546
585
  * Where `BfColorSchemeService` keeps the colour scheme choice (the key `bf-theme`): `localStorage`
547
586
  * when it is available, otherwise an in-memory map. Provide another store (a native preferences
@@ -608,6 +647,61 @@ export declare class BfColorSchemeService {
608
647
  * @since 0.3.1
609
648
  */
610
649
  export declare function provideBfColorScheme(): EnvironmentProviders;
650
+ /**
651
+ * Where `BfSidebarStateService` keeps whether the sidebar is collapsed (the key
652
+ * `bf-sidebar-collapsed`, `'true'` or `'false'`): `localStorage` when it is available, otherwise
653
+ * an in-memory map. Provide another store (`sessionStorage`, or an in-memory one in tests) to keep
654
+ * it elsewhere.
655
+ *
656
+ * @example
657
+ * providers: [{ provide: BF_SIDEBAR_STATE_STORAGE, useValue: sessionStorage }]
658
+ * @summary Injection token for the store that keeps the collapsed sidebar between visits
659
+ * @since 0.3.2
660
+ */
661
+ export declare const BF_SIDEBAR_STATE_STORAGE: InjectionToken<Pick<Storage, "getItem" | "setItem">>;
662
+ /**
663
+ * Whether the app's `bf-sidebar` is collapsed to an icon rail, remembered between visits: the app
664
+ * binds the sidebar's `[(collapsed)]` to `sidebarState.collapsed`. With `provideBfSidebarState()`
665
+ * every change is stored in `BF_SIDEBAR_STATE_STORAGE` under `bf-sidebar-collapsed`; without it
666
+ * the signal still holds the state but nothing is written. Storage is read in the browser only, so a
667
+ * server render starts expanded and writes nothing. The widgets never inject it.
668
+ *
669
+ * @example
670
+ * protected readonly sidebarState = inject(BfSidebarStateService);
671
+ * // <bf-sidebar [(collapsed)]="sidebarState.collapsed">…</bf-sidebar>
672
+ * @summary The sidebar's collapsed state, kept in storage between visits of the app
673
+ * @since 0.3.2
674
+ */
675
+ export declare class BfSidebarStateService {
676
+ private readonly storage;
677
+ private readonly injector;
678
+ private readonly browser;
679
+ /** Whether the sidebar is collapsed: the stored state in the browser, else false. Bind it
680
+ * two-way to `bf-sidebar`'s `collapsed`. */
681
+ readonly collapsed: import("@angular/core").WritableSignal<boolean>;
682
+ private claimed;
683
+ /**
684
+ * Starts storing every change, once: called by `provideBfSidebarState()`. Nothing is written on
685
+ * the server.
686
+ * @internal
687
+ */
688
+ claimStorage(): void;
689
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfSidebarStateService, never>;
690
+ static ɵprov: i0.ɵɵInjectableDeclaration<any>;
691
+ }
692
+ /**
693
+ * Lets `BfSidebarStateService` remember the collapsed sidebar: it stores every change of its
694
+ * `collapsed` signal (key `bf-sidebar-collapsed`, `localStorage` in the browser), so the app opens
695
+ * with the sidebar as the user left it. Add it to `ApplicationConfig.providers` and bind the
696
+ * sidebar's `[(collapsed)]` to `sidebarState.collapsed`.
697
+ *
698
+ * @example
699
+ * export const appConfig: ApplicationConfig = { providers: [provideBfSidebarState()] };
700
+ * @returns The providers that make the service store the state and start it with the app.
701
+ * @summary Remembers the collapsed sidebar between visits, for desktop web apps
702
+ * @since 0.3.2
703
+ */
704
+ export declare function provideBfSidebarState(): EnvironmentProviders;
611
705
  /**
612
706
  * The diameter of a `bf-spinner`: sm, md or lg.
613
707
  *
@@ -3474,6 +3568,15 @@ export declare class BfAlertComponent {
3474
3568
  * @since 0.3.0
3475
3569
  */
3476
3570
  type BfEmptyStateHeadingLevel = 2 | 3;
3571
+ /**
3572
+ * The heading level a `bf-empty-state` title takes: a `BfEmptyStateHeadingLevel`, or `1` when the
3573
+ * empty state is the page itself (a not-found or no-access page). A new type, so `Record`s over
3574
+ * the released `BfEmptyStateHeadingLevel` keep compiling.
3575
+ *
3576
+ * @summary The heading level of an empty state title, one for a whole page
3577
+ * @since 0.3.2
3578
+ */
3579
+ type BfEmptyStateHeading = BfEmptyStateHeadingLevel | 1;
3477
3580
  /**
3478
3581
  * Placeholder for a screen or list with nothing in it yet: an icon tile, a title, one sentence,
3479
3582
  * and the action that fills it.
@@ -3494,8 +3597,8 @@ export declare class BfEmptyStateComponent {
3494
3597
  readonly title: import("@angular/core").InputSignal<string>;
3495
3598
  /** One sentence on how to fill it. */
3496
3599
  readonly description: import("@angular/core").InputSignal<string>;
3497
- /** Heading level of the title so the empty state fits the page outline. */
3498
- readonly headingLevel: import("@angular/core").InputSignal<BfEmptyStateHeadingLevel>;
3600
+ /** Heading level of the title so the empty state fits the page outline; 1 when it is the page. */
3601
+ readonly headingLevel: import("@angular/core").InputSignal<BfEmptyStateHeading>;
3499
3602
  static ɵfac: i0.ɵɵFactoryDeclaration<BfEmptyStateComponent, never>;
3500
3603
  static ɵcmp: i0.ɵɵComponentDeclaration<BfEmptyStateComponent, "bf-empty-state", never, {
3501
3604
  "title": {
@@ -3683,7 +3786,7 @@ export declare class BfTabComponent {
3683
3786
  /** `aria-current` of the link form: `page` while the active tab's root page is shown, `true`
3684
3787
  * while a child page of it is (the tab is the current section, not the current page), else
3685
3788
  * `null`. */
3686
- readonly current: import("@angular/core").Signal<"page" | "true" | null>;
3789
+ readonly current: import("@angular/core").Signal<"true" | "page" | null>;
3687
3790
  /** The badge as announced after the label in the accessible name when `badge()` is set. */
3688
3791
  readonly badgeAnnouncement: import("@angular/core").Signal<string | null>;
3689
3792
  /**
@@ -4153,7 +4256,7 @@ export declare class BfPageHeaderComponent {
4153
4256
  * @since 0.3.1
4154
4257
  * @slot default The search field and the filters (bf-input, bf-select, bf-chip-group), in order.
4155
4258
  * @slot view A view switch after the filters, such as a bf-segmented of list and grid.
4156
- * @slot actions The trailing actions, kept together at the inline end of the row.
4259
+ * @slot actions The trailing actions, kept together at the inline end of the row, beside the status.
4157
4260
  */
4158
4261
  export declare class BfToolbarComponent {
4159
4262
  /** The group's accessible name, such as "Project filters"; unnamed when empty. */
@@ -4247,6 +4350,15 @@ type BfTableAlign = 'start' | 'end';
4247
4350
  * @since 0.3.1
4248
4351
  */
4249
4352
  type BfTableSortDirection = 'ascending' | 'descending';
4353
+ /**
4354
+ * When a `bf-table` renders each row as a card of label/value pairs: `never` (the default),
4355
+ * `narrow` while the table is narrower than 36rem (a container query), or `coarse` under a coarse
4356
+ * pointer at any width.
4357
+ *
4358
+ * @summary When a table stacks its rows into cards: never, when narrow, or under touch
4359
+ * @since 0.3.2
4360
+ */
4361
+ type BfTableStack = 'never' | 'narrow' | 'coarse';
4250
4362
  /**
4251
4363
  * One column of a `bf-table`: the row property it shows, its header and how it behaves.
4252
4364
  *
@@ -4296,7 +4408,8 @@ interface BfTableEntry<T> {
4296
4408
  /**
4297
4409
  * Data table for desktop: column headers that set a sort, optional row selection with
4298
4410
  * checkboxes, custom cells from `bfTableCell` templates and an empty slot. It never sorts or
4299
- * filters itself; the consumer sorts the rows in a `computed()` from `sort`.
4411
+ * filters itself; the consumer sorts the rows in a `computed()` from `sort`. With `stack` it
4412
+ * renders each row as a tile of label/value pairs in a narrow space or under touch.
4300
4413
  *
4301
4414
  * @example
4302
4415
  * <bf-table label="Tasks" [rows]="sorted()" [columns]="columns" [(sort)]="sort" selectable [(selection)]="selected">
@@ -4331,11 +4444,16 @@ export declare class BfTableComponent<T = unknown> {
4331
4444
  /** Row height step: sm 40, md 48, lg 56 px (the header 32/40/48; at least 44 px under a coarse
4332
4445
  * pointer); unset follows `provideBfDefaults()` (`controlSize`, `md` by default). */
4333
4446
  readonly size: import("@angular/core").InputSignal<BfSize | undefined>;
4334
- private readonly labels;
4447
+ /** When the rows render as cards of label/value pairs: `never`, `narrow` (the table is
4448
+ * narrower than 36rem) or `coarse` (under a coarse pointer, at any width). */
4449
+ readonly stack: import("@angular/core").InputSignal<BfTableStack>;
4450
+ protected readonly labels: import("@bitforgehq/ui").BfLabels;
4335
4451
  private readonly defaults;
4336
4452
  private readonly table;
4337
4453
  private readonly cells;
4338
4454
  private readonly id;
4455
+ /** The caption's id, which names the table while it can stack. */
4456
+ protected readonly captionId: string;
4339
4457
  /** The size in effect: `size`, else the app's `controlSize` default. */
4340
4458
  protected readonly resolvedSize: import("@angular/core").Signal<BfSize>;
4341
4459
  /** The header checkbox's name: `selectAllLabel`, else the `tableSelectAll` label. */
@@ -4351,19 +4469,37 @@ export declare class BfTableComponent<T = unknown> {
4351
4469
  protected readonly someSelected: import("@angular/core").Signal<boolean>;
4352
4470
  /** The number of columns, the selection column included: the empty row's `colspan`. */
4353
4471
  protected readonly columnCount: import("@angular/core").Signal<number>;
4354
- protected readonly sortButton: string;
4472
+ /** Whether the table can stack its rows (any `stack` but `never`); it then sets explicit
4473
+ * table roles, because some browsers drop a table's semantics once its display changes. */
4474
+ protected readonly stacks: import("@angular/core").Signal<boolean>;
4475
+ /** The Sort by select's options: Not sorted (`''`), then each sortable column ascending and
4476
+ * descending; none without a sortable column. */
4477
+ protected readonly sortOptions: import("@angular/core").Signal<BfSelectOption<string>[]>;
4478
+ /** The Sort by select's value: the option of `sort`, Not sorted while `sort` is null. */
4479
+ protected readonly sortValue: import("@angular/core").Signal<string>;
4480
+ protected readonly hostClasses: import("@angular/core").Signal<string>;
4481
+ protected readonly stackBarClasses: import("@angular/core").Signal<string>;
4482
+ protected readonly tableClasses: import("@angular/core").Signal<string>;
4483
+ protected readonly headClasses: import("@angular/core").Signal<string>;
4484
+ protected readonly bodyGroupClasses: import("@angular/core").Signal<string>;
4485
+ protected readonly sortButtonClasses: import("@angular/core").Signal<string>;
4486
+ protected readonly notStackedClasses: import("@angular/core").Signal<string>;
4487
+ protected readonly stackedOnlyClasses: import("@angular/core").Signal<string>;
4488
+ protected readonly stackEmptyClasses: import("@angular/core").Signal<string>;
4355
4489
  protected readonly selectHeadClasses: import("@angular/core").Signal<string>;
4356
4490
  protected readonly selectBodyClasses: import("@angular/core").Signal<string>;
4491
+ /** A body cell's height step, with the coarse-pointer height unless the table stacks there. */
4492
+ private readonly bodyHeight;
4357
4493
  /**
4358
4494
  * The classes of a column's header cell.
4359
4495
  * @internal
4360
4496
  */
4361
- headClasses(column: BfTableColumn): string;
4497
+ headCellClasses(column: BfTableColumn): string;
4362
4498
  /**
4363
- * The classes of a column's body cell.
4499
+ * The classes of a column's body cell; the first one is a stacked tile's title.
4364
4500
  * @internal
4365
4501
  */
4366
- bodyClasses(column: BfTableColumn): string;
4502
+ bodyClasses(column: BfTableColumn, first: boolean): string;
4367
4503
  /**
4368
4504
  * The classes of the body row with this key.
4369
4505
  * @internal
@@ -4395,6 +4531,12 @@ export declare class BfTableComponent<T = unknown> {
4395
4531
  * @param key The column's `key`.
4396
4532
  */
4397
4533
  sortBy(key: string): void;
4534
+ /**
4535
+ * Sorts by a Sort by option (`<key>:<direction>`) of a stacked table; Not sorted sets `sort` to
4536
+ * null.
4537
+ * @internal
4538
+ */
4539
+ sortFromOption(value: string): void;
4398
4540
  /**
4399
4541
  * Selects or clears every row; keys of rows not shown stay as they are.
4400
4542
  * @param selected True to select every row, false to clear them.
@@ -4459,6 +4601,11 @@ export declare class BfTableComponent<T = unknown> {
4459
4601
  "required": false;
4460
4602
  "isSignal": true;
4461
4603
  };
4604
+ "stack": {
4605
+ "alias": "stack";
4606
+ "required": false;
4607
+ "isSignal": true;
4608
+ };
4462
4609
  }, {
4463
4610
  "sort": "sortChange";
4464
4611
  "selection": "selectionChange";
@@ -4543,6 +4690,15 @@ export declare class BfDescriptionItemComponent {
4543
4690
  * @since 0.3.1
4544
4691
  */
4545
4692
  type BfStatVariant = 'plain' | 'card';
4693
+ /**
4694
+ * The surface of a `bf-stat`, as its `variant` input takes it: a `BfStatVariant` or tile (a
4695
+ * sunken, borderless tile for a stats row inside a raised card). A new type, so `Record`s over
4696
+ * the released `BfStatVariant` keep compiling.
4697
+ *
4698
+ * @summary The three stat surfaces, plain, an outlined card or a sunken tile
4699
+ * @since 0.3.2
4700
+ */
4701
+ type BfStatAppearance = BfStatVariant | 'tile';
4546
4702
  /**
4547
4703
  * The direction of a `bf-stat` delta: up, down or flat (no change).
4548
4704
  *
@@ -4566,6 +4722,7 @@ type BfStatTrendIntent = 'positive' | 'negative';
4566
4722
  *
4567
4723
  * @example
4568
4724
  * <bf-stat label="Revenue" value="€48,200" delta="+12%" trend="up" />
4725
+ * <bf-stat label="Orders" value="1,204" variant="tile" />
4569
4726
  * <bf-stat label="Cook time" value="30 min" variant="card">
4570
4727
  * <bf-icon bfSlot="icon" [icon]="Flame" />
4571
4728
  * Oven at 200 °C
@@ -4581,8 +4738,8 @@ export declare class BfStatComponent {
4581
4738
  readonly label: import("@angular/core").InputSignal<string>;
4582
4739
  /** The figure, already formatted (`45 min`, `1,204`, `98%`). */
4583
4740
  readonly value: import("@angular/core").InputSignal<string>;
4584
- /** Surface: plain (default) on its container, or card, an outlined tile of its own. */
4585
- readonly variant: import("@angular/core").InputSignal<BfStatVariant>;
4741
+ /** Surface: plain (default) on its container, card (an outlined tile) or tile (sunken, no border). */
4742
+ readonly variant: import("@angular/core").InputSignal<BfStatAppearance>;
4586
4743
  /** A change shown in a pill beside the value, already formatted (`+12%`); empty shows none. */
4587
4744
  readonly delta: import("@angular/core").InputSignal<string>;
4588
4745
  /** The delta's direction: an arrow mark and a hidden word; left unset, the pill is neutral. */
@@ -4592,6 +4749,8 @@ export declare class BfStatComponent {
4592
4749
  private readonly labels;
4593
4750
  readonly classes: import("@angular/core").Signal<string>;
4594
4751
  /** @internal */
4752
+ readonly iconTileClasses: import("@angular/core").Signal<string>;
4753
+ /** @internal */
4595
4754
  readonly deltaClasses: import("@angular/core").Signal<string>;
4596
4755
  /** @internal */
4597
4756
  readonly markClasses: import("@angular/core").Signal<string>;
@@ -4760,9 +4919,9 @@ export declare class BfBreadcrumbItemComponent {
4760
4919
  /**
4761
4920
  * The vertical navigation of a desktop app: a `nav` landmark with a `header` slot (the brand),
4762
4921
  * the destinations (`a[bfNavItem]` links, optionally in `bf-nav-group`s) and a `footer` slot.
4763
- * `collapsed` turns it into an icon rail; the consumer owns the toggle button and binds
4764
- * `[(collapsed)]`. Below a breakpoint hide it (`class="hidden md:flex"`) and drive a
4765
- * `bf-menu-button` from the same routes.
4922
+ * `collapsed` turns it into an icon rail: put a `bf-sidebar-toggle` (`@bitforgehq/ui/overlay`) in
4923
+ * it, or bind `[(collapsed)]` to your own button. Below a breakpoint hide it
4924
+ * (`class="hidden md:flex"`) and drive a `bf-menu-button` from the same routes.
4766
4925
  *
4767
4926
  * @example
4768
4927
  * <bf-sidebar label="Main" [(collapsed)]="collapsed" class="hidden md:flex">
@@ -4786,9 +4945,13 @@ export declare class BfSidebarComponent {
4786
4945
  * ("Main"). Name each landmark differently when a page has more than one. */
4787
4946
  readonly label: import("@angular/core").InputSignal<string>;
4788
4947
  /** Collapses the sidebar to an icon rail: items show their icon only, their label stays for
4789
- * screen readers and becomes a tooltip. Bind `[(collapsed)]` to your own toggle button. */
4948
+ * screen readers and becomes a tooltip. A `bf-sidebar-toggle` inside flips it; bind
4949
+ * `[(collapsed)]` to keep it in your state. */
4790
4950
  readonly collapsed: import("@angular/core").ModelSignal<boolean>;
4791
4951
  private readonly labels;
4952
+ /** The `nav` element's id, which `bf-sidebar-toggle` points `aria-controls` at.
4953
+ * @internal */
4954
+ readonly navId: string;
4792
4955
  /** The rendered navigation name: `label`, else the `navigation` label. */
4793
4956
  protected readonly name: import("@angular/core").Signal<string>;
4794
4957
  private readonly width;
@@ -4934,6 +5097,87 @@ export declare class BfNavItemComponent {
4934
5097
  };
4935
5098
  }, {}, never, ["[bfSlot=icon]", "*"], true, never>;
4936
5099
  }
5100
+ /**
5101
+ * The viewport width from which `bf-app-frame` shows its sidebar column instead of the narrow
5102
+ * header bar: Tailwind's `md` (768 px) or `lg` (1024 px).
5103
+ *
5104
+ * @summary The breakpoint where an app frame switches from its header bar to the sidebar
5105
+ * @since 0.3.2
5106
+ */
5107
+ type BfAppFrameBreakpoint = 'md' | 'lg';
5108
+ /**
5109
+ * The maximum width of `bf-app-frame`'s content column: `md` 48rem, `lg` 64rem, `xl` 80rem, or
5110
+ * `full` for no limit.
5111
+ *
5112
+ * @summary The maximum width of an app frame's content column, from medium to full
5113
+ * @since 0.3.2
5114
+ */
5115
+ type BfAppFrameContentWidth = 'md' | 'lg' | 'xl' | 'full';
5116
+ /**
5117
+ * The frame of a desktop web app: a skip link, a sticky full-height sidebar column from the
5118
+ * breakpoint up, a header bar with the narrow-screen menu, the brand and actions below it, and
5119
+ * the `main` landmark with a content column of a set maximum width.
5120
+ *
5121
+ * @example
5122
+ * <bf-app-frame>
5123
+ * <bf-sidebar bfSlot="sidebar" label="Main">…</bf-sidebar>
5124
+ * <bf-menu-button bfSlot="menu" [menu]="navMenu">Sections</bf-menu-button>
5125
+ * <span bfSlot="brand" class="text-heading">Atlas</span>
5126
+ * <router-outlet />
5127
+ * </bf-app-frame>
5128
+ * @summary Desktop app frame with skip link, sticky sidebar, narrow header and main content
5129
+ * @category Navigation
5130
+ * @since 0.3.2
5131
+ * @slot sidebar The `bf-sidebar`, shown from the breakpoint up; it fills the column's height.
5132
+ * @slot brand The app's name or logo in the narrow header bar, after the menu.
5133
+ * @slot menu The narrow-screen navigation: a `bf-menu-button` of `a[bfMenuItem]` links, at the
5134
+ * header bar's inline start.
5135
+ * @slot actions End actions of the narrow header bar, such as the theme menu.
5136
+ * @slot default The page: what the router shows, inside the `main` landmark.
5137
+ */
5138
+ export declare class BfAppFrameComponent {
5139
+ /** The viewport width from which the sidebar column replaces the narrow header bar. */
5140
+ readonly breakpoint: import("@angular/core").InputSignal<BfAppFrameBreakpoint>;
5141
+ /** The maximum width of the content column (`md` 48rem, `lg` 64rem, `xl` 80rem, `full`). */
5142
+ readonly contentWidth: import("@angular/core").InputSignal<BfAppFrameContentWidth>;
5143
+ /** The id of the `main` landmark, the skip link's target; generated when left out. */
5144
+ readonly mainId: import("@angular/core").InputSignal<string>;
5145
+ protected readonly labels: import("@bitforgehq/ui").BfLabels;
5146
+ private readonly host;
5147
+ private readonly main;
5148
+ /** True when the frame sits inside another `main` landmark, so its own drops the role. */
5149
+ protected readonly nested: import("@angular/core").WritableSignal<boolean>;
5150
+ protected readonly sidebarClasses: import("@angular/core").Signal<string>;
5151
+ protected readonly headerClasses: import("@angular/core").Signal<string>;
5152
+ protected readonly paddingClasses: import("@angular/core").Signal<string>;
5153
+ protected readonly widthClasses: import("@angular/core").Signal<string>;
5154
+ constructor();
5155
+ /**
5156
+ * Moves focus to the content without following the href (see the template comment).
5157
+ *
5158
+ * @internal
5159
+ * @param event The skip link's click (also fired by Enter).
5160
+ */
5161
+ skip(event: Event): void;
5162
+ static ɵfac: i0.ɵɵFactoryDeclaration<BfAppFrameComponent, never>;
5163
+ static ɵcmp: i0.ɵɵComponentDeclaration<BfAppFrameComponent, "bf-app-frame", never, {
5164
+ "breakpoint": {
5165
+ "alias": "breakpoint";
5166
+ "required": false;
5167
+ "isSignal": true;
5168
+ };
5169
+ "contentWidth": {
5170
+ "alias": "contentWidth";
5171
+ "required": false;
5172
+ "isSignal": true;
5173
+ };
5174
+ "mainId": {
5175
+ "alias": "mainId";
5176
+ "required": false;
5177
+ "isSignal": true;
5178
+ };
5179
+ }, {}, never, ["[bfSlot=sidebar]", "[bfSlot=menu]", "[bfSlot=brand]", "[bfSlot=actions]", "*"], true, never>;
5180
+ }
4937
5181
  /**
4938
5182
  * The shape of a `bf-skeleton`: text lines, a rectangle (an image, a chart, a field) or a circle
4939
5183
  * (an avatar).
@@ -5579,6 +5823,26 @@ declare const COARSE_HIT_BASE = "pointer-coarse:after:absolute pointer-coarse:af
5579
5823
  * (1.5 px border) position the ::after inside the border, so their inset adds the border back.
5580
5824
  */
5581
5825
  declare const PILL_HIT: Record<BfSize, Record<'plain' | 'bordered', string>>;
5826
+ /** Where a nav item sits: a vertical sidebar or a horizontal top row. */
5827
+ type BfNavLayout = 'sidebar' | 'top';
5828
+ /** What `a[bfNavItem]`, `bf-nav-group` and `bf-sidebar-toggle` read from the enclosing `bf-sidebar`
5829
+ * or `bf-top-nav`. */
5830
+ interface BfNavHost {
5831
+ /** The host's layout: full-width rows in a sidebar, inline items in a top row. */
5832
+ readonly layout: BfNavLayout;
5833
+ /** True while the sidebar is collapsed to an icon rail; always false in a top nav. */
5834
+ readonly collapsed: Signal<boolean>;
5835
+ /** The id of the host's `nav` element (for a toggle's `aria-controls`); null in a top nav. */
5836
+ readonly navId: string | null;
5837
+ /** Writes the sidebar's `collapsed` model, as a user change; does nothing in a top nav. */
5838
+ setCollapsed(collapsed: boolean): void;
5839
+ }
5840
+ /**
5841
+ * Provided by `bf-sidebar` and `bf-top-nav`, so their items and groups follow the layout and the
5842
+ * collapsed state without the item files importing the container files. `bf-sidebar-toggle`
5843
+ * (`@bitforgehq/ui/overlay`) reads and flips the state through it, as the internal `ɵBF_NAV`.
5844
+ */
5845
+ declare const BF_NAV: InjectionToken<BfNavHost>;
5582
5846
  /**
5583
5847
  * Removes what overlays and themes leave on a document: the `dark` and `cdk-global-scrollblock`
5584
5848
  * classes on `<html>`, `inert` on the children of `<body>`, and every child of a
@@ -5588,4 +5852,4 @@ declare const PILL_HIT: Record<BfSize, Record<'plain' | 'bordered', string>>;
5588
5852
  declare function resetBfDocument(document: Document): void;
5589
5853
  /** Runs `resetBfDocument()` when the environment injector that holds it is destroyed. Internal. */
5590
5854
  declare function provideBfDocumentReset(): EnvironmentProviders;
5591
- export { type BfAlertVariant, type BfAutocapitalize, type BfAvatarSize, type BfAvatarVariant, type BfBadgeAppearance, type BfBadgeVariant, type BfButtonAppearance, type BfButtonSize, type BfButtonType, type BfButtonVariant, type BfCalendarDisabledDate, type BfCalendarWeekday, type BfCardPadding, type BfCardVariant, type BfChipGroupMode, type BfChipVariant, type BfColorScheme, type BfCompareWith, type BfDefaults, type BfDefaultsOptions, type BfDescriptionListLayout, type BfEmptyStateHeadingLevel, type BfEnterKeyHint, type BfFieldControlState, type BfFieldSize, type BfIconButtonVariant, type BfInputAutocapitalize, type BfInputEnterKeyHint, type BfInputInputMode, type BfInputMode, type BfInputType, type BfLabels, type BfLabelsOverrides, type BfPageHeaderHeadingLevel, type BfProgressSize, type BfProgressTone, type BfRadioGroupOrientation, type BfRadioOption, type BfSegmentOption, type BfSegmentedSize, type BfSelectOption, type BfSize, type BfSkeletonShape, type BfSpinnerSize, type BfStatTrend, type BfStatTrendIntent, type BfStatVariant, type BfTabBarController, type BfTabBarHost, type BfTabLinks, type BfTableAlign, type BfTableCellContext, type BfTableColumn, type BfTableRowKey, type BfTableSort, type BfTableSortDirection, type BfToggleLabelPosition, type BfValidationMessages, BUTTON_CLASSES as ɵBF_BUTTON_CLASSES, ICON_BUTTON_CLASSES as ɵBF_ICON_BUTTON_CLASSES, FIELD_BOX as ɵFIELD_BOX, FIELD_ICON_END as ɵFIELD_ICON_END, FIELD_ICON_START as ɵFIELD_ICON_START, FIELD_PADDING_END as ɵFIELD_PADDING_END, FIELD_PADDING_START as ɵFIELD_PADDING_START, PILL_HIT as ɵPILL_HIT, compareIso as ɵcompareIso, createMemoryColorSchemeStorage as ɵcreateMemoryColorSchemeStorage, daysInMonth as ɵdaysInMonth, fieldDescribedBy as ɵfieldDescribedBy, fieldErrorMessageId as ɵfieldErrorMessageId, fieldErrorText as ɵfieldErrorText, fieldShowsError as ɵfieldShowsError, formatIsoDate as ɵformatIsoDate, localIsoDate as ɵlocalIsoDate, parseIsoDate as ɵparseIsoDate, provideBfDocumentReset as ɵprovideBfDocumentReset, uniqueId as ɵuniqueId, validIsoDate as ɵvalidIsoDate };
5855
+ export { type BfAlertVariant, type BfAppFrameBreakpoint, type BfAppFrameContentWidth, type BfAutocapitalize, type BfAvatarSize, type BfAvatarVariant, type BfBadgeAppearance, type BfBadgeVariant, type BfButtonAppearance, type BfButtonSize, type BfButtonType, type BfButtonVariant, type BfCalendarDisabledDate, type BfCalendarWeekday, type BfCardPadding, type BfCardVariant, type BfChipGroupMode, type BfChipVariant, type BfColorScheme, type BfCompareWith, type BfDefaults, type BfDefaultsOptions, type BfDescriptionListLayout, type BfEmptyStateHeading, type BfEmptyStateHeadingLevel, type BfEnterKeyHint, type BfFieldControlState, type BfFieldSize, type BfIconButtonVariant, type BfInputAutocapitalize, type BfInputEnterKeyHint, type BfInputInputMode, type BfInputMode, type BfInputType, type BfLabels, type BfLabelsOverrides, type BfPageHeaderHeadingLevel, type BfProgressSize, type BfProgressTone, type BfRadioGroupOrientation, type BfRadioOption, type BfSegmentOption, type BfSegmentedSize, type BfSelectOption, type BfSize, type BfSkeletonShape, type BfSpinnerSize, type BfStatAppearance, type BfStatTrend, type BfStatTrendIntent, type BfStatVariant, type BfTabBarController, type BfTabBarHost, type BfTabLinks, type BfTableAlign, type BfTableCellContext, type BfTableColumn, type BfTableRowKey, type BfTableSort, type BfTableSortDirection, type BfTableStack, type BfToggleLabelPosition, type BfValidationMessages, BUTTON_CLASSES as ɵBF_BUTTON_CLASSES, ICON_BUTTON_CLASSES as ɵBF_ICON_BUTTON_CLASSES, BF_NAV as ɵBF_NAV, type BfNavHost as ɵBfNavHost, FIELD_BOX as ɵFIELD_BOX, FIELD_ICON_END as ɵFIELD_ICON_END, FIELD_ICON_START as ɵFIELD_ICON_START, FIELD_PADDING_END as ɵFIELD_PADDING_END, FIELD_PADDING_START as ɵFIELD_PADDING_START, PILL_HIT as ɵPILL_HIT, compareIso as ɵcompareIso, createMemoryColorSchemeStorage as ɵcreateMemoryColorSchemeStorage, daysInMonth as ɵdaysInMonth, fieldDescribedBy as ɵfieldDescribedBy, fieldErrorMessageId as ɵfieldErrorMessageId, fieldErrorText as ɵfieldErrorText, fieldShowsError as ɵfieldShowsError, formatIsoDate as ɵformatIsoDate, localIsoDate as ɵlocalIsoDate, parseIsoDate as ɵparseIsoDate, provideBfDocumentReset as ɵprovideBfDocumentReset, uniqueId as ɵuniqueId, validIsoDate as ɵvalidIsoDate };