torch-glare 2.5.5 → 2.6.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/README.md +4 -3
- package/dist/bin/index.js +9 -24
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts +2 -2
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +4 -70
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/hook.d.ts +5 -4
- package/dist/src/commands/hook.d.ts.map +1 -1
- package/dist/src/commands/hook.js +7 -75
- package/dist/src/commands/hook.js.map +1 -1
- package/dist/src/commands/init.js +1 -1
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/layout.d.ts +5 -4
- package/dist/src/commands/layout.d.ts.map +1 -1
- package/dist/src/commands/layout.js +7 -75
- package/dist/src/commands/layout.js.map +1 -1
- package/dist/src/commands/provider.d.ts +5 -4
- package/dist/src/commands/provider.d.ts.map +1 -1
- package/dist/src/commands/provider.js +7 -75
- package/dist/src/commands/provider.js.map +1 -1
- package/dist/src/commands/update.d.ts.map +1 -1
- package/dist/src/commands/update.js +78 -43
- package/dist/src/commands/update.js.map +1 -1
- package/dist/src/commands/utils.d.ts +5 -4
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +7 -80
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/addFromRegistry.d.ts +16 -0
- package/dist/src/shared/addFromRegistry.d.ts.map +1 -0
- package/dist/src/shared/addFromRegistry.js +88 -0
- package/dist/src/shared/addFromRegistry.js.map +1 -0
- package/dist/src/shared/getInstallCommand.d.ts.map +1 -1
- package/dist/src/shared/getInstallCommand.js +5 -0
- package/dist/src/shared/getInstallCommand.js.map +1 -1
- package/dist/src/shared/installDependencies.d.ts +0 -10
- package/dist/src/shared/installDependencies.d.ts.map +1 -1
- package/dist/src/shared/installDependencies.js +0 -17
- package/dist/src/shared/installDependencies.js.map +1 -1
- package/dist/src/shared/installFromPlan.d.ts +7 -5
- package/dist/src/shared/installFromPlan.d.ts.map +1 -1
- package/dist/src/shared/installFromPlan.js +103 -36
- package/dist/src/shared/installFromPlan.js.map +1 -1
- package/dist/src/shared/loadRegistry.d.ts +12 -3
- package/dist/src/shared/loadRegistry.d.ts.map +1 -1
- package/dist/src/shared/loadRegistry.js +19 -20
- package/dist/src/shared/loadRegistry.js.map +1 -1
- package/dist/src/shared/registryClient.d.ts +19 -0
- package/dist/src/shared/registryClient.d.ts.map +1 -0
- package/dist/src/shared/registryClient.js +128 -0
- package/dist/src/shared/registryClient.js.map +1 -0
- package/dist/src/shared/resolveEntry.d.ts +10 -7
- package/dist/src/shared/resolveEntry.d.ts.map +1 -1
- package/dist/src/shared/resolveEntry.js +18 -13
- package/dist/src/shared/resolveEntry.js.map +1 -1
- package/dist/src/shared/suggestOtherCommand.d.ts +7 -1
- package/dist/src/shared/suggestOtherCommand.d.ts.map +1 -1
- package/dist/src/shared/suggestOtherCommand.js +29 -23
- package/dist/src/shared/suggestOtherCommand.js.map +1 -1
- package/dist/src/types/main.d.ts +31 -2
- package/dist/src/types/main.d.ts.map +1 -1
- package/package.json +6 -11
- package/apps/lib/components/ActionButton.tsx +0 -93
- package/apps/lib/components/ActionsGroup.tsx +0 -27
- package/apps/lib/components/AlertDialog.tsx +0 -204
- package/apps/lib/components/Avatar.tsx +0 -46
- package/apps/lib/components/Badge.tsx +0 -250
- package/apps/lib/components/BadgeField.tsx +0 -338
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -317
- package/apps/lib/components/ButtonGroup.tsx +0 -190
- package/apps/lib/components/Calendar.tsx +0 -115
- package/apps/lib/components/Card.tsx +0 -95
- package/apps/lib/components/Checkbox.tsx +0 -42
- package/apps/lib/components/ColorPicker.tsx +0 -441
- package/apps/lib/components/ConclusionHeader.tsx +0 -148
- package/apps/lib/components/ContextMenu.tsx +0 -571
- package/apps/lib/components/CountBadge.tsx +0 -52
- package/apps/lib/components/DataTable.tsx +0 -213
- package/apps/lib/components/DataViews/badge.ts +0 -49
- package/apps/lib/components/DataViews/cell.tsx +0 -324
- package/apps/lib/components/DataViews/context.ts +0 -144
- package/apps/lib/components/DataViews/data-views.tsx +0 -383
- package/apps/lib/components/DataViews/filters/children.tsx +0 -98
- package/apps/lib/components/DataViews/filters/custom.tsx +0 -34
- package/apps/lib/components/DataViews/filters/filters.tsx +0 -157
- package/apps/lib/components/DataViews/filters/index.ts +0 -4
- package/apps/lib/components/DataViews/filters/labelled.tsx +0 -20
- package/apps/lib/components/DataViews/filters/presets.tsx +0 -65
- package/apps/lib/components/DataViews/filters/sync.tsx +0 -35
- package/apps/lib/components/DataViews/filters/values.ts +0 -173
- package/apps/lib/components/DataViews/header.tsx +0 -220
- package/apps/lib/components/DataViews/hooks/index.ts +0 -5
- package/apps/lib/components/DataViews/hooks/useActiveRow.ts +0 -22
- package/apps/lib/components/DataViews/hooks/useControllable.ts +0 -52
- package/apps/lib/components/DataViews/index.ts +0 -84
- package/apps/lib/components/DataViews/panel/columns.tsx +0 -153
- package/apps/lib/components/DataViews/panel/controls.tsx +0 -106
- package/apps/lib/components/DataViews/panel/index.ts +0 -3
- package/apps/lib/components/DataViews/panel/panel.tsx +0 -164
- package/apps/lib/components/DataViews/panel/saved-views.tsx +0 -67
- package/apps/lib/components/DataViews/panel/section.tsx +0 -81
- package/apps/lib/components/DataViews/panel/sort.tsx +0 -42
- package/apps/lib/components/DataViews/panel/tab.tsx +0 -31
- package/apps/lib/components/DataViews/slots.ts +0 -63
- package/apps/lib/components/DataViews/states.tsx +0 -38
- package/apps/lib/components/DataViews/types.ts +0 -510
- package/apps/lib/components/DataViews/views/board-view.tsx +0 -381
- package/apps/lib/components/DataViews/views/card-rows.tsx +0 -36
- package/apps/lib/components/DataViews/views/inbox-view.tsx +0 -260
- package/apps/lib/components/DataViews/views/pane-views.tsx +0 -196
- package/apps/lib/components/DataViews/views/table-view.tsx +0 -493
- package/apps/lib/components/DataViews/views/tree-view.tsx +0 -367
- package/apps/lib/components/DatePicker.tsx +0 -232
- package/apps/lib/components/Dialog.tsx +0 -116
- package/apps/lib/components/Divider.tsx +0 -28
- package/apps/lib/components/Drawer.tsx +0 -420
- package/apps/lib/components/DropdownMenu.tsx +0 -540
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -73
- package/apps/lib/components/FormBuilder/field-kind.ts +0 -28
- package/apps/lib/components/FormBuilder/fields/ChoiceFields.tsx +0 -60
- package/apps/lib/components/FormBuilder/fields/ColorField.tsx +0 -59
- package/apps/lib/components/FormBuilder/fields/CustomField.tsx +0 -11
- package/apps/lib/components/FormBuilder/fields/DateField.tsx +0 -32
- package/apps/lib/components/FormBuilder/fields/FieldArray.tsx +0 -74
- package/apps/lib/components/FormBuilder/fields/FieldShell.tsx +0 -163
- package/apps/lib/components/FormBuilder/fields/FileField.tsx +0 -39
- package/apps/lib/components/FormBuilder/fields/OptionListFields.tsx +0 -132
- package/apps/lib/components/FormBuilder/fields/OtpField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/PhoneField.tsx +0 -109
- package/apps/lib/components/FormBuilder/fields/RichTextEditorField.tsx +0 -31
- package/apps/lib/components/FormBuilder/fields/SelectField.tsx +0 -91
- package/apps/lib/components/FormBuilder/fields/SignatureField.tsx +0 -157
- package/apps/lib/components/FormBuilder/fields/SliderField.tsx +0 -67
- package/apps/lib/components/FormBuilder/fields/SwitchBoxField.tsx +0 -41
- package/apps/lib/components/FormBuilder/fields/TableField.tsx +0 -336
- package/apps/lib/components/FormBuilder/fields/TextField.tsx +0 -213
- package/apps/lib/components/FormBuilder/fields/TreeSelectField.tsx +0 -43
- package/apps/lib/components/FormBuilder/fields/countries.ts +0 -303
- package/apps/lib/components/FormBuilder/fields/index.ts +0 -25
- package/apps/lib/components/FormBuilder/form-builder.tsx +0 -198
- package/apps/lib/components/FormBuilder/index.ts +0 -31
- package/apps/lib/components/FormBuilder/numberFormat.ts +0 -16
- package/apps/lib/components/FormBuilder/submit.tsx +0 -47
- package/apps/lib/components/FormBuilder/types.ts +0 -311
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -128
- package/apps/lib/components/FormRenderer/detail.tsx +0 -207
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -297
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -15
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -339
- package/apps/lib/components/FormRenderer/types.ts +0 -78
- package/apps/lib/components/FormSummary.tsx +0 -282
- package/apps/lib/components/HeaderBar.tsx +0 -117
- package/apps/lib/components/ImageAttachment.tsx +0 -209
- package/apps/lib/components/InnerLabelField.tsx +0 -154
- package/apps/lib/components/Input.tsx +0 -224
- package/apps/lib/components/InputField.tsx +0 -147
- package/apps/lib/components/InputOTP.tsx +0 -84
- package/apps/lib/components/Label.tsx +0 -129
- package/apps/lib/components/LabelField.tsx +0 -76
- package/apps/lib/components/LabeledCheckBox.tsx +0 -51
- package/apps/lib/components/LabeledRadio.tsx +0 -51
- package/apps/lib/components/LinkButton.tsx +0 -94
- package/apps/lib/components/LoginButton.tsx +0 -51
- package/apps/lib/components/PasswordLevel.tsx +0 -58
- package/apps/lib/components/Popover.tsx +0 -312
- package/apps/lib/components/ProfileMenu.tsx +0 -85
- package/apps/lib/components/Radio.tsx +0 -59
- package/apps/lib/components/RadioCard.tsx +0 -50
- package/apps/lib/components/ScrollArea.tsx +0 -54
- package/apps/lib/components/SearchField.tsx +0 -62
- package/apps/lib/components/SearchableSelect.tsx +0 -318
- package/apps/lib/components/SearchableTable.tsx +0 -344
- package/apps/lib/components/SearchableTree.tsx +0 -485
- package/apps/lib/components/SearchableTreeDialog.tsx +0 -502
- package/apps/lib/components/SectionBlock.tsx +0 -147
- package/apps/lib/components/Select.tsx +0 -347
- package/apps/lib/components/SimpleSelect.tsx +0 -225
- package/apps/lib/components/Skeleton.tsx +0 -12
- package/apps/lib/components/SlideDatePicker.tsx +0 -253
- package/apps/lib/components/SpinLoading.tsx +0 -174
- package/apps/lib/components/Stepper.tsx +0 -480
- package/apps/lib/components/Switch.tsx +0 -82
- package/apps/lib/components/TabFormItem.tsx +0 -153
- package/apps/lib/components/TabSwitch.tsx +0 -172
- package/apps/lib/components/Table.tsx +0 -610
- package/apps/lib/components/TextEditor/ChartBlockTool.ts +0 -676
- package/apps/lib/components/TextEditor/RichTextField.tsx +0 -46
- package/apps/lib/components/TextEditor/TableDnDWrapper.ts +0 -462
- package/apps/lib/components/TextEditor/TextEditor.tsx +0 -1164
- package/apps/lib/components/TextEditor/TextEditorToolbar.tsx +0 -429
- package/apps/lib/components/TextEditor/editor-tools/AlignmentTune.ts +0 -70
- package/apps/lib/components/TextEditor/editor-tools/ColorInlineTool.ts +0 -50
- package/apps/lib/components/TextEditor/editor-tools/StrikethroughInlineTool.ts +0 -48
- package/apps/lib/components/TextEditor/editor-tools/inlineFormat.ts +0 -98
- package/apps/lib/components/TextEditor/editorjs.d.ts +0 -60
- package/apps/lib/components/TextEditor/index.ts +0 -7
- package/apps/lib/components/TextEditor/markdownParser.ts +0 -346
- package/apps/lib/components/Textarea.tsx +0 -117
- package/apps/lib/components/Timeline.tsx +0 -263
- package/apps/lib/components/Toast.tsx +0 -87
- package/apps/lib/components/Toggle.tsx +0 -125
- package/apps/lib/components/ToggleButton.tsx +0 -140
- package/apps/lib/components/Tooltip.tsx +0 -116
- package/apps/lib/components/TransparentLabel.tsx +0 -71
- package/apps/lib/components/TreeDropDown.tsx +0 -115
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +0 -380
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +0 -75
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +0 -354
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +0 -60
- package/apps/lib/components/TreeFolder/icons.tsx +0 -60
- package/apps/lib/components/TreeFolder/index.ts +0 -24
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +0 -109
- package/apps/lib/components/TreeFolder/types.ts +0 -77
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +0 -118
- package/apps/lib/hooks/useActiveTreeItem.ts +0 -58
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useInfiniteScroll.ts +0 -108
- package/apps/lib/hooks/useIsMobile.ts +0 -21
- package/apps/lib/hooks/useResize.ts +0 -67
- package/apps/lib/hooks/useTagSelection.ts +0 -214
- package/apps/lib/layouts/CNLayout.tsx +0 -372
- package/apps/lib/layouts/DataViewCard.tsx +0 -62
- package/apps/lib/layouts/FieldSection.tsx +0 -91
- package/apps/lib/layouts/TreeSubLayout.tsx +0 -173
- package/apps/lib/providers/ThemeProvider.tsx +0 -84
- package/apps/lib/registry.json +0 -1201
- package/apps/lib/tsconfig.json +0 -9
- package/apps/lib/tsconfig.tsbuildinfo +0 -1
- package/apps/lib/utils/cn.ts +0 -6
- package/apps/lib/utils/color.ts +0 -175
- package/apps/lib/utils/dataViews/path.ts +0 -67
- package/apps/lib/utils/dataViews/query.ts +0 -73
- package/apps/lib/utils/dataViews/types.ts +0 -187
- package/apps/lib/utils/dateFormat.ts +0 -108
- package/apps/lib/utils/resize.ts +0 -31
- package/apps/lib/utils/types.ts +0 -16
- package/docs/BLOCKS.md +0 -129
- package/docs/CHANGELOG-1.1.16.md +0 -108
- package/docs/Cover.png +0 -0
- package/docs/README.md +0 -215
- package/docs/components/action-button.md +0 -638
- package/docs/components/actions-group.md +0 -708
- package/docs/components/alert-dialog.md +0 -920
- package/docs/components/avatar.md +0 -709
- package/docs/components/badge-field.md +0 -712
- package/docs/components/badge.md +0 -301
- package/docs/components/breadcrumb.md +0 -930
- package/docs/components/button-group.md +0 -650
- package/docs/components/button.md +0 -639
- package/docs/components/calendar.md +0 -555
- package/docs/components/card.md +0 -622
- package/docs/components/chart-block-tool.md +0 -129
- package/docs/components/checkbox.md +0 -699
- package/docs/components/cn-layout.md +0 -854
- package/docs/components/color-picker.md +0 -101
- package/docs/components/conclusion-header.md +0 -80
- package/docs/components/context-menu.md +0 -483
- package/docs/components/count-badge.md +0 -560
- package/docs/components/data-table.md +0 -854
- package/docs/components/data-views/backend-response.md +0 -324
- package/docs/components/data-views/examples/a11y-rtl.md +0 -250
- package/docs/components/data-views/examples/api-orders-route.md +0 -130
- package/docs/components/data-views/examples/fields.md +0 -362
- package/docs/components/data-views/examples/filters.md +0 -307
- package/docs/components/data-views/examples/inbox-routing.md +0 -218
- package/docs/components/data-views/examples/index.md +0 -29
- package/docs/components/data-views/examples/overview.md +0 -244
- package/docs/components/data-views/examples/panel.md +0 -212
- package/docs/components/data-views/examples/scale.md +0 -231
- package/docs/components/data-views/examples/server-side.md +0 -210
- package/docs/components/data-views/examples/state.md +0 -250
- package/docs/components/data-views/examples/tree-custom.md +0 -388
- package/docs/components/data-views/examples/view-registry.md +0 -313
- package/docs/components/data-views/examples/views.md +0 -534
- package/docs/components/data-views/guide.md +0 -405
- package/docs/components/data-views/index.md +0 -1495
- package/docs/components/data-views/migration.md +0 -79
- package/docs/components/date-picker.md +0 -857
- package/docs/components/dialog.md +0 -929
- package/docs/components/divider.md +0 -766
- package/docs/components/drawer.md +0 -654
- package/docs/components/dropdown-menu.md +0 -668
- package/docs/components/field-hint.md +0 -898
- package/docs/components/field-section.md +0 -781
- package/docs/components/form-builder.md +0 -276
- package/docs/components/form-renderer.md +0 -326
- package/docs/components/form-summary.md +0 -138
- package/docs/components/form.md +0 -785
- package/docs/components/header-bar.md +0 -188
- package/docs/components/image-attachment.md +0 -906
- package/docs/components/inner-label-field.md +0 -819
- package/docs/components/input-field.md +0 -623
- package/docs/components/input-otp.md +0 -756
- package/docs/components/input.md +0 -634
- package/docs/components/label-field.md +0 -770
- package/docs/components/label.md +0 -761
- package/docs/components/labeled-check-box.md +0 -642
- package/docs/components/labeled-radio.md +0 -796
- package/docs/components/link-button.md +0 -685
- package/docs/components/login-button.md +0 -872
- package/docs/components/password-level.md +0 -803
- package/docs/components/popover.md +0 -649
- package/docs/components/profile-menu.md +0 -656
- package/docs/components/radio-card.md +0 -801
- package/docs/components/radio.md +0 -735
- package/docs/components/scroll-area.md +0 -691
- package/docs/components/search-field.md +0 -702
- package/docs/components/searchable-select.md +0 -368
- package/docs/components/searchable-table.md +0 -438
- package/docs/components/searchable-tree-dialog.md +0 -190
- package/docs/components/searchable-tree.md +0 -200
- package/docs/components/section-block.md +0 -477
- package/docs/components/select.md +0 -709
- package/docs/components/simple-select.md +0 -741
- package/docs/components/skeleton.md +0 -706
- package/docs/components/slide-date-picker.md +0 -837
- package/docs/components/spin-loading.md +0 -696
- package/docs/components/stepper.md +0 -316
- package/docs/components/switch.md +0 -770
- package/docs/components/tab-form-item.md +0 -773
- package/docs/components/tab-switch.md +0 -170
- package/docs/components/table-dnd-wrapper.md +0 -107
- package/docs/components/table.md +0 -1088
- package/docs/components/text-editor.md +0 -735
- package/docs/components/textarea.md +0 -681
- package/docs/components/timeline.md +0 -254
- package/docs/components/toast.md +0 -773
- package/docs/components/toggle-button.md +0 -643
- package/docs/components/toggle.md +0 -882
- package/docs/components/tooltip.md +0 -513
- package/docs/components/transparent-label.md +0 -721
- package/docs/components/tree-drop-down.md +0 -740
- package/docs/components/tree-folder.md +0 -110
- package/docs/components/tree-sub-layout.md +0 -707
- package/docs/explanation/architecture.md +0 -54
- package/docs/explanation/design-system.md +0 -52
- package/docs/how-to/form-and-list-recipes.md +0 -386
- package/docs/how-to/forms-with-form-builder.md +0 -472
- package/docs/how-to/guides.md +0 -1027
- package/docs/migration/changelog.md +0 -54
- package/docs/migration/form-builder-2.5.2.md +0 -113
- package/docs/reference/cli.md +0 -112
- package/docs/reference/components.md +0 -572
- package/docs/reference/hooks.md +0 -1500
- package/docs/reference/providers.md +0 -866
- package/docs/reference/tailwind-plugins.md +0 -942
- package/docs/reference/theme.md +0 -85
- package/docs/reference/types.md +0 -1016
- package/docs/reference/utilities.md +0 -704
- package/docs/tutorials/building-first-form.md +0 -846
- package/docs/tutorials/component-composition.md +0 -882
- package/docs/tutorials/getting-started.md +0 -302
- package/docs/tutorials/theming-basics.md +0 -785
|
@@ -1,681 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: Textarea
|
|
3
|
-
version: 2.4.5
|
|
4
|
-
status: stable
|
|
5
|
-
category: components/forms
|
|
6
|
-
tags: [form, textarea, multiline, input, field, accessible, auto-resize]
|
|
7
|
-
last-reviewed: 2024-11-05
|
|
8
|
-
bundle-size: 2.2kb
|
|
9
|
-
dependencies:
|
|
10
|
-
- "class-variance-authority": "^0.7.0"
|
|
11
|
-
- "@/components/Label": "internal"
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# Textarea
|
|
15
|
-
|
|
16
|
-
> A versatile multi-line text input component with auto-resizing capability, integrated label support, and flexible layout options. Perfect for comments, descriptions, and long-form text input.
|
|
17
|
-
|
|
18
|
-
## Installation
|
|
19
|
-
|
|
20
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
21
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
npx torch-glare@latest init
|
|
25
|
-
npx torch-glare@latest add Textarea
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
`add` also copies any components, hooks, and utilities that `Textarea` depends on.
|
|
29
|
-
|
|
30
|
-
## Import
|
|
31
|
-
|
|
32
|
-
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
33
|
-
|
|
34
|
-
```tsx
|
|
35
|
-
import { Textarea } from "@/components/Textarea";
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## Quick Examples
|
|
39
|
-
|
|
40
|
-
### Basic Usage
|
|
41
|
-
|
|
42
|
-
```typescript
|
|
43
|
-
import { Textarea } from '@/components/Textarea'
|
|
44
|
-
|
|
45
|
-
function Example() {
|
|
46
|
-
const [value, setValue] = useState('')
|
|
47
|
-
|
|
48
|
-
return (
|
|
49
|
-
<Textarea
|
|
50
|
-
value={value}
|
|
51
|
-
onChange={(e) => setValue(e.target.value)}
|
|
52
|
-
placeholder="Enter your message..."
|
|
53
|
-
/>
|
|
54
|
-
)
|
|
55
|
-
}
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### With Label
|
|
59
|
-
|
|
60
|
-
```typescript
|
|
61
|
-
function LabeledTextarea() {
|
|
62
|
-
return (
|
|
63
|
-
<Textarea
|
|
64
|
-
label="Description"
|
|
65
|
-
placeholder="Describe your issue..."
|
|
66
|
-
rows={4}
|
|
67
|
-
/>
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Required Field
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
function RequiredTextarea() {
|
|
76
|
-
return (
|
|
77
|
-
<Textarea
|
|
78
|
-
label="Comments"
|
|
79
|
-
requiredLabel="*"
|
|
80
|
-
secondaryLabel="(min 50 characters)"
|
|
81
|
-
placeholder="Please provide detailed feedback..."
|
|
82
|
-
minLength={50}
|
|
83
|
-
required
|
|
84
|
-
/>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### Error State
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
function ErrorTextarea() {
|
|
93
|
-
const [value, setValue] = useState('')
|
|
94
|
-
const hasError = value.length > 0 && value.length < 10
|
|
95
|
-
|
|
96
|
-
return (
|
|
97
|
-
<Textarea
|
|
98
|
-
value={value}
|
|
99
|
-
onChange={(e) => setValue(e.target.value)}
|
|
100
|
-
state={hasError ? 'negative' : undefined}
|
|
101
|
-
placeholder="Minimum 10 characters..."
|
|
102
|
-
/>
|
|
103
|
-
)
|
|
104
|
-
}
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Different Layouts
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
110
|
-
// Horizontal layout (label beside textarea)
|
|
111
|
-
<Textarea
|
|
112
|
-
label="Note"
|
|
113
|
-
direction="row"
|
|
114
|
-
placeholder="Add a note..."
|
|
115
|
-
/>
|
|
116
|
-
|
|
117
|
-
// Vertical layout (label above textarea)
|
|
118
|
-
<Textarea
|
|
119
|
-
label="Description"
|
|
120
|
-
direction="column"
|
|
121
|
-
placeholder="Enter description..."
|
|
122
|
-
/>
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
### Auto-Resizing
|
|
126
|
-
|
|
127
|
-
```typescript
|
|
128
|
-
function AutoResizeTextarea() {
|
|
129
|
-
// The textarea automatically resizes based on content
|
|
130
|
-
// due to field-sizing-content CSS property
|
|
131
|
-
return (
|
|
132
|
-
<Textarea
|
|
133
|
-
placeholder="This textarea grows as you type..."
|
|
134
|
-
className="min-h-[100px] max-h-[400px]"
|
|
135
|
-
/>
|
|
136
|
-
)
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### Themed Textarea
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
function ThemedTextarea() {
|
|
144
|
-
return (
|
|
145
|
-
<>
|
|
146
|
-
<Textarea
|
|
147
|
-
theme="light"
|
|
148
|
-
label="Light Theme"
|
|
149
|
-
placeholder="Light theme textarea..."
|
|
150
|
-
/>
|
|
151
|
-
|
|
152
|
-
<Textarea
|
|
153
|
-
theme="dark"
|
|
154
|
-
label="Dark Theme"
|
|
155
|
-
placeholder="Dark theme textarea..."
|
|
156
|
-
/>
|
|
157
|
-
</>
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
## API Reference
|
|
163
|
-
|
|
164
|
-
### Textarea Props
|
|
165
|
-
|
|
166
|
-
| Prop | Type | Default | Description |
|
|
167
|
-
|------|------|---------|-------------|
|
|
168
|
-
| `label` | `string` | - | Label text for the textarea |
|
|
169
|
-
| `requiredLabel` | `string` | - | Text for required field indicator |
|
|
170
|
-
| `secondaryLabel` | `string` | - | Additional label text/hint |
|
|
171
|
-
| `direction` | `'row' \| 'column'` | `'row'` | Layout direction for label |
|
|
172
|
-
| `state` | `'negative'` | - | Visual state for errors |
|
|
173
|
-
| `theme` | `'dark' \| 'light' \| 'default'` | - | Theme variant |
|
|
174
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
175
|
-
| `placeholder` | `string` | - | Placeholder text |
|
|
176
|
-
| `value` | `string` | - | Textarea value |
|
|
177
|
-
| `onChange` | `(e: ChangeEvent) => void` | - | Change event handler |
|
|
178
|
-
| `rows` | `number` | - | Initial number of rows |
|
|
179
|
-
| `cols` | `number` | - | Number of columns |
|
|
180
|
-
| `maxLength` | `number` | - | Maximum character length |
|
|
181
|
-
| `minLength` | `number` | - | Minimum character length |
|
|
182
|
-
| `disabled` | `boolean` | `false` | Disables the textarea |
|
|
183
|
-
| `required` | `boolean` | `false` | Makes field required |
|
|
184
|
-
| `readOnly` | `boolean` | `false` | Makes field read-only |
|
|
185
|
-
|
|
186
|
-
Plus all standard HTML textarea attributes.
|
|
187
|
-
|
|
188
|
-
### TypeScript
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
interface TextareaProps extends TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
192
|
-
label?: string
|
|
193
|
-
requiredLabel?: string
|
|
194
|
-
secondaryLabel?: string
|
|
195
|
-
direction?: 'row' | 'column'
|
|
196
|
-
state?: 'negative'
|
|
197
|
-
theme?: 'dark' | 'light' | 'default'
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
export const Textarea: React.ForwardRefExoticComponent<TextareaProps>
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
## Common Patterns
|
|
204
|
-
|
|
205
|
-
### Character Counter
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
function TextareaWithCounter() {
|
|
209
|
-
const [value, setValue] = useState('')
|
|
210
|
-
const maxLength = 500
|
|
211
|
-
|
|
212
|
-
return (
|
|
213
|
-
<div className="space-y-2">
|
|
214
|
-
<Textarea
|
|
215
|
-
value={value}
|
|
216
|
-
onChange={(e) => setValue(e.target.value)}
|
|
217
|
-
maxLength={maxLength}
|
|
218
|
-
label="Bio"
|
|
219
|
-
secondaryLabel={`${value.length}/${maxLength} characters`}
|
|
220
|
-
placeholder="Tell us about yourself..."
|
|
221
|
-
state={value.length > maxLength * 0.9 ? 'negative' : undefined}
|
|
222
|
-
/>
|
|
223
|
-
</div>
|
|
224
|
-
)
|
|
225
|
-
}
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
### Form Integration
|
|
229
|
-
|
|
230
|
-
```typescript
|
|
231
|
-
function ContactForm() {
|
|
232
|
-
const [formData, setFormData] = useState({
|
|
233
|
-
name: '',
|
|
234
|
-
email: '',
|
|
235
|
-
message: ''
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
const handleSubmit = (e: FormEvent) => {
|
|
239
|
-
e.preventDefault()
|
|
240
|
-
// Handle submission
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
return (
|
|
244
|
-
<form onSubmit={handleSubmit} className="space-y-4">
|
|
245
|
-
<Input
|
|
246
|
-
label="Name"
|
|
247
|
-
value={formData.name}
|
|
248
|
-
onChange={(e) => setFormData({...formData, name: e.target.value})}
|
|
249
|
-
/>
|
|
250
|
-
|
|
251
|
-
<Input
|
|
252
|
-
label="Email"
|
|
253
|
-
type="email"
|
|
254
|
-
value={formData.email}
|
|
255
|
-
onChange={(e) => setFormData({...formData, email: e.target.value})}
|
|
256
|
-
/>
|
|
257
|
-
|
|
258
|
-
<Textarea
|
|
259
|
-
label="Message"
|
|
260
|
-
requiredLabel="*"
|
|
261
|
-
value={formData.message}
|
|
262
|
-
onChange={(e) => setFormData({...formData, message: e.target.value})}
|
|
263
|
-
placeholder="Your message..."
|
|
264
|
-
rows={5}
|
|
265
|
-
required
|
|
266
|
-
/>
|
|
267
|
-
|
|
268
|
-
<Button type="submit">Send Message</Button>
|
|
269
|
-
</form>
|
|
270
|
-
)
|
|
271
|
-
}
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Markdown Editor
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
function MarkdownEditor() {
|
|
278
|
-
const [markdown, setMarkdown] = useState('')
|
|
279
|
-
const [preview, setPreview] = useState(false)
|
|
280
|
-
|
|
281
|
-
return (
|
|
282
|
-
<div className="space-y-4">
|
|
283
|
-
<div className="flex justify-between items-center">
|
|
284
|
-
<h3>Markdown Editor</h3>
|
|
285
|
-
<button onClick={() => setPreview(!preview)}>
|
|
286
|
-
{preview ? 'Edit' : 'Preview'}
|
|
287
|
-
</button>
|
|
288
|
-
</div>
|
|
289
|
-
|
|
290
|
-
{preview ? (
|
|
291
|
-
<div className="prose">
|
|
292
|
-
{/* Render markdown preview */}
|
|
293
|
-
<div dangerouslySetInnerHTML={{__html: markdown}} />
|
|
294
|
-
</div>
|
|
295
|
-
) : (
|
|
296
|
-
<Textarea
|
|
297
|
-
value={markdown}
|
|
298
|
-
onChange={(e) => setMarkdown(e.target.value)}
|
|
299
|
-
placeholder="Write in markdown..."
|
|
300
|
-
className="font-mono"
|
|
301
|
-
rows={10}
|
|
302
|
-
/>
|
|
303
|
-
)}
|
|
304
|
-
</div>
|
|
305
|
-
)
|
|
306
|
-
}
|
|
307
|
-
```
|
|
308
|
-
|
|
309
|
-
### Auto-Save Textarea
|
|
310
|
-
|
|
311
|
-
```typescript
|
|
312
|
-
function AutoSaveTextarea() {
|
|
313
|
-
const [content, setContent] = useState('')
|
|
314
|
-
const [saving, setSaving] = useState(false)
|
|
315
|
-
const [lastSaved, setLastSaved] = useState<Date>()
|
|
316
|
-
|
|
317
|
-
// Auto-save after 2 seconds of inactivity
|
|
318
|
-
useEffect(() => {
|
|
319
|
-
const timer = setTimeout(() => {
|
|
320
|
-
if (content) {
|
|
321
|
-
setSaving(true)
|
|
322
|
-
// Simulate save
|
|
323
|
-
setTimeout(() => {
|
|
324
|
-
setSaving(false)
|
|
325
|
-
setLastSaved(new Date())
|
|
326
|
-
}, 500)
|
|
327
|
-
}
|
|
328
|
-
}, 2000)
|
|
329
|
-
|
|
330
|
-
return () => clearTimeout(timer)
|
|
331
|
-
}, [content])
|
|
332
|
-
|
|
333
|
-
return (
|
|
334
|
-
<div>
|
|
335
|
-
<Textarea
|
|
336
|
-
label="Notes"
|
|
337
|
-
secondaryLabel={
|
|
338
|
-
saving ? 'Saving...' :
|
|
339
|
-
lastSaved ? `Last saved: ${lastSaved.toLocaleTimeString()}` :
|
|
340
|
-
'Auto-saves as you type'
|
|
341
|
-
}
|
|
342
|
-
value={content}
|
|
343
|
-
onChange={(e) => setContent(e.target.value)}
|
|
344
|
-
placeholder="Start typing..."
|
|
345
|
-
/>
|
|
346
|
-
</div>
|
|
347
|
-
)
|
|
348
|
-
}
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
## Testing
|
|
352
|
-
|
|
353
|
-
### Unit Test Example
|
|
354
|
-
|
|
355
|
-
```typescript
|
|
356
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
357
|
-
import { Textarea } from '@/components/Textarea'
|
|
358
|
-
|
|
359
|
-
describe('Textarea', () => {
|
|
360
|
-
it('handles user input', () => {
|
|
361
|
-
const handleChange = jest.fn()
|
|
362
|
-
render(
|
|
363
|
-
<Textarea
|
|
364
|
-
onChange={handleChange}
|
|
365
|
-
placeholder="Type here..."
|
|
366
|
-
/>
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
const textarea = screen.getByPlaceholderText('Type here...')
|
|
370
|
-
fireEvent.change(textarea, { target: { value: 'Hello World' } })
|
|
371
|
-
|
|
372
|
-
expect(handleChange).toHaveBeenCalled()
|
|
373
|
-
expect(textarea).toHaveValue('Hello World')
|
|
374
|
-
})
|
|
375
|
-
|
|
376
|
-
it('shows error state', () => {
|
|
377
|
-
const { container } = render(
|
|
378
|
-
<Textarea
|
|
379
|
-
state="negative"
|
|
380
|
-
placeholder="Error textarea"
|
|
381
|
-
/>
|
|
382
|
-
)
|
|
383
|
-
|
|
384
|
-
const textarea = container.querySelector('textarea')
|
|
385
|
-
expect(textarea).toHaveClass('border-border-presentation-state-negative')
|
|
386
|
-
})
|
|
387
|
-
|
|
388
|
-
it('renders with label', () => {
|
|
389
|
-
render(
|
|
390
|
-
<Textarea
|
|
391
|
-
label="Comments"
|
|
392
|
-
requiredLabel="*"
|
|
393
|
-
secondaryLabel="Optional"
|
|
394
|
-
/>
|
|
395
|
-
)
|
|
396
|
-
|
|
397
|
-
expect(screen.getByText('Comments')).toBeInTheDocument()
|
|
398
|
-
expect(screen.getByText('*')).toBeInTheDocument()
|
|
399
|
-
expect(screen.getByText('Optional')).toBeInTheDocument()
|
|
400
|
-
})
|
|
401
|
-
|
|
402
|
-
it('respects character limits', () => {
|
|
403
|
-
render(
|
|
404
|
-
<Textarea
|
|
405
|
-
maxLength={10}
|
|
406
|
-
placeholder="Max 10 chars"
|
|
407
|
-
/>
|
|
408
|
-
)
|
|
409
|
-
|
|
410
|
-
const textarea = screen.getByPlaceholderText('Max 10 chars')
|
|
411
|
-
expect(textarea).toHaveAttribute('maxLength', '10')
|
|
412
|
-
})
|
|
413
|
-
})
|
|
414
|
-
```
|
|
415
|
-
|
|
416
|
-
### Accessibility Test
|
|
417
|
-
|
|
418
|
-
```typescript
|
|
419
|
-
import { axe } from '@axe-core/react'
|
|
420
|
-
|
|
421
|
-
test('Textarea meets WCAG standards', async () => {
|
|
422
|
-
const { container } = render(
|
|
423
|
-
<Textarea
|
|
424
|
-
label="Message"
|
|
425
|
-
requiredLabel="*"
|
|
426
|
-
placeholder="Enter message..."
|
|
427
|
-
required
|
|
428
|
-
/>
|
|
429
|
-
)
|
|
430
|
-
|
|
431
|
-
const results = await axe(container)
|
|
432
|
-
expect(results).toHaveNoViolations()
|
|
433
|
-
})
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
## Known Limitations & Frontend Patterns
|
|
437
|
-
|
|
438
|
-
### `Textarea` auto-sizes to its own content and cannot be made full-width via `className`
|
|
439
|
-
|
|
440
|
-
The shipped component has these hardcoded base classes:
|
|
441
|
-
|
|
442
|
-
```
|
|
443
|
-
field-sizing-content w-full min-w-[100px] max-w-[100%]
|
|
444
|
-
```
|
|
445
|
-
|
|
446
|
-
Two consequences:
|
|
447
|
-
|
|
448
|
-
1. **`field-sizing-content`** sizes the textarea to its content. An empty textarea collapses to ~100 × 36 px regardless of explicit `width`/`min-height` until the user types enough to expand it.
|
|
449
|
-
2. **`className` is forwarded to the wrapping `Label`**, not the inner `<textarea>` element — so passing `className="w-full min-h-24"` does not override the inner sizing.
|
|
450
|
-
|
|
451
|
-
Real-world impact: a description textarea inside a full-width card renders as a tiny ~100 × 40 px box even with `className="w-full min-h-24"`.
|
|
452
|
-
|
|
453
|
-
**Workaround used in production — drop the wrapper and use a plain `<textarea>` with TORCH design tokens:**
|
|
454
|
-
|
|
455
|
-
```tsx
|
|
456
|
-
<textarea
|
|
457
|
-
{...register("notes")}
|
|
458
|
-
placeholder="Optional notes..."
|
|
459
|
-
rows={4}
|
|
460
|
-
className={[
|
|
461
|
-
"w-full min-h-24 px-3 py-2 rounded-lg",
|
|
462
|
-
"border border-border-presentation-global-primary",
|
|
463
|
-
"bg-background-presentation-form-field-primary",
|
|
464
|
-
"text-content-presentation-action-light-primary",
|
|
465
|
-
"typography-body-medium-regular",
|
|
466
|
-
"outline-none resize-y",
|
|
467
|
-
"hover:border-border-presentation-action-hover",
|
|
468
|
-
"focus:border-border-presentation-state-focus",
|
|
469
|
-
"transition-colors",
|
|
470
|
-
].join(" ")}
|
|
471
|
-
/>
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
This gives you the TORCH look-and-feel without `field-sizing-content`. Switch back to the wrapped `Textarea` once the underlying component drops the auto-sizing default and forwards `className` correctly.
|
|
475
|
-
|
|
476
|
-
## Accessibility
|
|
477
|
-
|
|
478
|
-
### Keyboard Support
|
|
479
|
-
|
|
480
|
-
- **Tab**: Move focus to/from textarea
|
|
481
|
-
- **Arrow Keys**: Navigate text cursor
|
|
482
|
-
- **Home/End**: Jump to start/end of line
|
|
483
|
-
- **Ctrl/Cmd + Home/End**: Jump to start/end of text
|
|
484
|
-
- **Page Up/Down**: Scroll through content
|
|
485
|
-
|
|
486
|
-
### ARIA Attributes
|
|
487
|
-
|
|
488
|
-
```typescript
|
|
489
|
-
// Error state
|
|
490
|
-
<Textarea
|
|
491
|
-
aria-invalid={hasError}
|
|
492
|
-
aria-describedby="error-message"
|
|
493
|
-
state={hasError ? 'negative' : undefined}
|
|
494
|
-
/>
|
|
495
|
-
|
|
496
|
-
// Required field
|
|
497
|
-
<Textarea
|
|
498
|
-
aria-required="true"
|
|
499
|
-
required
|
|
500
|
-
label="Required Field"
|
|
501
|
-
requiredLabel="*"
|
|
502
|
-
/>
|
|
503
|
-
|
|
504
|
-
// With description
|
|
505
|
-
<Textarea
|
|
506
|
-
aria-describedby="help-text"
|
|
507
|
-
label="Description"
|
|
508
|
-
/>
|
|
509
|
-
<span id="help-text">Provide detailed information</span>
|
|
510
|
-
```
|
|
511
|
-
|
|
512
|
-
### Screen Reader Support
|
|
513
|
-
|
|
514
|
-
- Label association is automatic through Label component
|
|
515
|
-
- Announces required state
|
|
516
|
-
- Reads placeholder text
|
|
517
|
-
- Announces character limits
|
|
518
|
-
|
|
519
|
-
### Focus Management
|
|
520
|
-
|
|
521
|
-
- Visible focus ring on keyboard navigation
|
|
522
|
-
- Maintains focus during value changes
|
|
523
|
-
- Auto-scrolls to cursor position
|
|
524
|
-
|
|
525
|
-
## Styling
|
|
526
|
-
|
|
527
|
-
### Custom Styles
|
|
528
|
-
|
|
529
|
-
```typescript
|
|
530
|
-
<Textarea
|
|
531
|
-
className="custom-textarea font-mono text-sm"
|
|
532
|
-
style={{ minHeight: '200px' }}
|
|
533
|
-
/>
|
|
534
|
-
```
|
|
535
|
-
|
|
536
|
-
### CSS Variables
|
|
537
|
-
|
|
538
|
-
```css
|
|
539
|
-
/* Custom theme variables */
|
|
540
|
-
[data-theme="custom"] {
|
|
541
|
-
--textarea-bg: #your-background;
|
|
542
|
-
--textarea-border: #your-border;
|
|
543
|
-
--textarea-text: #your-text;
|
|
544
|
-
--textarea-placeholder: #your-placeholder;
|
|
545
|
-
--textarea-focus: #your-focus-color;
|
|
546
|
-
--textarea-error: #your-error-color;
|
|
547
|
-
}
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
### State Styling
|
|
551
|
-
|
|
552
|
-
```css
|
|
553
|
-
/* Negative state */
|
|
554
|
-
.textarea-negative {
|
|
555
|
-
border-color: var(--color-negative);
|
|
556
|
-
caret-color: var(--color-negative);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
/* Disabled state */
|
|
560
|
-
.textarea:disabled {
|
|
561
|
-
background: var(--color-disabled);
|
|
562
|
-
cursor: not-allowed;
|
|
563
|
-
}
|
|
564
|
-
```
|
|
565
|
-
|
|
566
|
-
## Performance
|
|
567
|
-
|
|
568
|
-
| Metric | Value |
|
|
569
|
-
|--------|-------|
|
|
570
|
-
| Bundle size (gzip) | 2.2kb |
|
|
571
|
-
| First render | <8ms |
|
|
572
|
-
| Re-render | <3ms |
|
|
573
|
-
| Auto-resize | <2ms |
|
|
574
|
-
| Tree-shakeable | ✅ |
|
|
575
|
-
|
|
576
|
-
### Optimization Tips
|
|
577
|
-
|
|
578
|
-
1. Use `React.memo()` for parent components with frequent re-renders
|
|
579
|
-
2. Debounce onChange for expensive operations
|
|
580
|
-
3. Use `useCallback` for event handlers
|
|
581
|
-
4. Consider virtual scrolling for very long content
|
|
582
|
-
5. Lazy load preview/formatting features
|
|
583
|
-
|
|
584
|
-
## Migration
|
|
585
|
-
|
|
586
|
-
### From v1.0.x
|
|
587
|
-
|
|
588
|
-
```diff
|
|
589
|
-
// Import path changed
|
|
590
|
-
- import Textarea from 'torch-glare/Textarea'
|
|
591
|
-
+ import { Textarea } from '@/components/Textarea'
|
|
592
|
-
|
|
593
|
-
// Label integration
|
|
594
|
-
- <div>
|
|
595
|
-
- <label>Comments</label>
|
|
596
|
-
- <Textarea />
|
|
597
|
-
- </div>
|
|
598
|
-
+ <Textarea
|
|
599
|
-
+ label="Comments"
|
|
600
|
-
+ />
|
|
601
|
-
```
|
|
602
|
-
|
|
603
|
-
## Troubleshooting
|
|
604
|
-
|
|
605
|
-
### Auto-resize not working
|
|
606
|
-
|
|
607
|
-
**Solution:** Check CSS field-sizing support
|
|
608
|
-
|
|
609
|
-
```css
|
|
610
|
-
/* Fallback for browsers without field-sizing support */
|
|
611
|
-
.textarea {
|
|
612
|
-
field-sizing: content;
|
|
613
|
-
/* Fallback */
|
|
614
|
-
min-height: 100px;
|
|
615
|
-
resize: vertical;
|
|
616
|
-
}
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
### Label not associated
|
|
620
|
-
|
|
621
|
-
**Solution:** Label is automatically associated via Label component
|
|
622
|
-
|
|
623
|
-
```typescript
|
|
624
|
-
// ✅ Correct - automatic association
|
|
625
|
-
<Textarea label="Description" />
|
|
626
|
-
|
|
627
|
-
// Alternative manual association
|
|
628
|
-
<label htmlFor="desc">Description</label>
|
|
629
|
-
<Textarea id="desc" />
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
### Character limit not enforced
|
|
633
|
-
|
|
634
|
-
**Solution:** HTML maxLength is a soft limit, add validation
|
|
635
|
-
|
|
636
|
-
```typescript
|
|
637
|
-
const [value, setValue] = useState('')
|
|
638
|
-
const maxLength = 500
|
|
639
|
-
|
|
640
|
-
<Textarea
|
|
641
|
-
value={value}
|
|
642
|
-
onChange={(e) => {
|
|
643
|
-
if (e.target.value.length <= maxLength) {
|
|
644
|
-
setValue(e.target.value)
|
|
645
|
-
}
|
|
646
|
-
}}
|
|
647
|
-
maxLength={maxLength}
|
|
648
|
-
/>
|
|
649
|
-
```
|
|
650
|
-
|
|
651
|
-
## Related Components
|
|
652
|
-
|
|
653
|
-
- [Input](/docs/components/input.md) - Single-line text input
|
|
654
|
-
- [InputField](/docs/components/input-field.md) - Enhanced input with extras
|
|
655
|
-
- [Label](/docs/components/label.md) - Form field labeling
|
|
656
|
-
- [Form](/docs/components/form.md) - Form wrapper with validation
|
|
657
|
-
|
|
658
|
-
## Browser Support
|
|
659
|
-
|
|
660
|
-
- Chrome 90+ ✅
|
|
661
|
-
- Firefox 88+ ✅
|
|
662
|
-
- Safari 14+ ✅
|
|
663
|
-
- Edge 90+ ✅
|
|
664
|
-
- Mobile browsers ✅
|
|
665
|
-
|
|
666
|
-
Note: `field-sizing: content` has limited support. Component includes fallbacks.
|
|
667
|
-
|
|
668
|
-
## Changelog
|
|
669
|
-
|
|
670
|
-
### v1.1.15
|
|
671
|
-
- Added auto-resize with field-sizing
|
|
672
|
-
- Improved label integration
|
|
673
|
-
- Enhanced TypeScript types
|
|
674
|
-
|
|
675
|
-
### v1.1.14
|
|
676
|
-
- Added state variants
|
|
677
|
-
- Fixed focus styles
|
|
678
|
-
- Performance optimizations
|
|
679
|
-
|
|
680
|
-
### v1.1.0
|
|
681
|
-
- Initial stable release
|