@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,371 @@
|
|
|
1
|
+
# bf-textarea
|
|
2
|
+
|
|
3
|
+
Multi-line text field with label, help and error text, and Signal Forms binding
|
|
4
|
+
|
|
5
|
+
`BfTextareaComponent` from `@bitforgehq/ui` · Forms · since 0.1.0
|
|
6
|
+
|
|
7
|
+
## Example
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Component, signal } from '@angular/core';
|
|
11
|
+
import { BfTextareaComponent } from '@bitforgehq/ui';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* The bf-textarea overview.
|
|
15
|
+
*
|
|
16
|
+
* Live demo of `bf-textarea`: a bound fixed-rows field with a character count and an auto-resizing one; then the sm, md and lg sizes in a row.
|
|
17
|
+
*/
|
|
18
|
+
@Component({
|
|
19
|
+
selector: 'app-example-textarea-overview',
|
|
20
|
+
imports: [BfTextareaComponent],
|
|
21
|
+
template: `
|
|
22
|
+
<div class="flex flex-col gap-3">
|
|
23
|
+
<bf-textarea label="Notes" [rows]="3" placeholder="Add a note" [(value)]="notes" />
|
|
24
|
+
<p data-status aria-live="polite" class="text-caption text-text-muted">
|
|
25
|
+
{{ notes().length }} characters
|
|
26
|
+
</p>
|
|
27
|
+
<bf-textarea label="Description" [autoResize]="true" value="Grows with the content" />
|
|
28
|
+
<div data-sizes class="flex flex-wrap items-center gap-3">
|
|
29
|
+
<bf-textarea
|
|
30
|
+
size="sm"
|
|
31
|
+
ariaLabel="Small textarea"
|
|
32
|
+
placeholder="sm"
|
|
33
|
+
[rows]="2"
|
|
34
|
+
class="w-40"
|
|
35
|
+
/>
|
|
36
|
+
<bf-textarea ariaLabel="Medium textarea" placeholder="md" [rows]="2" class="w-40" />
|
|
37
|
+
<bf-textarea
|
|
38
|
+
size="lg"
|
|
39
|
+
ariaLabel="Large textarea"
|
|
40
|
+
placeholder="lg"
|
|
41
|
+
[rows]="2"
|
|
42
|
+
class="w-40"
|
|
43
|
+
/>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
`,
|
|
47
|
+
})
|
|
48
|
+
export class TextareaOverviewExampleComponent {
|
|
49
|
+
readonly notes = signal('');
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Overview
|
|
54
|
+
|
|
55
|
+
Multi-line text field with the same chrome and Signal Forms binding as `bf-input`.
|
|
56
|
+
|
|
57
|
+
The multi-line text field. Same label, help and error chrome as `bf-input`, same Signal Forms binding.
|
|
58
|
+
|
|
59
|
+
## When to use
|
|
60
|
+
|
|
61
|
+
Use `bf-textarea` for free text that runs over several lines: a comment, a description, notes. Use [bf-input](https://bitforge-ui.web.app/components/input) instead for a single value such as a title or an email.
|
|
62
|
+
|
|
63
|
+
## Basic usage
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { Component, signal } from '@angular/core';
|
|
67
|
+
import { BfTextareaComponent } from '@bitforgehq/ui';
|
|
68
|
+
|
|
69
|
+
/** A four-row description field bound to a signal. */
|
|
70
|
+
@Component({
|
|
71
|
+
selector: 'app-example-textarea-basic',
|
|
72
|
+
imports: [BfTextareaComponent],
|
|
73
|
+
template: `
|
|
74
|
+
<bf-textarea
|
|
75
|
+
label="Description"
|
|
76
|
+
[rows]="4"
|
|
77
|
+
placeholder="What is this project about?"
|
|
78
|
+
[(value)]="description"
|
|
79
|
+
/>
|
|
80
|
+
`,
|
|
81
|
+
})
|
|
82
|
+
export class TextareaBasicExampleComponent {
|
|
83
|
+
protected readonly description = signal('');
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`(changed)` emits the new text right after each user edit, the moment `value` changes; a
|
|
88
|
+
programmatic write to `value` does not emit.
|
|
89
|
+
|
|
90
|
+
## Auto-resize
|
|
91
|
+
|
|
92
|
+
`autoResize` lets the box grow with its content using CSS field sizing (`field-sizing: content`). It starts at `rows` lines, empty or not, so it is exactly as tall as a fixed textarea with the same `rows`. Pair it with a length limit to keep the text bounded: the `maxLength` input, or with Signal Forms a `maxLength()` rule, which binds the native `maxlength` itself (`[maxLength]` cannot be set next to `[formField]`). A browser without field sizing (Firefox before its support) keeps the fixed `rows` and the resize handle instead.
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
import { Component, signal } from '@angular/core';
|
|
96
|
+
import { FormField, form, maxLength } from '@angular/forms/signals';
|
|
97
|
+
import { BfTextareaComponent } from '@bitforgehq/ui';
|
|
98
|
+
|
|
99
|
+
/** A notes field that grows with its text; the `maxLength()` rule caps it at 500 characters. */
|
|
100
|
+
@Component({
|
|
101
|
+
selector: 'app-example-textarea-auto-resize',
|
|
102
|
+
imports: [FormField, BfTextareaComponent],
|
|
103
|
+
template: ` <bf-textarea label="Notes" [autoResize]="true" [formField]="task.notes" /> `,
|
|
104
|
+
})
|
|
105
|
+
export class TextareaAutoResizeExampleComponent {
|
|
106
|
+
private readonly model = signal({ notes: '' });
|
|
107
|
+
protected readonly task = form(this.model, (p) => {
|
|
108
|
+
maxLength(p.notes, 500);
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Bounded auto-resize
|
|
114
|
+
|
|
115
|
+
`maxRows` stops the growth: past that many lines the box keeps its height and scrolls. Use it for a comment box in a dense layout, so a long paste never pushes the page's actions out of view.
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
import { Component, signal } from '@angular/core';
|
|
119
|
+
import { BfTextareaComponent } from '@bitforgehq/ui';
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* A comment box that grows from 3 to 6 lines, then scrolls.
|
|
123
|
+
*
|
|
124
|
+
* `autoResize` with `rows` 3 and `maxRows` 6.
|
|
125
|
+
*/
|
|
126
|
+
@Component({
|
|
127
|
+
selector: 'app-example-textarea-max-rows',
|
|
128
|
+
imports: [BfTextareaComponent],
|
|
129
|
+
template: `
|
|
130
|
+
<bf-textarea
|
|
131
|
+
label="Comment"
|
|
132
|
+
autoResize
|
|
133
|
+
[rows]="3"
|
|
134
|
+
[maxRows]="6"
|
|
135
|
+
[(value)]="comment"
|
|
136
|
+
class="w-full sm:w-80"
|
|
137
|
+
/>
|
|
138
|
+
`,
|
|
139
|
+
})
|
|
140
|
+
export class TextareaMaxRowsExampleComponent {
|
|
141
|
+
protected readonly comment = signal('');
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Read-only
|
|
146
|
+
|
|
147
|
+
`readonly` keeps the text selectable and the field in the tab order on the muted surface; nothing
|
|
148
|
+
can be typed. Signal Forms binds it from `readonly()` rules.
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { Component } from '@angular/core';
|
|
152
|
+
import { BfTextareaComponent } from '@bitforgehq/ui';
|
|
153
|
+
|
|
154
|
+
/** A read-only notes field. */
|
|
155
|
+
@Component({
|
|
156
|
+
selector: 'app-example-textarea-readonly',
|
|
157
|
+
imports: [BfTextareaComponent],
|
|
158
|
+
template: `<bf-textarea label="Notes" [readonly]="true" [value]="notes" />`,
|
|
159
|
+
})
|
|
160
|
+
export class TextareaReadonlyExampleComponent {
|
|
161
|
+
protected readonly notes = 'Kick-off on Monday; the client brings the brand book.';
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Without a visible label
|
|
166
|
+
|
|
167
|
+
An inline comment box or a grid cell editor can skip the visible `label`; give it `ariaLabel`, or
|
|
168
|
+
`ariaLabelledby` pointing at the element that names it. A textarea without a visible label needs
|
|
169
|
+
one of the two. Both are ignored while `label` is set.
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { Component, signal } from '@angular/core';
|
|
173
|
+
import { BfTextareaComponent } from '@bitforgehq/ui';
|
|
174
|
+
|
|
175
|
+
/** A comment box named by `ariaLabel` instead of a visible label. */
|
|
176
|
+
@Component({
|
|
177
|
+
selector: 'app-example-textarea-unlabelled',
|
|
178
|
+
imports: [BfTextareaComponent],
|
|
179
|
+
template: `<bf-textarea ariaLabel="Comment" [rows]="2" [(value)]="comment" />`,
|
|
180
|
+
})
|
|
181
|
+
export class TextareaUnlabelledExampleComponent {
|
|
182
|
+
protected readonly comment = signal('');
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## Sizes
|
|
187
|
+
|
|
188
|
+
A textarea has no fixed height (`rows` and `autoResize` set it), so its step sets the padding and the type to match the single-line fields of the same step: `sm` (12 px sides, 13 px type), `md` (default, 14 px sides, 14 px type), `lg` (16 px sides, 15 px type on 24 px lines). Unset, `size` follows `provideBfDefaults()`'s `fieldSize`, `md` by default; a Capacitor app sets `provideBfDefaults({ fieldSize: 'lg' })` once for the 48 px phone look, and a dense sub-tree (a filter bar, a table) can set `{ size: 'sm' }` in a component's `providers`. Fields get no touch extension: `sm`/`md` fields stay 32/40 px under a coarse pointer, so touch apps use `provideBfDefaults({ fieldSize: 'lg' })`.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
import { Component, signal } from '@angular/core';
|
|
192
|
+
import { BfTextareaComponent } from '@bitforgehq/ui';
|
|
193
|
+
|
|
194
|
+
/** The sm, md and lg textarea sizes. */
|
|
195
|
+
@Component({
|
|
196
|
+
selector: 'app-example-textarea-sizes',
|
|
197
|
+
imports: [BfTextareaComponent],
|
|
198
|
+
template: `
|
|
199
|
+
<div class="flex flex-col gap-3">
|
|
200
|
+
<bf-textarea size="sm" label="Comment" [rows]="2" [(value)]="comment" />
|
|
201
|
+
<bf-textarea label="Notes" [(value)]="notes" />
|
|
202
|
+
<bf-textarea size="lg" label="Description" [(value)]="description" />
|
|
203
|
+
</div>
|
|
204
|
+
`,
|
|
205
|
+
})
|
|
206
|
+
export class TextareaSizesExampleComponent {
|
|
207
|
+
protected readonly comment = signal('');
|
|
208
|
+
protected readonly notes = signal('');
|
|
209
|
+
protected readonly description = signal('');
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
## Validation
|
|
214
|
+
|
|
215
|
+
Once the control is touched it shows the first error as text: the error's own `message`, else the default for its kind from `provideBfLabels()`'s `validation` labels (`required` "Fill in this field", `email`, `pattern`, `parse`, `min(n)`, `max(n)`, `minLength(n)` "Use at least n characters", `maxLength(n)`, `minDate(d)`, `maxDate(d)`, and `fallback` "Check this value" for any other kind), so it never turns red without text. Reactive Forms `Validators.*` errors carry no message and get the same defaults (`minlength`/`maxlength` read their limit from the error's `context`). An explicit `errorMessage` wins over both and shows at once, e.g. for a server error.
|
|
216
|
+
|
|
217
|
+
```ts
|
|
218
|
+
import { Component, signal } from '@angular/core';
|
|
219
|
+
import { FormField, FormRoot, form, minLength } from '@angular/forms/signals';
|
|
220
|
+
import { BfButtonComponent, BfTextareaComponent } from '@bitforgehq/ui';
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* A minimum length with the default message.
|
|
224
|
+
*
|
|
225
|
+
* `minLength(p.notes, 5)` has no message, so a short note shows "Use at least 5 characters".
|
|
226
|
+
*/
|
|
227
|
+
@Component({
|
|
228
|
+
selector: 'app-example-textarea-validation',
|
|
229
|
+
imports: [FormField, FormRoot, BfButtonComponent, BfTextareaComponent],
|
|
230
|
+
template: `
|
|
231
|
+
<form [formRoot]="report" class="flex flex-col items-start gap-3">
|
|
232
|
+
<bf-textarea label="Notes" class="self-stretch" [formField]="report.notes" />
|
|
233
|
+
<bf-button type="submit">Send</bf-button>
|
|
234
|
+
</form>
|
|
235
|
+
`,
|
|
236
|
+
})
|
|
237
|
+
export class TextareaValidationExampleComponent {
|
|
238
|
+
private readonly model = signal({ notes: 'Hi' });
|
|
239
|
+
protected readonly report = form(
|
|
240
|
+
this.model,
|
|
241
|
+
(p) => {
|
|
242
|
+
minLength(p.notes, 5);
|
|
243
|
+
},
|
|
244
|
+
{ submission: { action: () => Promise.resolve(undefined) } },
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Desktop
|
|
250
|
+
|
|
251
|
+
The field has no hover state; the text cursor shows over it. The `primary` border and the focus ring show on every focus, by mouse or keyboard, because a focused field takes typing. A textarea has no fixed height: `rows` and `autoResize` set it, and the `size` step sets only the padding and the type (`sm` 12 px sides and 13 px type for a dense desktop form, `md` 14 px by default); `provideBfDefaults({ fieldSize: 'sm' })` sets it for a sub-tree ([density guide](https://bitforge-ui.web.app/density)). Without `autoResize` the browser's resize handle lets the user drag the box taller; with it the box grows by itself (to `maxRows`, then scrolls with the wheel or trackpad).
|
|
252
|
+
|
|
253
|
+
## Theming
|
|
254
|
+
|
|
255
|
+
- Border: `border-strong` (the control boundary, ≥ 3:1), switching to `danger-border` on error; focus: `primary` border with a `ring` ring.
|
|
256
|
+
- Disabled: `surface-sunken` border, `surface-muted` background, `text-disabled` text. Read-only: `surface-muted` background. Placeholder: `text-muted` (≥ 4.5:1).
|
|
257
|
+
- Label, help and error text come from the `bf-field` wrapper (see its Theming section).
|
|
258
|
+
|
|
259
|
+
## Accessibility
|
|
260
|
+
|
|
261
|
+
Native `<textarea>`, so it inherits the platform's resize and selection behaviour. `bf-field` renders the `<label for>`; the textarea itself wires `aria-describedby` to the help paragraph and the error paragraph under it (both while shown, help first) and, while it is invalid, `aria-errormessage` to the error paragraph; `aria-invalid` is set once the field is touched and invalid (an explicit `errorMessage` shows immediately); `maxlength` and `minlength` reflect `maxLength` and `minLength` (Signal Forms binds both from its rules). `aria-label` and `aria-labelledby` carry `ariaLabel` and `ariaLabelledby` only while there is no visible `label`. `readonly` uses the native attribute: the textarea stays in the tab order and is announced as read-only. `focus()` focuses the native textarea; Signal Forms calls it from `focusBoundControl()`.
|
|
262
|
+
|
|
263
|
+
### Keyboard
|
|
264
|
+
|
|
265
|
+
| Key | Action |
|
|
266
|
+
| ------------------------------------------------ | ----------------------------------------------------------------------------- |
|
|
267
|
+
| <kbd>Tab</kbd> / <kbd>Shift</kbd>+<kbd>Tab</kbd> | Moves focus to and from the textarea; a `readonly` one stays in the tab order |
|
|
268
|
+
| <kbd>Enter</kbd> | Inserts a line break; it never submits the form |
|
|
269
|
+
|
|
270
|
+
## Inputs
|
|
271
|
+
|
|
272
|
+
| Name | Type | Default | Description |
|
|
273
|
+
| ---------------- | ----------------------------------------------------------- | ----------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
274
|
+
| `size` | `BfSize \| undefined` (`'sm' \| 'md' \| 'lg' \| undefined`) | `undefined` | Padding and type step: sm, md, lg (a textarea's height comes from `rows`); unset follows `provideBfDefaults()` (`fieldSize`, `md` by default). |
|
|
275
|
+
| `label` | `string` | `''` | Visible label above the control. |
|
|
276
|
+
| `ariaLabel` | `string` | `''` | Accessible name when no visible label is rendered (e.g. an inline comment box). Ignored when `label` is set. |
|
|
277
|
+
| `ariaLabelledby` | `string` | `''` | Id(s) of the element(s) that name the field when no visible label is rendered. Ignored when `label` is set. |
|
|
278
|
+
| `placeholder` | `string` | `''` | Example value shown while empty. |
|
|
279
|
+
| `helpText` | `string` | `''` | Helper text under the control. |
|
|
280
|
+
| `errorMessage` | `string` | `''` | Explicit error text; takes precedence over Signal Forms errors. |
|
|
281
|
+
| `disabled` | `boolean` | `false` | Disables the control. Set by `[formField]`; do not bind it yourself. |
|
|
282
|
+
| `readonly` | `boolean` | `false` | Makes the control read-only. Set by `[formField]`; do not bind it yourself. |
|
|
283
|
+
| `required` | `boolean` | `false` | Marks the control required. Set by `[formField]`; do not bind it yourself. |
|
|
284
|
+
| `invalid` | `boolean` | `false` | Field validity from Signal Forms. Set by `[formField]`; do not bind it yourself. |
|
|
285
|
+
| `touched` | `boolean` | `false` | Whether the user has left the field. Set by `[formField]`; do not bind it yourself. |
|
|
286
|
+
| `errors` | `readonly ValidationError.WithOptionalFieldTree[]` | `[]` | Validation errors from Signal Forms. Set by `[formField]`; do not bind it yourself. |
|
|
287
|
+
| `name` | `string` | `''` | Native name attribute. Set by `[formField]`; do not bind it yourself. |
|
|
288
|
+
| `id` | `string` | `generated` | Control id; generated when not set. |
|
|
289
|
+
| `rows` | `number` | `3` | Visible rows; with `autoResize`, the rows the empty box starts at. |
|
|
290
|
+
| `autoResize` | `boolean` | `false` | Grows with the content (CSS `field-sizing: content`) from `rows` up to `maxRows`. Where the browser has no `field-sizing` it keeps the fixed `rows`. |
|
|
291
|
+
| `maxRows` | `number \| undefined` | `undefined` | With `autoResize`, the rows the box grows to at most; past them it scrolls. Unset, it grows without a bound. |
|
|
292
|
+
| `maxLength` | `number \| undefined` | `undefined` | Maximum number of characters (native `maxlength`); bound by Signal Forms `maxLength()`. Set by `[formField]`; do not bind it yourself. |
|
|
293
|
+
| `minLength` | `number \| undefined` | `undefined` | Minimum number of characters (native `minlength`); bound by Signal Forms `minLength()`. Set by `[formField]`; do not bind it yourself. |
|
|
294
|
+
| `value` | `string` | `''` | The text value; two-way bindable and bound by `[formField]`. Two-way: `[(value)]`. |
|
|
295
|
+
|
|
296
|
+
## Outputs
|
|
297
|
+
|
|
298
|
+
| Name | Payload | Description |
|
|
299
|
+
| --------- | ------------ | ------------------------------------------------------------------------------------------------------- |
|
|
300
|
+
| `changed` | `string` | Emitted with the new text right after the user changes it (each keystroke or paste). |
|
|
301
|
+
| `focused` | `FocusEvent` | Emitted when the control gains focus. |
|
|
302
|
+
| `blurred` | `FocusEvent` | Emitted when the control loses focus. |
|
|
303
|
+
| `touch` | `void` | Emitted on blur so Signal Forms marks the field touched. Set by `[formField]`; do not bind it yourself. |
|
|
304
|
+
|
|
305
|
+
## Methods
|
|
306
|
+
|
|
307
|
+
### `focus(options?: FocusOptions): void`
|
|
308
|
+
|
|
309
|
+
Focuses the native textarea; Signal Forms calls it from `focusBoundControl()`.
|
|
310
|
+
|
|
311
|
+
| Parameter | Type | Description |
|
|
312
|
+
| ---------- | -------------- | --------------------------------------------------------------------- |
|
|
313
|
+
| `options?` | `FocusOptions` | Passed on to the native `focus()`, such as `{ preventScroll: true }`. |
|
|
314
|
+
|
|
315
|
+
## Notes
|
|
316
|
+
|
|
317
|
+
### Do
|
|
318
|
+
|
|
319
|
+
- Set `rows` to the typical length of the expected text.
|
|
320
|
+
- Show remaining characters in `helpText` when `maxLength` matters.
|
|
321
|
+
|
|
322
|
+
### Don't
|
|
323
|
+
|
|
324
|
+
- Don't use a textarea for single values; use `bf-input`.
|
|
325
|
+
|
|
326
|
+
## Migration notes
|
|
327
|
+
|
|
328
|
+
### 0.3.0
|
|
329
|
+
|
|
330
|
+
New `changed` output: the new text right after each user edit (not for a programmatic write).
|
|
331
|
+
|
|
332
|
+
**Breaking:** the default `size` is `md` instead of `lg`; `size` is a `BfSize` (`sm` is new) and,
|
|
333
|
+
unset, follows `provideBfDefaults()`'s `fieldSize`. A step sets padding and type, never a height
|
|
334
|
+
(`rows` and `autoResize` do), and the docs now say so. See Migration 2.
|
|
335
|
+
|
|
336
|
+
**Behaviour:** an error without a message shows its kind's default text (was a red border only):
|
|
337
|
+
once touched, the field shows the first error's own `message`, else `provideBfLabels()`'s
|
|
338
|
+
`validation` text for its kind (Signal Forms and Reactive interop kinds), else
|
|
339
|
+
`validation.fallback`. `errorMessage` still wins. See Migration 1.
|
|
340
|
+
|
|
341
|
+
JSDoc of `textarea.component.ts` for the API reference: `@param` docs; template handlers and
|
|
342
|
+
framework hooks marked `@internal`, so the reference leaves them out. No behaviour change.
|
|
343
|
+
|
|
344
|
+
**Behaviour:** the help text stays while an error shows, with the error under it (F-020):
|
|
345
|
+
`aria-describedby` lists both (`"<id>-help <id>-error"`), and `aria-errormessage` points at the
|
|
346
|
+
error paragraph while `aria-invalid="true"`. See Migration 25.
|
|
347
|
+
|
|
348
|
+
New `maxRows = input<number | undefined>(undefined)` (F-019). With `autoResize` the box keeps
|
|
349
|
+
`field-sizing: content` and now starts at `rows` lines (a `min-block-size` of `rows` times `1lh`
|
|
350
|
+
plus the size's padding and border), so an empty auto-resizing textarea is as tall as a fixed one with the
|
|
351
|
+
same `rows` (it was one line); with `maxRows` it stops at that many lines (`max-block-size`, the same
|
|
352
|
+
way) and scrolls. **Behaviour:** where the browser has no `field-sizing` (`CSS.supports()` says no, read once;
|
|
353
|
+
also on the server) the box keeps its fixed `rows` and the resize
|
|
354
|
+
handle instead of the one-line box it had.
|
|
355
|
+
|
|
356
|
+
### 0.2.0
|
|
357
|
+
|
|
358
|
+
The rest border is `border-strong` and the placeholder `text-muted`, as on `bf-input`.
|
|
359
|
+
|
|
360
|
+
Changed: the border narrows to 1 px (was 1.5 px), as on `bf-input`.
|
|
361
|
+
|
|
362
|
+
Changed: the focus ring narrows to 2 px (was 4 px), as on `bf-input`.
|
|
363
|
+
|
|
364
|
+
Added: `minLength` (native `minlength`), and `ariaLabel` / `ariaLabelledby` for a textarea without a
|
|
365
|
+
visible `label` (ignored while `label` is set). `focus(options?)` focuses the native control, so
|
|
366
|
+
Signal Forms' `focusBoundControl()` and "focus the first invalid field" on submit now work (they
|
|
367
|
+
were no-ops).
|
|
368
|
+
|
|
369
|
+
### 0.1.0
|
|
370
|
+
|
|
371
|
+
Same `md`/`lg` size rename as `bf-input`. The host no longer reflects a static `id` attribute onto `<bf-textarea>`.
|