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,656 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: ProfileMenu
|
|
3
|
-
description: User profile menu component with avatar, name, and optional dropdown content
|
|
4
|
-
group: Overlays & Dialogs
|
|
5
|
-
keywords: [profile-menu, user-menu, avatar-menu, account-menu, popover]
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
# ProfileMenu
|
|
9
|
-
|
|
10
|
-
> A specialized popover-based component for user profile menus. Features avatar display, user name, animated purple accent on hover, and optional dropdown content with auto-sizing to match button width.
|
|
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 ProfileMenu
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
`add` also copies any components, hooks, and utilities that `ProfileMenu` 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 { ProfileMenu } from "@/components/ProfileMenu";
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Quick Examples
|
|
33
|
-
|
|
34
|
-
### Basic Usage
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
38
|
-
|
|
39
|
-
function Example() {
|
|
40
|
-
return (
|
|
41
|
-
<ProfileMenu
|
|
42
|
-
label="John Doe"
|
|
43
|
-
icon="/avatar.jpg"
|
|
44
|
-
/>
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### With Dropdown Content
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
53
|
-
import { PopoverItem } from "@/components/Popover";
|
|
54
|
-
|
|
55
|
-
function ProfileDropdown() {
|
|
56
|
-
return (
|
|
57
|
-
<ProfileMenu
|
|
58
|
-
label="John Doe"
|
|
59
|
-
icon="/avatar.jpg"
|
|
60
|
-
popoverChildren={
|
|
61
|
-
<>
|
|
62
|
-
<PopoverItem variant="SystemStyle">My Profile</PopoverItem>
|
|
63
|
-
<PopoverItem variant="SystemStyle">Settings</PopoverItem>
|
|
64
|
-
<PopoverItem variant="SystemStyle">Logout</PopoverItem>
|
|
65
|
-
</>
|
|
66
|
-
}
|
|
67
|
-
/>
|
|
68
|
-
)
|
|
69
|
-
}
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Selected State
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
76
|
-
import { useState } from 'react'
|
|
77
|
-
|
|
78
|
-
function SelectedProfile() {
|
|
79
|
-
const [selected, setSelected] = useState(true)
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<ProfileMenu
|
|
83
|
-
label="John Doe"
|
|
84
|
-
icon="/avatar.jpg"
|
|
85
|
-
selected={selected}
|
|
86
|
-
/>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
### With Overlay Blur
|
|
92
|
-
|
|
93
|
-
```typescript
|
|
94
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
95
|
-
import { PopoverItem } from "@/components/Popover";
|
|
96
|
-
|
|
97
|
-
function BlurredProfileMenu() {
|
|
98
|
-
return (
|
|
99
|
-
<ProfileMenu
|
|
100
|
-
label="Admin User"
|
|
101
|
-
icon="/admin-avatar.jpg"
|
|
102
|
-
overlayBlur={true}
|
|
103
|
-
popoverChildren={
|
|
104
|
-
<>
|
|
105
|
-
<PopoverItem variant="SystemStyle">Admin Dashboard</PopoverItem>
|
|
106
|
-
<PopoverItem variant="SystemStyle">System Settings</PopoverItem>
|
|
107
|
-
<PopoverItem variant="SystemStyle">Sign Out</PopoverItem>
|
|
108
|
-
</>
|
|
109
|
-
}
|
|
110
|
-
/>
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
```
|
|
114
|
-
|
|
115
|
-
### Complete User Menu
|
|
116
|
-
|
|
117
|
-
```typescript
|
|
118
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
119
|
-
import { PopoverItem } from "@/components/Popover";
|
|
120
|
-
import { useRouter } from 'next/navigation'
|
|
121
|
-
|
|
122
|
-
function UserMenu({ user }: { user: User }) {
|
|
123
|
-
const router = useRouter()
|
|
124
|
-
|
|
125
|
-
const handleLogout = () => {
|
|
126
|
-
// Logout logic
|
|
127
|
-
router.push('/login')
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return (
|
|
131
|
-
<ProfileMenu
|
|
132
|
-
label={user.name}
|
|
133
|
-
icon={user.avatar}
|
|
134
|
-
popoverChildren={
|
|
135
|
-
<>
|
|
136
|
-
<PopoverItem
|
|
137
|
-
variant="SystemStyle"
|
|
138
|
-
onClick={() => router.push('/profile')}
|
|
139
|
-
>
|
|
140
|
-
<i className="ri-user-line" />
|
|
141
|
-
<span>My Profile</span>
|
|
142
|
-
</PopoverItem>
|
|
143
|
-
<PopoverItem
|
|
144
|
-
variant="SystemStyle"
|
|
145
|
-
onClick={() => router.push('/settings')}
|
|
146
|
-
>
|
|
147
|
-
<i className="ri-settings-line" />
|
|
148
|
-
<span>Settings</span>
|
|
149
|
-
</PopoverItem>
|
|
150
|
-
<PopoverItem
|
|
151
|
-
variant="SystemStyle"
|
|
152
|
-
onClick={() => router.push('/billing')}
|
|
153
|
-
>
|
|
154
|
-
<i className="ri-bank-card-line" />
|
|
155
|
-
<span>Billing</span>
|
|
156
|
-
</PopoverItem>
|
|
157
|
-
<div className="border-t my-1" />
|
|
158
|
-
<PopoverItem
|
|
159
|
-
variant="Negative"
|
|
160
|
-
onClick={handleLogout}
|
|
161
|
-
>
|
|
162
|
-
<i className="ri-logout-box-line" />
|
|
163
|
-
<span>Sign Out</span>
|
|
164
|
-
</PopoverItem>
|
|
165
|
-
</>
|
|
166
|
-
}
|
|
167
|
-
/>
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### With Status Indicator
|
|
173
|
-
|
|
174
|
-
```typescript
|
|
175
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
176
|
-
import { PopoverItem } from "@/components/Popover";
|
|
177
|
-
|
|
178
|
-
function OnlineProfileMenu() {
|
|
179
|
-
return (
|
|
180
|
-
<ProfileMenu
|
|
181
|
-
label={
|
|
182
|
-
<div className="flex items-center gap-2">
|
|
183
|
-
<span>John Doe</span>
|
|
184
|
-
<span className="w-2 h-2 bg-green-500 rounded-full" />
|
|
185
|
-
</div>
|
|
186
|
-
}
|
|
187
|
-
icon="/avatar.jpg"
|
|
188
|
-
popoverChildren={
|
|
189
|
-
<>
|
|
190
|
-
<PopoverItem variant="SystemStyle">Set Status</PopoverItem>
|
|
191
|
-
<PopoverItem variant="SystemStyle">Profile</PopoverItem>
|
|
192
|
-
<PopoverItem variant="SystemStyle">Logout</PopoverItem>
|
|
193
|
-
</>
|
|
194
|
-
}
|
|
195
|
-
/>
|
|
196
|
-
)
|
|
197
|
-
}
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### With Role Badge
|
|
201
|
-
|
|
202
|
-
```typescript
|
|
203
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
204
|
-
import { Badge } from "@/components/Badge";
|
|
205
|
-
import { PopoverItem } from "@/components/Popover";
|
|
206
|
-
|
|
207
|
-
function AdminProfileMenu({ user }: { user: User }) {
|
|
208
|
-
return (
|
|
209
|
-
<ProfileMenu
|
|
210
|
-
label={
|
|
211
|
-
<div className="flex flex-col items-start">
|
|
212
|
-
<span>{user.name}</span>
|
|
213
|
-
<Badge color="purple" size="XS" label={user.role} />
|
|
214
|
-
</div>
|
|
215
|
-
}
|
|
216
|
-
icon={user.avatar}
|
|
217
|
-
popoverChildren={
|
|
218
|
-
<>
|
|
219
|
-
<PopoverItem variant="SystemStyle">Dashboard</PopoverItem>
|
|
220
|
-
<PopoverItem variant="SystemStyle">Users</PopoverItem>
|
|
221
|
-
<PopoverItem variant="SystemStyle">Settings</PopoverItem>
|
|
222
|
-
</>
|
|
223
|
-
}
|
|
224
|
-
/>
|
|
225
|
-
)
|
|
226
|
-
}
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### Dark Theme
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
233
|
-
import { PopoverItem } from "@/components/Popover";
|
|
234
|
-
|
|
235
|
-
function DarkProfileMenu() {
|
|
236
|
-
return (
|
|
237
|
-
<ProfileMenu
|
|
238
|
-
label="John Doe"
|
|
239
|
-
icon="/avatar.jpg"
|
|
240
|
-
theme="dark"
|
|
241
|
-
popoverChildren={
|
|
242
|
-
<>
|
|
243
|
-
<PopoverItem variant="SystemStyle">Profile</PopoverItem>
|
|
244
|
-
<PopoverItem variant="SystemStyle">Settings</PopoverItem>
|
|
245
|
-
</>
|
|
246
|
-
}
|
|
247
|
-
/>
|
|
248
|
-
)
|
|
249
|
-
}
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Multiple Profile Switcher
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
256
|
-
import { PopoverItem } from "@/components/Popover";
|
|
257
|
-
import { useState } from 'react'
|
|
258
|
-
|
|
259
|
-
function ProfileSwitcher() {
|
|
260
|
-
const [currentUser, setCurrentUser] = useState('user1')
|
|
261
|
-
|
|
262
|
-
const users = [
|
|
263
|
-
{ id: 'user1', name: 'Personal', avatar: '/personal.jpg' },
|
|
264
|
-
{ id: 'user2', name: 'Work', avatar: '/work.jpg' },
|
|
265
|
-
]
|
|
266
|
-
|
|
267
|
-
const current = users.find(u => u.id === currentUser)!
|
|
268
|
-
|
|
269
|
-
return (
|
|
270
|
-
<ProfileMenu
|
|
271
|
-
label={current.name}
|
|
272
|
-
icon={current.avatar}
|
|
273
|
-
popoverChildren={
|
|
274
|
-
<>
|
|
275
|
-
{users.map((user) => (
|
|
276
|
-
<PopoverItem
|
|
277
|
-
key={user.id}
|
|
278
|
-
variant="SystemStyle"
|
|
279
|
-
active={currentUser === user.id}
|
|
280
|
-
onClick={() => setCurrentUser(user.id)}
|
|
281
|
-
>
|
|
282
|
-
<img
|
|
283
|
-
src={user.avatar}
|
|
284
|
-
className="w-6 h-6 rounded-full"
|
|
285
|
-
alt={user.name}
|
|
286
|
-
/>
|
|
287
|
-
<span>{user.name}</span>
|
|
288
|
-
</PopoverItem>
|
|
289
|
-
))}
|
|
290
|
-
<div className="border-t my-1" />
|
|
291
|
-
<PopoverItem variant="SystemStyle">
|
|
292
|
-
Add Account
|
|
293
|
-
</PopoverItem>
|
|
294
|
-
</>
|
|
295
|
-
}
|
|
296
|
-
/>
|
|
297
|
-
)
|
|
298
|
-
}
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### With Custom Actions
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
305
|
-
import { PopoverItem } from "@/components/Popover";
|
|
306
|
-
|
|
307
|
-
function ActionsProfileMenu() {
|
|
308
|
-
return (
|
|
309
|
-
<ProfileMenu
|
|
310
|
-
label="Developer"
|
|
311
|
-
icon="/dev-avatar.jpg"
|
|
312
|
-
popoverChildren={
|
|
313
|
-
<>
|
|
314
|
-
<PopoverItem variant="SystemStyle">
|
|
315
|
-
<i className="ri-code-line" />
|
|
316
|
-
<span>View Source</span>
|
|
317
|
-
</PopoverItem>
|
|
318
|
-
<PopoverItem variant="SystemStyle">
|
|
319
|
-
<i className="ri-terminal-line" />
|
|
320
|
-
<span>Open Terminal</span>
|
|
321
|
-
</PopoverItem>
|
|
322
|
-
<PopoverItem variant="SystemStyle">
|
|
323
|
-
<i className="ri-bug-line" />
|
|
324
|
-
<span>Report Issue</span>
|
|
325
|
-
</PopoverItem>
|
|
326
|
-
</>
|
|
327
|
-
}
|
|
328
|
-
/>
|
|
329
|
-
)
|
|
330
|
-
}
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
### With Keyboard Shortcuts
|
|
334
|
-
|
|
335
|
-
```typescript
|
|
336
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
337
|
-
import { PopoverItem } from "@/components/Popover";
|
|
338
|
-
|
|
339
|
-
function ShortcutProfileMenu() {
|
|
340
|
-
return (
|
|
341
|
-
<ProfileMenu
|
|
342
|
-
label="Pro User"
|
|
343
|
-
icon="/pro-avatar.jpg"
|
|
344
|
-
popoverChildren={
|
|
345
|
-
<>
|
|
346
|
-
<PopoverItem variant="SystemStyle">
|
|
347
|
-
<span>Profile</span>
|
|
348
|
-
<span className="ml-auto text-xs opacity-60">⌘P</span>
|
|
349
|
-
</PopoverItem>
|
|
350
|
-
<PopoverItem variant="SystemStyle">
|
|
351
|
-
<span>Settings</span>
|
|
352
|
-
<span className="ml-auto text-xs opacity-60">⌘,</span>
|
|
353
|
-
</PopoverItem>
|
|
354
|
-
<PopoverItem variant="SystemStyle">
|
|
355
|
-
<span>Help</span>
|
|
356
|
-
<span className="ml-auto text-xs opacity-60">⌘?</span>
|
|
357
|
-
</PopoverItem>
|
|
358
|
-
</>
|
|
359
|
-
}
|
|
360
|
-
/>
|
|
361
|
-
)
|
|
362
|
-
}
|
|
363
|
-
```
|
|
364
|
-
|
|
365
|
-
## API Reference
|
|
366
|
-
|
|
367
|
-
### ProfileMenu Props
|
|
368
|
-
|
|
369
|
-
| Prop | Type | Default | Description |
|
|
370
|
-
|------|------|---------|-------------|
|
|
371
|
-
| `label` | `ReactNode` | Required | User name or label content |
|
|
372
|
-
| `icon` | `string` | - | Avatar image URL |
|
|
373
|
-
| `selected` | `boolean` | `false` | Selected/active state |
|
|
374
|
-
| `theme` | `'dark' \| 'light' \| 'default'` | - | Theme variant |
|
|
375
|
-
| `popoverChildren` | `ReactNode` | - | Dropdown menu content |
|
|
376
|
-
| `overlayBlur` | `boolean` | `false` | Add blurred backdrop |
|
|
377
|
-
| `className` | `string` | - | Additional CSS classes |
|
|
378
|
-
| `onClick` | `() => void` | - | Click handler for button |
|
|
379
|
-
| `onPointerDown` | `(e: PointerEvent) => void` | - | Pointer down handler |
|
|
380
|
-
|
|
381
|
-
## TypeScript
|
|
382
|
-
|
|
383
|
-
### Full Type Definitions
|
|
384
|
-
|
|
385
|
-
```typescript
|
|
386
|
-
import { HTMLAttributes, ReactNode } from 'react'
|
|
387
|
-
|
|
388
|
-
interface ProfileMenuProps extends HTMLAttributes<HTMLButtonElement> {
|
|
389
|
-
label: ReactNode
|
|
390
|
-
icon?: string
|
|
391
|
-
selected?: boolean
|
|
392
|
-
theme?: 'dark' | 'light' | 'default'
|
|
393
|
-
popoverChildren?: ReactNode
|
|
394
|
-
overlayBlur?: boolean
|
|
395
|
-
className?: string
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
export const ProfileMenu: React.FC<ProfileMenuProps>
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
### Usage with TypeScript
|
|
402
|
-
|
|
403
|
-
```typescript
|
|
404
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
405
|
-
|
|
406
|
-
interface User {
|
|
407
|
-
name: string
|
|
408
|
-
avatar: string
|
|
409
|
-
role: string
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
function TypedProfileMenu({ user }: { user: User }) {
|
|
413
|
-
const profileMenuProps: React.ComponentProps<typeof ProfileMenu> = {
|
|
414
|
-
label: user.name,
|
|
415
|
-
icon: user.avatar,
|
|
416
|
-
theme: 'dark',
|
|
417
|
-
popoverChildren: (
|
|
418
|
-
<>
|
|
419
|
-
{/* Menu items */}
|
|
420
|
-
</>
|
|
421
|
-
),
|
|
422
|
-
}
|
|
423
|
-
|
|
424
|
-
return <ProfileMenu {...profileMenuProps} />
|
|
425
|
-
}
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
## Features
|
|
429
|
-
|
|
430
|
-
### Visual Effects
|
|
431
|
-
|
|
432
|
-
**Purple Accent on Hover**:
|
|
433
|
-
- Purple line indicator appears on left
|
|
434
|
-
- Arrow icon turns purple
|
|
435
|
-
- Smooth transition (150ms)
|
|
436
|
-
|
|
437
|
-
**Arrow Rotation**:
|
|
438
|
-
- Rotates 180° when dropdown opens
|
|
439
|
-
- Smooth animation
|
|
440
|
-
- Visual feedback for state
|
|
441
|
-
|
|
442
|
-
**Auto-Sizing**:
|
|
443
|
-
- Dropdown width matches button width
|
|
444
|
-
- Maintains consistent UI alignment
|
|
445
|
-
- Responsive to content
|
|
446
|
-
|
|
447
|
-
### Interaction States
|
|
448
|
-
|
|
449
|
-
**Default State**:
|
|
450
|
-
- Gray text and icon
|
|
451
|
-
- No background
|
|
452
|
-
- Subtle hover effect
|
|
453
|
-
|
|
454
|
-
**Hover State**:
|
|
455
|
-
- Purple accent line (left side)
|
|
456
|
-
- Purple arrow icon
|
|
457
|
-
- Light background highlight
|
|
458
|
-
|
|
459
|
-
**Selected State**:
|
|
460
|
-
- Purple accent visible
|
|
461
|
-
- Active background color
|
|
462
|
-
- Indicates current selection
|
|
463
|
-
|
|
464
|
-
**Open State**:
|
|
465
|
-
- Arrow rotated 180°
|
|
466
|
-
- Dropdown visible below
|
|
467
|
-
- z-index elevated
|
|
468
|
-
|
|
469
|
-
## Common Patterns
|
|
470
|
-
|
|
471
|
-
### Navigation Bar Profile
|
|
472
|
-
|
|
473
|
-
```typescript
|
|
474
|
-
function NavBarProfile({ user }: { user: User }) {
|
|
475
|
-
return (
|
|
476
|
-
<nav className="flex items-center justify-between p-4">
|
|
477
|
-
<div>Logo</div>
|
|
478
|
-
<div className="flex items-center gap-4">
|
|
479
|
-
<button>Notifications</button>
|
|
480
|
-
<ProfileMenu
|
|
481
|
-
label={user.name}
|
|
482
|
-
icon={user.avatar}
|
|
483
|
-
popoverChildren={
|
|
484
|
-
<>
|
|
485
|
-
<PopoverItem variant="SystemStyle">Profile</PopoverItem>
|
|
486
|
-
<PopoverItem variant="SystemStyle">Logout</PopoverItem>
|
|
487
|
-
</>
|
|
488
|
-
}
|
|
489
|
-
/>
|
|
490
|
-
</div>
|
|
491
|
-
</nav>
|
|
492
|
-
)
|
|
493
|
-
}
|
|
494
|
-
```
|
|
495
|
-
|
|
496
|
-
### Sidebar Profile
|
|
497
|
-
|
|
498
|
-
```typescript
|
|
499
|
-
function SidebarProfile({ user }: { user: User }) {
|
|
500
|
-
return (
|
|
501
|
-
<div className="sidebar">
|
|
502
|
-
{/* Sidebar content */}
|
|
503
|
-
<div className="mt-auto p-4">
|
|
504
|
-
<ProfileMenu
|
|
505
|
-
label={user.name}
|
|
506
|
-
icon={user.avatar}
|
|
507
|
-
selected
|
|
508
|
-
popoverChildren={
|
|
509
|
-
<>
|
|
510
|
-
<PopoverItem variant="SystemStyle">Switch Account</PopoverItem>
|
|
511
|
-
<PopoverItem variant="SystemStyle">Settings</PopoverItem>
|
|
512
|
-
<PopoverItem variant="SystemStyle">Sign Out</PopoverItem>
|
|
513
|
-
</>
|
|
514
|
-
}
|
|
515
|
-
/>
|
|
516
|
-
</div>
|
|
517
|
-
</div>
|
|
518
|
-
)
|
|
519
|
-
}
|
|
520
|
-
```
|
|
521
|
-
|
|
522
|
-
## Testing
|
|
523
|
-
|
|
524
|
-
### Unit Test Example
|
|
525
|
-
|
|
526
|
-
```typescript
|
|
527
|
-
import { render, screen, fireEvent } from '@testing-library/react'
|
|
528
|
-
import { ProfileMenu } from "@/components/ProfileMenu";
|
|
529
|
-
import { PopoverItem } from "@/components/Popover";
|
|
530
|
-
|
|
531
|
-
describe('ProfileMenu', () => {
|
|
532
|
-
it('renders user name and avatar', () => {
|
|
533
|
-
render(
|
|
534
|
-
<ProfileMenu
|
|
535
|
-
label="Test User"
|
|
536
|
-
icon="/test-avatar.jpg"
|
|
537
|
-
/>
|
|
538
|
-
)
|
|
539
|
-
|
|
540
|
-
expect(screen.getByText('Test User')).toBeInTheDocument()
|
|
541
|
-
expect(screen.getByRole('img')).toHaveAttribute('src', '/test-avatar.jpg')
|
|
542
|
-
})
|
|
543
|
-
|
|
544
|
-
it('opens dropdown on click', () => {
|
|
545
|
-
render(
|
|
546
|
-
<ProfileMenu
|
|
547
|
-
label="Test User"
|
|
548
|
-
icon="/avatar.jpg"
|
|
549
|
-
popoverChildren={
|
|
550
|
-
<PopoverItem>Profile</PopoverItem>
|
|
551
|
-
}
|
|
552
|
-
/>
|
|
553
|
-
)
|
|
554
|
-
|
|
555
|
-
fireEvent.click(screen.getByText('Test User'))
|
|
556
|
-
expect(screen.getByText('Profile')).toBeInTheDocument()
|
|
557
|
-
})
|
|
558
|
-
|
|
559
|
-
it('handles menu item click', () => {
|
|
560
|
-
const handleClick = jest.fn()
|
|
561
|
-
|
|
562
|
-
render(
|
|
563
|
-
<ProfileMenu
|
|
564
|
-
label="User"
|
|
565
|
-
icon="/avatar.jpg"
|
|
566
|
-
popoverChildren={
|
|
567
|
-
<PopoverItem onClick={handleClick}>Logout</PopoverItem>
|
|
568
|
-
}
|
|
569
|
-
/>
|
|
570
|
-
)
|
|
571
|
-
|
|
572
|
-
fireEvent.click(screen.getByText('User'))
|
|
573
|
-
fireEvent.click(screen.getByText('Logout'))
|
|
574
|
-
expect(handleClick).toHaveBeenCalled()
|
|
575
|
-
})
|
|
576
|
-
})
|
|
577
|
-
```
|
|
578
|
-
|
|
579
|
-
## Accessibility
|
|
580
|
-
|
|
581
|
-
- **Keyboard Support**:
|
|
582
|
-
- Enter/Space: Open dropdown
|
|
583
|
-
- Arrow keys: Navigate menu items
|
|
584
|
-
- Escape: Close dropdown
|
|
585
|
-
- **ARIA Attributes**: Inherited from Popover component
|
|
586
|
-
- **Focus Management**: Keyboard navigation supported
|
|
587
|
-
- **Screen Readers**: Announces user name and menu items
|
|
588
|
-
|
|
589
|
-
### Accessibility Best Practices
|
|
590
|
-
|
|
591
|
-
```typescript
|
|
592
|
-
// Provide alt text for avatar
|
|
593
|
-
<ProfileMenu
|
|
594
|
-
label="John Doe"
|
|
595
|
-
icon="/avatar.jpg"
|
|
596
|
-
// Ensure PopoverItems have clear labels
|
|
597
|
-
popoverChildren={
|
|
598
|
-
<PopoverItem aria-label="View profile">
|
|
599
|
-
Profile
|
|
600
|
-
</PopoverItem>
|
|
601
|
-
}
|
|
602
|
-
/>
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
## Performance
|
|
606
|
-
|
|
607
|
-
| Metric | Value |
|
|
608
|
-
|--------|-------|
|
|
609
|
-
| Bundle size (minified) | ~2kb |
|
|
610
|
-
| Bundle size (gzipped) | ~1kb |
|
|
611
|
-
| Dependencies | Internal Popover |
|
|
612
|
-
| Hover animation | 150ms |
|
|
613
|
-
| Arrow rotation | Smooth CSS transition |
|
|
614
|
-
| Tree-shakeable | ✅ |
|
|
615
|
-
|
|
616
|
-
### Performance Tips
|
|
617
|
-
|
|
618
|
-
1. **Optimize avatar images**: Use appropriate sizes
|
|
619
|
-
```typescript
|
|
620
|
-
// Use optimized 28x28px images
|
|
621
|
-
<ProfileMenu icon="/avatar-28x28.jpg" />
|
|
622
|
-
```
|
|
623
|
-
|
|
624
|
-
2. **Lazy load dropdown content**: Render only when open
|
|
625
|
-
3. **Memoize menu items**: Prevent unnecessary re-renders
|
|
626
|
-
|
|
627
|
-
## Best Practices
|
|
628
|
-
|
|
629
|
-
1. **Always provide label and icon**: Both required for proper UI
|
|
630
|
-
```typescript
|
|
631
|
-
<ProfileMenu label="User Name" icon="/avatar.jpg" />
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
2. **Use selected state for active profiles**: Visual feedback
|
|
635
|
-
```typescript
|
|
636
|
-
<ProfileMenu selected={isActive} />
|
|
637
|
-
```
|
|
638
|
-
|
|
639
|
-
3. **Group related menu items**: Use separators
|
|
640
|
-
```typescript
|
|
641
|
-
<PopoverItem>Profile</PopoverItem>
|
|
642
|
-
<div className="border-t my-1" />
|
|
643
|
-
<PopoverItem>Logout</PopoverItem>
|
|
644
|
-
```
|
|
645
|
-
|
|
646
|
-
4. **Place at consistent location**: Typically top-right or sidebar bottom
|
|
647
|
-
5. **Use overlay blur for critical actions**: Important confirmations
|
|
648
|
-
6. **Provide logout option**: Always include sign out
|
|
649
|
-
7. **Consider multi-account switching**: If applicable
|
|
650
|
-
|
|
651
|
-
## Related Components
|
|
652
|
-
|
|
653
|
-
- [Popover](./popover.md) - Base popover component
|
|
654
|
-
- [PopoverItem](./popover.md#popoveritem) - Menu item component
|
|
655
|
-
- [Avatar](./avatar.md) - Avatar display component
|
|
656
|
-
- [DropdownMenu](./dropdown-menu.md) - Alternative menu component
|