torch-glare 2.5.6 → 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 -403
- package/apps/lib/components/Breadcrumb.tsx +0 -280
- package/apps/lib/components/Button.tsx +0 -325
- 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 -395
- 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 -88
- 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 -72
- package/apps/lib/components/DataViews/states.tsx +0 -73
- 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 -451
- package/apps/lib/components/DropdownMenu.tsx +0 -554
- package/apps/lib/components/FieldHint.tsx +0 -69
- package/apps/lib/components/Form.tsx +0 -182
- package/apps/lib/components/FormBuilder/context.ts +0 -85
- 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 -168
- 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 -114
- 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 -67
- package/apps/lib/components/FormBuilder/types.ts +0 -316
- package/apps/lib/components/FormRenderer/FormDrawer.tsx +0 -250
- package/apps/lib/components/FormRenderer/detail.tsx +0 -256
- package/apps/lib/components/FormRenderer/form-renderer.tsx +0 -358
- package/apps/lib/components/FormRenderer/header.tsx +0 -88
- package/apps/lib/components/FormRenderer/index.ts +0 -17
- package/apps/lib/components/FormRenderer/notch-action.tsx +0 -64
- package/apps/lib/components/FormRenderer/section.tsx +0 -39
- package/apps/lib/components/FormRenderer/stepper.tsx +0 -393
- package/apps/lib/components/FormRenderer/types.ts +0 -115
- 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 -168
- 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 -255
- 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 -597
- 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 -61
- package/apps/lib/hooks/useClickOutside.ts +0 -27
- package/apps/lib/hooks/useDragDrop.tsx +0 -365
- package/apps/lib/hooks/useHtmlDir.ts +0 -31
- 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 -300
- 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 -1217
- 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/scroller.ts +0 -26
- 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 -738
- 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 -1521
- package/docs/components/data-views/migration.md +0 -81
- 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 -284
- package/docs/components/form-renderer.md +0 -396
- 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 -483
- 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 -60
- 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 -1523
- 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 -726
- 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,649 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: Popover
|
|
3
|
-
description: Non-modal overlay component for displaying rich content relative to a trigger element
|
|
4
|
-
group: Overlays & Dialogs
|
|
5
|
-
keywords: [popover, overlay, dropdown, radix-ui, menu, non-modal]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# Popover
|
|
9
|
-
|
|
10
|
-
> A non-modal overlay component that displays rich, interactive content anchored to a trigger element. Perfect for dropdowns, selection lists, and contextual menus with optional backdrop blur.
|
|
11
|
-
|
|
12
|
-
## Installation
|
|
13
|
-
|
|
14
|
-
TORCH Glare is a copy-in library: the CLI copies this component's source into your project
|
|
15
|
-
(you do **not** install it from the npm package). Run `init` once, then `add`:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
npx torch-glare@latest init
|
|
19
|
-
npx torch-glare@latest add Popover
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`add` also copies any components, hooks, and utilities that `Popover` depends on.
|
|
23
|
-
|
|
24
|
-
## Import
|
|
25
|
-
|
|
26
|
-
Import from your project's local path — the alias configured in `glare.json` (e.g. `@/*`):
|
|
27
|
-
|
|
28
|
-
```tsx
|
|
29
|
-
import { Popover } from "@/components/Popover";
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick Examples
|
|
33
|
-
|
|
34
|
-
### Basic Usage
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { Popover, PopoverTrigger, PopoverContent } from "@/components/Popover";
|
|
38
|
-
import { Button } from "@/components/Button";
|
|
39
|
-
|
|
40
|
-
function Example() {
|
|
41
|
-
return (
|
|
42
|
-
<Popover>
|
|
43
|
-
<PopoverTrigger asChild>
|
|
44
|
-
<Button>Open Popover</Button>
|
|
45
|
-
</PopoverTrigger>
|
|
46
|
-
<PopoverContent>
|
|
47
|
-
<div className="p-4">
|
|
48
|
-
<p>This is popover content</p>
|
|
49
|
-
</div>
|
|
50
|
-
</PopoverContent>
|
|
51
|
-
</Popover>
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
### With PopoverItem List
|
|
57
|
-
|
|
58
|
-
```typescript
|
|
59
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
60
|
-
|
|
61
|
-
function SelectPopover() {
|
|
62
|
-
const items = ['Option 1', 'Option 2', 'Option 3']
|
|
63
|
-
|
|
64
|
-
return (
|
|
65
|
-
<Popover>
|
|
66
|
-
<PopoverTrigger asChild>
|
|
67
|
-
<button>Select an option</button>
|
|
68
|
-
</PopoverTrigger>
|
|
69
|
-
<PopoverContent>
|
|
70
|
-
{items.map((item) => (
|
|
71
|
-
<PopoverItem
|
|
72
|
-
key={item}
|
|
73
|
-
onClick={() => console.log(item)}
|
|
74
|
-
>
|
|
75
|
-
{item}
|
|
76
|
-
</PopoverItem>
|
|
77
|
-
))}
|
|
78
|
-
</PopoverContent>
|
|
79
|
-
</Popover>
|
|
80
|
-
)
|
|
81
|
-
}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### SystemStyle Variant
|
|
85
|
-
|
|
86
|
-
```typescript
|
|
87
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
88
|
-
|
|
89
|
-
function SystemStylePopover() {
|
|
90
|
-
return (
|
|
91
|
-
<Popover>
|
|
92
|
-
<PopoverTrigger asChild>
|
|
93
|
-
<button>System Menu</button>
|
|
94
|
-
</PopoverTrigger>
|
|
95
|
-
<PopoverContent variant="SystemStyle">
|
|
96
|
-
<PopoverItem variant="SystemStyle">Settings</PopoverItem>
|
|
97
|
-
<PopoverItem variant="SystemStyle">Profile</PopoverItem>
|
|
98
|
-
<PopoverItem variant="SystemStyle">Logout</PopoverItem>
|
|
99
|
-
</PopoverContent>
|
|
100
|
-
</Popover>
|
|
101
|
-
)
|
|
102
|
-
}
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### With Icons
|
|
106
|
-
|
|
107
|
-
```typescript
|
|
108
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
109
|
-
|
|
110
|
-
function IconPopover() {
|
|
111
|
-
return (
|
|
112
|
-
<Popover>
|
|
113
|
-
<PopoverTrigger asChild>
|
|
114
|
-
<button>Actions</button>
|
|
115
|
-
</PopoverTrigger>
|
|
116
|
-
<PopoverContent>
|
|
117
|
-
<PopoverItem>
|
|
118
|
-
<i className="ri-edit-line" />
|
|
119
|
-
<span>Edit</span>
|
|
120
|
-
</PopoverItem>
|
|
121
|
-
<PopoverItem>
|
|
122
|
-
<i className="ri-share-line" />
|
|
123
|
-
<span>Share</span>
|
|
124
|
-
</PopoverItem>
|
|
125
|
-
<PopoverItem variant="Negative">
|
|
126
|
-
<i className="ri-delete-bin-line" />
|
|
127
|
-
<span>Delete</span>
|
|
128
|
-
</PopoverItem>
|
|
129
|
-
</PopoverContent>
|
|
130
|
-
</Popover>
|
|
131
|
-
)
|
|
132
|
-
}
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### With Active State
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
139
|
-
import { useState } from 'react'
|
|
140
|
-
|
|
141
|
-
function SelectablePopover() {
|
|
142
|
-
const [selected, setSelected] = useState('option1')
|
|
143
|
-
|
|
144
|
-
return (
|
|
145
|
-
<Popover>
|
|
146
|
-
<PopoverTrigger asChild>
|
|
147
|
-
<button>Selected: {selected}</button>
|
|
148
|
-
</PopoverTrigger>
|
|
149
|
-
<PopoverContent>
|
|
150
|
-
<PopoverItem
|
|
151
|
-
active={selected === 'option1'}
|
|
152
|
-
onClick={() => setSelected('option1')}
|
|
153
|
-
>
|
|
154
|
-
Option 1
|
|
155
|
-
</PopoverItem>
|
|
156
|
-
<PopoverItem
|
|
157
|
-
active={selected === 'option2'}
|
|
158
|
-
onClick={() => setSelected('option2')}
|
|
159
|
-
>
|
|
160
|
-
Option 2
|
|
161
|
-
</PopoverItem>
|
|
162
|
-
<PopoverItem
|
|
163
|
-
active={selected === 'option3'}
|
|
164
|
-
onClick={() => setSelected('option3')}
|
|
165
|
-
>
|
|
166
|
-
Option 3
|
|
167
|
-
</PopoverItem>
|
|
168
|
-
</PopoverContent>
|
|
169
|
-
</Popover>
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
### With Overlay Blur
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
178
|
-
|
|
179
|
-
function BlurredPopover() {
|
|
180
|
-
return (
|
|
181
|
-
<Popover>
|
|
182
|
-
<PopoverTrigger asChild>
|
|
183
|
-
<button>Important Action</button>
|
|
184
|
-
</PopoverTrigger>
|
|
185
|
-
<PopoverContent overlayBlur={true}>
|
|
186
|
-
<PopoverItem>Confirm Action</PopoverItem>
|
|
187
|
-
<PopoverItem variant="Negative">Cancel</PopoverItem>
|
|
188
|
-
</PopoverContent>
|
|
189
|
-
</Popover>
|
|
190
|
-
)
|
|
191
|
-
}
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Warning Items
|
|
195
|
-
|
|
196
|
-
```typescript
|
|
197
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
198
|
-
|
|
199
|
-
function WarningPopover() {
|
|
200
|
-
return (
|
|
201
|
-
<Popover>
|
|
202
|
-
<PopoverTrigger asChild>
|
|
203
|
-
<button>Danger Zone</button>
|
|
204
|
-
</PopoverTrigger>
|
|
205
|
-
<PopoverContent>
|
|
206
|
-
<PopoverItem variant="Warning">
|
|
207
|
-
<i className="ri-alert-line" />
|
|
208
|
-
<span>Clear Cache</span>
|
|
209
|
-
</PopoverItem>
|
|
210
|
-
<PopoverItem variant="Negative">
|
|
211
|
-
<i className="ri-delete-bin-line" />
|
|
212
|
-
<span>Delete All Data</span>
|
|
213
|
-
</PopoverItem>
|
|
214
|
-
</PopoverContent>
|
|
215
|
-
</Popover>
|
|
216
|
-
)
|
|
217
|
-
}
|
|
218
|
-
```
|
|
219
|
-
|
|
220
|
-
### Size Variants
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
224
|
-
|
|
225
|
-
function SizedPopover() {
|
|
226
|
-
return (
|
|
227
|
-
<Popover>
|
|
228
|
-
<PopoverTrigger asChild>
|
|
229
|
-
<button>Sizes</button>
|
|
230
|
-
</PopoverTrigger>
|
|
231
|
-
<PopoverContent>
|
|
232
|
-
<PopoverItem size="S">Small Item</PopoverItem>
|
|
233
|
-
<PopoverItem size="M">Medium Item (default)</PopoverItem>
|
|
234
|
-
</PopoverContent>
|
|
235
|
-
</Popover>
|
|
236
|
-
)
|
|
237
|
-
}
|
|
238
|
-
```
|
|
239
|
-
|
|
240
|
-
### Controlled Popover
|
|
241
|
-
|
|
242
|
-
```typescript
|
|
243
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
244
|
-
import { useState } from 'react'
|
|
245
|
-
|
|
246
|
-
function ControlledPopover() {
|
|
247
|
-
const [open, setOpen] = useState(false)
|
|
248
|
-
|
|
249
|
-
const handleSelect = (value: string) => {
|
|
250
|
-
console.log(value)
|
|
251
|
-
setOpen(false) // Close after selection
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return (
|
|
255
|
-
<Popover open={open} onOpenChange={setOpen}>
|
|
256
|
-
<PopoverTrigger asChild>
|
|
257
|
-
<button>Controlled</button>
|
|
258
|
-
</PopoverTrigger>
|
|
259
|
-
<PopoverContent>
|
|
260
|
-
<PopoverItem onClick={() => handleSelect('A')}>Option A</PopoverItem>
|
|
261
|
-
<PopoverItem onClick={() => handleSelect('B')}>Option B</PopoverItem>
|
|
262
|
-
</PopoverContent>
|
|
263
|
-
</Popover>
|
|
264
|
-
)
|
|
265
|
-
}
|
|
266
|
-
```
|
|
267
|
-
|
|
268
|
-
### Positioning
|
|
269
|
-
|
|
270
|
-
```typescript
|
|
271
|
-
import { Popover, PopoverTrigger, PopoverContent } from "@/components/Popover";
|
|
272
|
-
|
|
273
|
-
function PositionedPopover() {
|
|
274
|
-
return (
|
|
275
|
-
<Popover>
|
|
276
|
-
<PopoverTrigger asChild>
|
|
277
|
-
<button>Positioned</button>
|
|
278
|
-
</PopoverTrigger>
|
|
279
|
-
<PopoverContent
|
|
280
|
-
align="start" // or "center", "end"
|
|
281
|
-
side="bottom" // or "top", "left", "right"
|
|
282
|
-
sideOffset={8}
|
|
283
|
-
>
|
|
284
|
-
<div>Positioned content</div>
|
|
285
|
-
</PopoverContent>
|
|
286
|
-
</Popover>
|
|
287
|
-
)
|
|
288
|
-
}
|
|
289
|
-
```
|
|
290
|
-
|
|
291
|
-
## API Reference
|
|
292
|
-
|
|
293
|
-
### Popover (Root)
|
|
294
|
-
|
|
295
|
-
| Prop | Type | Default | Description |
|
|
296
|
-
|------|------|---------|-------------|
|
|
297
|
-
| `open` | `boolean` | - | Controlled open state |
|
|
298
|
-
| `onOpenChange` | `(open: boolean) => void` | - | Callback when state changes |
|
|
299
|
-
| `defaultOpen` | `boolean` | `false` | Uncontrolled default open state |
|
|
300
|
-
| `modal` | `boolean` | `false` | Whether to block outside interactions |
|
|
301
|
-
|
|
302
|
-
### PopoverTrigger
|
|
303
|
-
|
|
304
|
-
| Prop | Type | Default | Description |
|
|
305
|
-
|------|------|---------|-------------|
|
|
306
|
-
| `asChild` | `boolean` | `false` | Render trigger as child element |
|
|
307
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
308
|
-
|
|
309
|
-
### PopoverContent
|
|
310
|
-
|
|
311
|
-
| Prop | Type | Default | Description |
|
|
312
|
-
|------|------|---------|-------------|
|
|
313
|
-
| `variant` | `'SystemStyle' \| 'PresentationStyle'` | `'SystemStyle'` | Visual style variant |
|
|
314
|
-
| `overlayBlur` | `boolean` | `false` | Add blurred backdrop |
|
|
315
|
-
| `align` | `'start' \| 'center' \| 'end'` | `'center'` | Alignment relative to trigger |
|
|
316
|
-
| `side` | `'top' \| 'right' \| 'bottom' \| 'left'` | `'bottom'` | Preferred side to display |
|
|
317
|
-
| `sideOffset` | `number` | `4` | Distance from trigger (px) |
|
|
318
|
-
| `theme` | `'dark' \| 'light' \| 'default'` | - | Theme variant |
|
|
319
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
320
|
-
|
|
321
|
-
### PopoverItem
|
|
322
|
-
|
|
323
|
-
| Prop | Type | Default | Description |
|
|
324
|
-
|------|------|---------|-------------|
|
|
325
|
-
| `variant` | `'Default' \| 'Warning' \| 'Negative' \| 'SystemStyle'` | `'Default'` | Item style variant |
|
|
326
|
-
| `size` | `'S' \| 'M'` | `'M'` | Item size (S: 24px, M: 32px) |
|
|
327
|
-
| `active` | `boolean` | `false` | Active/selected state |
|
|
328
|
-
| `disabled` | `boolean` | `false` | Disabled state |
|
|
329
|
-
| `asChild` | `boolean` | `false` | Render as child element |
|
|
330
|
-
| `as` | `React.ElementType` | `'button'` | Element type to render as |
|
|
331
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
332
|
-
|
|
333
|
-
## TypeScript
|
|
334
|
-
|
|
335
|
-
### Full Type Definitions
|
|
336
|
-
|
|
337
|
-
```typescript
|
|
338
|
-
import * as PopoverPrimitive from '@radix-ui/react-popover'
|
|
339
|
-
|
|
340
|
-
// Root component
|
|
341
|
-
interface PopoverProps {
|
|
342
|
-
open?: boolean
|
|
343
|
-
onOpenChange?: (open: boolean) => void
|
|
344
|
-
defaultOpen?: boolean
|
|
345
|
-
modal?: boolean
|
|
346
|
-
children: React.ReactNode
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
export const Popover: React.FC<PopoverProps>
|
|
350
|
-
|
|
351
|
-
// Content component
|
|
352
|
-
interface PopoverContentProps
|
|
353
|
-
extends React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content> {
|
|
354
|
-
variant?: 'SystemStyle' | 'PresentationStyle'
|
|
355
|
-
overlayBlur?: boolean
|
|
356
|
-
theme?: 'dark' | 'light' | 'default'
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
export const PopoverContent: React.ForwardRefExoticComponent<PopoverContentProps>
|
|
360
|
-
|
|
361
|
-
// Item component
|
|
362
|
-
interface PopoverItemProps<T extends React.ElementType = 'button'>
|
|
363
|
-
extends React.HTMLAttributes<HTMLElement> {
|
|
364
|
-
variant?: 'Default' | 'Warning' | 'Negative' | 'SystemStyle'
|
|
365
|
-
size?: 'S' | 'M'
|
|
366
|
-
active?: boolean
|
|
367
|
-
disabled?: boolean
|
|
368
|
-
asChild?: boolean
|
|
369
|
-
as?: T
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
export const PopoverItem: <T extends React.ElementType = 'button'>(
|
|
373
|
-
props: PopoverItemProps<T>
|
|
374
|
-
) => React.ReactElement
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
## Variants
|
|
378
|
-
|
|
379
|
-
### Content Variants
|
|
380
|
-
|
|
381
|
-
**SystemStyle**:
|
|
382
|
-
- Dark background with shadow
|
|
383
|
-
- For system/application menus
|
|
384
|
-
- Higher z-index and prominent shadow
|
|
385
|
-
|
|
386
|
-
**PresentationStyle** (default):
|
|
387
|
-
- Light background
|
|
388
|
-
- Subtle shadow
|
|
389
|
-
- For contextual content
|
|
390
|
-
|
|
391
|
-
### Item Variants
|
|
392
|
-
|
|
393
|
-
**Default**:
|
|
394
|
-
- Standard gray styling
|
|
395
|
-
- For general menu items
|
|
396
|
-
|
|
397
|
-
**Warning**:
|
|
398
|
-
- Blue/info color
|
|
399
|
-
- For informational actions
|
|
400
|
-
|
|
401
|
-
**Negative**:
|
|
402
|
-
- Red color
|
|
403
|
-
- For destructive actions
|
|
404
|
-
|
|
405
|
-
**SystemStyle**:
|
|
406
|
-
- Matches SystemStyle content
|
|
407
|
-
- For system menu items
|
|
408
|
-
|
|
409
|
-
## Features
|
|
410
|
-
|
|
411
|
-
### Auto-Scrolling
|
|
412
|
-
- Active items automatically scroll into view
|
|
413
|
-
- Smooth scrolling behavior
|
|
414
|
-
- Centers active item in viewport
|
|
415
|
-
|
|
416
|
-
### Collision Detection
|
|
417
|
-
- Automatically adjusts position to stay in viewport
|
|
418
|
-
- Prevents clipping at screen edges
|
|
419
|
-
- Smooth repositioning
|
|
420
|
-
|
|
421
|
-
## Common Patterns
|
|
422
|
-
|
|
423
|
-
### Select Pattern
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
427
|
-
import { useState } from 'react'
|
|
428
|
-
|
|
429
|
-
function SelectField() {
|
|
430
|
-
const [value, setValue] = useState('')
|
|
431
|
-
|
|
432
|
-
return (
|
|
433
|
-
<Popover>
|
|
434
|
-
<PopoverTrigger asChild>
|
|
435
|
-
<button className="w-full text-left p-2 border rounded">
|
|
436
|
-
{value || 'Select an option'}
|
|
437
|
-
</button>
|
|
438
|
-
</PopoverTrigger>
|
|
439
|
-
<PopoverContent className="w-[var(--radix-popover-trigger-width)]">
|
|
440
|
-
{options.map((option) => (
|
|
441
|
-
<PopoverItem
|
|
442
|
-
key={option}
|
|
443
|
-
active={value === option}
|
|
444
|
-
onClick={() => setValue(option)}
|
|
445
|
-
>
|
|
446
|
-
{option}
|
|
447
|
-
</PopoverItem>
|
|
448
|
-
))}
|
|
449
|
-
</PopoverContent>
|
|
450
|
-
</Popover>
|
|
451
|
-
)
|
|
452
|
-
}
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
### Context Menu Pattern
|
|
456
|
-
|
|
457
|
-
```typescript
|
|
458
|
-
function ContextMenu({ onEdit, onDelete }) {
|
|
459
|
-
return (
|
|
460
|
-
<Popover>
|
|
461
|
-
<PopoverTrigger asChild>
|
|
462
|
-
<button>
|
|
463
|
-
<i className="ri-more-2-fill" />
|
|
464
|
-
</button>
|
|
465
|
-
</PopoverTrigger>
|
|
466
|
-
<PopoverContent>
|
|
467
|
-
<PopoverItem onClick={onEdit}>
|
|
468
|
-
<i className="ri-edit-line" />
|
|
469
|
-
Edit
|
|
470
|
-
</PopoverItem>
|
|
471
|
-
<PopoverItem variant="Negative" onClick={onDelete}>
|
|
472
|
-
<i className="ri-delete-bin-line" />
|
|
473
|
-
Delete
|
|
474
|
-
</PopoverItem>
|
|
475
|
-
</PopoverContent>
|
|
476
|
-
</Popover>
|
|
477
|
-
)
|
|
478
|
-
}
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
## Testing
|
|
482
|
-
|
|
483
|
-
### Unit Test Example
|
|
484
|
-
|
|
485
|
-
```typescript
|
|
486
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
487
|
-
import { Popover, PopoverTrigger, PopoverContent, PopoverItem } from "@/components/Popover";
|
|
488
|
-
|
|
489
|
-
describe('Popover', () => {
|
|
490
|
-
it('opens on trigger click', () => {
|
|
491
|
-
render(
|
|
492
|
-
<Popover>
|
|
493
|
-
<PopoverTrigger>Open</PopoverTrigger>
|
|
494
|
-
<PopoverContent>
|
|
495
|
-
<PopoverItem>Item 1</PopoverItem>
|
|
496
|
-
</PopoverContent>
|
|
497
|
-
</Popover>
|
|
498
|
-
)
|
|
499
|
-
|
|
500
|
-
fireEvent.click(screen.getByText('Open'))
|
|
501
|
-
expect(screen.getByText('Item 1')).toBeInTheDocument()
|
|
502
|
-
})
|
|
503
|
-
|
|
504
|
-
it('calls onClick handler', () => {
|
|
505
|
-
const handleClick = jest.fn()
|
|
506
|
-
|
|
507
|
-
render(
|
|
508
|
-
<Popover defaultOpen>
|
|
509
|
-
<PopoverContent>
|
|
510
|
-
<PopoverItem onClick={handleClick}>Click me</PopoverItem>
|
|
511
|
-
</PopoverContent>
|
|
512
|
-
</Popover>
|
|
513
|
-
)
|
|
514
|
-
|
|
515
|
-
fireEvent.click(screen.getByText('Click me'))
|
|
516
|
-
expect(handleClick).toHaveBeenCalled()
|
|
517
|
-
})
|
|
518
|
-
|
|
519
|
-
it('renders with active state', () => {
|
|
520
|
-
render(
|
|
521
|
-
<Popover defaultOpen>
|
|
522
|
-
<PopoverContent>
|
|
523
|
-
<PopoverItem active>Active Item</PopoverItem>
|
|
524
|
-
</PopoverContent>
|
|
525
|
-
</Popover>
|
|
526
|
-
)
|
|
527
|
-
|
|
528
|
-
const item = screen.getByText('Active Item')
|
|
529
|
-
expect(item).toHaveClass('bg-background-presentation-action-selected')
|
|
530
|
-
})
|
|
531
|
-
})
|
|
532
|
-
```
|
|
533
|
-
|
|
534
|
-
## Accessibility
|
|
535
|
-
|
|
536
|
-
- **Keyboard Support**:
|
|
537
|
-
- Escape: Close popover
|
|
538
|
-
- Tab: Navigate items
|
|
539
|
-
- Arrow keys: Navigate when appropriate
|
|
540
|
-
- Enter/Space: Activate item
|
|
541
|
-
- **ARIA Attributes**:
|
|
542
|
-
- Items have appropriate roles
|
|
543
|
-
- Active states announced
|
|
544
|
-
- Disabled items marked
|
|
545
|
-
- **Focus Management**:
|
|
546
|
-
- Focus trapped when modal
|
|
547
|
-
- Focus returns to trigger on close
|
|
548
|
-
- Active items scrolled into view
|
|
549
|
-
|
|
550
|
-
### Accessibility Best Practices
|
|
551
|
-
|
|
552
|
-
```typescript
|
|
553
|
-
// Provide clear labels
|
|
554
|
-
<PopoverTrigger aria-label="Open menu">
|
|
555
|
-
<i className="ri-more-2-fill" />
|
|
556
|
-
</PopoverTrigger>
|
|
557
|
-
|
|
558
|
-
// Use semantic button elements
|
|
559
|
-
<PopoverItem as="button" type="button">
|
|
560
|
-
Action
|
|
561
|
-
</PopoverItem>
|
|
562
|
-
|
|
563
|
-
// Mark disabled items
|
|
564
|
-
<PopoverItem disabled>Unavailable Action</PopoverItem>
|
|
565
|
-
```
|
|
566
|
-
|
|
567
|
-
## Performance
|
|
568
|
-
|
|
569
|
-
| Metric | Value |
|
|
570
|
-
|--------|-------|
|
|
571
|
-
| Bundle size (minified) | ~5kb |
|
|
572
|
-
| Bundle size (gzipped) | ~2kb |
|
|
573
|
-
| Dependencies | @radix-ui/react-popover (~10kb) |
|
|
574
|
-
| Open/close | <16ms |
|
|
575
|
-
| Max height | 200px (scrollable) |
|
|
576
|
-
| Tree-shakeable | ✅ |
|
|
577
|
-
|
|
578
|
-
### Performance Tips
|
|
579
|
-
|
|
580
|
-
1. **Use asChild prop**: Avoid wrapper elements
|
|
581
|
-
```typescript
|
|
582
|
-
<PopoverTrigger asChild>
|
|
583
|
-
<Button>Open</Button>
|
|
584
|
-
</PopoverTrigger>
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
2. **Virtualize long lists**: For 100+ items
|
|
588
|
-
3. **Memoize item handlers**:
|
|
589
|
-
```typescript
|
|
590
|
-
const handleClick = useCallback(() => {...}, [])
|
|
591
|
-
```
|
|
592
|
-
|
|
593
|
-
## Migration from DropdownMenu
|
|
594
|
-
|
|
595
|
-
```diff
|
|
596
|
-
- import { DropdownMenu } from "@/components/DropdownMenu";
|
|
597
|
-
+ import { Popover } from "@/components/Popover";
|
|
598
|
-
|
|
599
|
-
- <DropdownMenu>
|
|
600
|
-
- <DropdownMenuTrigger>Open</DropdownMenuTrigger>
|
|
601
|
-
- <DropdownMenuContent>
|
|
602
|
-
- <DropdownMenuItem>Item</DropdownMenuItem>
|
|
603
|
-
- </DropdownMenuContent>
|
|
604
|
-
- </DropdownMenu>
|
|
605
|
-
|
|
606
|
-
+ <Popover>
|
|
607
|
-
+ <PopoverTrigger>Open</PopoverTrigger>
|
|
608
|
-
+ <PopoverContent>
|
|
609
|
-
+ <PopoverItem>Item</PopoverItem>
|
|
610
|
-
+ </PopoverContent>
|
|
611
|
-
+ </Popover>
|
|
612
|
-
```
|
|
613
|
-
|
|
614
|
-
## Best Practices
|
|
615
|
-
|
|
616
|
-
1. **Match width to trigger**: For select-style popovers
|
|
617
|
-
```typescript
|
|
618
|
-
<PopoverContent className="w-[var(--radix-popover-trigger-width)]">
|
|
619
|
-
```
|
|
620
|
-
|
|
621
|
-
2. **Use appropriate variant**: SystemStyle for app menus, PresentationStyle for contextual
|
|
622
|
-
```typescript
|
|
623
|
-
<PopoverContent variant="SystemStyle">
|
|
624
|
-
```
|
|
625
|
-
|
|
626
|
-
3. **Handle selection**: Close popover after item click
|
|
627
|
-
```typescript
|
|
628
|
-
<PopoverItem onClick={() => { setValue(item); setOpen(false) }}>
|
|
629
|
-
```
|
|
630
|
-
|
|
631
|
-
4. **Provide visual feedback**: Use active state for selected items
|
|
632
|
-
```typescript
|
|
633
|
-
<PopoverItem active={selected === item}>
|
|
634
|
-
```
|
|
635
|
-
|
|
636
|
-
5. **Use overlay blur sparingly**: Only for critical actions
|
|
637
|
-
```typescript
|
|
638
|
-
<PopoverContent overlayBlur={true}> {/* Only when needed */}
|
|
639
|
-
```
|
|
640
|
-
|
|
641
|
-
6. **Limit item count**: Keep lists manageable or add search
|
|
642
|
-
7. **Use icons consistently**: All items with icons or none
|
|
643
|
-
|
|
644
|
-
## Related Components
|
|
645
|
-
|
|
646
|
-
- [DropdownMenu](./dropdown-menu.md) - Menu-specific popover variant
|
|
647
|
-
- [Tooltip](./tooltip.md) - Simple hover text
|
|
648
|
-
- [Select](./select.md) - Form select field
|
|
649
|
-
- [ProfileMenu](./profile-menu.md) - User profile popover
|