@redis-ui/components 42.8.0 → 43.2.1

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.
Files changed (228) hide show
  1. package/dist/AutoCompleteSelect/AutoCompleteSelect.cjs +7 -1
  2. package/dist/AutoCompleteSelect/AutoCompleteSelect.js +7 -1
  3. package/dist/AutoCompleteSelect/hooks/useAutoCompleteSelect.cjs +7 -1
  4. package/dist/AutoCompleteSelect/hooks/useAutoCompleteSelect.d.ts +8 -1
  5. package/dist/AutoCompleteSelect/hooks/useAutoCompleteSelect.js +7 -1
  6. package/dist/BoxSelectionGroup/components/Item/components/BoxStateIndicator/BoxStateIndicator.cjs +8 -4
  7. package/dist/BoxSelectionGroup/components/Item/components/BoxStateIndicator/BoxStateIndicator.js +8 -4
  8. package/dist/BoxSelectionGroup/components/Item/components/Compose/Compose.style.cjs +18 -4
  9. package/dist/BoxSelectionGroup/components/Item/components/Compose/Compose.style.js +18 -4
  10. package/dist/BoxSelectionGroup/hooks/useBoxSelectionGroup.cjs +3 -1
  11. package/dist/BoxSelectionGroup/hooks/useBoxSelectionGroup.js +3 -1
  12. package/dist/Button/Button.style.cjs +4 -1
  13. package/dist/Button/Button.style.js +4 -1
  14. package/dist/Button/Button.style.utils.cjs +16 -1
  15. package/dist/Button/Button.style.utils.js +16 -1
  16. package/dist/Button/Button.types.cjs +1 -1
  17. package/dist/Button/Button.types.d.ts +1 -1
  18. package/dist/Button/Button.types.js +1 -1
  19. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.cjs +59 -0
  20. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.d.ts +4 -0
  21. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.js +57 -0
  22. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.cjs +40 -0
  23. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.d.ts +8 -0
  24. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.style.js +38 -0
  25. package/dist/Button/CopyToClipboardButton/CopyToClipboardButton.types.d.ts +5 -0
  26. package/dist/Button/TextButton/TextButton.style.cjs +4 -1
  27. package/dist/Button/TextButton/TextButton.style.js +4 -1
  28. package/dist/Button/TextButton/TextButton.types.cjs +1 -1
  29. package/dist/Button/TextButton/TextButton.types.d.ts +1 -1
  30. package/dist/Button/TextButton/TextButton.types.js +1 -1
  31. package/dist/Button/index.d.ts +2 -0
  32. package/dist/Checkbox/components/Label/Label.style.cjs +15 -3
  33. package/dist/Checkbox/components/Label/Label.style.js +15 -3
  34. package/dist/Chip/components/CloseButton/CloseButton.cjs +3 -1
  35. package/dist/Chip/components/CloseButton/CloseButton.js +3 -1
  36. package/dist/Chip/components/Compose/Compose.style.cjs +4 -1
  37. package/dist/Chip/components/Compose/Compose.style.js +4 -1
  38. package/dist/Drawer/components/Description/Description.cjs +3 -1
  39. package/dist/Drawer/components/Description/Description.js +3 -1
  40. package/dist/Helpers/contexts/Popper/PopperCollisionBoundaryManager.cjs +3 -1
  41. package/dist/Helpers/contexts/Popper/PopperCollisionBoundaryManager.js +3 -1
  42. package/dist/Helpers/contexts/PrimitiveContextState.cjs +28 -16
  43. package/dist/Helpers/contexts/PrimitiveContextState.js +28 -16
  44. package/dist/Helpers/contexts/SharedId.context.cjs +9 -5
  45. package/dist/Helpers/contexts/SharedId.context.js +9 -5
  46. package/dist/Helpers/css.utils.cjs +18 -4
  47. package/dist/Helpers/css.utils.d.ts +15 -3
  48. package/dist/Helpers/css.utils.js +18 -4
  49. package/dist/Helpers/hooks/useScrollable.cjs +3 -1
  50. package/dist/Helpers/hooks/useScrollable.js +3 -1
  51. package/dist/Helpers/react.utils.cjs +6 -2
  52. package/dist/Helpers/react.utils.js +6 -2
  53. package/dist/HighlightedIcon/HighlightedIcon.cjs +26 -0
  54. package/dist/HighlightedIcon/HighlightedIcon.d.ts +3 -0
  55. package/dist/HighlightedIcon/HighlightedIcon.js +26 -0
  56. package/dist/HighlightedIcon/HighlightedIcon.style.cjs +49 -0
  57. package/dist/HighlightedIcon/HighlightedIcon.style.d.ts +5 -0
  58. package/dist/HighlightedIcon/HighlightedIcon.style.js +47 -0
  59. package/dist/HighlightedIcon/HighlightedIcon.types.d.ts +8 -0
  60. package/dist/HighlightedIcon/index.d.ts +3 -0
  61. package/dist/Inputs/QuantityCounter/components/InputGroup/components/ValueLabel/ValueLabel.cjs +9 -5
  62. package/dist/Inputs/QuantityCounter/components/InputGroup/components/ValueLabel/ValueLabel.js +9 -5
  63. package/dist/Inputs/components/Compose/Compose.style.cjs +29 -6
  64. package/dist/Inputs/components/Compose/Compose.style.js +29 -6
  65. package/dist/Inputs/hooks/numericInput/numericInput.utils.cjs +12 -4
  66. package/dist/Inputs/hooks/numericInput/numericInput.utils.js +12 -4
  67. package/dist/Inputs/hooks/numericInput/useNumericInput.cjs +15 -3
  68. package/dist/Inputs/hooks/numericInput/useNumericInput.js +15 -3
  69. package/dist/Loader/Loader.cjs +1 -0
  70. package/dist/Loader/Loader.js +1 -0
  71. package/dist/Menu/components/Content/components/Item/Components/Compose/Compose.style.cjs +19 -4
  72. package/dist/Menu/components/Content/components/Item/Components/Compose/Compose.style.js +19 -4
  73. package/dist/Menu/components/Content/components/Label/components/Compose/Compose.style.cjs +4 -1
  74. package/dist/Menu/components/Content/components/Label/components/Compose/Compose.style.js +4 -1
  75. package/dist/Modal/components/Content/components/Compose/Compose.cjs +3 -1
  76. package/dist/Modal/components/Content/components/Compose/Compose.js +3 -1
  77. package/dist/Modal/components/Content/components/Description/Description.cjs +3 -1
  78. package/dist/Modal/components/Content/components/Description/Description.js +3 -1
  79. package/dist/MultiSelect/components/Compose/hooks/useMultiSelectContextApi.cjs +3 -1
  80. package/dist/MultiSelect/components/Compose/hooks/useMultiSelectContextApi.js +3 -1
  81. package/dist/MultiSelect/components/Trigger/components/MultiValue/MultiValue.cjs +3 -1
  82. package/dist/MultiSelect/components/Trigger/components/MultiValue/MultiValue.js +3 -1
  83. package/dist/Overflow/Overflow.cjs +3 -1
  84. package/dist/Overflow/Overflow.js +3 -1
  85. package/dist/Overflow/Overflow.utils.cjs +15 -6
  86. package/dist/Overflow/Overflow.utils.js +15 -6
  87. package/dist/Overflow/components/OverflowContainer/OverflowContainer.cjs +3 -1
  88. package/dist/Overflow/components/OverflowContainer/OverflowContainer.js +3 -1
  89. package/dist/Pagination/components/PageSizeSelect.cjs +3 -1
  90. package/dist/Pagination/components/PageSizeSelect.js +3 -1
  91. package/dist/Popover/components/Content/Content.cjs +3 -1
  92. package/dist/Popover/components/Content/Content.js +3 -1
  93. package/dist/Popover/components/Content/components/Footer/Footer.cjs +3 -1
  94. package/dist/Popover/components/Content/components/Footer/Footer.js +3 -1
  95. package/dist/RadioGroup/components/Item/components/Label/Label.style.cjs +15 -3
  96. package/dist/RadioGroup/components/Item/components/Label/Label.style.js +15 -3
  97. package/dist/ScreenReaderAnnounce/ScreenReaderAnnounce.cjs +3 -1
  98. package/dist/ScreenReaderAnnounce/ScreenReaderAnnounce.js +3 -1
  99. package/dist/Section/components/Header/components/CollapseButton/CollapseButton.cjs +3 -1
  100. package/dist/Section/components/Header/components/CollapseButton/CollapseButton.js +3 -1
  101. package/dist/Select/components/Content/components/Option/components/Compose/Compose.style.cjs +16 -4
  102. package/dist/Select/components/Content/components/Option/components/Compose/Compose.style.js +16 -4
  103. package/dist/Select/components/Content/components/OptionList/OptionList.cjs +6 -4
  104. package/dist/Select/components/Content/components/OptionList/OptionList.js +6 -4
  105. package/dist/Select/components/Content/components/OptionList/Virtual.cjs +9 -5
  106. package/dist/Select/components/Content/components/OptionList/Virtual.js +9 -5
  107. package/dist/Select/components/Context/hooks/useSearch.cjs +3 -1
  108. package/dist/Select/components/Context/hooks/useSearch.js +3 -1
  109. package/dist/Select/components/Trigger/components/Compose/Compose.style.cjs +33 -7
  110. package/dist/Select/components/Trigger/components/Compose/Compose.style.js +33 -7
  111. package/dist/SideBar/components/Item/Item.style.cjs +14 -3
  112. package/dist/SideBar/components/Item/Item.style.js +14 -3
  113. package/dist/Skeleton/components/Circle/Circle.cjs +1 -1
  114. package/dist/Skeleton/components/Circle/Circle.js +1 -1
  115. package/dist/Skeleton/components/Square/Square.cjs +1 -1
  116. package/dist/Skeleton/components/Square/Square.js +1 -1
  117. package/dist/Slider/components/Label/Compose/Compose.cjs +3 -1
  118. package/dist/Slider/components/Label/Compose/Compose.js +3 -1
  119. package/dist/Slider/components/Mark/Compose/Compose.cjs +3 -1
  120. package/dist/Slider/components/Mark/Compose/Compose.js +3 -1
  121. package/dist/Slider/hooks/useOffset.cjs +3 -1
  122. package/dist/Slider/hooks/useOffset.js +3 -1
  123. package/dist/Stepper/Stepper.cjs +14 -5
  124. package/dist/Stepper/Stepper.d.ts +2 -0
  125. package/dist/Stepper/Stepper.js +14 -5
  126. package/dist/Stepper/Stepper.utils.cjs +12 -0
  127. package/dist/Stepper/Stepper.utils.d.ts +2 -0
  128. package/dist/Stepper/Stepper.utils.js +12 -0
  129. package/dist/Stepper/components/Compose/Compose.d.ts +1 -0
  130. package/dist/Stepper/components/Step/Step.cjs +2 -0
  131. package/dist/Stepper/components/Step/Step.d.ts +1 -0
  132. package/dist/Stepper/components/Step/Step.js +2 -0
  133. package/dist/Stepper/components/Step/components/Compose/Compose.cjs +5 -10
  134. package/dist/Stepper/components/Step/components/Compose/Compose.js +5 -10
  135. package/dist/Stepper/components/Step/components/Separator/Separator.cjs +15 -0
  136. package/dist/Stepper/components/Step/components/Separator/Separator.d.ts +3 -0
  137. package/dist/Stepper/components/Step/components/Separator/Separator.js +15 -0
  138. package/dist/Stepper/components/Step/components/Separator/Separator.style.cjs +24 -0
  139. package/dist/Stepper/components/Step/components/Separator/Separator.style.d.ts +1 -0
  140. package/dist/Stepper/components/Step/components/Separator/Separator.style.js +22 -0
  141. package/dist/Stepper/components/Step/components/Separator/Separator.types.d.ts +5 -0
  142. package/dist/Stepper/hooks/useStepperInteractive.cjs +12 -4
  143. package/dist/Stepper/hooks/useStepperInteractive.js +12 -4
  144. package/dist/Switch/components/Switcher/Switcher.cjs +3 -1
  145. package/dist/Switch/components/Switcher/Switcher.js +3 -1
  146. package/dist/Switch/components/Switcher/Switcher.style.cjs +31 -8
  147. package/dist/Switch/components/Switcher/Switcher.style.js +31 -8
  148. package/dist/Tabs/components/TabBar/components/Trigger/components/Marker/Marker.style.cjs +24 -5
  149. package/dist/Tabs/components/TabBar/components/Trigger/components/Marker/Marker.style.js +24 -5
  150. package/dist/Tabs/components/TabBar/components/Trigger/components/Tab/Tab.style.cjs +24 -5
  151. package/dist/Tabs/components/TabBar/components/Trigger/components/Tab/Tab.style.js +24 -5
  152. package/dist/ThemeModeSwitch/useThemeModeSwitch.cjs +6 -2
  153. package/dist/ThemeModeSwitch/useThemeModeSwitch.js +6 -2
  154. package/dist/Toast/core/content.helper.cjs +8 -4
  155. package/dist/Toast/core/content.helper.js +8 -4
  156. package/dist/Tooltip/components/Content/Content.cjs +3 -1
  157. package/dist/Tooltip/components/Content/Content.js +3 -1
  158. package/dist/TreeView/TreeView.cjs +3 -1
  159. package/dist/TreeView/TreeView.js +3 -1
  160. package/dist/TreeView/components/TreeItem/components/Compose/Compose.cjs +6 -4
  161. package/dist/TreeView/components/TreeItem/components/Compose/Compose.js +6 -4
  162. package/dist/Typography/Typography.types.cjs +4 -0
  163. package/dist/Typography/Typography.types.d.ts +2 -1
  164. package/dist/Typography/Typography.types.js +4 -0
  165. package/dist/index.cjs +8 -0
  166. package/dist/index.d.ts +1 -0
  167. package/dist/index.js +98 -90
  168. package/package.json +10 -9
  169. package/skills/redis-ui-components/SKILL.md +126 -0
  170. package/skills/redis-ui-components/references/ActionIconButton.md +96 -0
  171. package/skills/redis-ui-components/references/AppBar.md +161 -0
  172. package/skills/redis-ui-components/references/AppSelectionMenu.md +184 -0
  173. package/skills/redis-ui-components/references/AutoCompleteSelect.md +193 -0
  174. package/skills/redis-ui-components/references/Badge.md +77 -0
  175. package/skills/redis-ui-components/references/Banner.md +563 -0
  176. package/skills/redis-ui-components/references/BoxSelectionGroup.md +487 -0
  177. package/skills/redis-ui-components/references/Breadcrumbs.md +214 -0
  178. package/skills/redis-ui-components/references/Button.md +169 -0
  179. package/skills/redis-ui-components/references/ButtonGroup.md +126 -0
  180. package/skills/redis-ui-components/references/Card.md +56 -0
  181. package/skills/redis-ui-components/references/Checkbox.md +171 -0
  182. package/skills/redis-ui-components/references/Chip.md +154 -0
  183. package/skills/redis-ui-components/references/ChipList.md +307 -0
  184. package/skills/redis-ui-components/references/CopyToClipboardButton.md +47 -0
  185. package/skills/redis-ui-components/references/CountryFlag.md +57 -0
  186. package/skills/redis-ui-components/references/Drawer.md +298 -0
  187. package/skills/redis-ui-components/references/Filters.md +162 -0
  188. package/skills/redis-ui-components/references/FlexDivider.md +152 -0
  189. package/skills/redis-ui-components/references/FlexGroup.md +149 -0
  190. package/skills/redis-ui-components/references/FlexItem.md +58 -0
  191. package/skills/redis-ui-components/references/FlexSplit.md +37 -0
  192. package/skills/redis-ui-components/references/FormField.md +678 -0
  193. package/skills/redis-ui-components/references/IconButton.md +63 -0
  194. package/skills/redis-ui-components/references/Input.md +295 -0
  195. package/skills/redis-ui-components/references/KeyValueList.md +501 -0
  196. package/skills/redis-ui-components/references/Label.md +238 -0
  197. package/skills/redis-ui-components/references/Link.md +402 -0
  198. package/skills/redis-ui-components/references/Loader.md +100 -0
  199. package/skills/redis-ui-components/references/Menu.md +988 -0
  200. package/skills/redis-ui-components/references/MidBar.md +358 -0
  201. package/skills/redis-ui-components/references/Modal.md +525 -0
  202. package/skills/redis-ui-components/references/MoreInfoIcon.md +119 -0
  203. package/skills/redis-ui-components/references/MultiSelect.md +558 -0
  204. package/skills/redis-ui-components/references/NumericInput.md +322 -0
  205. package/skills/redis-ui-components/references/Overflow.md +127 -0
  206. package/skills/redis-ui-components/references/Pagination.md +151 -0
  207. package/skills/redis-ui-components/references/PasswordInput.md +262 -0
  208. package/skills/redis-ui-components/references/Popover.md +868 -0
  209. package/skills/redis-ui-components/references/ProfileIcon.md +65 -0
  210. package/skills/redis-ui-components/references/ProgressBar.md +103 -0
  211. package/skills/redis-ui-components/references/QuantityCounter.md +555 -0
  212. package/skills/redis-ui-components/references/RadioGroup.md +265 -0
  213. package/skills/redis-ui-components/references/ScreenReaderAnnounce.md +147 -0
  214. package/skills/redis-ui-components/references/SearchBar.md +242 -0
  215. package/skills/redis-ui-components/references/SearchInput.md +213 -0
  216. package/skills/redis-ui-components/references/Section.md +349 -0
  217. package/skills/redis-ui-components/references/Select.md +517 -0
  218. package/skills/redis-ui-components/references/SideBar.md +468 -0
  219. package/skills/redis-ui-components/references/Slider.md +398 -0
  220. package/skills/redis-ui-components/references/Stepper.md +288 -0
  221. package/skills/redis-ui-components/references/Switch.md +193 -0
  222. package/skills/redis-ui-components/references/Tabs.md +383 -0
  223. package/skills/redis-ui-components/references/TextArea.md +139 -0
  224. package/skills/redis-ui-components/references/TextButton.md +217 -0
  225. package/skills/redis-ui-components/references/Toast.md +399 -0
  226. package/skills/redis-ui-components/references/ToggleButton.md +163 -0
  227. package/skills/redis-ui-components/references/Tooltip.md +636 -0
  228. package/skills/redis-ui-components/references/Typography.md +323 -0
@@ -0,0 +1,868 @@
1
+ # Popover
2
+
3
+ Popup component with trigger/content composition and a richer `Popover.Card` surface for formatted content.
4
+
5
+ ## Import
6
+
7
+ ```tsx
8
+ import { Popover } from '@redislabsdev/redis-ui-components';
9
+ ```
10
+
11
+ If you use the story examples that rely on icons, also import them from `@redislabsdev/redis-ui-icons`.
12
+
13
+ ## Props
14
+
15
+ | Prop | Type | Default | Description |
16
+ |------|------|---------|-------------|
17
+ | children | `React.ReactNode` | required | Trigger content rendered inside the popover |
18
+ | content | `React.ReactNode` | - | Content rendered inside the popover popup |
19
+ | defaultOpen | `boolean` | - | Uncontrolled initial open state |
20
+ | open | `boolean` | `visible` | Controlled open state |
21
+ | onOpenChange | `(open: boolean) => void` | `onVisibilityChange` | Controlled open-state callback |
22
+ | disabled | `boolean` | - | Disables opening and closes controlled content |
23
+ | visible | `boolean` | - | Deprecated alias for `open` |
24
+ | onVisibilityChange | `(open: boolean) => void` | - | Deprecated alias for `onOpenChange` |
25
+ | withButton | `boolean` | - | Wraps the trigger in an invisible button when needed |
26
+ | placement | `'top' \| 'bottom' \| 'left' \| 'right'` | `bottom` | Preferred popup side |
27
+ | sideOffset | `number` | `5` | Offset between trigger and popup |
28
+ | persistent | `boolean` | `false` | Prevents closing on outside click |
29
+ | onClickOutside | `(event) => void` | - | Outside click handler |
30
+ | alignOffset | `number` | - | Additional alignment offset |
31
+ | align | `'start' \| 'center' \| 'end'` | `center` | Alignment against the trigger |
32
+ | maxWidth | `string` | - | Max popup width override |
33
+ | portal | `HTMLElement \| null` | `document.body` | Portal container or `null` to render inline |
34
+ | collisionBoundary | `RadixPopover.PopoverContentProps['collisionBoundary']` | - | Radix collision boundary override |
35
+ | windowBar | `WindowBarProps` | - | Deprecated `Popover.Content` alias for `Popover.Card` window bar content |
36
+ | title | `string` | - | Deprecated `Popover.Content` alias for card header title |
37
+ | text | `ContentBodyProps['text']` | - | Deprecated `Popover.Content` alias for card body text |
38
+ | actionButtonText | `string` | - | Deprecated `Popover.Content` alias for card footer action label |
39
+ | actionButtonHandler | `(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void` | - | Deprecated `Popover.Content` alias for card footer action callback |
40
+ | link | `string` | - | Deprecated `Popover.Content` alias for card footer link |
41
+ | linkText | `string` | - | Deprecated `Popover.Content` alias for card footer link text |
42
+
43
+ ## Sub-components
44
+
45
+ - `Popover.Compose` - Controlled root wrapper.
46
+ - `Popover.Trigger` - Trigger wrapper for button and non-button triggers.
47
+ - `Popover.Content` - Popup content surface.
48
+ - `Popover.Card` - Rich content card surface.
49
+ - `Popover.Content.Text` - Text wrapper for string content inside `Popover.Content`.
50
+ - `Popover.Card.Close` - Close button alias for `Popover.Content.Close`.
51
+
52
+ ## Examples
53
+
54
+ ### Playground
55
+
56
+ ```tsx
57
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
58
+
59
+ <Popover content="Popovers can display any content" onOpenChange={() => {}}>
60
+ <Button>Click me</Button>
61
+ </Popover>
62
+ ```
63
+
64
+ ### TriggerWithButton
65
+
66
+ > `Popover.Trigger` has a `withButton` prop that wraps trigger elements with an invisible button.
67
+ >
68
+ > Use it when you have multiple trigger elements or when the trigger content does not work as a button, such as SVG or plain text.
69
+
70
+ ```tsx
71
+ import { Popover } from '@redislabsdev/redis-ui-components';
72
+ import { InfoIcon } from '@redislabsdev/redis-ui-icons';
73
+ import { useViewMode } from '../../helpers/useViewMode';
74
+
75
+ function Render() {
76
+ const { inStory } = useViewMode();
77
+
78
+ return (
79
+ <>
80
+ <Popover content="Plain text trigger" withButton defaultOpen={inStory}>
81
+ Plain text
82
+ </Popover>
83
+ <Popover content="SVG trigger" withButton defaultOpen={inStory}>
84
+ <InfoIcon />
85
+ </Popover>
86
+ <Popover content="Multiple elements trigger" withButton defaultOpen={inStory}>
87
+ <strong>Multiple</strong>&nbsp;<em>Elements</em>
88
+ </Popover>
89
+ </>
90
+ );
91
+ }
92
+ ```
93
+
94
+ ### ProgrammaticallyOpened
95
+
96
+ > `Popover` can be controlled by setting `open` and `onOpenChange`.
97
+
98
+ ```tsx
99
+ import { useEffect, useState } from 'react';
100
+ import { Button, Popover, Switch, Typography } from '@redislabsdev/redis-ui-components';
101
+ import { StoryHList } from '../../helpers/Story.style';
102
+
103
+ function Render() {
104
+ const [open, setOpen] = useState(false);
105
+ const [enabled, setEnabled] = useState(false);
106
+ const [countDown, setCountDown] = useState(0);
107
+
108
+ const resetTimer = () => {
109
+ setCountDown(3);
110
+ };
111
+
112
+ useEffect(() => {
113
+ if (enabled) {
114
+ if (countDown > 0) {
115
+ const timer = setTimeout(() => {
116
+ setCountDown(countDown - 1);
117
+ }, 1000);
118
+
119
+ return () => clearTimeout(timer);
120
+ }
121
+
122
+ setOpen(true);
123
+ } else {
124
+ resetTimer();
125
+ }
126
+
127
+ return undefined;
128
+ }, [countDown, enabled]);
129
+
130
+ return (
131
+ <StoryHList $gap="2rem">
132
+ <Switch checked={enabled} onCheckedChange={setEnabled} />
133
+ {enabled ? (
134
+ <>
135
+ <Typography.Heading size="M">
136
+ Popover will be open in {countDown} seconds
137
+ </Typography.Heading>
138
+ <Popover
139
+ open={open}
140
+ onOpenChange={(toOpen) => {
141
+ if (!toOpen) {
142
+ setOpen(false);
143
+ setEnabled(false);
144
+ }
145
+ }}
146
+ content={
147
+ <div
148
+ style={{
149
+ display: 'flex',
150
+ flexDirection: 'column',
151
+ alignItems: 'center',
152
+ gap: 20
153
+ }}
154
+ >
155
+ <div>This Popover is opened programmatically</div>
156
+ <Button
157
+ onClick={() => {
158
+ setOpen(false);
159
+ setEnabled(false);
160
+ }}
161
+ >
162
+ Close
163
+ </Button>
164
+ </div>
165
+ }
166
+ withButton
167
+ >
168
+ Popover will be opened here
169
+ </Popover>
170
+ </>
171
+ ) : (
172
+ <Typography.Heading size="M">Switch timer ON</Typography.Heading>
173
+ )}
174
+ </StoryHList>
175
+ );
176
+ }
177
+ ```
178
+
179
+ ### PopoverPlacements
180
+
181
+ > Use `placement` to choose the preferred side of the trigger. The popover can flip when collisions occur.
182
+
183
+ ```tsx
184
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
185
+ import { useViewMode } from '../../helpers/useViewMode';
186
+
187
+ function Render() {
188
+ const { inStory } = useViewMode();
189
+
190
+ return (
191
+ <>
192
+ <Popover open={inStory} content="Left" placement="left">
193
+ <Button>Left</Button>
194
+ </Popover>
195
+ <Popover open={inStory} content="Top" placement="top">
196
+ <Button>Top</Button>
197
+ </Popover>
198
+ <Popover open={inStory} content="Bottom" placement="bottom">
199
+ <Button>Bottom</Button>
200
+ </Popover>
201
+ <Popover open={inStory} content="Right" placement="right">
202
+ <Button>Right</Button>
203
+ </Popover>
204
+ </>
205
+ );
206
+ }
207
+ ```
208
+
209
+ ### PopoverAlign
210
+
211
+ > Use `align` to choose the preferred alignment against the trigger. `alignOffset` can nudge the popup slightly.
212
+
213
+ ```tsx
214
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
215
+ import { useViewMode } from '../../helpers/useViewMode';
216
+
217
+ function Render() {
218
+ const { inStory } = useViewMode();
219
+
220
+ return (
221
+ <>
222
+ <Popover
223
+ open={inStory}
224
+ content={
225
+ <>
226
+ Popover with <strong>align: end</strong> and <strong>alignOffset</strong>
227
+ </>
228
+ }
229
+ placement="top"
230
+ align="end"
231
+ alignOffset={-20}
232
+ >
233
+ <Button>align: end</Button>
234
+ </Popover>
235
+ <Popover
236
+ open={inStory}
237
+ content={
238
+ <>
239
+ Popover with <strong>align: center</strong>
240
+ </>
241
+ }
242
+ placement="top"
243
+ align="center"
244
+ >
245
+ <Button>align: center</Button>
246
+ </Popover>
247
+ <Popover
248
+ open={inStory}
249
+ content={
250
+ <>
251
+ Popover with <strong>align: start</strong>
252
+ </>
253
+ }
254
+ placement="top"
255
+ align="start"
256
+ >
257
+ <Button>align: start</Button>
258
+ </Popover>
259
+ </>
260
+ );
261
+ }
262
+ ```
263
+
264
+ ### LongText
265
+
266
+ > Long text in the popover content will wrap.
267
+
268
+ ```tsx
269
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
270
+ import { useViewMode } from '../../helpers/useViewMode';
271
+
272
+ function Render() {
273
+ const { inStory } = useViewMode();
274
+
275
+ return (
276
+ <Popover
277
+ defaultOpen={inStory}
278
+ content="This is Popover content with a really really really really really really really really really really really really long text"
279
+ >
280
+ <Button>Click me</Button>
281
+ </Popover>
282
+ );
283
+ }
284
+ ```
285
+
286
+ ### CustomMaxWidth
287
+
288
+ > `maxWidth` can make long text or wider content layout more consistently.
289
+
290
+ ```tsx
291
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
292
+ import { useViewMode } from '../../helpers/useViewMode';
293
+
294
+ function Render() {
295
+ const { inStory } = useViewMode();
296
+
297
+ return (
298
+ <Popover
299
+ defaultOpen={inStory}
300
+ maxWidth="1000rem"
301
+ content="Custom maxWidth can be defined to make very long text laid out more consistently or contain wider content"
302
+ >
303
+ <Button>Click me</Button>
304
+ </Popover>
305
+ );
306
+ }
307
+ ```
308
+
309
+ ### PersistentPopover
310
+
311
+ > Use `persistent` when the popover should not close accidentally on outside click.
312
+ >
313
+ > Add a `Close` button so users can dismiss it explicitly.
314
+
315
+ ```tsx
316
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
317
+
318
+ <Popover
319
+ persistent
320
+ content={
321
+ <>
322
+ <Popover.Content.Close />
323
+ If Popover should not be accidentally closed, <strong>persistent</strong> flag can be used
324
+ <Popover.Card.Footer
325
+ actionButtonText="Click me"
326
+ linkText="Read me"
327
+ actionButtonHandler={() => {}}
328
+ link="#"
329
+ />
330
+ </>
331
+ }
332
+ >
333
+ <Button>Click me</Button>
334
+ </Popover>
335
+ ```
336
+
337
+ ### ClickOutsideEvent
338
+
339
+ > `onClickOutside` lets you react when the user clicks outside an opened popover.
340
+ >
341
+ > In this example, clicking outside causes the green indicator to flash.
342
+
343
+ ```tsx
344
+ import { useState } from 'react';
345
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
346
+ import * as S from './PopoverStory.style';
347
+
348
+ function useAnimTrigger() {
349
+ const [counter, setCounter] = useState(0);
350
+
351
+ return [counter, () => setCounter((c) => c + 1)] as const;
352
+ }
353
+
354
+ function Render() {
355
+ const [state, turnOnIndicator] = useAnimTrigger();
356
+
357
+ return (
358
+ <>
359
+ <Popover
360
+ onClickOutside={turnOnIndicator}
361
+ content="Click outside of this popup. The green indicator should show that the event has fired."
362
+ >
363
+ <Button>Regular</Button>
364
+ </Popover>
365
+ <S.Indicator key={state} $state={state} />
366
+ <Popover
367
+ persistent
368
+ onClickOutside={turnOnIndicator}
369
+ content={
370
+ <>
371
+ <Popover.Content.Close />
372
+ Click outside of this popup. The green indicator should show that the event has fired.
373
+ </>
374
+ }
375
+ >
376
+ <Button>Persistent</Button>
377
+ </Popover>
378
+ </>
379
+ );
380
+ }
381
+ ```
382
+
383
+ ### DisabledAndEmptyPopover
384
+
385
+ > An empty `content` value or the `disabled` flag prevents the popover from opening.
386
+
387
+ ```tsx
388
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
389
+
390
+ <>
391
+ <Popover
392
+ content={
393
+ <>
394
+ Popover with empty (falsy) content or Popover with <strong>disabled</strong> flag will
395
+ not be visible
396
+ </>
397
+ }
398
+ >
399
+ <Button>Click me</Button>
400
+ </Popover>
401
+ <Popover content="Disabled" disabled open>
402
+ <Button>Disabled</Button>
403
+ </Popover>
404
+ <Popover content="" open>
405
+ <Button>Empty content</Button>
406
+ </Popover>
407
+ </>
408
+ ```
409
+
410
+ ### Portal
411
+
412
+ > `Popover` can render without a portal or inside a custom portal container.
413
+
414
+ ```tsx
415
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
416
+ import { useViewMode } from '../../helpers/useViewMode';
417
+
418
+ function Render() {
419
+ const { inStory } = useViewMode();
420
+
421
+ return (
422
+ <>
423
+ <Popover
424
+ open={inStory}
425
+ maxWidth="20vw"
426
+ content="This Popover is rendered with default portal (document.body)"
427
+ >
428
+ <Button>With portal</Button>
429
+ </Popover>
430
+ <Popover open={inStory} portal={null} content="This Popover is rendered without portal">
431
+ <Button>No portal</Button>
432
+ </Popover>
433
+ </>
434
+ );
435
+ }
436
+ ```
437
+
438
+ ### InModal
439
+
440
+ > `Popover` opened from `Modal` should appear over the modal.
441
+
442
+ ```tsx
443
+ import { Button, Modal, Popover } from '@redislabsdev/redis-ui-components';
444
+
445
+ <Modal.Compose>
446
+ <Modal.Trigger>
447
+ <Button variant="primary">Open Modal</Button>
448
+ </Modal.Trigger>
449
+ <Modal.Content.Compose style={{ width: '400px', height: '200px' }}>
450
+ <Modal.Content.Header title="Modal Title" />
451
+ <Modal.Content.Body.Compose>
452
+ <Popover content="This Popover is opened from Modal">
453
+ <Button>Open popover</Button>
454
+ </Popover>
455
+ </Modal.Content.Body.Compose>
456
+ </Modal.Content.Compose>
457
+ </Modal.Compose>
458
+ ```
459
+
460
+ ### ComposePopover
461
+
462
+ > `Popover` can be composed with `Popover.Trigger`, `Popover.Content`, and `Popover.Content.Text`.
463
+ >
464
+ > `Popover.Card` is available for richer content.
465
+ >
466
+ > With composition, `backgroundColor` also applies to the popup arrow.
467
+
468
+ ```tsx
469
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
470
+ import { InfoIcon } from '@redislabsdev/redis-ui-icons';
471
+ import * as S from './PopoverStory.style';
472
+ import { useViewMode } from '../../helpers/useViewMode';
473
+
474
+ function Render() {
475
+ const { inStory } = useViewMode();
476
+
477
+ return (
478
+ <Popover.Compose defaultOpen={inStory}>
479
+ <Popover.Trigger withButton>
480
+ <InfoIcon />
481
+ Click me
482
+ </Popover.Trigger>
483
+ <Popover.Content.Compose backgroundColor="#eff9f5">
484
+ <S.PopoverContentText>This Popover is composed</S.PopoverContentText>
485
+ </Popover.Content.Compose>
486
+ </Popover.Compose>
487
+ );
488
+ }
489
+ ```
490
+
491
+ ### AsyncContent
492
+
493
+ > Popover with async content.
494
+
495
+ ```tsx
496
+ import { useEffect, useState } from 'react';
497
+ import { Button, Loader, Popover } from '@redislabsdev/redis-ui-components';
498
+
499
+ function AsyncContentComponent() {
500
+ const [loading, setLoading] = useState(true);
501
+
502
+ useEffect(() => {
503
+ const timeout = setTimeout(setLoading, 1500, false);
504
+
505
+ return () => clearTimeout(timeout);
506
+ }, []);
507
+
508
+ return loading ? (
509
+ <Loader size="15" />
510
+ ) : (
511
+ <div>
512
+ <p>Async content:</p>
513
+ <p>Loaded</p>
514
+ </div>
515
+ );
516
+ }
517
+
518
+ function Render() {
519
+ return (
520
+ <Popover content={<AsyncContentComponent />}>
521
+ <Button>Get async content</Button>
522
+ </Popover>
523
+ );
524
+ }
525
+ ```
526
+
527
+ ## Popover API
528
+
529
+ ### `Popover.Compose` Props
530
+
531
+ | Prop | Type | Default | Description |
532
+ |------|------|---------|-------------|
533
+ | children | `React.ReactNode` | required | Popover composition tree |
534
+ | defaultOpen | `boolean` | - | Uncontrolled initial open state |
535
+ | open | `boolean` | `visible` | Controlled open state |
536
+ | onOpenChange | `(open: boolean) => void` | `onVisibilityChange` | Controlled open-state callback |
537
+ | disabled | `boolean` | - | Disables the popover root |
538
+ | visible | `boolean` | - | Deprecated alias for `open` |
539
+ | onVisibilityChange | `(open: boolean) => void` | - | Deprecated alias for `onOpenChange` |
540
+
541
+ ### `Popover.Trigger` Props
542
+
543
+ | Prop | Type | Default | Description |
544
+ |------|------|---------|-------------|
545
+ | children | `React.ReactNode` | required | Trigger content |
546
+ | withButton | `boolean` | - | Wraps the trigger in an invisible button |
547
+
548
+ ### `Popover.Content` Props
549
+
550
+ | Prop | Type | Default | Description |
551
+ |------|------|---------|-------------|
552
+ | content | `React.ReactNode` | - | Popup content |
553
+ | backgroundColor | `string` | - | Popup background color override |
554
+ | placement | `'top' \| 'bottom' \| 'left' \| 'right'` | `bottom` | Preferred popup side |
555
+ | sideOffset | `number` | `5` | Offset between trigger and popup |
556
+ | persistent | `boolean` | `false` | Prevents closing on outside click |
557
+ | onClickOutside | `(event) => void` | - | Outside click handler |
558
+ | alignOffset | `number` | - | Additional alignment offset |
559
+ | align | `'start' \| 'center' \| 'end'` | `center` | Alignment against the trigger |
560
+ | maxWidth | `string` | - | Max popup width override |
561
+ | portal | `HTMLElement \| null` | `document.body` | Portal container or `null` to render inline |
562
+ | collisionBoundary | `RadixPopover.PopoverContentProps['collisionBoundary']` | - | Radix collision boundary override |
563
+ | windowBar | `WindowBarProps` | - | Deprecated alias for `Popover.Card.WindowBar` content |
564
+ | title | `string` | - | Deprecated alias for `Popover.Card.Header` title |
565
+ | text | `ContentBodyProps['text']` | - | Deprecated alias for `Popover.Card.Body` text |
566
+ | actionButtonText | `string` | - | Deprecated alias for `Popover.Card.Footer` action label |
567
+ | actionButtonHandler | `(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void` | - | Deprecated alias for `Popover.Card.Footer` action callback |
568
+ | link | `string` | - | Deprecated alias for `Popover.Card.Footer` link |
569
+ | linkText | `string` | - | Deprecated alias for `Popover.Card.Footer` link text |
570
+ | other div props | `Omit<PopoverContentComposeProps, 'children'>` | - | Standard popup container props forwarded to the composed content |
571
+
572
+ ### `Popover.Content.Compose` Props
573
+
574
+ | Prop | Type | Default | Description |
575
+ |------|------|---------|-------------|
576
+ | children | `React.ReactNode` | required | Popup content |
577
+ | backgroundColor | `string` | - | Popup background color override |
578
+ | placement | `'top' \| 'bottom' \| 'left' \| 'right'` | `bottom` | Preferred popup side |
579
+ | sideOffset | `number` | `5` | Offset between trigger and popup |
580
+ | persistent | `boolean` | `false` | Prevents closing on outside click |
581
+ | onClickOutside | `(event) => void` | - | Outside click handler |
582
+ | alignOffset | `number` | - | Additional alignment offset |
583
+ | align | `'start' \| 'center' \| 'end'` | `center` | Alignment against the trigger |
584
+ | maxWidth | `string` | - | Max popup width override |
585
+ | portal | `HTMLElement \| null` | `document.body` | Portal container or `null` to render inline |
586
+ | collisionBoundary | `RadixPopover.PopoverContentProps['collisionBoundary']` | - | Radix collision boundary override |
587
+ | other div props | `PopoverContentComposeProps` | - | Standard popup container props |
588
+
589
+ ### `Popover.Content.Close` Props
590
+
591
+ | Prop | Type | Default | Description |
592
+ |------|------|---------|-------------|
593
+ | icon | `IconType` | `CancelIcon` | Override icon used by the close button |
594
+ | other button props | `PopoverCloseProps` | - | Standard button props forwarded to the close button |
595
+
596
+ ### `Popover.Content.Text`
597
+
598
+ Inherits `TypographyBodyProps`. This is the styled text wrapper used when `Popover.content` is a string.
599
+
600
+ ### `Popover.Content.Header` Props
601
+
602
+ | Prop | Type | Default | Description |
603
+ |------|------|---------|-------------|
604
+ | title | `string` | - | Header title text |
605
+ | hideCloseButton | `boolean` | `false` | Hides the close button |
606
+ | other div props | `ContentHeaderComposeProps` | - | Standard header container props |
607
+
608
+ ### `Popover.Content.Header.Compose` Props
609
+
610
+ | Prop | Type | Default | Description |
611
+ |------|------|---------|-------------|
612
+ | other div props | `ContentHeaderComposeProps` | - | Standard header container props |
613
+
614
+ ### `Popover.Content.Header.Title`
615
+
616
+ Inherits `TypographyHeadingProps`. The wrapper renders the title with `size="S"` by default.
617
+
618
+ ### `Popover.Content.Body` Props
619
+
620
+ | Prop | Type | Default | Description |
621
+ |------|------|---------|-------------|
622
+ | text | `string` | - | Body text |
623
+ | other div props | `ContentBodyComposeProps` | - | Standard body container props |
624
+
625
+ ### `Popover.Content.Body.Compose` Props
626
+
627
+ | Prop | Type | Default | Description |
628
+ |------|------|---------|-------------|
629
+ | other div props | `ContentBodyComposeProps` | - | Standard body container props |
630
+
631
+ ### `Popover.Content.Body.Text`
632
+
633
+ Inherits `TypographyBodyProps`.
634
+
635
+ ### `Popover.Content.Footer` Props
636
+
637
+ | Prop | Type | Default | Description |
638
+ |------|------|---------|-------------|
639
+ | actionButtonText | `string` | - | Action button label |
640
+ | actionButtonHandler | `(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void` | - | Action button click handler |
641
+ | link | `string` | - | Footer link URL |
642
+ | linkText | `string` | - | Footer link label |
643
+ | other div props | `ContentFooterComposeProps` | - | Standard footer container props |
644
+
645
+ ### `Popover.Content.Footer.Compose` Props
646
+
647
+ | Prop | Type | Default | Description |
648
+ |------|------|---------|-------------|
649
+ | other div props | `ContentFooterComposeProps` | - | Standard footer container props |
650
+
651
+ ### `Popover.Content.WindowBar` Props
652
+
653
+ | Prop | Type | Default | Description |
654
+ |------|------|---------|-------------|
655
+ | title | `string` | `''` | Window bar title text |
656
+ | variant | `BadgeVariants` | `default` | Semantic window bar variant |
657
+ | hideCloseButton | `boolean` | `false` | Hides the close button |
658
+ | withIcon | `boolean` | `true` | Shows the icon slot when a variant icon is available |
659
+ | icon | `IconType` | - | Custom icon override |
660
+ | other div props | `WindowBarComposeProps` | - | Standard window bar container props |
661
+
662
+ ### `Popover.Content.WindowBar.Compose` Props
663
+
664
+ | Prop | Type | Default | Description |
665
+ |------|------|---------|-------------|
666
+ | variant | `BadgeVariants` | - | Semantic window bar variant |
667
+ | other div props | `WindowBarComposeProps` | - | Standard window bar container props |
668
+
669
+ ### `Popover.Content.WindowBar.Header` Props
670
+
671
+ | Prop | Type | Default | Description |
672
+ |------|------|---------|-------------|
673
+ | children | `React.ReactNode` | required | Header content |
674
+
675
+ ### `Popover.Content.WindowBar.Heading`
676
+
677
+ Inherits `TypographyHeadingProps`. The styled wrapper keeps the heading line-height tight.
678
+
679
+ ### `Popover.Content.WindowBar.Icon`
680
+
681
+ Uses `BadgeIconProps`. Story usage passes `variant`, `icon`, `size`, and `customColor`.
682
+
683
+ ### `Popover.Content.WindowBar.Close` Props
684
+
685
+ | Prop | Type | Default | Description |
686
+ |------|------|---------|-------------|
687
+ | icon | `IconType` | `CancelIcon` | Override icon used by the close button |
688
+ | other button props | `React.HTMLAttributes<HTMLButtonElement>` | - | Standard button props forwarded to the close button |
689
+
690
+ ## Popover.Card
691
+
692
+ ### Props
693
+
694
+ | Prop | Type | Default | Description |
695
+ |------|------|---------|-------------|
696
+ | title | `string` | - | Card header title |
697
+ | text | `ContentBodyProps['text']` | - | Card body text |
698
+ | actionButtonText | `string` | - | Footer action button label |
699
+ | actionButtonHandler | `(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => void` | - | Footer action button callback |
700
+ | link | `string` | - | Footer link URL |
701
+ | linkText | `string` | - | Footer link label |
702
+ | windowBar | `WindowBarProps` | - | Optional semantic window bar content |
703
+ | persistent | `boolean` | - | Keeps the content open on outside click |
704
+ | other div props | `Omit<ComposeProps, 'children' | 'title'>` | - | Standard card container props |
705
+
706
+ ### Sub-components
707
+
708
+ - `Popover.Card.Compose` - Card container surface.
709
+ - `Popover.Card.Header` - Alias of `Popover.Content.Header`.
710
+ - `Popover.Card.Body` - Alias of `Popover.Content.Body`.
711
+ - `Popover.Card.Footer` - Alias of `Popover.Content.Footer`.
712
+ - `Popover.Card.WindowBar` - Alias of `Popover.Content.WindowBar`.
713
+ - `Popover.Card.WindowBar.Header` - Alias of `Popover.Content.WindowBar.Header`.
714
+ - `Popover.Card.WindowBar.Icon` - Alias of `Popover.Content.WindowBar.Icon`.
715
+ - `Popover.Card.WindowBar.Close` - Alias of `Popover.Content.WindowBar.Close`.
716
+
717
+ ### `Popover.Card.Compose` Props
718
+
719
+ | Prop | Type | Default | Description |
720
+ |------|------|---------|-------------|
721
+ | children | `React.ReactNode` | required | Card content |
722
+ | other div props | `ComposeProps` | - | Standard card container props |
723
+
724
+ ### `Popover.Card.Close`
725
+
726
+ Uses the same props as `Popover.Content.Close`.
727
+
728
+ ### `Popover.Card Header / Body / Footer / WindowBar`
729
+
730
+ These aliases reuse the same prop surfaces as the corresponding `Popover.Content.*` subcomponents. The card stories exercise them through the composed card example.
731
+
732
+ ### `Popover.Card` Notes
733
+
734
+ - `Popover.Card.WindowBar` supports semantic variants. When you compose the bar manually, apply the variant to the icon as well.
735
+ - `Popover.Card` is the preferred replacement for the deprecated `Popover.Content` card-style props.
736
+
737
+ ## Popover.Card Examples
738
+
739
+ ### Playground
740
+
741
+ ```tsx
742
+ import { Popover } from '@redislabsdev/redis-ui-components';
743
+ import { PhoneIcon } from '@redislabsdev/redis-ui-icons';
744
+
745
+ <Popover
746
+ open
747
+ content={
748
+ <Popover.Card
749
+ windowBar={{
750
+ title: 'WindowBar Title',
751
+ withIcon: true,
752
+ variant: 'default',
753
+ icon: PhoneIcon
754
+ }}
755
+ title="Popover Card title"
756
+ text="Popover Card displays formatted content"
757
+ link="#"
758
+ actionButtonHandler={() => {}}
759
+ actionButtonText="Action"
760
+ />
761
+ }
762
+ >
763
+ <span />
764
+ </Popover>
765
+ ```
766
+
767
+ ### CardVariants
768
+
769
+ > `Popover.Card.WindowBar` supports semantic variants. To set the variant, use the `variant` prop on `WindowBar` or on the `windowBar` prop.
770
+ >
771
+ > In composition, apply the same variant to the icon as well.
772
+
773
+ ```tsx
774
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
775
+ import { useViewMode } from '../../helpers/useViewMode';
776
+
777
+ const variants = ['default', 'informative', 'notice', 'danger', 'attention', 'success'] as const;
778
+
779
+ function Render() {
780
+ const { inStory } = useViewMode();
781
+
782
+ return (
783
+ <>
784
+ {variants.map((variant) => (
785
+ <Popover
786
+ key={variant}
787
+ open={inStory}
788
+ content={
789
+ <Popover.Card
790
+ windowBar={{ variant, title: 'WindowBar title' }}
791
+ title="Header title"
792
+ text="Body text"
793
+ actionButtonText="Action"
794
+ actionButtonHandler={() => {}}
795
+ link="#"
796
+ />
797
+ }
798
+ >
799
+ <Button>{variant}</Button>
800
+ </Popover>
801
+ ))}
802
+ </>
803
+ );
804
+ }
805
+ ```
806
+
807
+ ### ComposeCard
808
+
809
+ > `Popover.Card` can be composed from `WindowBar`, `Header`, `Body`, and `Footer` pieces.
810
+
811
+ ```tsx
812
+ import { Button, Popover } from '@redislabsdev/redis-ui-components';
813
+ import { PhoneIcon } from '@redislabsdev/redis-ui-icons';
814
+ import { useViewMode } from '../../helpers/useViewMode';
815
+
816
+ function Render() {
817
+ const { inStory } = useViewMode();
818
+
819
+ return (
820
+ <Popover
821
+ defaultOpen={inStory}
822
+ content={
823
+ <Popover.Card.Compose>
824
+ <Popover.Card.WindowBar.Compose>
825
+ <Popover.Card.WindowBar.Header>
826
+ <Popover.Card.WindowBar.Icon
827
+ icon={PhoneIcon}
828
+ variant="default"
829
+ size="L"
830
+ customColor="currentColor"
831
+ />
832
+ <Popover.Card.WindowBar.Heading size="S">
833
+ Custom WindowBar.Header
834
+ </Popover.Card.WindowBar.Heading>
835
+ </Popover.Card.WindowBar.Header>
836
+ <Popover.Card.WindowBar.Close />
837
+ </Popover.Card.WindowBar.Compose>
838
+ <Popover.Card.Header.Compose>
839
+ <Popover.Card.Header.Title>Custom Header title</Popover.Card.Header.Title>
840
+ </Popover.Card.Header.Compose>
841
+ <Popover.Card.Body.Compose>
842
+ <Popover.Card.Body.Text>Custom Body text</Popover.Card.Body.Text>
843
+ </Popover.Card.Body.Compose>
844
+ <Popover.Card.Footer.Compose>
845
+ <Button>Custom Footer button</Button>
846
+ </Popover.Card.Footer.Compose>
847
+ </Popover.Card.Compose>
848
+ }
849
+ >
850
+ <Button>Click me</Button>
851
+ </Popover>
852
+ );
853
+ }
854
+ ```
855
+
856
+ ## Notes
857
+
858
+ - `visible` and `onVisibilityChange` are deprecated aliases for `open` and `onOpenChange`.
859
+ - `Popover.Content` still accepts deprecated card-style props (`windowBar`, `title`, `text`, `actionButtonText`, `actionButtonHandler`, `link`, `linkText`), but `Popover.Card` is the preferred API.
860
+ - `Popover.Trigger` with `withButton` is useful when the trigger content is plain text, SVG, or multiple elements.
861
+ - `Popover.Content.Text` is the string-content wrapper used by the default `Popover` render path.
862
+ - `Popover.Card.Close` mirrors `Popover.Content.Close`.
863
+ - Use `placement`, `align`, and `alignOffset` together for positioning control; collisions can still flip the popup.
864
+ - `persistent` prevents outside clicks from closing the popup, so pair it with an explicit close control.
865
+ - `onClickOutside` fires when the user clicks outside the popover.
866
+ - Empty or falsy `content` and `disabled` popovers will not open.
867
+ - `portal={null}` renders the popover inline instead of through a portal.
868
+ - `Popover.Content.WindowBar` returns `null` when it has no title.