@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.
- package/CHANGELOG.md +3665 -0
- package/LICENSE +21 -0
- package/README.md +175 -0
- package/ai/MANIFEST.index.json +383 -0
- package/ai/MANIFEST.json +7528 -0
- package/ai/REFERENCE.index.json +1461 -0
- package/ai/REFERENCE.json +7213 -0
- package/ai/UI_GUIDE.md +1159 -0
- package/ai/components/action-bar.md +209 -0
- package/ai/components/action-sheet.md +526 -0
- package/ai/components/alert-dialog.md +509 -0
- package/ai/components/alert.md +376 -0
- package/ai/components/avatar.md +146 -0
- package/ai/components/back-button.md +286 -0
- package/ai/components/badge.md +171 -0
- package/ai/components/button.md +431 -0
- package/ai/components/card.md +303 -0
- package/ai/components/checkbox.md +418 -0
- package/ai/components/chip-group.md +205 -0
- package/ai/components/chip.md +300 -0
- package/ai/components/content.md +474 -0
- package/ai/components/desktop-toast.md +420 -0
- package/ai/components/dialog.md +962 -0
- package/ai/components/empty-state.md +146 -0
- package/ai/components/field.md +319 -0
- package/ai/components/header.md +809 -0
- package/ai/components/icon-button.md +221 -0
- package/ai/components/icon.md +176 -0
- package/ai/components/input.md +455 -0
- package/ai/components/list-item.md +326 -0
- package/ai/components/list.md +178 -0
- package/ai/components/menu-button.md +377 -0
- package/ai/components/menu.md +661 -0
- package/ai/components/modal.md +613 -0
- package/ai/components/number-input.md +423 -0
- package/ai/components/page.md +299 -0
- package/ai/components/progress.md +215 -0
- package/ai/components/radio-group.md +432 -0
- package/ai/components/refresher.md +377 -0
- package/ai/components/segmented.md +517 -0
- package/ai/components/select.md +510 -0
- package/ai/components/sheet.md +845 -0
- package/ai/components/spinner.md +171 -0
- package/ai/components/stack-outlet.md +661 -0
- package/ai/components/tab-bar.md +427 -0
- package/ai/components/tab.md +295 -0
- package/ai/components/tabs.md +408 -0
- package/ai/components/textarea.md +371 -0
- package/ai/components/toast.md +522 -0
- package/ai/components/toggle.md +387 -0
- package/ai/reference/bf-action-directive.md +21 -0
- package/ai/reference/bf-action-sheet-action-role.md +27 -0
- package/ai/reference/bf-action-sheet-action.md +28 -0
- package/ai/reference/bf-action-sheet-options.md +28 -0
- package/ai/reference/bf-action-sheet-service.md +33 -0
- package/ai/reference/bf-alert-dialog-button-role.md +27 -0
- package/ai/reference/bf-alert-dialog-button.md +27 -0
- package/ai/reference/bf-alert-dialog-options.md +29 -0
- package/ai/reference/bf-alert-dialog-service.md +34 -0
- package/ai/reference/bf-alert-variant.md +28 -0
- package/ai/reference/bf-autocapitalize.md +30 -0
- package/ai/reference/bf-avatar-size.md +27 -0
- package/ai/reference/bf-avatar-variant.md +28 -0
- package/ai/reference/bf-back-at-root.md +28 -0
- package/ai/reference/bf-back-button-service.md +40 -0
- package/ai/reference/bf-badge-variant.md +29 -0
- package/ai/reference/bf-button-size.md +29 -0
- package/ai/reference/bf-button-type.md +28 -0
- package/ai/reference/bf-button-variant.md +29 -0
- package/ai/reference/bf-card-padding.md +26 -0
- package/ai/reference/bf-card-variant.md +28 -0
- package/ai/reference/bf-chip-group-mode.md +27 -0
- package/ai/reference/bf-chip-variant.md +26 -0
- package/ai/reference/bf-compare-with.md +24 -0
- package/ai/reference/bf-component-overlay-ref.md +33 -0
- package/ai/reference/bf-confirm-button-role.md +26 -0
- package/ai/reference/bf-confirm-button.md +27 -0
- package/ai/reference/bf-confirm-options.md +31 -0
- package/ai/reference/bf-confirm-size.md +26 -0
- package/ai/reference/bf-content-scroll-event.md +21 -0
- package/ai/reference/bf-defaults-options.md +32 -0
- package/ai/reference/bf-defaults.md +28 -0
- package/ai/reference/bf-desktop-toast-config.md +28 -0
- package/ai/reference/bf-desktop-toast-harness.md +33 -0
- package/ai/reference/bf-desktop-toast-options.md +28 -0
- package/ai/reference/bf-desktop-toast-position.md +28 -0
- package/ai/reference/bf-desktop-toast-service.md +42 -0
- package/ai/reference/bf-dialog-config.md +44 -0
- package/ai/reference/bf-dialog-harness.md +52 -0
- package/ai/reference/bf-dialog-ref.md +44 -0
- package/ai/reference/bf-dialog-role.md +26 -0
- package/ai/reference/bf-dialog-service.md +55 -0
- package/ai/reference/bf-dialog-size.md +31 -0
- package/ai/reference/bf-dialog-template-context.md +32 -0
- package/ai/reference/bf-empty-state-heading-level.md +26 -0
- package/ai/reference/bf-enter-key-hint.md +31 -0
- package/ai/reference/bf-field-control-class.md +32 -0
- package/ai/reference/bf-field-control-state.md +28 -0
- package/ai/reference/bf-field-size.md +29 -0
- package/ai/reference/bf-haptics-impact-style.md +27 -0
- package/ai/reference/bf-haptics-notification-type.md +27 -0
- package/ai/reference/bf-haptics-service.md +41 -0
- package/ai/reference/bf-harness-filters.md +29 -0
- package/ai/reference/bf-horizontal-scroll-directive.md +129 -0
- package/ai/reference/bf-icon-button-variant.md +28 -0
- package/ai/reference/bf-icon-size.md +27 -0
- package/ai/reference/bf-input-autocapitalize.md +36 -0
- package/ai/reference/bf-input-enter-key-hint.md +38 -0
- package/ai/reference/bf-input-input-mode.md +38 -0
- package/ai/reference/bf-input-mode.md +32 -0
- package/ai/reference/bf-input-type.md +35 -0
- package/ai/reference/bf-jsdom-shim-options.md +22 -0
- package/ai/reference/bf-keyboard-assist-behavior.md +26 -0
- package/ai/reference/bf-keyboard-assist-directive.md +185 -0
- package/ai/reference/bf-keyboard-phase.md +30 -0
- package/ai/reference/bf-keyboard-service.md +50 -0
- package/ai/reference/bf-labels-overrides.md +26 -0
- package/ai/reference/bf-labels.md +44 -0
- package/ai/reference/bf-menu-button-harness.md +40 -0
- package/ai/reference/bf-menu-button-variant.md +27 -0
- package/ai/reference/bf-menu-divider-directive.md +13 -0
- package/ai/reference/bf-menu-group-directive.md +14 -0
- package/ai/reference/bf-menu-harness.md +55 -0
- package/ai/reference/bf-menu-item-checkbox-directive.md +31 -0
- package/ai/reference/bf-menu-item-directive.md +31 -0
- package/ai/reference/bf-menu-item-harness.md +52 -0
- package/ai/reference/bf-menu-item-radio-directive.md +29 -0
- package/ai/reference/bf-menu-placement.md +29 -0
- package/ai/reference/bf-menu-trigger-directive.md +46 -0
- package/ai/reference/bf-modal-options.md +30 -0
- package/ai/reference/bf-modal-presentation.md +26 -0
- package/ai/reference/bf-modal-service.md +38 -0
- package/ai/reference/bf-nav-controller.md +59 -0
- package/ai/reference/bf-nav-direction.md +23 -0
- package/ai/reference/bf-nav-target.md +21 -0
- package/ai/reference/bf-number-input-mode.md +28 -0
- package/ai/reference/bf-number-input-step.md +25 -0
- package/ai/reference/bf-overlay-auto-focus.md +29 -0
- package/ai/reference/bf-overlay-controller.md +22 -0
- package/ai/reference/bf-overlay-host.md +36 -0
- package/ai/reference/bf-overlay-options.md +53 -0
- package/ai/reference/bf-overlay-position.md +30 -0
- package/ai/reference/bf-overlay-ref.md +53 -0
- package/ai/reference/bf-overlay-role.md +27 -0
- package/ai/reference/bf-overlay-service.md +53 -0
- package/ai/reference/bf-overlay-stack-options.md +24 -0
- package/ai/reference/bf-overlay-stack.md +81 -0
- package/ai/reference/bf-overlay-template-context.md +24 -0
- package/ai/reference/bf-overscroll-stretch-directive.md +163 -0
- package/ai/reference/bf-page-context.md +24 -0
- package/ai/reference/bf-platform-service.md +53 -0
- package/ai/reference/bf-platform.md +28 -0
- package/ai/reference/bf-progress-size.md +26 -0
- package/ai/reference/bf-progress-tone.md +28 -0
- package/ai/reference/bf-radio-group-harness.md +49 -0
- package/ai/reference/bf-radio-group-orientation.md +26 -0
- package/ai/reference/bf-radio-option.md +30 -0
- package/ai/reference/bf-refresher-refresh-event.md +22 -0
- package/ai/reference/bf-segment-option.md +29 -0
- package/ai/reference/bf-segmented-harness.md +48 -0
- package/ai/reference/bf-segmented-size.md +29 -0
- package/ai/reference/bf-select-harness.md +70 -0
- package/ai/reference/bf-select-option.md +29 -0
- package/ai/reference/bf-sheet-auto-focus.md +29 -0
- package/ai/reference/bf-sheet-options.md +32 -0
- package/ai/reference/bf-sheet-ref.md +45 -0
- package/ai/reference/bf-sheet-service.md +34 -0
- package/ai/reference/bf-shell-config-mode.md +28 -0
- package/ai/reference/bf-shell-config.md +38 -0
- package/ai/reference/bf-shell-dynamic-type-limit.md +21 -0
- package/ai/reference/bf-shell-dynamic-type.md +25 -0
- package/ai/reference/bf-shell-mode.md +28 -0
- package/ai/reference/bf-shell-testing-options.md +26 -0
- package/ai/reference/bf-size.md +45 -0
- package/ai/reference/bf-spinner-size.md +27 -0
- package/ai/reference/bf-stack-change.md +22 -0
- package/ai/reference/bf-stack-reuse-strategy.md +32 -0
- package/ai/reference/bf-stack-transition-event.md +26 -0
- package/ai/reference/bf-stack-transition.md +26 -0
- package/ai/reference/bf-stacked-overlay.md +23 -0
- package/ai/reference/bf-system-bars-style.md +38 -0
- package/ai/reference/bf-tab-bar-controller.md +51 -0
- package/ai/reference/bf-tab-bar-host.md +52 -0
- package/ai/reference/bf-tab-context.md +32 -0
- package/ai/reference/bf-tab-links.md +37 -0
- package/ai/reference/bf-testing-options.md +27 -0
- package/ai/reference/bf-text-scale-service.md +35 -0
- package/ai/reference/bf-theme.md +27 -0
- package/ai/reference/bf-toast-action.md +25 -0
- package/ai/reference/bf-toast-controller.md +17 -0
- package/ai/reference/bf-toast-dismiss-reason.md +29 -0
- package/ai/reference/bf-toast-options.md +29 -0
- package/ai/reference/bf-toast-position.md +26 -0
- package/ai/reference/bf-toast-ref.md +41 -0
- package/ai/reference/bf-toast-service.md +39 -0
- package/ai/reference/bf-toggle-label-position.md +26 -0
- package/ai/reference/bf-transition-kind.md +28 -0
- package/ai/reference/bf-validation-message.md +31 -0
- package/ai/reference/bf-validation-messages.md +33 -0
- package/ai/reference/bf-view-event.md +28 -0
- package/ai/reference/bf-view-lifecycle.md +41 -0
- package/ai/reference/bf-view-state.md +28 -0
- package/ai/reference/bf_default_labels.md +21 -0
- package/ai/reference/bf_default_values.md +21 -0
- package/ai/reference/bf_defaults.md +21 -0
- package/ai/reference/bf_desktop_toast_defaults.md +21 -0
- package/ai/reference/bf_dialog_data.md +17 -0
- package/ai/reference/bf_labels.md +21 -0
- package/ai/reference/bf_overlay_data.md +19 -0
- package/ai/reference/bf_overlay_host.md +21 -0
- package/ai/reference/bf_sheet_default_snap_points.md +17 -0
- package/ai/reference/bf_shell_config.md +21 -0
- package/ai/reference/bf_shell_defaults.md +21 -0
- package/ai/reference/bf_tab_bar.md +21 -0
- package/ai/reference/bf_tab_bar_controller.md +21 -0
- package/ai/reference/bf_tab_context.md +21 -0
- package/ai/reference/bf_tab_links.md +21 -0
- package/ai/reference/bf_theme_storage.md +19 -0
- package/ai/reference/create-transition.md +36 -0
- package/ai/reference/duration_fast.md +17 -0
- package/ai/reference/duration_md.md +17 -0
- package/ai/reference/duration_overlay.md +17 -0
- package/ai/reference/duration_push.md +17 -0
- package/ai/reference/fade-down.md +26 -0
- package/ai/reference/fade-in.md +25 -0
- package/ai/reference/fade-out.md +25 -0
- package/ai/reference/fade-up.md +26 -0
- package/ai/reference/inject-shell-mode.md +23 -0
- package/ai/reference/install-bf-jsdom-shims.md +31 -0
- package/ai/reference/ios_duration.md +17 -0
- package/ai/reference/ios_easing.md +17 -0
- package/ai/reference/is-text-entry.md +25 -0
- package/ai/reference/max_complete_ms.md +17 -0
- package/ai/reference/md-transition.md +31 -0
- package/ai/reference/md_duration.md +17 -0
- package/ai/reference/md_easing.md +17 -0
- package/ai/reference/overlay_duration.md +21 -0
- package/ai/reference/overlay_easing.md +19 -0
- package/ai/reference/overlay_reduced_duration.md +17 -0
- package/ai/reference/pop-frames-at.md +25 -0
- package/ai/reference/prefers-reduced-motion.md +25 -0
- package/ai/reference/provide-bf-defaults.md +33 -0
- package/ai/reference/provide-bf-desktop-toast.md +28 -0
- package/ai/reference/provide-bf-labels.md +38 -0
- package/ai/reference/provide-bf-shell-testing.md +34 -0
- package/ai/reference/provide-bf-shell.md +41 -0
- package/ai/reference/provide-bf-testing.md +33 -0
- package/ai/reference/reduced-transition.md +28 -0
- package/ai/reference/reduced_duration.md +17 -0
- package/ai/reference/resolve-shell-mode.md +33 -0
- package/ai/reference/scale-in.md +25 -0
- package/ai/reference/settle-duration.md +25 -0
- package/ai/reference/settle-pop.md +33 -0
- package/ai/reference/settle_easing.md +17 -0
- package/ai/reference/should-complete-pop.md +26 -0
- package/ai/reference/slide-down.md +26 -0
- package/ai/reference/slide-up.md +26 -0
- package/ai/reference/with-bf-shell-routing.md +19 -0
- package/bin/bf-ui.js +81 -0
- package/fesm2022/bitforgehq-ui-icons.mjs +230 -0
- package/fesm2022/bitforgehq-ui-icons.mjs.map +1 -0
- package/fesm2022/bitforgehq-ui-mobile.mjs +5530 -0
- package/fesm2022/bitforgehq-ui-mobile.mjs.map +1 -0
- package/fesm2022/bitforgehq-ui-number-input.mjs +680 -0
- package/fesm2022/bitforgehq-ui-number-input.mjs.map +1 -0
- package/fesm2022/bitforgehq-ui-overlay.mjs +2675 -0
- package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -0
- package/fesm2022/bitforgehq-ui-testing.mjs +402 -0
- package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -0
- package/fesm2022/bitforgehq-ui.mjs +7765 -0
- package/fesm2022/bitforgehq-ui.mjs.map +1 -0
- package/llms-full.txt +25394 -0
- package/llms.txt +329 -0
- package/package.json +94 -0
- package/theme.css +253 -0
- package/types/bitforgehq-ui-icons.d.ts +50 -0
- package/types/bitforgehq-ui-mobile.d.ts +2914 -0
- package/types/bitforgehq-ui-number-input.d.ts +282 -0
- package/types/bitforgehq-ui-overlay.d.ts +1514 -0
- package/types/bitforgehq-ui-testing.d.ts +495 -0
- package/types/bitforgehq-ui.d.ts +3499 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# bf-page
|
|
2
|
+
|
|
3
|
+
Frame for one stacked mobile screen that supplies lifecycle events and shared page state
|
|
4
|
+
|
|
5
|
+
`BfPageComponent` from `@bitforgehq/ui/mobile` · Navigation · since 0.2.0
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Component, inject, signal } from '@angular/core';
|
|
11
|
+
import { BfButtonComponent, BfListComponent, BfListItemComponent } from '@bitforgehq/ui';
|
|
12
|
+
import {
|
|
13
|
+
BfContentComponent,
|
|
14
|
+
BfHeaderComponent,
|
|
15
|
+
BfNavController,
|
|
16
|
+
BfPageComponent,
|
|
17
|
+
} from '@bitforgehq/ui/mobile';
|
|
18
|
+
|
|
19
|
+
/** `bf-page` showcase: logs this page's lifecycle events and shows its view state. */
|
|
20
|
+
@Component({
|
|
21
|
+
selector: 'app-page-showcase',
|
|
22
|
+
imports: [
|
|
23
|
+
BfPageComponent,
|
|
24
|
+
BfHeaderComponent,
|
|
25
|
+
BfContentComponent,
|
|
26
|
+
BfButtonComponent,
|
|
27
|
+
BfListComponent,
|
|
28
|
+
BfListItemComponent,
|
|
29
|
+
],
|
|
30
|
+
template: `
|
|
31
|
+
<bf-page
|
|
32
|
+
#page
|
|
33
|
+
data-showcase="page"
|
|
34
|
+
(bfViewWillEnter)="log('bfViewWillEnter')"
|
|
35
|
+
(bfViewDidEnter)="log('bfViewDidEnter')"
|
|
36
|
+
(bfViewWillLeave)="log('bfViewWillLeave')"
|
|
37
|
+
(bfViewDidLeave)="log('bfViewDidLeave')"
|
|
38
|
+
>
|
|
39
|
+
<bf-header title="Page" [largeTitle]="false" />
|
|
40
|
+
<bf-content>
|
|
41
|
+
<div class="flex flex-col gap-4 p-4">
|
|
42
|
+
<p class="text-caption text-text-muted">
|
|
43
|
+
Push a page, then go back: this page stays alive underneath and logs all four lifecycle
|
|
44
|
+
events.
|
|
45
|
+
</p>
|
|
46
|
+
<p data-showcase-result class="text-body">View state: {{ page.viewState() }}</p>
|
|
47
|
+
<bf-button (clicked)="push()">Push a page</bf-button>
|
|
48
|
+
<bf-list [inset]="false">
|
|
49
|
+
@for (entry of events(); track $index) {
|
|
50
|
+
<bf-list-item [title]="entry" [subtitle]="'Event ' + ($index + 1)" />
|
|
51
|
+
}
|
|
52
|
+
</bf-list>
|
|
53
|
+
</div>
|
|
54
|
+
</bf-content>
|
|
55
|
+
</bf-page>
|
|
56
|
+
`,
|
|
57
|
+
})
|
|
58
|
+
export class PageShowcasePage {
|
|
59
|
+
private readonly nav = inject(BfNavController);
|
|
60
|
+
|
|
61
|
+
protected readonly events = signal<readonly string[]>([]);
|
|
62
|
+
|
|
63
|
+
log(event: string): void {
|
|
64
|
+
this.events.update((events) => [...events, event]);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
push(): void {
|
|
68
|
+
void this.nav.forward('/showcase/page/next');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Overview
|
|
74
|
+
|
|
75
|
+
The page frame of a mobile app: `bf-stack-outlet` positions one per stacked page and provides
|
|
76
|
+
its `BfViewLifecycle` through the element injector. Everything scrollable inside a page goes
|
|
77
|
+
into `bf-content`; `bf-page` is only the frame, the lifecycle signal and a per-page
|
|
78
|
+
`BfPageContext` (provided for its children, where `bf-content` registers its scroller). The
|
|
79
|
+
page an outlet shows makes its `bf-content` the document's `main` landmark. Used
|
|
80
|
+
standalone (outside an outlet, e.g. in a docs demo) it falls back to a local, inert lifecycle
|
|
81
|
+
instance instead of throwing, and exposes no `main` landmark.
|
|
82
|
+
|
|
83
|
+
The page frame of a mobile app. `bf-stack-outlet` creates one wrapper frame per stacked page and
|
|
84
|
+
positions `bf-page` to fill it; use one `bf-page` as the root element of every routed page
|
|
85
|
+
component. Everything scrollable inside a page goes into `bf-content` — `bf-page` itself does not
|
|
86
|
+
scroll, it is just the frame, the lifecycle signal and the per-page `BfPageContext`.
|
|
87
|
+
|
|
88
|
+
## When to use
|
|
89
|
+
|
|
90
|
+
Use `bf-page` as the root element of every routed page under a [bf-stack-outlet](https://bitforge-ui.web.app/components/stack-outlet), for the frame and the view lifecycle. Use a plain page component instead under a normal `router-outlet` on desktop.
|
|
91
|
+
|
|
92
|
+
## Basic usage
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { Component } from '@angular/core';
|
|
96
|
+
import { BfPageComponent } from '@bitforgehq/ui/mobile';
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* A page of the stack.
|
|
100
|
+
*
|
|
101
|
+
* `data-bf-page-title` marks the heading the page is named by.
|
|
102
|
+
*
|
|
103
|
+
* @preview none
|
|
104
|
+
*/
|
|
105
|
+
@Component({
|
|
106
|
+
selector: 'app-example-page-basic',
|
|
107
|
+
imports: [BfPageComponent],
|
|
108
|
+
template: `
|
|
109
|
+
<bf-page>
|
|
110
|
+
<h1 data-bf-page-title>Item</h1>
|
|
111
|
+
<p>Page content</p>
|
|
112
|
+
</bf-page>
|
|
113
|
+
`,
|
|
114
|
+
})
|
|
115
|
+
export class PageBasicExampleComponent {}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Lifecycle
|
|
119
|
+
|
|
120
|
+
`bf-page` injects the `BfViewLifecycle` the outlet provides for this page and re-exposes it as
|
|
121
|
+
`(bfViewWillEnter)`, `(bfViewDidEnter)`, `(bfViewWillLeave)`, `(bfViewDidLeave)` and as
|
|
122
|
+
`viewState()` (`'entering' | 'active' | 'leaving' | 'inactive'`). Load or refresh data on
|
|
123
|
+
`bfViewDidEnter` rather than the component's constructor, so a page parked in the stack and later
|
|
124
|
+
returned to (a pop landing on it) reloads only if you choose to, and a page pushed back on top of
|
|
125
|
+
itself (rare, but possible with `nav.root()`) reloads correctly.
|
|
126
|
+
|
|
127
|
+
The events are delivered synchronously as the outlet fires them: a new page — the app's first page,
|
|
128
|
+
a pushed page, the page `nav.root()` creates — gets `bfViewWillEnter` and then `bfViewDidEnter`
|
|
129
|
+
once its transition settles (at once with `[animated]="false"`), and a popped or root-replaced page
|
|
130
|
+
gets `bfViewWillLeave` and `bfViewDidLeave` before it is destroyed. A `bf-page` rendered later than
|
|
131
|
+
its routed component's first render (inside an `@if` or `@defer`) misses the events that fired
|
|
132
|
+
before it existed; read `viewState()` there instead.
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
import { Component, signal } from '@angular/core';
|
|
136
|
+
import { BfPageComponent } from '@bitforgehq/ui/mobile';
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Loading when the page has entered.
|
|
140
|
+
*
|
|
141
|
+
* `bfViewDidEnter` fires each time the page becomes the visible one, also on the way back.
|
|
142
|
+
*
|
|
143
|
+
* @preview none
|
|
144
|
+
*/
|
|
145
|
+
@Component({
|
|
146
|
+
selector: 'app-example-page-lifecycle',
|
|
147
|
+
imports: [BfPageComponent],
|
|
148
|
+
template: `
|
|
149
|
+
<bf-page (bfViewDidEnter)="load()">
|
|
150
|
+
<p>{{ item()?.name }}</p>
|
|
151
|
+
</bf-page>
|
|
152
|
+
`,
|
|
153
|
+
})
|
|
154
|
+
export class PageLifecycleExampleComponent {
|
|
155
|
+
protected readonly item = signal<{ name: string } | null>(null);
|
|
156
|
+
|
|
157
|
+
protected load(): void {
|
|
158
|
+
this.item.set({ name: 'Atlas rebrand' });
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Used outside a `bf-stack-outlet` — for example in a docs demo, or a unit test that renders the
|
|
164
|
+
page component directly — `bf-page` falls back to a local, inert `BfViewLifecycle` instead of
|
|
165
|
+
throwing; its outputs simply never fire.
|
|
166
|
+
|
|
167
|
+
## Page context
|
|
168
|
+
|
|
169
|
+
`bf-page` provides a fresh `BfPageContext` to everything inside it. `bf-content` registers its
|
|
170
|
+
scroll container there (`scroller`, a `signal<HTMLElement | null>`) on init and clears it on
|
|
171
|
+
destroy, so a sibling such as a header can follow the page's scroll without querying the DOM.
|
|
172
|
+
`mainLandmark` (a `signal(true)`) makes that scroller the document's `main` landmark. It stays
|
|
173
|
+
true for the page a `bf-stack-outlet` shows; a `bf-page` outside an outlet (a docs illustration)
|
|
174
|
+
or nested in another page sets it to false, and so does `bf-modal` for its content.
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
import { Component, computed, inject } from '@angular/core';
|
|
178
|
+
import { BfContentComponent, BfPageComponent, BfPageContext } from '@bitforgehq/ui/mobile';
|
|
179
|
+
|
|
180
|
+
/** A bar that follows the page's scroller through the page context. */
|
|
181
|
+
@Component({
|
|
182
|
+
selector: 'app-scroll-hint',
|
|
183
|
+
template: `<p class="text-caption text-text-muted p-4">{{ hint() }}</p>`,
|
|
184
|
+
})
|
|
185
|
+
export class ScrollHintComponent {
|
|
186
|
+
private readonly scroller = inject(BfPageContext, { optional: true })?.scroller;
|
|
187
|
+
protected readonly hint = computed(() =>
|
|
188
|
+
this.scroller?.() ? 'The page scrolls in bf-content.' : 'No scroller yet.',
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* The page context.
|
|
194
|
+
*
|
|
195
|
+
* `bf-content` registers its scroller in the page's `BfPageContext`, so a sibling reads it
|
|
196
|
+
* without querying the DOM.
|
|
197
|
+
*
|
|
198
|
+
* @preview none
|
|
199
|
+
*/
|
|
200
|
+
@Component({
|
|
201
|
+
selector: 'app-example-page-context',
|
|
202
|
+
imports: [BfContentComponent, BfPageComponent, ScrollHintComponent],
|
|
203
|
+
template: `
|
|
204
|
+
<bf-page>
|
|
205
|
+
<app-scroll-hint />
|
|
206
|
+
<bf-content>
|
|
207
|
+
<p class="p-4">Page content</p>
|
|
208
|
+
</bf-content>
|
|
209
|
+
</bf-page>
|
|
210
|
+
`,
|
|
211
|
+
})
|
|
212
|
+
export class PageContextExampleComponent {}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Desktop
|
|
216
|
+
|
|
217
|
+
`bf-page` is part of the Capacitor shell (`provideBfShell()`). A desktop web app routes plain page components through `router-outlet` and uses Angular's own lifecycle hooks; `bfViewDidEnter` and the other view events exist only because the stack keeps pages alive.
|
|
218
|
+
|
|
219
|
+
## Theming
|
|
220
|
+
|
|
221
|
+
- Background: `bg` (the page's own frame, so a sliding page never shows the page under it through
|
|
222
|
+
transparent areas).
|
|
223
|
+
- Layout: `absolute inset-0 flex flex-col`, filling whatever frame the outlet gives it (or, used
|
|
224
|
+
standalone, its containing block).
|
|
225
|
+
|
|
226
|
+
## Accessibility
|
|
227
|
+
|
|
228
|
+
`bf-page` itself carries no `tabindex`; on push, the outlet moves focus to the page's title — the
|
|
229
|
+
element marked `data-bf-page-title` (the `bf-header` title once it exists) — or, when there is no
|
|
230
|
+
such element, to the positioned wrapper the outlet creates around the page. Give every page one
|
|
231
|
+
element marked `data-bf-page-title` so a screen reader announces where it landed. The page's
|
|
232
|
+
`bf-content` is the document's `main` landmark while the page is shown; a parked page is
|
|
233
|
+
`aria-hidden`, so exactly one `main` is exposed.
|
|
234
|
+
|
|
235
|
+
## Outputs
|
|
236
|
+
|
|
237
|
+
| Name | Payload | Description |
|
|
238
|
+
| ----------------- | ------- | ----------------------------------------------------------- |
|
|
239
|
+
| `bfViewWillEnter` | `void` | Emitted when the page starts entering the top of the stack. |
|
|
240
|
+
| `bfViewDidEnter` | `void` | Emitted once the page is active at the top of the stack. |
|
|
241
|
+
| `bfViewWillLeave` | `void` | Emitted when the page starts leaving the top of the stack. |
|
|
242
|
+
| `bfViewDidLeave` | `void` | Emitted once the page has left the top of the stack. |
|
|
243
|
+
|
|
244
|
+
## Slots
|
|
245
|
+
|
|
246
|
+
- `default`: The page: a `bf-header` and a `bf-content`.
|
|
247
|
+
|
|
248
|
+
## Notes
|
|
249
|
+
|
|
250
|
+
### Do
|
|
251
|
+
|
|
252
|
+
- Use exactly one `bf-page` as the top-level element of a routed page component.
|
|
253
|
+
- Load data in `bfViewDidEnter`, not the constructor, so a returned-to page can choose whether to
|
|
254
|
+
reload.
|
|
255
|
+
- Mark the page's heading with `data-bf-page-title` so push focuses it.
|
|
256
|
+
|
|
257
|
+
### Don't
|
|
258
|
+
|
|
259
|
+
- Don't put scrollable content directly inside `bf-page`; wrap it in `bf-content`.
|
|
260
|
+
- Don't set a `tabindex` on `bf-page` yourself; the outlet manages focus on its wrapper.
|
|
261
|
+
|
|
262
|
+
## Migration notes
|
|
263
|
+
|
|
264
|
+
### 0.3.0
|
|
265
|
+
|
|
266
|
+
JSDoc of `page-context.ts` for the API reference: `@summary`/`@since` on the exported symbols. No
|
|
267
|
+
behaviour change.
|
|
268
|
+
|
|
269
|
+
JSDoc of `page.component.ts` for the API reference: `@slot` docs for `default`. No behaviour change.
|
|
270
|
+
|
|
271
|
+
`BfPageContext` gains `safeAreaTop` (a `signal(true)`): whether the page reaches the top of the
|
|
272
|
+
screen, so its header and a `fullscreen` content pad the top safe area. `bf-modal`'s page-sheet
|
|
273
|
+
presentation sets it to false.
|
|
274
|
+
|
|
275
|
+
`BfPageContext` gains `mainLandmark` (a `signal(true)`): whether the page's `bf-content` is the
|
|
276
|
+
`main` landmark. A `bf-page` outside a `bf-stack-outlet` (a docs illustration) or nested in
|
|
277
|
+
another page sets it to false, so the document keeps one `main` (Migration 36).
|
|
278
|
+
|
|
279
|
+
### 0.2.0
|
|
280
|
+
|
|
281
|
+
New `bf-page`: the page frame (`absolute inset-0 flex flex-col bg-bg`) that `bf-stack-outlet`
|
|
282
|
+
positions one of per stacked page. Injects the per-page `BfViewLifecycle` the outlet provides
|
|
283
|
+
(falling back to a local, inert instance when used standalone, e.g. in a docs demo) and re-exposes
|
|
284
|
+
it as `viewState` (`computed`) plus outputs `bfViewWillEnter`, `bfViewDidEnter`, `bfViewWillLeave`,
|
|
285
|
+
`bfViewDidLeave`, delivered synchronously through `BfViewLifecycle.on()`: a new page gets
|
|
286
|
+
`bfViewWillEnter` and `bfViewDidEnter` (also the first page, without animation and after
|
|
287
|
+
`nav.root()`), and a popped or root-replaced page gets `bfViewWillLeave` and `bfViewDidLeave` before
|
|
288
|
+
it is destroyed. Carries no `tabindex` itself; the outlet still owns push/pop focus
|
|
289
|
+
management on its own wrapper.
|
|
290
|
+
|
|
291
|
+
`bf-page` now provides a per-page `BfPageContext` (`providers: [BfPageContext]`) whose `scroller`
|
|
292
|
+
signal (`HTMLElement | null`) is where `bf-content` registers its scroll container on init and
|
|
293
|
+
clears it on destroy, so `bf-header` can follow the page's scroll without querying the DOM. Its
|
|
294
|
+
`headerHeight` signal (px, 0 by default) is where a `translucent` `bf-header` publishes its
|
|
295
|
+
expanded height for `bf-content` to pad by.
|
|
296
|
+
|
|
297
|
+
Inside `bf-stack-outlet`, the outermost `bf-page` of a stacked page also registers its
|
|
298
|
+
`BfPageContext` with the outlet (a nested `bf-page` leaves it), so the outlet can scroll the page's
|
|
299
|
+
content to the top when its tab is re-selected.
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# bf-progress
|
|
2
|
+
|
|
3
|
+
Progress bar in two sizes and four tones for completion, quotas and unknown waits
|
|
4
|
+
|
|
5
|
+
`BfProgressComponent` from `@bitforgehq/ui` · Data display · since 0.1.0
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Component, signal } from '@angular/core';
|
|
11
|
+
import { BfButtonComponent, BfProgressComponent } from '@bitforgehq/ui';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The bf-progress overview.
|
|
15
|
+
*
|
|
16
|
+
* Live demo of `bf-progress`: a bar stepped by −10 % / +10 % buttons, a success bar and a `md` warning-tone bar.
|
|
17
|
+
*/
|
|
18
|
+
@Component({
|
|
19
|
+
selector: 'app-example-progress-overview',
|
|
20
|
+
imports: [BfProgressComponent, BfButtonComponent],
|
|
21
|
+
template: `
|
|
22
|
+
<div class="flex flex-col gap-3">
|
|
23
|
+
<bf-progress [value]="value()" label="Atlas rebrand progress" />
|
|
24
|
+
<div class="flex items-center gap-2">
|
|
25
|
+
<bf-button variant="tonal" size="sm" [disabled]="value() <= 0" (clicked)="step(-10)">
|
|
26
|
+
−10 %
|
|
27
|
+
</bf-button>
|
|
28
|
+
<bf-button variant="tonal" size="sm" [disabled]="value() >= 100" (clicked)="step(10)">
|
|
29
|
+
+10 %
|
|
30
|
+
</bf-button>
|
|
31
|
+
<span data-status aria-live="polite" class="text-caption text-text-muted"
|
|
32
|
+
>{{ value() }} %</span
|
|
33
|
+
>
|
|
34
|
+
</div>
|
|
35
|
+
<bf-progress [value]="42" label="Bloom moodboard progress" tone="success" />
|
|
36
|
+
<bf-progress [value]="20" label="Storage used" size="md" tone="warning" />
|
|
37
|
+
</div>
|
|
38
|
+
`,
|
|
39
|
+
})
|
|
40
|
+
export class ProgressOverviewExampleComponent {
|
|
41
|
+
readonly value = signal(68);
|
|
42
|
+
|
|
43
|
+
step(delta: number): void {
|
|
44
|
+
this.value.update((value) => Math.min(100, Math.max(0, value + delta)));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Overview
|
|
50
|
+
|
|
51
|
+
Progress bar for completion and quotas, determinate by default, or `indeterminate` while the
|
|
52
|
+
amount of work is unknown.
|
|
53
|
+
|
|
54
|
+
A progress bar for completion ("12 of 18 tasks") and quotas, or, with `indeterminate`, for work whose amount is not known yet.
|
|
55
|
+
|
|
56
|
+
## When to use
|
|
57
|
+
|
|
58
|
+
Use `bf-progress` when the share of work done is known: tasks completed, storage used, an upload; use `indeterminate` for a bar-shaped wait whose amount is not known yet (an upload before its size arrives). Use [bf-spinner](https://bitforge-ui.web.app/components/spinner) instead for a short wait of unknown length inside a control, and [bf-badge](https://bitforge-ui.web.app/components/badge) for a plain status without a quantity.
|
|
59
|
+
|
|
60
|
+
## Basic usage
|
|
61
|
+
|
|
62
|
+
`value` is the completion in percent, clamped to 0–100. Without `value` (and without `indeterminate`) the bar shows 0 %.
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
import { Component } from '@angular/core';
|
|
66
|
+
import { BfProgressComponent } from '@bitforgehq/ui';
|
|
67
|
+
|
|
68
|
+
/** A labelled progress bar at 68 %. */
|
|
69
|
+
@Component({
|
|
70
|
+
selector: 'app-example-progress-basic',
|
|
71
|
+
imports: [BfProgressComponent],
|
|
72
|
+
template: `<bf-progress [value]="68" label="Atlas rebrand" />`,
|
|
73
|
+
})
|
|
74
|
+
export class ProgressBasicExampleComponent {}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Value in words
|
|
78
|
+
|
|
79
|
+
`valueText` gives assistive tech the value in words (`aria-valuetext`), such as "12 of 18 tasks" instead of "67 %". Show the same words next to the bar for everyone else.
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
import { Component } from '@angular/core';
|
|
83
|
+
import { BfProgressComponent } from '@bitforgehq/ui';
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* A progress bar that announces its value in words.
|
|
87
|
+
*
|
|
88
|
+
* `valueText` becomes `aria-valuetext`: "12 of 18 tasks" instead of "67 %".
|
|
89
|
+
*/
|
|
90
|
+
@Component({
|
|
91
|
+
selector: 'app-example-progress-value-text',
|
|
92
|
+
imports: [BfProgressComponent],
|
|
93
|
+
template: `
|
|
94
|
+
<div class="flex flex-col gap-1.5">
|
|
95
|
+
<bf-progress [value]="67" label="Atlas rebrand" valueText="12 of 18 tasks" />
|
|
96
|
+
<span class="text-caption text-text-muted">12 of 18 tasks</span>
|
|
97
|
+
</div>
|
|
98
|
+
`,
|
|
99
|
+
})
|
|
100
|
+
export class ProgressValueTextExampleComponent {}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Indeterminate
|
|
104
|
+
|
|
105
|
+
`indeterminate` drops the native value, so assistive tech announces a busy bar without a percentage, and a 40 % stripe runs across the track in the tone's colour. Under reduced motion (`prefers-reduced-motion: reduce`) the stripe stands still at the start: a static 40 % bar. `value` is ignored while `indeterminate` is set; set it back to `false` with the real value once it is known.
|
|
106
|
+
|
|
107
|
+
```ts
|
|
108
|
+
import { Component, signal } from '@angular/core';
|
|
109
|
+
import { BfButtonComponent, BfProgressComponent } from '@bitforgehq/ui';
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* An indeterminate bar that turns determinate.
|
|
113
|
+
*
|
|
114
|
+
* While the size of the upload is unknown the bar is `indeterminate`; "Size known" sets the real
|
|
115
|
+
* value.
|
|
116
|
+
*/
|
|
117
|
+
@Component({
|
|
118
|
+
selector: 'app-example-progress-indeterminate',
|
|
119
|
+
imports: [BfButtonComponent, BfProgressComponent],
|
|
120
|
+
template: `
|
|
121
|
+
<div class="flex flex-col gap-3">
|
|
122
|
+
<bf-progress label="Uploading report.pdf" [indeterminate]="unknown()" [value]="40" />
|
|
123
|
+
<bf-button variant="outline" size="sm" class="self-start" (clicked)="unknown.set(!unknown())">
|
|
124
|
+
{{ unknown() ? 'Size known' : 'Size unknown' }}
|
|
125
|
+
</bf-button>
|
|
126
|
+
</div>
|
|
127
|
+
`,
|
|
128
|
+
})
|
|
129
|
+
export class ProgressIndeterminateExampleComponent {
|
|
130
|
+
protected readonly unknown = signal(true);
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Size and tone
|
|
135
|
+
|
|
136
|
+
`md` (10 px) suits cards on mobile; the tone follows the meaning of the number.
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
import { Component } from '@angular/core';
|
|
140
|
+
import { BfProgressComponent } from '@bitforgehq/ui';
|
|
141
|
+
|
|
142
|
+
/** A thicker progress bar in the warning tone. */
|
|
143
|
+
@Component({
|
|
144
|
+
selector: 'app-example-progress-size-tone',
|
|
145
|
+
imports: [BfProgressComponent],
|
|
146
|
+
template: `<bf-progress [value]="41" label="Bloom app" size="md" tone="warning" />`,
|
|
147
|
+
})
|
|
148
|
+
export class ProgressSizeToneExampleComponent {}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Theming
|
|
152
|
+
|
|
153
|
+
- Track: `surface-sunken`.
|
|
154
|
+
- Fill by `tone`: `primary-strong` (the `primary` tone, default; ≥ 3:1 on the track for any
|
|
155
|
+
configured primary), `success`, `warning`, `danger`. The indeterminate stripe uses the same fill
|
|
156
|
+
(`CanvasText` under forced colours).
|
|
157
|
+
- Motion: the stripe runs with `--animate-progress-indeterminate` (1.4 s, `--ease-md`), and stops
|
|
158
|
+
under reduced motion.
|
|
159
|
+
|
|
160
|
+
## Accessibility
|
|
161
|
+
|
|
162
|
+
Native `<progress>`, which is a `progressbar` without any role attribute, with `aria-label` carrying the required `label`; its `value`/`max` communicate the percentage to assistive tech, and `valueText` replaces it with words (`aria-valuetext`). An `indeterminate` bar renders no `value` attribute, the native indeterminate state; the stripe is `aria-hidden`.
|
|
163
|
+
|
|
164
|
+
## Inputs
|
|
165
|
+
|
|
166
|
+
| Name | Type | Default | Description |
|
|
167
|
+
| --------------- | -------------------------------------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
168
|
+
| `value` | `number \| undefined` | `undefined` | Completion in percent; clamped to 0–100. Without it (and without `indeterminate`) the bar shows 0 %. Ignored while `indeterminate`. |
|
|
169
|
+
| `indeterminate` | `boolean` | `false` | The amount of work is unknown: the native bar carries no value (assistive tech announces it as busy) and a stripe runs across the track, a static 40 % bar under reduced motion. |
|
|
170
|
+
| `valueText` | `string` | `''` | The value in words for assistive tech (`aria-valuetext`), such as "12 of 18 tasks"; the percentage is announced while it is empty. |
|
|
171
|
+
| `label` | `string` | required | Accessible name of the bar ("Atlas rebrand"). |
|
|
172
|
+
| `size` | `BfProgressSize` (`'sm' \| 'md'`) | `'sm'` | Bar height: sm 8 px (default), md 10 px. |
|
|
173
|
+
| `tone` | `BfProgressTone` (`'primary' \| 'success' \| 'warning' \| 'danger'`) | `'primary'` | Fill color by meaning. |
|
|
174
|
+
|
|
175
|
+
## Notes
|
|
176
|
+
|
|
177
|
+
### Do
|
|
178
|
+
|
|
179
|
+
- Always pass `label`; it is what screen readers announce with the percentage.
|
|
180
|
+
- Put the numbers next to it in text ("12 of 18 tasks").
|
|
181
|
+
|
|
182
|
+
### Don't
|
|
183
|
+
|
|
184
|
+
- Don't animate the bar on first paint from 0; set the real value immediately.
|
|
185
|
+
|
|
186
|
+
## Migration notes
|
|
187
|
+
|
|
188
|
+
### 0.3.0
|
|
189
|
+
|
|
190
|
+
**Behaviour:** the default `primary` tone fills with `primary-strong` (was `primary`), so the fill
|
|
191
|
+
reaches 3:1 on its `surface-sunken` track for any configured primary.
|
|
192
|
+
|
|
193
|
+
JSDoc of `progress.component.ts` for the API reference: `@summary`/`@since` on the exported symbols.
|
|
194
|
+
No behaviour change.
|
|
195
|
+
|
|
196
|
+
**Behaviour:** `value` is optional (`input<number | undefined>(undefined)`, was required); without
|
|
197
|
+
it and without `indeterminate` the bar renders 0 %. The redundant `role="progressbar"` attribute on
|
|
198
|
+
the native `<progress>` is dropped (it is a progressbar natively). New `valueText = input('')`,
|
|
199
|
+
rendered as `aria-valuetext` when set (F-039). New `indeterminate` (boolean): the native bar
|
|
200
|
+
renders without `value` (indeterminate for assistive tech) and a 40 % stripe in the tone's fill
|
|
201
|
+
runs across the track (`animate-progress-indeterminate`), standing still at the start under
|
|
202
|
+
`motion-reduce:`. The host is a one-cell `grid` (was `block`) with `overflow-hidden
|
|
203
|
+
rounded-full`, so the stripe shares the track's cell and stays in it.
|
|
204
|
+
|
|
205
|
+
The indeterminate stripe runs from the inline start: under `dir="rtl"` it takes
|
|
206
|
+
`--animate-progress-indeterminate-rtl` (mirrored keyframes), and stands still under reduced motion
|
|
207
|
+
in both directions.
|
|
208
|
+
|
|
209
|
+
### 0.2.0
|
|
210
|
+
|
|
211
|
+
The value's width transition is off under `prefers-reduced-motion`.
|
|
212
|
+
|
|
213
|
+
### 0.1.0
|
|
214
|
+
|
|
215
|
+
New `bf-progress`: a determinate `role="progressbar"` for completion and quotas. `value` is clamped to 0–100 and rounded; `size` is `sm` (8 px, default) or `md` (10 px); `tone` (`primary` default, `success`, `warning`, `danger`) colors the fill. `label` is required and becomes the bar's `aria-label`. The native `<progress>` element now carries an explicit `role="progressbar"` attribute (it already had the role implicitly) so consumers and specs can select on it directly. `percent` now guards against a non-finite `value` (e.g. `NaN`), rendering `0` instead of propagating `NaN` into the fill width and `aria-valuenow`.
|