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,691 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: ScrollArea
|
|
3
|
-
description: Custom styled scrollable container with controlled scrollbar appearance built on Radix UI.
|
|
4
|
-
component: true
|
|
5
|
-
group: Layout & Containers
|
|
6
|
-
keywords: [scroll, scrollbar, overflow, container, viewport, radix]
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# ScrollArea
|
|
10
|
-
|
|
11
|
-
A customizable scrollable container component with styled scrollbars. Built on Radix UI's ScrollArea primitive for consistent cross-browser scrolling behavior.
|
|
12
|
-
|
|
13
|
-
## Installation
|
|
14
|
-
|
|
15
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
16
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
npx torch-glare@latest init
|
|
20
|
-
npx torch-glare@latest add ScrollArea
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
`add` also copies any components, hooks, and utilities that `ScrollArea` depends on.
|
|
24
|
-
|
|
25
|
-
## Imports
|
|
26
|
-
|
|
27
|
-
```typescript
|
|
28
|
-
import { ScrollArea, ScrollBar } from '@/components/ScrollArea'
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## Basic Usage
|
|
32
|
-
|
|
33
|
-
```tsx
|
|
34
|
-
import { ScrollArea } from '@/components/ScrollArea'
|
|
35
|
-
|
|
36
|
-
export function BasicScrollArea() {
|
|
37
|
-
return (
|
|
38
|
-
<ScrollArea className="h-[300px] w-full rounded-lg p-4">
|
|
39
|
-
<div className="space-y-4">
|
|
40
|
-
{Array.from({ length: 20 }).map((_, i) => (
|
|
41
|
-
<div key={i} className="p-4 border rounded">
|
|
42
|
-
Item {i + 1}
|
|
43
|
-
</div>
|
|
44
|
-
))}
|
|
45
|
-
</div>
|
|
46
|
-
</ScrollArea>
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## Examples
|
|
52
|
-
|
|
53
|
-
### Vertical Scrolling
|
|
54
|
-
|
|
55
|
-
Standard vertical scroll container.
|
|
56
|
-
|
|
57
|
-
```tsx
|
|
58
|
-
export function VerticalScroll() {
|
|
59
|
-
const items = Array.from({ length: 50 }, (_, i) => ({
|
|
60
|
-
id: i + 1,
|
|
61
|
-
title: `Article ${i + 1}`,
|
|
62
|
-
content: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
|
|
63
|
-
}))
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<ScrollArea className="h-[500px] w-full rounded-lg border">
|
|
67
|
-
<div className="p-6 space-y-4">
|
|
68
|
-
{items.map(item => (
|
|
69
|
-
<article key={item.id} className="pb-4 border-b">
|
|
70
|
-
<h3 className="font-semibold text-lg mb-2">{item.title}</h3>
|
|
71
|
-
<p className="text-content-presentation-global-secondary">
|
|
72
|
-
{item.content}
|
|
73
|
-
</p>
|
|
74
|
-
</article>
|
|
75
|
-
))}
|
|
76
|
-
</div>
|
|
77
|
-
</ScrollArea>
|
|
78
|
-
)
|
|
79
|
-
}
|
|
80
|
-
```
|
|
81
|
-
|
|
82
|
-
### Horizontal Scrolling
|
|
83
|
-
|
|
84
|
-
Horizontal scroll for wide content.
|
|
85
|
-
|
|
86
|
-
```tsx
|
|
87
|
-
export function HorizontalScroll() {
|
|
88
|
-
return (
|
|
89
|
-
<ScrollArea className="w-full rounded-lg border">
|
|
90
|
-
<div className="flex gap-4 p-4" style={{ width: 'max-content' }}>
|
|
91
|
-
{Array.from({ length: 20 }).map((_, i) => (
|
|
92
|
-
<div
|
|
93
|
-
key={i}
|
|
94
|
-
className="flex-shrink-0 w-64 h-40 rounded-lg bg-gradient-to-br from-blue-400 to-purple-500 flex items-center justify-center text-white font-bold text-2xl"
|
|
95
|
-
>
|
|
96
|
-
Card {i + 1}
|
|
97
|
-
</div>
|
|
98
|
-
))}
|
|
99
|
-
</div>
|
|
100
|
-
<ScrollBar orientation="horizontal" />
|
|
101
|
-
</ScrollArea>
|
|
102
|
-
)
|
|
103
|
-
}
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Both Directions
|
|
107
|
-
|
|
108
|
-
Scroll in both vertical and horizontal directions.
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
export function BidirectionalScroll() {
|
|
112
|
-
return (
|
|
113
|
-
<ScrollArea className="h-[400px] w-full rounded-lg border">
|
|
114
|
-
<div className="p-4" style={{ minWidth: '1200px' }}>
|
|
115
|
-
<table className="w-full">
|
|
116
|
-
<thead>
|
|
117
|
-
<tr className="bg-background-presentation-global-secondary">
|
|
118
|
-
{Array.from({ length: 10 }).map((_, i) => (
|
|
119
|
-
<th key={i} className="p-3 text-left whitespace-nowrap">
|
|
120
|
-
Column {i + 1}
|
|
121
|
-
</th>
|
|
122
|
-
))}
|
|
123
|
-
</tr>
|
|
124
|
-
</thead>
|
|
125
|
-
<tbody>
|
|
126
|
-
{Array.from({ length: 30 }).map((_, rowIndex) => (
|
|
127
|
-
<tr key={rowIndex} className="border-b">
|
|
128
|
-
{Array.from({ length: 10 }).map((_, colIndex) => (
|
|
129
|
-
<td key={colIndex} className="p-3 whitespace-nowrap">
|
|
130
|
-
Data {rowIndex + 1},{colIndex + 1}
|
|
131
|
-
</td>
|
|
132
|
-
))}
|
|
133
|
-
</tr>
|
|
134
|
-
))}
|
|
135
|
-
</tbody>
|
|
136
|
-
</table>
|
|
137
|
-
</div>
|
|
138
|
-
<ScrollBar orientation="horizontal" />
|
|
139
|
-
</ScrollArea>
|
|
140
|
-
)
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Chat Messages
|
|
145
|
-
|
|
146
|
-
Scrollable chat message container.
|
|
147
|
-
|
|
148
|
-
```tsx
|
|
149
|
-
export function ChatMessages() {
|
|
150
|
-
const messages = [
|
|
151
|
-
{ id: 1, user: 'John', text: 'Hey! How are you?', time: '10:30 AM', own: false },
|
|
152
|
-
{ id: 2, user: 'You', text: 'I\'m good! Thanks for asking.', time: '10:31 AM', own: true },
|
|
153
|
-
{ id: 3, user: 'John', text: 'Working on anything interesting?', time: '10:32 AM', own: false },
|
|
154
|
-
// ... more messages
|
|
155
|
-
]
|
|
156
|
-
|
|
157
|
-
const scrollRef = useRef<HTMLDivElement>(null)
|
|
158
|
-
|
|
159
|
-
useEffect(() => {
|
|
160
|
-
// Scroll to bottom on new messages
|
|
161
|
-
if (scrollRef.current) {
|
|
162
|
-
scrollRef.current.scrollTop = scrollRef.current.scrollHeight
|
|
163
|
-
}
|
|
164
|
-
}, [messages])
|
|
165
|
-
|
|
166
|
-
return (
|
|
167
|
-
<div className="flex flex-col h-[600px] border rounded-lg">
|
|
168
|
-
<div className="p-4 border-b">
|
|
169
|
-
<h3 className="font-semibold">Chat with John</h3>
|
|
170
|
-
</div>
|
|
171
|
-
|
|
172
|
-
<ScrollArea className="flex-1">
|
|
173
|
-
<div ref={scrollRef} className="p-4 space-y-4">
|
|
174
|
-
{messages.map(message => (
|
|
175
|
-
<div
|
|
176
|
-
key={message.id}
|
|
177
|
-
className={cn(
|
|
178
|
-
"flex",
|
|
179
|
-
message.own ? "justify-end" : "justify-start"
|
|
180
|
-
)}
|
|
181
|
-
>
|
|
182
|
-
<div
|
|
183
|
-
className={cn(
|
|
184
|
-
"max-w-[70%] rounded-lg p-3",
|
|
185
|
-
message.own
|
|
186
|
-
? "bg-blue-500 text-white"
|
|
187
|
-
: "bg-background-presentation-global-secondary"
|
|
188
|
-
)}
|
|
189
|
-
>
|
|
190
|
-
{!message.own && (
|
|
191
|
-
<div className="text-xs font-semibold mb-1">{message.user}</div>
|
|
192
|
-
)}
|
|
193
|
-
<div>{message.text}</div>
|
|
194
|
-
<div className="text-xs opacity-70 mt-1">{message.time}</div>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
))}
|
|
198
|
-
</div>
|
|
199
|
-
</ScrollArea>
|
|
200
|
-
|
|
201
|
-
<div className="p-4 border-t">
|
|
202
|
-
<input
|
|
203
|
-
type="text"
|
|
204
|
-
placeholder="Type a message..."
|
|
205
|
-
className="w-full px-3 py-2 border rounded"
|
|
206
|
-
/>
|
|
207
|
-
</div>
|
|
208
|
-
</div>
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
### Code Block
|
|
214
|
-
|
|
215
|
-
Scrollable code display.
|
|
216
|
-
|
|
217
|
-
```tsx
|
|
218
|
-
export function CodeBlock() {
|
|
219
|
-
const code = `function bubbleSort(arr) {
|
|
220
|
-
const n = arr.length;
|
|
221
|
-
for (let i = 0; i < n - 1; i++) {
|
|
222
|
-
for (let j = 0; j < n - i - 1; j++) {
|
|
223
|
-
if (arr[j] > arr[j + 1]) {
|
|
224
|
-
// Swap elements
|
|
225
|
-
[arr[j], arr[j + 1]] = [arr[j + 1], arr[j]];
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
return arr;
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
// Example usage
|
|
233
|
-
const numbers = [64, 34, 25, 12, 22, 11, 90];
|
|
234
|
-
console.log("Original array:", numbers);
|
|
235
|
-
const sorted = bubbleSort([...numbers]);
|
|
236
|
-
console.log("Sorted array:", sorted);`
|
|
237
|
-
|
|
238
|
-
return (
|
|
239
|
-
<div className="rounded-lg overflow-hidden border">
|
|
240
|
-
<div className="bg-gray-800 text-white px-4 py-2 flex justify-between items-center">
|
|
241
|
-
<span className="text-sm font-mono">bubbleSort.js</span>
|
|
242
|
-
<button className="text-xs hover:bg-gray-700 px-2 py-1 rounded">
|
|
243
|
-
Copy
|
|
244
|
-
</button>
|
|
245
|
-
</div>
|
|
246
|
-
|
|
247
|
-
<ScrollArea className="h-[300px]">
|
|
248
|
-
<pre className="p-4 bg-gray-900 text-gray-100 font-mono text-sm">
|
|
249
|
-
<code>{code}</code>
|
|
250
|
-
</pre>
|
|
251
|
-
<ScrollBar orientation="horizontal" />
|
|
252
|
-
</ScrollArea>
|
|
253
|
-
</div>
|
|
254
|
-
)
|
|
255
|
-
}
|
|
256
|
-
```
|
|
257
|
-
|
|
258
|
-
### Notification List
|
|
259
|
-
|
|
260
|
-
Scrollable notifications panel.
|
|
261
|
-
|
|
262
|
-
```tsx
|
|
263
|
-
export function NotificationList() {
|
|
264
|
-
const notifications = [
|
|
265
|
-
{
|
|
266
|
-
id: 1,
|
|
267
|
-
type: 'message',
|
|
268
|
-
title: 'New message from Sarah',
|
|
269
|
-
description: 'Hey, can we schedule a meeting?',
|
|
270
|
-
time: '2 minutes ago',
|
|
271
|
-
unread: true,
|
|
272
|
-
},
|
|
273
|
-
// ... more notifications
|
|
274
|
-
]
|
|
275
|
-
|
|
276
|
-
return (
|
|
277
|
-
<div className="w-96 border rounded-lg shadow-lg">
|
|
278
|
-
<div className="p-4 border-b flex justify-between items-center">
|
|
279
|
-
<h3 className="font-semibold">Notifications</h3>
|
|
280
|
-
<button className="text-sm text-blue-500">Mark all as read</button>
|
|
281
|
-
</div>
|
|
282
|
-
|
|
283
|
-
<ScrollArea className="h-[400px]">
|
|
284
|
-
<div>
|
|
285
|
-
{notifications.map(notification => (
|
|
286
|
-
<div
|
|
287
|
-
key={notification.id}
|
|
288
|
-
className={cn(
|
|
289
|
-
"p-4 border-b hover:bg-background-presentation-global-secondary cursor-pointer transition-colors",
|
|
290
|
-
notification.unread && "bg-blue-50"
|
|
291
|
-
)}
|
|
292
|
-
>
|
|
293
|
-
<div className="flex gap-3">
|
|
294
|
-
<div className={cn(
|
|
295
|
-
"w-2 h-2 rounded-full mt-2",
|
|
296
|
-
notification.unread ? "bg-blue-500" : "bg-transparent"
|
|
297
|
-
)} />
|
|
298
|
-
<div className="flex-1">
|
|
299
|
-
<h4 className="font-medium">{notification.title}</h4>
|
|
300
|
-
<p className="text-sm text-content-presentation-global-secondary mt-1">
|
|
301
|
-
{notification.description}
|
|
302
|
-
</p>
|
|
303
|
-
<span className="text-xs text-content-presentation-global-tertiary mt-2 block">
|
|
304
|
-
{notification.time}
|
|
305
|
-
</span>
|
|
306
|
-
</div>
|
|
307
|
-
</div>
|
|
308
|
-
</div>
|
|
309
|
-
))}
|
|
310
|
-
</div>
|
|
311
|
-
</ScrollArea>
|
|
312
|
-
</div>
|
|
313
|
-
)
|
|
314
|
-
}
|
|
315
|
-
```
|
|
316
|
-
|
|
317
|
-
### File Explorer
|
|
318
|
-
|
|
319
|
-
Scrollable directory tree.
|
|
320
|
-
|
|
321
|
-
```tsx
|
|
322
|
-
export function FileExplorer() {
|
|
323
|
-
const fileStructure = {
|
|
324
|
-
name: 'project',
|
|
325
|
-
type: 'folder',
|
|
326
|
-
children: [
|
|
327
|
-
{
|
|
328
|
-
name: 'src',
|
|
329
|
-
type: 'folder',
|
|
330
|
-
children: [
|
|
331
|
-
{ name: 'components', type: 'folder', children: [] },
|
|
332
|
-
{ name: 'utils', type: 'folder', children: [] },
|
|
333
|
-
{ name: 'index.tsx', type: 'file' },
|
|
334
|
-
]
|
|
335
|
-
},
|
|
336
|
-
{ name: 'package.json', type: 'file' },
|
|
337
|
-
// ... more files
|
|
338
|
-
]
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
const FileTreeItem = ({ item, depth = 0 }) => (
|
|
342
|
-
<div>
|
|
343
|
-
<div
|
|
344
|
-
className="flex items-center gap-2 px-2 py-1 hover:bg-background-presentation-global-secondary cursor-pointer rounded"
|
|
345
|
-
style={{ paddingLeft: `${depth * 16 + 8}px` }}
|
|
346
|
-
>
|
|
347
|
-
<i className={item.type === 'folder' ? 'ri-folder-line' : 'ri-file-line'}></i>
|
|
348
|
-
<span className="text-sm">{item.name}</span>
|
|
349
|
-
</div>
|
|
350
|
-
{item.children?.map((child, index) => (
|
|
351
|
-
<FileTreeItem key={index} item={child} depth={depth + 1} />
|
|
352
|
-
))}
|
|
353
|
-
</div>
|
|
354
|
-
)
|
|
355
|
-
|
|
356
|
-
return (
|
|
357
|
-
<div className="w-64 border rounded-lg">
|
|
358
|
-
<div className="p-3 border-b font-semibold">
|
|
359
|
-
Explorer
|
|
360
|
-
</div>
|
|
361
|
-
|
|
362
|
-
<ScrollArea className="h-[500px]">
|
|
363
|
-
<div className="p-2">
|
|
364
|
-
<FileTreeItem item={fileStructure} />
|
|
365
|
-
</div>
|
|
366
|
-
</ScrollArea>
|
|
367
|
-
</div>
|
|
368
|
-
)
|
|
369
|
-
}
|
|
370
|
-
```
|
|
371
|
-
|
|
372
|
-
### Image Gallery
|
|
373
|
-
|
|
374
|
-
Horizontal scrolling gallery.
|
|
375
|
-
|
|
376
|
-
```tsx
|
|
377
|
-
export function ImageGallery() {
|
|
378
|
-
const images = Array.from({ length: 15 }, (_, i) => ({
|
|
379
|
-
id: i + 1,
|
|
380
|
-
url: `/images/photo-${i + 1}.jpg`,
|
|
381
|
-
title: `Photo ${i + 1}`
|
|
382
|
-
}))
|
|
383
|
-
|
|
384
|
-
return (
|
|
385
|
-
<div>
|
|
386
|
-
<h2 className="text-2xl font-bold mb-4">Gallery</h2>
|
|
387
|
-
|
|
388
|
-
<ScrollArea className="w-full rounded-lg">
|
|
389
|
-
<div className="flex gap-4 p-4" style={{ width: 'max-content' }}>
|
|
390
|
-
{images.map(image => (
|
|
391
|
-
<div key={image.id} className="flex-shrink-0">
|
|
392
|
-
<div className="w-64 h-48 bg-gray-200 rounded-lg overflow-hidden">
|
|
393
|
-
<img
|
|
394
|
-
src={image.url}
|
|
395
|
-
alt={image.title}
|
|
396
|
-
className="w-full h-full object-cover"
|
|
397
|
-
/>
|
|
398
|
-
</div>
|
|
399
|
-
<p className="mt-2 text-sm text-center">{image.title}</p>
|
|
400
|
-
</div>
|
|
401
|
-
))}
|
|
402
|
-
</div>
|
|
403
|
-
<ScrollBar orientation="horizontal" />
|
|
404
|
-
</ScrollArea>
|
|
405
|
-
</div>
|
|
406
|
-
)
|
|
407
|
-
}
|
|
408
|
-
```
|
|
409
|
-
|
|
410
|
-
### Settings Panel
|
|
411
|
-
|
|
412
|
-
Scrollable settings with sections.
|
|
413
|
-
|
|
414
|
-
```tsx
|
|
415
|
-
export function SettingsPanel() {
|
|
416
|
-
return (
|
|
417
|
-
<div className="max-w-2xl border rounded-lg">
|
|
418
|
-
<div className="p-6 border-b">
|
|
419
|
-
<h2 className="text-2xl font-bold">Settings</h2>
|
|
420
|
-
<p className="text-sm text-content-presentation-global-secondary mt-1">
|
|
421
|
-
Manage your account preferences
|
|
422
|
-
</p>
|
|
423
|
-
</div>
|
|
424
|
-
|
|
425
|
-
<ScrollArea className="h-[600px]">
|
|
426
|
-
<div className="p-6 space-y-6">
|
|
427
|
-
{/* Profile Section */}
|
|
428
|
-
<section>
|
|
429
|
-
<h3 className="text-lg font-semibold mb-4">Profile</h3>
|
|
430
|
-
<div className="space-y-4">
|
|
431
|
-
<div>
|
|
432
|
-
<label className="block text-sm font-medium mb-2">Display Name</label>
|
|
433
|
-
<input type="text" className="w-full px-3 py-2 border rounded" />
|
|
434
|
-
</div>
|
|
435
|
-
<div>
|
|
436
|
-
<label className="block text-sm font-medium mb-2">Bio</label>
|
|
437
|
-
<textarea rows={3} className="w-full px-3 py-2 border rounded"></textarea>
|
|
438
|
-
</div>
|
|
439
|
-
</div>
|
|
440
|
-
</section>
|
|
441
|
-
|
|
442
|
-
<Divider />
|
|
443
|
-
|
|
444
|
-
{/* Notifications Section */}
|
|
445
|
-
<section>
|
|
446
|
-
<h3 className="text-lg font-semibold mb-4">Notifications</h3>
|
|
447
|
-
<div className="space-y-3">
|
|
448
|
-
<LabeledCheckBox id="email" label="Email notifications" />
|
|
449
|
-
<LabeledCheckBox id="push" label="Push notifications" />
|
|
450
|
-
<LabeledCheckBox id="sms" label="SMS notifications" />
|
|
451
|
-
</div>
|
|
452
|
-
</section>
|
|
453
|
-
|
|
454
|
-
<Divider />
|
|
455
|
-
|
|
456
|
-
{/* More sections... */}
|
|
457
|
-
</div>
|
|
458
|
-
</ScrollArea>
|
|
459
|
-
</div>
|
|
460
|
-
)
|
|
461
|
-
}
|
|
462
|
-
```
|
|
463
|
-
|
|
464
|
-
## API Reference
|
|
465
|
-
|
|
466
|
-
### ScrollArea Props
|
|
467
|
-
|
|
468
|
-
Extends all Radix UI ScrollArea.Root props.
|
|
469
|
-
|
|
470
|
-
| Prop | Type | Default | Description |
|
|
471
|
-
|------|------|---------|-------------|
|
|
472
|
-
| className | `string` | - | Additional CSS classes |
|
|
473
|
-
| children | `ReactNode` | - | Scrollable content |
|
|
474
|
-
| ref | `Ref` | - | Forwarded ref |
|
|
475
|
-
|
|
476
|
-
### ScrollBar Props
|
|
477
|
-
|
|
478
|
-
Extends all Radix UI ScrollAreaScrollbar props.
|
|
479
|
-
|
|
480
|
-
| Prop | Type | Default | Description |
|
|
481
|
-
|------|------|---------|-------------|
|
|
482
|
-
| orientation | `'vertical' \| 'horizontal'` | `'vertical'` | Scrollbar orientation |
|
|
483
|
-
| className | `string` | - | Additional CSS classes |
|
|
484
|
-
| ref | `Ref` | - | Forwarded ref |
|
|
485
|
-
|
|
486
|
-
## Styling
|
|
487
|
-
|
|
488
|
-
### Default Styles
|
|
489
|
-
|
|
490
|
-
- **Container**: Border, shadow, background color
|
|
491
|
-
- **Scrollbar Width**: 10px (2.5 Tailwind units)
|
|
492
|
-
- **Scrollbar Thumb**: Rounded, border color
|
|
493
|
-
- **Overflow**: Hidden with custom scrollbars
|
|
494
|
-
|
|
495
|
-
### Customization
|
|
496
|
-
|
|
497
|
-
```tsx
|
|
498
|
-
// Custom height
|
|
499
|
-
<ScrollArea className="h-[500px]" />
|
|
500
|
-
|
|
501
|
-
// Custom width
|
|
502
|
-
<ScrollArea className="w-[600px]" />
|
|
503
|
-
|
|
504
|
-
// Remove default styles
|
|
505
|
-
<ScrollArea className="border-0 shadow-none" />
|
|
506
|
-
|
|
507
|
-
// Custom scrollbar
|
|
508
|
-
<ScrollBar className="w-4 bg-gray-100" />
|
|
509
|
-
```
|
|
510
|
-
|
|
511
|
-
## TypeScript Types
|
|
512
|
-
|
|
513
|
-
```typescript
|
|
514
|
-
import type * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'
|
|
515
|
-
|
|
516
|
-
type ScrollAreaProps = React.ComponentPropsWithoutRef<
|
|
517
|
-
typeof ScrollAreaPrimitive.Root
|
|
518
|
-
>
|
|
519
|
-
|
|
520
|
-
type ScrollBarProps = React.ComponentPropsWithoutRef<
|
|
521
|
-
typeof ScrollAreaPrimitive.ScrollAreaScrollbar
|
|
522
|
-
>
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
## Common Patterns
|
|
526
|
-
|
|
527
|
-
### Auto-Scroll to Bottom
|
|
528
|
-
|
|
529
|
-
```tsx
|
|
530
|
-
function AutoScrollContainer({ messages }) {
|
|
531
|
-
const scrollRef = useRef<HTMLDivElement>(null)
|
|
532
|
-
|
|
533
|
-
useEffect(() => {
|
|
534
|
-
if (scrollRef.current) {
|
|
535
|
-
const viewport = scrollRef.current.querySelector('[data-radix-scroll-area-viewport]')
|
|
536
|
-
if (viewport) {
|
|
537
|
-
viewport.scrollTop = viewport.scrollHeight
|
|
538
|
-
}
|
|
539
|
-
}
|
|
540
|
-
}, [messages])
|
|
541
|
-
|
|
542
|
-
return (
|
|
543
|
-
<ScrollArea ref={scrollRef} className="h-[400px]">
|
|
544
|
-
{/* Content */}
|
|
545
|
-
</ScrollArea>
|
|
546
|
-
)
|
|
547
|
-
}
|
|
548
|
-
```
|
|
549
|
-
|
|
550
|
-
### Programmatic Scrolling
|
|
551
|
-
|
|
552
|
-
```tsx
|
|
553
|
-
function ScrollToTop() {
|
|
554
|
-
const scrollRef = useRef<HTMLDivElement>(null)
|
|
555
|
-
|
|
556
|
-
const scrollToTop = () => {
|
|
557
|
-
const viewport = scrollRef.current?.querySelector('[data-radix-scroll-area-viewport]')
|
|
558
|
-
viewport?.scrollTo({ top: 0, behavior: 'smooth' })
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
return (
|
|
562
|
-
<>
|
|
563
|
-
<ScrollArea ref={scrollRef} className="h-[400px]">
|
|
564
|
-
{/* Content */}
|
|
565
|
-
</ScrollArea>
|
|
566
|
-
<button onClick={scrollToTop}>Back to Top</button>
|
|
567
|
-
</>
|
|
568
|
-
)
|
|
569
|
-
}
|
|
570
|
-
```
|
|
571
|
-
|
|
572
|
-
## Testing
|
|
573
|
-
|
|
574
|
-
```typescript
|
|
575
|
-
import { render, screen } from '@testing-library/react'
|
|
576
|
-
import { ScrollArea, ScrollBar } from '@/components/ScrollArea'
|
|
577
|
-
|
|
578
|
-
describe('ScrollArea', () => {
|
|
579
|
-
it('renders children correctly', () => {
|
|
580
|
-
render(
|
|
581
|
-
<ScrollArea>
|
|
582
|
-
<div>Test content</div>
|
|
583
|
-
</ScrollArea>
|
|
584
|
-
)
|
|
585
|
-
|
|
586
|
-
expect(screen.getByText('Test content')).toBeInTheDocument()
|
|
587
|
-
})
|
|
588
|
-
|
|
589
|
-
it('applies custom className', () => {
|
|
590
|
-
const { container } = render(
|
|
591
|
-
<ScrollArea className="custom-class">
|
|
592
|
-
Content
|
|
593
|
-
</ScrollArea>
|
|
594
|
-
)
|
|
595
|
-
|
|
596
|
-
expect(container.firstChild).toHaveClass('custom-class')
|
|
597
|
-
})
|
|
598
|
-
|
|
599
|
-
it('renders horizontal scrollbar', () => {
|
|
600
|
-
const { container } = render(
|
|
601
|
-
<ScrollArea>
|
|
602
|
-
Content
|
|
603
|
-
<ScrollBar orientation="horizontal" />
|
|
604
|
-
</ScrollArea>
|
|
605
|
-
)
|
|
606
|
-
|
|
607
|
-
const scrollbar = container.querySelector('[orientation="horizontal"]')
|
|
608
|
-
expect(scrollbar).toBeInTheDocument()
|
|
609
|
-
})
|
|
610
|
-
})
|
|
611
|
-
```
|
|
612
|
-
|
|
613
|
-
## Accessibility
|
|
614
|
-
|
|
615
|
-
- **Keyboard Navigation**: Arrow keys, Page Up/Down, Home/End
|
|
616
|
-
- **Screen Reader**: Announces scrollable region
|
|
617
|
-
- **Focus Management**: Maintains focus within scroll area
|
|
618
|
-
- **Touch Support**: Native touch scrolling on mobile
|
|
619
|
-
- **Scroll Indicators**: Visual scrollbar for context
|
|
620
|
-
|
|
621
|
-
## Performance
|
|
622
|
-
|
|
623
|
-
- **Virtual Scrolling**: Consider for large lists (use with react-window)
|
|
624
|
-
- **Render Optimization**: Only renders visible content
|
|
625
|
-
- **Smooth Scrolling**: Hardware-accelerated
|
|
626
|
-
- **Bundle Size**: ~2 KB (with Radix UI dependency)
|
|
627
|
-
|
|
628
|
-
### Performance Tips
|
|
629
|
-
|
|
630
|
-
```tsx
|
|
631
|
-
// Virtualize large lists
|
|
632
|
-
import { FixedSizeList } from 'react-window'
|
|
633
|
-
|
|
634
|
-
<ScrollArea className="h-[400px]">
|
|
635
|
-
<FixedSizeList
|
|
636
|
-
height={400}
|
|
637
|
-
itemCount={1000}
|
|
638
|
-
itemSize={35}
|
|
639
|
-
>
|
|
640
|
-
{({ index, style }) => (
|
|
641
|
-
<div style={style}>Item {index}</div>
|
|
642
|
-
)}
|
|
643
|
-
</FixedSizeList>
|
|
644
|
-
</ScrollArea>
|
|
645
|
-
|
|
646
|
-
// Memoize content
|
|
647
|
-
const MemoizedContent = React.memo(({ data }) => (
|
|
648
|
-
// Expensive content
|
|
649
|
-
))
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
## Migration Guide
|
|
653
|
-
|
|
654
|
-
### From Native Overflow
|
|
655
|
-
|
|
656
|
-
```tsx
|
|
657
|
-
// Before: Native scrolling
|
|
658
|
-
<div className="h-[400px] overflow-auto">
|
|
659
|
-
Content
|
|
660
|
-
</div>
|
|
661
|
-
|
|
662
|
-
// After: ScrollArea
|
|
663
|
-
<ScrollArea className="h-[400px]">
|
|
664
|
-
Content
|
|
665
|
-
</ScrollArea>
|
|
666
|
-
```
|
|
667
|
-
|
|
668
|
-
### From Other Libraries
|
|
669
|
-
|
|
670
|
-
```tsx
|
|
671
|
-
// Before: react-custom-scrollbars
|
|
672
|
-
<Scrollbars style={{ height: 400 }}>
|
|
673
|
-
Content
|
|
674
|
-
</Scrollbars>
|
|
675
|
-
|
|
676
|
-
// After: ScrollArea
|
|
677
|
-
<ScrollArea className="h-[400px]">
|
|
678
|
-
Content
|
|
679
|
-
</ScrollArea>
|
|
680
|
-
```
|
|
681
|
-
|
|
682
|
-
## Best Practices
|
|
683
|
-
|
|
684
|
-
1. **Set Fixed Height**: Always specify height for vertical scrolling
|
|
685
|
-
2. **Use Horizontal ScrollBar**: Add `<ScrollBar orientation="horizontal" />` for horizontal scrolling
|
|
686
|
-
3. **Consider Virtual Scrolling**: For lists with 100+ items
|
|
687
|
-
4. **Smooth Scrolling**: Use CSS `scroll-behavior: smooth` for animated scrolling
|
|
688
|
-
5. **Mobile Touch**: Test touch scrolling on mobile devices
|
|
689
|
-
6. **Accessibility**: Ensure keyboard navigation works properly
|
|
690
|
-
7. **Performance**: Memoize expensive content
|
|
691
|
-
8. **Auto-Scroll**: Implement auto-scroll for chat/log interfaces
|