@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,377 @@
|
|
|
1
|
+
# bf-menu-button
|
|
2
|
+
|
|
3
|
+
Styled button that opens a menu, with outline, text, tonal and icon-only looks
|
|
4
|
+
|
|
5
|
+
`BfMenuButtonComponent` from `@bitforgehq/ui/overlay` · Overlays · since 0.3.0
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Component, signal } from '@angular/core';
|
|
11
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
12
|
+
import {
|
|
13
|
+
BfMenuButtonComponent,
|
|
14
|
+
BfMenuComponent,
|
|
15
|
+
BfMenuItemDirective,
|
|
16
|
+
} from '@bitforgehq/ui/overlay';
|
|
17
|
+
import { Ellipsis } from 'lucide';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The bf-menu-button overview.
|
|
21
|
+
*
|
|
22
|
+
* Live demo of `bf-menu-button`: the outline and text variants and an icon-only "More actions"
|
|
23
|
+
* button, all opening the same menu; the result line reports the chosen item. The triggers and
|
|
24
|
+
* the result line carry `data-testid`s for the end-to-end suite.
|
|
25
|
+
*/
|
|
26
|
+
@Component({
|
|
27
|
+
selector: 'app-example-menu-button-overview',
|
|
28
|
+
imports: [BfIconComponent, BfMenuButtonComponent, BfMenuComponent, BfMenuItemDirective],
|
|
29
|
+
template: `
|
|
30
|
+
<div class="flex flex-col gap-4">
|
|
31
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
32
|
+
<bf-menu-button data-testid="menu-button-export" [menu]="exportMenu">Export</bf-menu-button>
|
|
33
|
+
<bf-menu-button data-testid="menu-button-export-text" [menu]="exportMenu" variant="text"
|
|
34
|
+
>Export</bf-menu-button
|
|
35
|
+
>
|
|
36
|
+
<bf-menu-button
|
|
37
|
+
data-testid="menu-button-more"
|
|
38
|
+
[menu]="exportMenu"
|
|
39
|
+
iconOnly
|
|
40
|
+
label="More actions"
|
|
41
|
+
variant="text"
|
|
42
|
+
placement="below-end"
|
|
43
|
+
>
|
|
44
|
+
<bf-icon [icon]="ellipsis" />
|
|
45
|
+
</bf-menu-button>
|
|
46
|
+
</div>
|
|
47
|
+
<p
|
|
48
|
+
data-status
|
|
49
|
+
data-testid="menu-button-result"
|
|
50
|
+
class="text-caption text-text-muted"
|
|
51
|
+
aria-live="polite"
|
|
52
|
+
>
|
|
53
|
+
{{ result() }}
|
|
54
|
+
</p>
|
|
55
|
+
</div>
|
|
56
|
+
|
|
57
|
+
<ng-template #exportMenu>
|
|
58
|
+
<bf-menu>
|
|
59
|
+
<button bfMenuItem (triggered)="result.set('Exported as CSV.')">Export as CSV</button>
|
|
60
|
+
<button bfMenuItem (triggered)="result.set('Exported as PDF.')">Export as PDF</button>
|
|
61
|
+
<button bfMenuItem (triggered)="result.set('Link copied.')">Copy link</button>
|
|
62
|
+
</bf-menu>
|
|
63
|
+
</ng-template>
|
|
64
|
+
`,
|
|
65
|
+
})
|
|
66
|
+
export class MenuButtonOverviewExampleComponent {
|
|
67
|
+
readonly ellipsis = Ellipsis;
|
|
68
|
+
readonly result = signal('');
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Overview
|
|
73
|
+
|
|
74
|
+
Button that opens a `bf-menu`: a native `<button>` styled like `bf-button` (or `bf-icon-button`
|
|
75
|
+
with `iconOnly`) in the outline, text or tonal variant, with `aria-haspopup="menu"` and
|
|
76
|
+
`aria-expanded`. Click, `Enter`, `Space` or `ArrowDown` open the menu with its first item
|
|
77
|
+
focused, `ArrowUp` with its last; closing it returns focus here.
|
|
78
|
+
|
|
79
|
+
A button that opens a `bf-menu`, from `@bitforgehq/ui/overlay` (needs `@angular/cdk`, no
|
|
80
|
+
Capacitor). It renders a native `<button>` that looks like a `bf-button` (or a `bf-icon-button`
|
|
81
|
+
with `iconOnly`) in the outline, text or tonal variant, with a caret after its label. Pass the
|
|
82
|
+
`ng-template` holding the menu as `menu`. The menu page covers the items, groups, submenus and
|
|
83
|
+
the keyboard. Import `BfMenuButtonComponent`, `BfMenuComponent` and `BfMenuItemDirective` from
|
|
84
|
+
`@bitforgehq/ui/overlay`.
|
|
85
|
+
|
|
86
|
+
## When to use
|
|
87
|
+
|
|
88
|
+
Use `bf-menu-button` for a button that opens a [bf-menu](https://bitforge-ui.web.app/components/menu) of actions: Export, Sort, a "More" button on a table row. Use [bf-button](https://bitforge-ui.web.app/components/button) instead for a single action, and [bf-select](https://bitforge-ui.web.app/components/select) to pick a form value.
|
|
89
|
+
|
|
90
|
+
## Basic usage
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import { Component, signal } from '@angular/core';
|
|
94
|
+
import {
|
|
95
|
+
BfMenuButtonComponent,
|
|
96
|
+
BfMenuComponent,
|
|
97
|
+
BfMenuItemDirective,
|
|
98
|
+
} from '@bitforgehq/ui/overlay';
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* An export menu button.
|
|
102
|
+
*
|
|
103
|
+
* The menu button passes its `ng-template` as `menu`; each format reports its export.
|
|
104
|
+
*/
|
|
105
|
+
@Component({
|
|
106
|
+
selector: 'app-example-menu-button-basic',
|
|
107
|
+
imports: [BfMenuButtonComponent, BfMenuComponent, BfMenuItemDirective],
|
|
108
|
+
template: `
|
|
109
|
+
<bf-menu-button [menu]="exportMenu">Export</bf-menu-button>
|
|
110
|
+
<p aria-live="polite" class="text-caption text-text-muted mt-3">{{ result() }}</p>
|
|
111
|
+
|
|
112
|
+
<ng-template #exportMenu>
|
|
113
|
+
<bf-menu>
|
|
114
|
+
<button bfMenuItem (triggered)="result.set('Exported as CSV.')">CSV</button>
|
|
115
|
+
<button bfMenuItem (triggered)="result.set('Exported as PDF.')">PDF</button>
|
|
116
|
+
</bf-menu>
|
|
117
|
+
</ng-template>
|
|
118
|
+
`,
|
|
119
|
+
})
|
|
120
|
+
export class MenuButtonBasicExampleComponent {
|
|
121
|
+
protected readonly result = signal('');
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
`opened` and `closed` fire as the menu opens and closes. `disabled` disables the button (the
|
|
126
|
+
menu cannot open). An icon goes in the `icon-start` slot.
|
|
127
|
+
|
|
128
|
+
```ts
|
|
129
|
+
import { Component, signal } from '@angular/core';
|
|
130
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
131
|
+
import {
|
|
132
|
+
BfMenuButtonComponent,
|
|
133
|
+
BfMenuComponent,
|
|
134
|
+
BfMenuItemDirective,
|
|
135
|
+
} from '@bitforgehq/ui/overlay';
|
|
136
|
+
import { Download } from 'lucide';
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* A tonal menu button with an icon.
|
|
140
|
+
*
|
|
141
|
+
* The icon goes in the icon-start slot; `closed` reports each time the menu closes.
|
|
142
|
+
*/
|
|
143
|
+
@Component({
|
|
144
|
+
selector: 'app-example-menu-button-icon',
|
|
145
|
+
imports: [BfIconComponent, BfMenuButtonComponent, BfMenuComponent, BfMenuItemDirective],
|
|
146
|
+
template: `
|
|
147
|
+
<bf-menu-button [menu]="exportMenu" variant="tonal" (closed)="closes.set(closes() + 1)">
|
|
148
|
+
<bf-icon bfSlot="icon-start" [icon]="download" />
|
|
149
|
+
Export
|
|
150
|
+
</bf-menu-button>
|
|
151
|
+
<p class="text-caption text-text-muted mt-3">Closed {{ closes() }} times.</p>
|
|
152
|
+
|
|
153
|
+
<ng-template #exportMenu>
|
|
154
|
+
<bf-menu>
|
|
155
|
+
<button bfMenuItem>CSV</button>
|
|
156
|
+
<button bfMenuItem>PDF</button>
|
|
157
|
+
</bf-menu>
|
|
158
|
+
</ng-template>
|
|
159
|
+
`,
|
|
160
|
+
})
|
|
161
|
+
export class MenuButtonIconExampleComponent {
|
|
162
|
+
protected readonly download = Download;
|
|
163
|
+
protected readonly closes = signal(0);
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Variants
|
|
168
|
+
|
|
169
|
+
`outline` (default), `text` and `tonal`, with the same colours as `bf-button`. A menu button is
|
|
170
|
+
never `primary`: it opens a choice, it is not the page's main action.
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { Component, signal } from '@angular/core';
|
|
174
|
+
import {
|
|
175
|
+
BfMenuButtonComponent,
|
|
176
|
+
BfMenuComponent,
|
|
177
|
+
BfMenuItemDirective,
|
|
178
|
+
} from '@bitforgehq/ui/overlay';
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* The outline, text and tonal menu buttons.
|
|
182
|
+
*
|
|
183
|
+
* Three triggers for one sort menu.
|
|
184
|
+
*/
|
|
185
|
+
@Component({
|
|
186
|
+
selector: 'app-example-menu-button-variants',
|
|
187
|
+
imports: [BfMenuButtonComponent, BfMenuComponent, BfMenuItemDirective],
|
|
188
|
+
template: `
|
|
189
|
+
<div class="flex flex-wrap gap-2">
|
|
190
|
+
<bf-menu-button [menu]="sortMenu">Sort</bf-menu-button>
|
|
191
|
+
<bf-menu-button [menu]="sortMenu" variant="text">Sort</bf-menu-button>
|
|
192
|
+
<bf-menu-button [menu]="sortMenu" variant="tonal">Sort</bf-menu-button>
|
|
193
|
+
</div>
|
|
194
|
+
<p aria-live="polite" class="text-caption text-text-muted mt-3">{{ result() }}</p>
|
|
195
|
+
|
|
196
|
+
<ng-template #sortMenu>
|
|
197
|
+
<bf-menu>
|
|
198
|
+
<button bfMenuItem (triggered)="result.set('Sorted by name.')">Name</button>
|
|
199
|
+
<button bfMenuItem (triggered)="result.set('Sorted by date.')">Date</button>
|
|
200
|
+
</bf-menu>
|
|
201
|
+
</ng-template>
|
|
202
|
+
`,
|
|
203
|
+
})
|
|
204
|
+
export class MenuButtonVariantsExampleComponent {
|
|
205
|
+
protected readonly result = signal('');
|
|
206
|
+
}
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
## Icon only
|
|
210
|
+
|
|
211
|
+
`iconOnly` renders a round button that holds only the projected icon, like `bf-icon-button`, and
|
|
212
|
+
drops the caret. Set `label`: it is the button's accessible name, as the icon gives none. A
|
|
213
|
+
"More" button on a table row is the typical use.
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { Component, signal } from '@angular/core';
|
|
217
|
+
import { BfIconComponent } from '@bitforgehq/ui/icons';
|
|
218
|
+
import {
|
|
219
|
+
BfMenuButtonComponent,
|
|
220
|
+
BfMenuComponent,
|
|
221
|
+
BfMenuItemDirective,
|
|
222
|
+
} from '@bitforgehq/ui/overlay';
|
|
223
|
+
import { Ellipsis } from 'lucide';
|
|
224
|
+
|
|
225
|
+
/** An icon-only menu button named by its label. */
|
|
226
|
+
@Component({
|
|
227
|
+
selector: 'app-example-menu-button-icon-only',
|
|
228
|
+
imports: [BfIconComponent, BfMenuButtonComponent, BfMenuComponent, BfMenuItemDirective],
|
|
229
|
+
template: `
|
|
230
|
+
<bf-menu-button [menu]="rowActions" iconOnly label="More actions" variant="text">
|
|
231
|
+
<bf-icon [icon]="ellipsis" />
|
|
232
|
+
</bf-menu-button>
|
|
233
|
+
<p aria-live="polite" class="text-caption text-text-muted mt-3">{{ result() }}</p>
|
|
234
|
+
|
|
235
|
+
<ng-template #rowActions>
|
|
236
|
+
<bf-menu>
|
|
237
|
+
<button bfMenuItem (triggered)="result.set('Renamed.')">Rename</button>
|
|
238
|
+
<button bfMenuItem (triggered)="result.set('Deleted.')">Delete</button>
|
|
239
|
+
</bf-menu>
|
|
240
|
+
</ng-template>
|
|
241
|
+
`,
|
|
242
|
+
})
|
|
243
|
+
export class MenuButtonIconOnlyExampleComponent {
|
|
244
|
+
protected readonly ellipsis = Ellipsis;
|
|
245
|
+
protected readonly result = signal('');
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Sizes and placement
|
|
250
|
+
|
|
251
|
+
`size` is `sm` 32, `md` 40 or `lg` 48 px; unset it follows `provideBfDefaults()` (`controlSize`,
|
|
252
|
+
`md` by default). Under a coarse pointer `sm` and `md` reach 44 px without changing their look.
|
|
253
|
+
`placement` sets where the menu opens: `'below-start'` (default), `'below-end'`,
|
|
254
|
+
`'above-start'` or `'above-end'`, flipping when it would overflow the viewport.
|
|
255
|
+
|
|
256
|
+
```ts
|
|
257
|
+
import { Component, signal } from '@angular/core';
|
|
258
|
+
import {
|
|
259
|
+
BfMenuButtonComponent,
|
|
260
|
+
BfMenuComponent,
|
|
261
|
+
BfMenuItemDirective,
|
|
262
|
+
} from '@bitforgehq/ui/overlay';
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* A small menu button that opens below its end.
|
|
266
|
+
*
|
|
267
|
+
* `size="sm"` sizes the trigger; `placement="below-end"` aligns the menu to its inline end.
|
|
268
|
+
*/
|
|
269
|
+
@Component({
|
|
270
|
+
selector: 'app-example-menu-button-sizes',
|
|
271
|
+
imports: [BfMenuButtonComponent, BfMenuComponent, BfMenuItemDirective],
|
|
272
|
+
template: `
|
|
273
|
+
<div class="flex justify-end">
|
|
274
|
+
<bf-menu-button [menu]="rowActions" size="sm" placement="below-end">Actions</bf-menu-button>
|
|
275
|
+
</div>
|
|
276
|
+
<p aria-live="polite" class="text-caption text-text-muted mt-3">{{ result() }}</p>
|
|
277
|
+
|
|
278
|
+
<ng-template #rowActions>
|
|
279
|
+
<bf-menu>
|
|
280
|
+
<button bfMenuItem (triggered)="result.set('Renamed.')">Rename</button>
|
|
281
|
+
<button bfMenuItem (triggered)="result.set('Archived.')">Archive</button>
|
|
282
|
+
</bf-menu>
|
|
283
|
+
</ng-template>
|
|
284
|
+
`,
|
|
285
|
+
})
|
|
286
|
+
export class MenuButtonSizesExampleComponent {
|
|
287
|
+
protected readonly result = signal('');
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
## Desktop
|
|
292
|
+
|
|
293
|
+
Hover and focus look like `bf-button` (or `bf-icon-button` with `iconOnly`): the fill, border or text darkens on hover with the pointer cursor, and the focus ring shows on keyboard focus only. A click opens the menu; a second click on the button closes it. Under a fine pointer the visible box is the hit area. Desktop density is the default `md` step; `provideBfDefaults({ size: 'sm' })`, or `{ size: 'sm' }` in a component's `providers`, makes a dense toolbar, table or sidebar ([density guide](https://bitforge-ui.web.app/density)).
|
|
294
|
+
|
|
295
|
+
## Theming
|
|
296
|
+
|
|
297
|
+
- Colours, border, radius, heights and the focus ring are `bf-button`'s (`bf-icon-button`'s with
|
|
298
|
+
`iconOnly`): outline `bg-surface` with a 1.5 px `border-border-strong`, text
|
|
299
|
+
`text-primary-text` (icon-only `text-text-muted` with a `surface-muted` hover), tonal
|
|
300
|
+
`bg-primary-soft` / `text-primary-strong`; disabled `bg-surface-sunken` / `text-disabled`.
|
|
301
|
+
- Caret: a CSS chevron in the label's colour.
|
|
302
|
+
|
|
303
|
+
## Accessibility
|
|
304
|
+
|
|
305
|
+
- A native `<button type="button">` with `aria-haspopup="menu"` and `aria-expanded`, and the
|
|
306
|
+
menu it opens is named by it. Its name is its label, or `label` (`aria-label`). With `iconOnly`,
|
|
307
|
+
`label` is required. With a visible label, leave `label` empty or start it with the visible text
|
|
308
|
+
([WCAG 2.5.3 Label in Name](https://www.w3.org/WAI/WCAG22/Understanding/label-in-name)).
|
|
309
|
+
- Keyboard ([APG menu button](https://www.w3.org/WAI/ARIA/apg/patterns/menu-button/)): `Enter`,
|
|
310
|
+
`Space` or `ArrowDown` open the menu with focus on the first item, `ArrowUp` with focus on the
|
|
311
|
+
last. Closing the menu (`Escape`, `Tab`, an item) returns focus to the button.
|
|
312
|
+
- The caret is drawn in CSS and adds nothing to the name.
|
|
313
|
+
- Hit area: at least 32 px, 44 px under a coarse pointer (as `bf-button`).
|
|
314
|
+
|
|
315
|
+
### Keyboard
|
|
316
|
+
|
|
317
|
+
The keys inside the open menu are on the [bf-menu](https://bitforge-ui.web.app/components/menu#keyboard) page.
|
|
318
|
+
|
|
319
|
+
| Key | Action |
|
|
320
|
+
| ---------------------------------------------------------- | ----------------------------------------------------------- |
|
|
321
|
+
| <kbd>Enter</kbd> / <kbd>Space</kbd> / <kbd>ArrowDown</kbd> | Opens the menu and focuses its first item |
|
|
322
|
+
| <kbd>ArrowUp</kbd> | Opens the menu and focuses its last item |
|
|
323
|
+
| <kbd>Escape</kbd> | In the open menu: closes it and returns focus to the button |
|
|
324
|
+
| <kbd>Tab</kbd> | In the open menu: closes it; focus moves on past the button |
|
|
325
|
+
|
|
326
|
+
## Inputs
|
|
327
|
+
|
|
328
|
+
| Name | Type | Default | Description |
|
|
329
|
+
| ----------- | ---------------------------------------------------------------------------------- | --------------- | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
330
|
+
| `menu` | `TemplateRef<unknown>` | required | The `ng-template` holding the `bf-menu` to open. |
|
|
331
|
+
| `variant` | `BfMenuButtonVariant` (`'outline' \| 'text' \| 'tonal'`) | `'outline'` | Visual style: outline (default), text, tonal. |
|
|
332
|
+
| `size` | `BfSize \| undefined` (`'sm' \| 'md' \| 'lg' \| undefined`) | `undefined` | Height step: sm 32, md 40, lg 48 px; unset follows `provideBfDefaults()` (`controlSize`, `md` by default). |
|
|
333
|
+
| `placement` | `BfMenuPlacement` (`'below-start' \| 'below-end' \| 'above-start' \| 'above-end'`) | `'below-start'` | Where the menu opens against the button; it flips when it would overflow. |
|
|
334
|
+
| `label` | `string` | `''` | Accessible name (`aria-label`). Required with `iconOnly`; with a visible label leave it empty or start it with the visible text. |
|
|
335
|
+
| `iconOnly` | `boolean` | `false` | Square button holding only the projected icon, like `bf-icon-button`; set `label`. |
|
|
336
|
+
| `disabled` | `boolean` | `false` | Disables the button; the menu cannot open. |
|
|
337
|
+
|
|
338
|
+
## Outputs
|
|
339
|
+
|
|
340
|
+
| Name | Payload | Description |
|
|
341
|
+
| -------- | ------- | ---------------- |
|
|
342
|
+
| `opened` | `void` | The menu opened. |
|
|
343
|
+
| `closed` | `void` | The menu closed. |
|
|
344
|
+
|
|
345
|
+
## Slots
|
|
346
|
+
|
|
347
|
+
- `icon-start`: An icon before the label.
|
|
348
|
+
- `default`: The label (the accessible name of an icon-only button).
|
|
349
|
+
|
|
350
|
+
## Notes
|
|
351
|
+
|
|
352
|
+
### Do
|
|
353
|
+
|
|
354
|
+
- Name the button after what the menu holds ("Export", "Sort", "Actions").
|
|
355
|
+
- Use the icon-only variant with a `label` for row actions ("More actions").
|
|
356
|
+
|
|
357
|
+
### Don't
|
|
358
|
+
|
|
359
|
+
- Don't use a menu button for a single action; use a `bf-button`.
|
|
360
|
+
- Don't use it to pick a form value; use `bf-select` or `bf-radio-group`.
|
|
361
|
+
|
|
362
|
+
## Migration notes
|
|
363
|
+
|
|
364
|
+
### 0.3.0
|
|
365
|
+
|
|
366
|
+
New `bf-menu-button` in `@bitforgehq/ui/overlay`: a native `<button>` that opens a `bf-menu`
|
|
367
|
+
(`menu`, a `TemplateRef`) with `aria-haspopup="menu"` and `aria-expanded`, styled like
|
|
368
|
+
`bf-button` (`variant` `outline` (default), `text`, `tonal`; a CSS caret) or, with `iconOnly`,
|
|
369
|
+
like `bf-icon-button`. `size` (unset follows `controlSize`), `placement`, `label` (the
|
|
370
|
+
`aria-label`, required with `iconOnly`), `disabled`, and `opened`/`closed` outputs. Its classes
|
|
371
|
+
come from `bf-button`'s and `bf-icon-button`'s own class maps (internal `ɵ` exports of
|
|
372
|
+
`@bitforgehq/ui`), so the looks never drift.
|
|
373
|
+
|
|
374
|
+
JSDoc of `menu-button.component.ts` for the API reference: `@summary`/`@since` on the exported
|
|
375
|
+
symbols; `@slot` docs for `icon-start`, `default`. No behaviour change.
|
|
376
|
+
|
|
377
|
+
**Behaviour:** a pressed state (F-045): the button and icon-only forms take `bf-button`'s and `bf-icon-button`'s pressed fills from their shared class maps. None while disabled; under forced colours the system colours win.
|