@coinbase/cds-mcp-server 8.17.2 → 8.17.4
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/CHANGELOG.md +8 -0
- package/mcp-docs/mobile/components/Accordion.txt +188 -0
- package/mcp-docs/mobile/components/AccordionItem.txt +29 -0
- package/mcp-docs/mobile/components/Alert.txt +155 -0
- package/mcp-docs/mobile/components/AreaChart.txt +265 -0
- package/mcp-docs/mobile/components/Avatar.txt +195 -0
- package/mcp-docs/mobile/components/AvatarButton.txt +225 -0
- package/mcp-docs/mobile/components/Banner.txt +221 -0
- package/mcp-docs/mobile/components/BarChart.txt +815 -0
- package/mcp-docs/mobile/components/Box.txt +173 -0
- package/mcp-docs/mobile/components/BrowserBar.txt +146 -0
- package/mcp-docs/mobile/components/Button.txt +198 -0
- package/mcp-docs/mobile/components/ButtonGroup.txt +79 -0
- package/mcp-docs/mobile/components/Carousel.txt +1083 -0
- package/mcp-docs/mobile/components/CartesianChart.txt +825 -0
- package/mcp-docs/mobile/components/CellMedia.txt +70 -0
- package/mcp-docs/mobile/components/Checkbox.txt +245 -0
- package/mcp-docs/mobile/components/CheckboxCell.txt +201 -0
- package/mcp-docs/mobile/components/CheckboxGroup.txt +284 -0
- package/mcp-docs/mobile/components/Chip.txt +194 -0
- package/mcp-docs/mobile/components/Coachmark.txt +157 -0
- package/mcp-docs/mobile/components/Collapsible.txt +104 -0
- package/mcp-docs/mobile/components/ContainedAssetCard.txt +134 -0
- package/mcp-docs/mobile/components/ContentCard.txt +365 -0
- package/mcp-docs/mobile/components/ContentCardBody.txt +135 -0
- package/mcp-docs/mobile/components/ContentCardFooter.txt +127 -0
- package/mcp-docs/mobile/components/ContentCardHeader.txt +145 -0
- package/mcp-docs/mobile/components/ContentCell.txt +226 -0
- package/mcp-docs/mobile/components/ControlGroup.txt +443 -0
- package/mcp-docs/mobile/components/DatePicker.txt +496 -0
- package/mcp-docs/mobile/components/Divider.txt +138 -0
- package/mcp-docs/mobile/components/DotCount.txt +145 -0
- package/mcp-docs/mobile/components/DotStatusColor.txt +58 -0
- package/mcp-docs/mobile/components/DotSymbol.txt +134 -0
- package/mcp-docs/mobile/components/Fallback.txt +157 -0
- package/mcp-docs/mobile/components/FloatingAssetCard.txt +155 -0
- package/mcp-docs/mobile/components/HStack.txt +234 -0
- package/mcp-docs/mobile/components/HeroSquare.txt +47 -0
- package/mcp-docs/mobile/components/Icon.txt +51 -0
- package/mcp-docs/mobile/components/IconButton.txt +268 -0
- package/mcp-docs/mobile/components/InputChip.txt +187 -0
- package/mcp-docs/mobile/components/Interactable.txt +186 -0
- package/mcp-docs/mobile/components/LineChart.txt +1324 -0
- package/mcp-docs/mobile/components/Link.txt +291 -0
- package/mcp-docs/mobile/components/ListCell.txt +412 -0
- package/mcp-docs/mobile/components/LogoMark.txt +84 -0
- package/mcp-docs/mobile/components/LogoWordMark.txt +93 -0
- package/mcp-docs/mobile/components/Lottie.txt +138 -0
- package/mcp-docs/mobile/components/LottieStatusAnimation.txt +46 -0
- package/mcp-docs/mobile/components/Modal.txt +83 -0
- package/mcp-docs/mobile/components/ModalBody.txt +33 -0
- package/mcp-docs/mobile/components/ModalFooter.txt +24 -0
- package/mcp-docs/mobile/components/ModalHeader.txt +27 -0
- package/mcp-docs/mobile/components/MultiContentModule.txt +379 -0
- package/mcp-docs/mobile/components/NavigationTitle.txt +131 -0
- package/mcp-docs/mobile/components/NavigationTitleSelect.txt +141 -0
- package/mcp-docs/mobile/components/NudgeCard.txt +89 -0
- package/mcp-docs/mobile/components/Numpad.txt +340 -0
- package/mcp-docs/mobile/components/Overlay.txt +151 -0
- package/mcp-docs/mobile/components/PageFooter.txt +160 -0
- package/mcp-docs/mobile/components/PageHeader.txt +185 -0
- package/mcp-docs/mobile/components/PeriodSelector.txt +407 -0
- package/mcp-docs/mobile/components/Pictogram.txt +47 -0
- package/mcp-docs/mobile/components/Point.txt +204 -0
- package/mcp-docs/mobile/components/PortalProvider.txt +78 -0
- package/mcp-docs/mobile/components/Pressable.txt +210 -0
- package/mcp-docs/mobile/components/ProgressBar.txt +129 -0
- package/mcp-docs/mobile/components/ProgressBarWithFixedLabels.txt +160 -0
- package/mcp-docs/mobile/components/ProgressBarWithFloatLabel.txt +137 -0
- package/mcp-docs/mobile/components/ProgressCircle.txt +236 -0
- package/mcp-docs/mobile/components/Radio.txt +241 -0
- package/mcp-docs/mobile/components/RadioCell.txt +201 -0
- package/mcp-docs/mobile/components/RadioGroup.txt +281 -0
- package/mcp-docs/mobile/components/ReferenceLine.txt +152 -0
- package/mcp-docs/mobile/components/RemoteImage.txt +105 -0
- package/mcp-docs/mobile/components/RemoteImageGroup.txt +60 -0
- package/mcp-docs/mobile/components/RollingNumber.txt +788 -0
- package/mcp-docs/mobile/components/Scrubber.txt +203 -0
- package/mcp-docs/mobile/components/SearchInput.txt +191 -0
- package/mcp-docs/mobile/components/SectionHeader.txt +204 -0
- package/mcp-docs/mobile/components/SegmentedTabs.txt +315 -0
- package/mcp-docs/mobile/components/Select.txt +211 -0
- package/mcp-docs/mobile/components/SelectChip.txt +323 -0
- package/mcp-docs/mobile/components/SelectOption.txt +84 -0
- package/mcp-docs/mobile/components/SlideButton.txt +330 -0
- package/mcp-docs/mobile/components/Spacer.txt +83 -0
- package/mcp-docs/mobile/components/Sparkline.txt +122 -0
- package/mcp-docs/mobile/components/SparklineGradient.txt +106 -0
- package/mcp-docs/mobile/components/SparklineInteractive.txt +156 -0
- package/mcp-docs/mobile/components/SparklineInteractiveHeader.txt +72 -0
- package/mcp-docs/mobile/components/Spinner.txt +48 -0
- package/mcp-docs/mobile/components/SpotIcon.txt +47 -0
- package/mcp-docs/mobile/components/SpotRectangle.txt +47 -0
- package/mcp-docs/mobile/components/SpotSquare.txt +47 -0
- package/mcp-docs/mobile/components/Stepper.txt +527 -0
- package/mcp-docs/mobile/components/SubBrandLogoMark.txt +125 -0
- package/mcp-docs/mobile/components/SubBrandLogoWordMark.txt +125 -0
- package/mcp-docs/mobile/components/Switch.txt +97 -0
- package/mcp-docs/mobile/components/TabIndicator.txt +48 -0
- package/mcp-docs/mobile/components/TabLabel.txt +153 -0
- package/mcp-docs/mobile/components/TabNavigation.txt +146 -0
- package/mcp-docs/mobile/components/TabbedChips.txt +142 -0
- package/mcp-docs/mobile/components/Tabs.txt +190 -0
- package/mcp-docs/mobile/components/Tag.txt +300 -0
- package/mcp-docs/mobile/components/Text.txt +211 -0
- package/mcp-docs/mobile/components/TextInput.txt +717 -0
- package/mcp-docs/mobile/components/ThemeProvider.txt +132 -0
- package/mcp-docs/mobile/components/Toast.txt +196 -0
- package/mcp-docs/mobile/components/Tooltip.txt +59 -0
- package/mcp-docs/mobile/components/TopNavBar.txt +161 -0
- package/mcp-docs/mobile/components/Tour.txt +158 -0
- package/mcp-docs/mobile/components/Tray.txt +252 -0
- package/mcp-docs/mobile/components/UpsellCard.txt +321 -0
- package/mcp-docs/mobile/components/VStack.txt +222 -0
- package/mcp-docs/mobile/components/XAxis.txt +621 -0
- package/mcp-docs/mobile/components/YAxis.txt +567 -0
- package/mcp-docs/mobile/getting-started/ai-overview.txt +108 -0
- package/mcp-docs/mobile/getting-started/installation.txt +57 -0
- package/mcp-docs/mobile/getting-started/introduction.txt +102 -0
- package/mcp-docs/mobile/getting-started/playground.txt +28 -0
- package/mcp-docs/mobile/getting-started/styling.txt +84 -0
- package/mcp-docs/mobile/getting-started/theming.txt +286 -0
- package/mcp-docs/mobile/hooks/useDimensions.txt +72 -0
- package/mcp-docs/mobile/hooks/useEventHandler.txt +120 -0
- package/mcp-docs/mobile/hooks/useMergeRefs.txt +116 -0
- package/mcp-docs/mobile/hooks/useOverlayContentContext.txt +280 -0
- package/mcp-docs/mobile/hooks/usePreviousValue.txt +74 -0
- package/mcp-docs/mobile/hooks/useRefMap.txt +178 -0
- package/mcp-docs/mobile/hooks/useTheme.txt +321 -0
- package/mcp-docs/mobile/routes.txt +139 -0
- package/mcp-docs/web/components/Accordion.txt +189 -0
- package/mcp-docs/web/components/AccordionItem.txt +31 -0
- package/mcp-docs/web/components/Alert.txt +164 -0
- package/mcp-docs/web/components/AreaChart.txt +510 -0
- package/mcp-docs/web/components/Avatar.txt +211 -0
- package/mcp-docs/web/components/AvatarButton.txt +240 -0
- package/mcp-docs/web/components/Banner.txt +226 -0
- package/mcp-docs/web/components/BarChart.txt +1267 -0
- package/mcp-docs/web/components/Box.txt +175 -0
- package/mcp-docs/web/components/Button.txt +212 -0
- package/mcp-docs/web/components/ButtonGroup.txt +79 -0
- package/mcp-docs/web/components/Calendar.txt +181 -0
- package/mcp-docs/web/components/Carousel.txt +1575 -0
- package/mcp-docs/web/components/CartesianChart.txt +1044 -0
- package/mcp-docs/web/components/CellMedia.txt +56 -0
- package/mcp-docs/web/components/Checkbox.txt +188 -0
- package/mcp-docs/web/components/CheckboxCell.txt +202 -0
- package/mcp-docs/web/components/CheckboxGroup.txt +219 -0
- package/mcp-docs/web/components/Chip.txt +196 -0
- package/mcp-docs/web/components/Coachmark.txt +188 -0
- package/mcp-docs/web/components/Collapsible.txt +119 -0
- package/mcp-docs/web/components/ContainedAssetCard.txt +232 -0
- package/mcp-docs/web/components/ContentCard.txt +367 -0
- package/mcp-docs/web/components/ContentCardBody.txt +137 -0
- package/mcp-docs/web/components/ContentCardFooter.txt +129 -0
- package/mcp-docs/web/components/ContentCardHeader.txt +147 -0
- package/mcp-docs/web/components/ContentCell.txt +219 -0
- package/mcp-docs/web/components/ControlGroup.txt +436 -0
- package/mcp-docs/web/components/DatePicker.txt +505 -0
- package/mcp-docs/web/components/Divider.txt +143 -0
- package/mcp-docs/web/components/DotCount.txt +149 -0
- package/mcp-docs/web/components/DotStatusColor.txt +58 -0
- package/mcp-docs/web/components/DotSymbol.txt +137 -0
- package/mcp-docs/web/components/Dropdown.txt +119 -0
- package/mcp-docs/web/components/Fallback.txt +163 -0
- package/mcp-docs/web/components/FloatingAssetCard.txt +250 -0
- package/mcp-docs/web/components/FullscreenAlert.txt +69 -0
- package/mcp-docs/web/components/FullscreenModal.txt +145 -0
- package/mcp-docs/web/components/FullscreenModalLayout.txt +187 -0
- package/mcp-docs/web/components/Grid.txt +236 -0
- package/mcp-docs/web/components/GridColumn.txt +209 -0
- package/mcp-docs/web/components/HStack.txt +236 -0
- package/mcp-docs/web/components/HeroSquare.txt +48 -0
- package/mcp-docs/web/components/Icon.txt +145 -0
- package/mcp-docs/web/components/IconButton.txt +390 -0
- package/mcp-docs/web/components/InputChip.txt +187 -0
- package/mcp-docs/web/components/Interactable.txt +193 -0
- package/mcp-docs/web/components/LineChart.txt +1576 -0
- package/mcp-docs/web/components/Link.txt +243 -0
- package/mcp-docs/web/components/ListCell.txt +418 -0
- package/mcp-docs/web/components/LogoMark.txt +84 -0
- package/mcp-docs/web/components/LogoWordMark.txt +93 -0
- package/mcp-docs/web/components/Lottie.txt +157 -0
- package/mcp-docs/web/components/LottieStatusAnimation.txt +57 -0
- package/mcp-docs/web/components/MediaQueryProvider.txt +108 -0
- package/mcp-docs/web/components/Modal.txt +196 -0
- package/mcp-docs/web/components/ModalBody.txt +117 -0
- package/mcp-docs/web/components/ModalFooter.txt +119 -0
- package/mcp-docs/web/components/ModalHeader.txt +123 -0
- package/mcp-docs/web/components/MultiContentModule.txt +381 -0
- package/mcp-docs/web/components/NavigationBar.txt +102 -0
- package/mcp-docs/web/components/NavigationTitle.txt +25 -0
- package/mcp-docs/web/components/NavigationTitleSelect.txt +45 -0
- package/mcp-docs/web/components/NudgeCard.txt +181 -0
- package/mcp-docs/web/components/Overlay.txt +171 -0
- package/mcp-docs/web/components/PageFooter.txt +184 -0
- package/mcp-docs/web/components/PageHeader.txt +243 -0
- package/mcp-docs/web/components/Pagination.txt +499 -0
- package/mcp-docs/web/components/PeriodSelector.txt +703 -0
- package/mcp-docs/web/components/Pictogram.txt +48 -0
- package/mcp-docs/web/components/Point.txt +460 -0
- package/mcp-docs/web/components/PortalProvider.txt +76 -0
- package/mcp-docs/web/components/Pressable.txt +193 -0
- package/mcp-docs/web/components/ProgressBar.txt +163 -0
- package/mcp-docs/web/components/ProgressBarWithFixedLabels.txt +212 -0
- package/mcp-docs/web/components/ProgressBarWithFloatLabel.txt +181 -0
- package/mcp-docs/web/components/ProgressCircle.txt +443 -0
- package/mcp-docs/web/components/Radio.txt +219 -0
- package/mcp-docs/web/components/RadioCell.txt +215 -0
- package/mcp-docs/web/components/RadioGroup.txt +288 -0
- package/mcp-docs/web/components/ReferenceLine.txt +451 -0
- package/mcp-docs/web/components/RemoteImage.txt +165 -0
- package/mcp-docs/web/components/RemoteImageGroup.txt +86 -0
- package/mcp-docs/web/components/RollingNumber.txt +1021 -0
- package/mcp-docs/web/components/Scrubber.txt +231 -0
- package/mcp-docs/web/components/SearchInput.txt +117 -0
- package/mcp-docs/web/components/SectionHeader.txt +217 -0
- package/mcp-docs/web/components/SegmentedTabs.txt +324 -0
- package/mcp-docs/web/components/Select.txt +224 -0
- package/mcp-docs/web/components/SelectChip.txt +314 -0
- package/mcp-docs/web/components/SelectOption.txt +165 -0
- package/mcp-docs/web/components/Sidebar.txt +349 -0
- package/mcp-docs/web/components/SidebarItem.txt +131 -0
- package/mcp-docs/web/components/SidebarMoreMenu.txt +30 -0
- package/mcp-docs/web/components/Spacer.txt +173 -0
- package/mcp-docs/web/components/Sparkline.txt +122 -0
- package/mcp-docs/web/components/SparklineGradient.txt +106 -0
- package/mcp-docs/web/components/SparklineInteractive.txt +153 -0
- package/mcp-docs/web/components/SparklineInteractiveHeader.txt +76 -0
- package/mcp-docs/web/components/Spinner.txt +128 -0
- package/mcp-docs/web/components/SpotIcon.txt +48 -0
- package/mcp-docs/web/components/SpotRectangle.txt +48 -0
- package/mcp-docs/web/components/SpotSquare.txt +48 -0
- package/mcp-docs/web/components/Stepper.txt +682 -0
- package/mcp-docs/web/components/SubBrandLogoMark.txt +125 -0
- package/mcp-docs/web/components/SubBrandLogoWordMark.txt +125 -0
- package/mcp-docs/web/components/Switch.txt +85 -0
- package/mcp-docs/web/components/TabIndicator.txt +48 -0
- package/mcp-docs/web/components/TabLabel.txt +158 -0
- package/mcp-docs/web/components/TabNavigation.txt +159 -0
- package/mcp-docs/web/components/TabbedChips.txt +155 -0
- package/mcp-docs/web/components/Table.txt +367 -0
- package/mcp-docs/web/components/TableBody.txt +83 -0
- package/mcp-docs/web/components/TableCaption.txt +102 -0
- package/mcp-docs/web/components/TableCell.txt +165 -0
- package/mcp-docs/web/components/TableCellFallback.txt +97 -0
- package/mcp-docs/web/components/TableFooter.txt +83 -0
- package/mcp-docs/web/components/TableHeader.txt +100 -0
- package/mcp-docs/web/components/TableRow.txt +140 -0
- package/mcp-docs/web/components/Tabs.txt +212 -0
- package/mcp-docs/web/components/Tag.txt +304 -0
- package/mcp-docs/web/components/Text.txt +232 -0
- package/mcp-docs/web/components/TextInput.txt +652 -0
- package/mcp-docs/web/components/ThemeProvider.txt +199 -0
- package/mcp-docs/web/components/TileButton.txt +158 -0
- package/mcp-docs/web/components/Toast.txt +203 -0
- package/mcp-docs/web/components/Tooltip.txt +89 -0
- package/mcp-docs/web/components/Tour.txt +179 -0
- package/mcp-docs/web/components/Tray.txt +288 -0
- package/mcp-docs/web/components/UpsellCard.txt +319 -0
- package/mcp-docs/web/components/VStack.txt +224 -0
- package/mcp-docs/web/components/XAxis.txt +619 -0
- package/mcp-docs/web/components/YAxis.txt +548 -0
- package/mcp-docs/web/getting-started/ai-overview.txt +108 -0
- package/mcp-docs/web/getting-started/installation.txt +103 -0
- package/mcp-docs/web/getting-started/introduction.txt +102 -0
- package/mcp-docs/web/getting-started/playground.txt +28 -0
- package/mcp-docs/web/getting-started/styling.txt +161 -0
- package/mcp-docs/web/getting-started/templates.txt +121 -0
- package/mcp-docs/web/getting-started/theming.txt +426 -0
- package/mcp-docs/web/hooks/useBreakpoints.txt +61 -0
- package/mcp-docs/web/hooks/useDimensions.txt +114 -0
- package/mcp-docs/web/hooks/useEventHandler.txt +120 -0
- package/mcp-docs/web/hooks/useHasMounted.txt +75 -0
- package/mcp-docs/web/hooks/useIsoEffect.txt +58 -0
- package/mcp-docs/web/hooks/useMediaQuery.txt +114 -0
- package/mcp-docs/web/hooks/useMergeRefs.txt +116 -0
- package/mcp-docs/web/hooks/useOverlayContentContext.txt +279 -0
- package/mcp-docs/web/hooks/usePreviousValue.txt +74 -0
- package/mcp-docs/web/hooks/useRefMap.txt +178 -0
- package/mcp-docs/web/hooks/useScrollBlocker.txt +82 -0
- package/mcp-docs/web/hooks/useTheme.txt +364 -0
- package/mcp-docs/web/routes.txt +163 -0
- package/package.json +1 -1
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# useEventHandler
|
|
2
|
+
|
|
3
|
+
Creates event handlers for components based on the EventHandlerProvider configuration. It enables centralized event handling and analytics tracking by mapping component actions to configured handlers.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { useEventHandler } from '@coinbase/cds-common/hooks/useEventHandler'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
:::warning
|
|
14
|
+
Must be used within an EventHandlerProvider. The provider's configuration determines which events are handled and how they are processed. The provider config should include:
|
|
15
|
+
|
|
16
|
+
- `actionMapping?: Record<string, string>` - Optional mapping of CDS actions to handler actions
|
|
17
|
+
- `handlers?: Record<EventHandlerComponent, Record<string, (eventData: EventCallbackProps) => void>>` - Event handlers for components
|
|
18
|
+
|
|
19
|
+
:::
|
|
20
|
+
|
|
21
|
+
### Parameters
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
type EventDataEntryTypes = string | number | boolean | null | undefined;
|
|
25
|
+
type EventDataEntry = EventDataEntryTypes | EventDataEntryTypes[];
|
|
26
|
+
type RecursiveMapType<T> = T | Record<string, T>;
|
|
27
|
+
|
|
28
|
+
type EventHandlerComponent = 'Button';
|
|
29
|
+
type EventHandlerAction = string;
|
|
30
|
+
type EventCustomData = Record<string, RecursiveMapType<EventDataEntry>>;
|
|
31
|
+
|
|
32
|
+
type EventHandlerCustomConfig = {
|
|
33
|
+
componentName: string;
|
|
34
|
+
actions: EventHandlerAction[];
|
|
35
|
+
data?: EventCustomData;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
function useEventHandler(
|
|
39
|
+
component: EventHandlerComponent,
|
|
40
|
+
action: EventHandlerAction,
|
|
41
|
+
eventConfig?: EventHandlerCustomConfig,
|
|
42
|
+
analyticsId?: string,
|
|
43
|
+
): () => void;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
- `component`: The component type to handle events for (currently supports 'Button')
|
|
47
|
+
- `action`: The action type to handle (e.g., 'onClick', 'onHover'). This is a string type that can be mapped to custom handler actions.
|
|
48
|
+
- `eventConfig` (optional): Configuration object for the event:
|
|
49
|
+
- `componentName`: Name of the component for tracking purposes
|
|
50
|
+
- `actions`: List of actions to track
|
|
51
|
+
- `data`: Additional data to pass to the handler
|
|
52
|
+
- `analyticsId` (optional): A unique identifier for analytics tracking that takes precedence over eventConfig
|
|
53
|
+
|
|
54
|
+
### Returns
|
|
55
|
+
|
|
56
|
+
```tsx
|
|
57
|
+
type EventCallbackProps = {
|
|
58
|
+
componentName?: string;
|
|
59
|
+
analyticsId?: string;
|
|
60
|
+
data?: EventCustomData;
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
type Return = () => void;
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Returns a callback function that when invoked will trigger the event handling. The function:
|
|
67
|
+
|
|
68
|
+
- Executes the configured handler for the component and action when called
|
|
69
|
+
- Maps CDS actions to custom handler actions if `actionMapping` is provided in the EventHandlerProvider
|
|
70
|
+
- Returns a no-op function if:
|
|
71
|
+
- No handlers are configured
|
|
72
|
+
- No eventConfig actions are provided and no analyticsId is set
|
|
73
|
+
- The handler for the component doesn't exist
|
|
74
|
+
- The action is not listed in eventConfig actions (when using eventConfig)
|
|
75
|
+
- The params object is empty
|
|
76
|
+
|
|
77
|
+
## Examples
|
|
78
|
+
|
|
79
|
+
### Usage
|
|
80
|
+
|
|
81
|
+
```tsx live
|
|
82
|
+
function ExampleWithProvider() {
|
|
83
|
+
const { show: showToast } = useToast();
|
|
84
|
+
|
|
85
|
+
// Example provider configuration with action mapping
|
|
86
|
+
const config = {
|
|
87
|
+
actionMapping: {
|
|
88
|
+
onClick: 'click', // Maps CDS onClick to custom 'click' handler
|
|
89
|
+
},
|
|
90
|
+
handlers: {
|
|
91
|
+
Button: {
|
|
92
|
+
click: ({ componentName, data }) => {
|
|
93
|
+
showToast(`Button ${componentName} clicked with data: ${JSON.stringify(data)}`);
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
function ButtonExample() {
|
|
100
|
+
const eventConfig = {
|
|
101
|
+
actions: ['click'], // Use mapped action name
|
|
102
|
+
componentName: 'mapped_button',
|
|
103
|
+
data: {
|
|
104
|
+
source: 'action_mapping_example',
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const handleButtonClick = useEventHandler('Button', 'onClick', eventConfig);
|
|
109
|
+
|
|
110
|
+
return <Button onClick={handleButtonClick}>Click for Mapped Action</Button>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return (
|
|
114
|
+
<EventHandlerProvider config={config}>
|
|
115
|
+
<ButtonExample />
|
|
116
|
+
</EventHandlerProvider>
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# useMergeRefs
|
|
2
|
+
|
|
3
|
+
Combines multiple refs into a single ref callback, allowing a component to work with multiple ref instances simultaneously. Useful when you need to combine refs from different sources, such as forwarded refs and internal component state.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { useMergeRefs } from '@coinbase/cds-common/hooks/useMergeRefs'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### Parameters
|
|
14
|
+
|
|
15
|
+
The `useMergeRefs` hook accepts a spread of refs as its parameter:
|
|
16
|
+
|
|
17
|
+
- `...refs: (React.MutableRefObject<T> | React.LegacyRef<T> | undefined | null)[]` - An array of refs to merge. Can include:
|
|
18
|
+
- `MutableRefObject` - Object-based refs created with `useRef`
|
|
19
|
+
- `LegacyRef` - Function-based refs or string refs (legacy)
|
|
20
|
+
- `undefined` or `null` - Optional refs that might not be provided
|
|
21
|
+
|
|
22
|
+
### Returns
|
|
23
|
+
|
|
24
|
+
Returns a `React.RefCallback<T>` function that can be used as a ref:
|
|
25
|
+
|
|
26
|
+
- The returned callback handles updating all provided refs when the referenced element changes
|
|
27
|
+
- Properly handles both object-based and function-based refs
|
|
28
|
+
- Safely handles undefined or null refs by ignoring them
|
|
29
|
+
|
|
30
|
+
:::tip
|
|
31
|
+
This hook is particularly useful when working with components that need to combine multiple refs, such as when using both forwarded refs and internal state refs, or when composing components that each require their own ref.
|
|
32
|
+
:::
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
### Basic usage
|
|
37
|
+
|
|
38
|
+
```tsx live
|
|
39
|
+
function Example() {
|
|
40
|
+
// Create an internal ref for component logic
|
|
41
|
+
const internalRef = useRef<HTMLDivElement>(null);
|
|
42
|
+
|
|
43
|
+
// Simulating a forwarded ref from parent
|
|
44
|
+
const Component = forwardRef((props, forwardedRef) => {
|
|
45
|
+
// Merge the internal ref with the forwarded ref
|
|
46
|
+
const refs = useMergeRefs(forwardedRef, internalRef);
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Box ref={refs} padding={3} background="bgAlternate" borderRadius={300}>
|
|
50
|
+
<TextBody>This box uses a merged ref</TextBody>
|
|
51
|
+
</Box>
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
return <Component />;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### With Multiple Refs
|
|
60
|
+
|
|
61
|
+
```tsx live
|
|
62
|
+
function Example() {
|
|
63
|
+
const firstRef = useRef<HTMLDivElement>(null);
|
|
64
|
+
const secondRef = useRef<HTMLDivElement>(null);
|
|
65
|
+
const thirdRef = useRef<HTMLDivElement>(null);
|
|
66
|
+
|
|
67
|
+
// Function to check if all refs are properly set
|
|
68
|
+
const checkRefs = () => {
|
|
69
|
+
const allRefsSet = firstRef.current && secondRef.current && thirdRef.current;
|
|
70
|
+
alert(`All refs are ${allRefsSet ? 'set' : 'not set'}`);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
// Merge all three refs
|
|
74
|
+
const mergedRefs = useMergeRefs(firstRef, secondRef, thirdRef);
|
|
75
|
+
|
|
76
|
+
return (
|
|
77
|
+
<VStack gap={2}>
|
|
78
|
+
<Box ref={mergedRefs} padding={3} background="bgAlternate" borderRadius={300}>
|
|
79
|
+
<TextBody>This element is referenced by three refs</TextBody>
|
|
80
|
+
</Box>
|
|
81
|
+
<Button onClick={checkRefs}>Check Refs</Button>
|
|
82
|
+
</VStack>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### With Function Ref
|
|
88
|
+
|
|
89
|
+
```tsx live
|
|
90
|
+
function Example() {
|
|
91
|
+
const [elementWidth, setElementWidth] = useState<number>(0);
|
|
92
|
+
|
|
93
|
+
// Create a function ref that measures the element
|
|
94
|
+
const functionRef = (element: HTMLDivElement | null) => {
|
|
95
|
+
if (element) {
|
|
96
|
+
setElementWidth(element.offsetWidth);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Create an object ref for other purposes
|
|
101
|
+
const objectRef = useRef<HTMLDivElement>(null);
|
|
102
|
+
|
|
103
|
+
// Merge both types of refs
|
|
104
|
+
const refs = useMergeRefs(functionRef, objectRef);
|
|
105
|
+
|
|
106
|
+
return (
|
|
107
|
+
<VStack gap={2}>
|
|
108
|
+
<Box ref={refs} padding={3} background="bgAlternate" borderRadius={300} width="100%">
|
|
109
|
+
<TextBody>This box uses both function and object refs</TextBody>
|
|
110
|
+
</Box>
|
|
111
|
+
<TextBody>Box width: {elementWidth}px</TextBody>
|
|
112
|
+
</VStack>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# useOverlayContentContext
|
|
2
|
+
|
|
3
|
+
A React context and hook for detecting if components are rendered inside overlay containers like modals, drawers, tours, and trays.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { OverlayContentContext, useOverlayContentContext } from '@coinbase/cds-common/overlays/OverlayContentContext'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### useOverlayContentContext
|
|
14
|
+
|
|
15
|
+
Returns the current overlay context information for mobile applications. This hook does not throw an error when used outside a provider, making it safe to use anywhere in your component tree.
|
|
16
|
+
|
|
17
|
+
#### Return Value
|
|
18
|
+
|
|
19
|
+
The hook returns an object with the following properties:
|
|
20
|
+
|
|
21
|
+
- **`isOverlay?: boolean`** - True if inside any overlay component (derived from other values if not explicitly set)
|
|
22
|
+
- **`isModal?: boolean`** - True if inside a Modal component
|
|
23
|
+
- **`isDrawer?: boolean`** - True if inside a Drawer or Tray component
|
|
24
|
+
- **`isTour?: boolean`** - True if inside a Tour component
|
|
25
|
+
|
|
26
|
+
### OverlayContentContext
|
|
27
|
+
|
|
28
|
+
The React context that provides overlay state information for mobile applications. Can be used directly with `React.useContext` or through the `useOverlayContentContext` hook.
|
|
29
|
+
|
|
30
|
+
#### Context Value Type
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
type OverlayContentContextValue = {
|
|
34
|
+
isOverlay?: boolean;
|
|
35
|
+
isModal?: boolean;
|
|
36
|
+
isDrawer?: boolean;
|
|
37
|
+
isTour?: boolean;
|
|
38
|
+
};
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Provider Usage
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { OverlayContentContext } from '@coinbase/cds-common/overlays/OverlayContentContext';
|
|
45
|
+
|
|
46
|
+
function MyMobileOverlayComponent() {
|
|
47
|
+
const contextValue = {
|
|
48
|
+
isModal: true,
|
|
49
|
+
isDrawer: false,
|
|
50
|
+
isTour: false,
|
|
51
|
+
// isOverlay will be automatically derived as true
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
return (
|
|
55
|
+
<OverlayContentContext.Provider value={contextValue}>
|
|
56
|
+
{/* Your mobile overlay content */}
|
|
57
|
+
</OverlayContentContext.Provider>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Mobile Considerations
|
|
63
|
+
|
|
64
|
+
On mobile platforms, overlay contexts are particularly useful for:
|
|
65
|
+
|
|
66
|
+
- **Touch Handling**: Adjusting touch behaviors based on overlay type
|
|
67
|
+
- **Safe Areas**: Managing safe area insets differently in overlays vs full-screen content
|
|
68
|
+
- **Navigation**: Preventing or modifying navigation gestures in overlay contexts
|
|
69
|
+
- **Accessibility**: Providing appropriate focus management for screen readers
|
|
70
|
+
|
|
71
|
+
### Automatic Derivation
|
|
72
|
+
|
|
73
|
+
If `isOverlay` is not explicitly provided in the context value, it will be automatically derived as `true` when any of `isModal`, `isDrawer`, or `isTour` is `true`. This ensures consistent behavior across the system.
|
|
74
|
+
|
|
75
|
+
**Important**: When adding new overlay types to the `OverlayContentContextValue` type, remember to update the derivation logic in the `useOverlayContentContext` hook.
|
|
76
|
+
|
|
77
|
+
## Examples
|
|
78
|
+
|
|
79
|
+
The `useOverlayContentContext` hook provides information about whether a component is rendered inside various types of overlay containers on mobile. This is useful for conditional rendering and behavior based on the overlay context.
|
|
80
|
+
|
|
81
|
+
### Basic usage
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
function ExampleComponent() {
|
|
85
|
+
const { isOverlay, isModal, isDrawer, isTour } = useOverlayContentContext();
|
|
86
|
+
|
|
87
|
+
return (
|
|
88
|
+
<VStack gap={2}>
|
|
89
|
+
<Text variant="title3">Overlay Context Information</Text>
|
|
90
|
+
<Text>Is inside any overlay: {isOverlay ? 'Yes' : 'No'}</Text>
|
|
91
|
+
<Text>Is inside modal: {isModal ? 'Yes' : 'No'}</Text>
|
|
92
|
+
<Text>Is inside drawer/tray: {isDrawer ? 'Yes' : 'No'}</Text>
|
|
93
|
+
<Text>Is inside tour: {isTour ? 'Yes' : 'No'}</Text>
|
|
94
|
+
</VStack>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Real Modal Example
|
|
100
|
+
|
|
101
|
+
This example shows how the hook works inside an actual mobile modal:
|
|
102
|
+
|
|
103
|
+
```tsx
|
|
104
|
+
function ModalExample() {
|
|
105
|
+
const { openModal } = useModal();
|
|
106
|
+
|
|
107
|
+
const ExampleComponent = () => {
|
|
108
|
+
const { isOverlay, isModal, isDrawer, isTour } = useOverlayContentContext();
|
|
109
|
+
|
|
110
|
+
return (
|
|
111
|
+
<VStack gap={2}>
|
|
112
|
+
<Text variant="title3">Overlay Context Information</Text>
|
|
113
|
+
<Text>Is inside any overlay: {isOverlay ? 'Yes' : 'No'}</Text>
|
|
114
|
+
<Text>Is inside modal: {isModal ? 'Yes' : 'No'}</Text>
|
|
115
|
+
<Text>Is inside drawer/tray: {isDrawer ? 'Yes' : 'No'}</Text>
|
|
116
|
+
<Text>Is inside tour: {isTour ? 'Yes' : 'No'}</Text>
|
|
117
|
+
</VStack>
|
|
118
|
+
);
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const ModalContent = () => {
|
|
122
|
+
return (
|
|
123
|
+
<VStack gap={3}>
|
|
124
|
+
<Text>This content is rendered inside a mobile modal. Notice the context values:</Text>
|
|
125
|
+
<VStack gap={2} padding={3} backgroundColor="surface1">
|
|
126
|
+
<ExampleComponent />
|
|
127
|
+
</VStack>
|
|
128
|
+
<Text color="muted" variant="caption">
|
|
129
|
+
The hook automatically detects it's inside a modal context on mobile!
|
|
130
|
+
</Text>
|
|
131
|
+
</VStack>
|
|
132
|
+
);
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const handleOpenModal = () => {
|
|
136
|
+
openModal({
|
|
137
|
+
children: <ModalContent />,
|
|
138
|
+
header: 'Mobile Modal with Context',
|
|
139
|
+
});
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return (
|
|
143
|
+
<VStack gap={3}>
|
|
144
|
+
<VStack gap={2} padding={3} backgroundColor="surface2">
|
|
145
|
+
<Text variant="title3">Outside Modal</Text>
|
|
146
|
+
<ExampleComponent />
|
|
147
|
+
</VStack>
|
|
148
|
+
|
|
149
|
+
<Button onPress={handleOpenModal}>Open Modal to See Context Change</Button>
|
|
150
|
+
</VStack>
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### Using the Context Provider
|
|
156
|
+
|
|
157
|
+
You can also use the `OverlayContentContext` directly to provide context values:
|
|
158
|
+
|
|
159
|
+
```tsx
|
|
160
|
+
function ContextProviderExample() {
|
|
161
|
+
const ExampleComponent = () => {
|
|
162
|
+
const { isOverlay, isModal, isDrawer, isTour } = useOverlayContentContext();
|
|
163
|
+
|
|
164
|
+
return (
|
|
165
|
+
<VStack gap={2}>
|
|
166
|
+
<Text variant="title3">Overlay Context Information</Text>
|
|
167
|
+
<Text>Is inside any overlay: {isOverlay ? 'Yes' : 'No'}</Text>
|
|
168
|
+
<Text>Is inside modal: {isModal ? 'Yes' : 'No'}</Text>
|
|
169
|
+
<Text>Is inside drawer/tray: {isDrawer ? 'Yes' : 'No'}</Text>
|
|
170
|
+
<Text>Is inside tour: {isTour ? 'Yes' : 'No'}</Text>
|
|
171
|
+
</VStack>
|
|
172
|
+
);
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const contextValue = {
|
|
176
|
+
isModal: true,
|
|
177
|
+
isDrawer: false,
|
|
178
|
+
isTour: false,
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<OverlayContentContext.Provider value={contextValue}>
|
|
183
|
+
<VStack gap={2} padding={3} backgroundColor="surface2">
|
|
184
|
+
<Text variant="title3">Inside Context Provider</Text>
|
|
185
|
+
<ExampleComponent />
|
|
186
|
+
</VStack>
|
|
187
|
+
</OverlayContentContext.Provider>
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
### Conditional Rendering
|
|
193
|
+
|
|
194
|
+
Use the hook to conditionally render content based on overlay context:
|
|
195
|
+
|
|
196
|
+
```tsx
|
|
197
|
+
function ConditionalRenderingExample() {
|
|
198
|
+
const { openModal } = useModal();
|
|
199
|
+
|
|
200
|
+
const ConditionalContent = () => {
|
|
201
|
+
const { isOverlay, isModal } = useOverlayContentContext();
|
|
202
|
+
|
|
203
|
+
return (
|
|
204
|
+
<VStack gap={2}>
|
|
205
|
+
<Text variant="title3">Conditional Content</Text>
|
|
206
|
+
{isOverlay ? (
|
|
207
|
+
<VStack gap={1}>
|
|
208
|
+
<Text color="positive">✓ This content shows when inside an overlay</Text>
|
|
209
|
+
{isModal && <Text color="primary">🎯 Specifically inside a modal!</Text>}
|
|
210
|
+
</VStack>
|
|
211
|
+
) : (
|
|
212
|
+
<Text color="muted">This content shows when not in an overlay</Text>
|
|
213
|
+
)}
|
|
214
|
+
</VStack>
|
|
215
|
+
);
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
const handleOpenConditionalModal = () => {
|
|
219
|
+
openModal({
|
|
220
|
+
children: <ConditionalContent />,
|
|
221
|
+
header: 'Conditional Content Demo',
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
return (
|
|
226
|
+
<VStack gap={3}>
|
|
227
|
+
<VStack gap={2} padding={3} backgroundColor="surface2">
|
|
228
|
+
<Text variant="title3">Outside Modal</Text>
|
|
229
|
+
<ConditionalContent />
|
|
230
|
+
</VStack>
|
|
231
|
+
|
|
232
|
+
<Button onPress={handleOpenConditionalModal}>Open Modal to See Different Content</Button>
|
|
233
|
+
</VStack>
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Mobile-Specific Behavior
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
function MobileBehaviorExample() {
|
|
242
|
+
const { isModal, isDrawer, isTour } = useOverlayContentContext();
|
|
243
|
+
|
|
244
|
+
// Adjust touch behavior based on overlay type
|
|
245
|
+
const getTouchHandler = () => {
|
|
246
|
+
if (isModal) return handleModalTouch;
|
|
247
|
+
if (isDrawer) return handleDrawerTouch;
|
|
248
|
+
if (isTour) return handleTourTouch;
|
|
249
|
+
return handleDefaultTouch;
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
return (
|
|
253
|
+
<Pressable onPress={getTouchHandler()}>
|
|
254
|
+
<VStack gap={2} padding={3}>
|
|
255
|
+
<Text variant="title3">Touch Behavior</Text>
|
|
256
|
+
<Text>Touch handling adapts to overlay context</Text>
|
|
257
|
+
</VStack>
|
|
258
|
+
</Pressable>
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Safe Area Adjustments
|
|
264
|
+
|
|
265
|
+
```tsx
|
|
266
|
+
function SafeAreaExample() {
|
|
267
|
+
const { isModal, isDrawer } = useOverlayContentContext();
|
|
268
|
+
|
|
269
|
+
// Adjust safe area behavior for different overlay types
|
|
270
|
+
const shouldUseSafeArea = !isModal && !isDrawer;
|
|
271
|
+
|
|
272
|
+
return (
|
|
273
|
+
<VStack gap={2} padding={3} paddingTop={shouldUseSafeArea ? 'safeTop' : 3}>
|
|
274
|
+
<Text variant="title3">Safe Area Handling</Text>
|
|
275
|
+
<Text>Safe area behavior adapts to overlay context</Text>
|
|
276
|
+
</VStack>
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# usePreviousValue
|
|
2
|
+
|
|
3
|
+
Returns the previous value of a given variable, useful for comparing current and previous states in effects or for tracking changes over time.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { usePreviousValue } from '@coinbase/cds-common/hooks/usePreviousValue'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## API
|
|
12
|
+
|
|
13
|
+
### Parameters
|
|
14
|
+
|
|
15
|
+
The `usePreviousValue` hook accepts a single parameter:
|
|
16
|
+
|
|
17
|
+
- `value: T` - The value to track. Can be of any type.
|
|
18
|
+
|
|
19
|
+
### Returns
|
|
20
|
+
|
|
21
|
+
Returns the previous value of type `T | undefined`:
|
|
22
|
+
|
|
23
|
+
- Returns `undefined` on the first render
|
|
24
|
+
- Returns the previous value of the tracked value on subsequent renders
|
|
25
|
+
|
|
26
|
+
:::tip
|
|
27
|
+
This hook is useful for comparing the current value with its previous state, such as in animations, transitions, or when you need to react to value changes. The hook uses a ref to store the previous value, ensuring it persists between renders.
|
|
28
|
+
:::
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
### Basic usage
|
|
33
|
+
|
|
34
|
+
```tsx live
|
|
35
|
+
function Example() {
|
|
36
|
+
const [count, setCount] = useState(0);
|
|
37
|
+
const previousCount = usePreviousValue(count);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<VStack gap={3} alignItems="start">
|
|
41
|
+
<VStack gap={1}>
|
|
42
|
+
<TextHeadline>Current count: {count}</TextHeadline>
|
|
43
|
+
<TextHeadline>Previous count: {previousCount ?? 'None'}</TextHeadline>
|
|
44
|
+
</VStack>
|
|
45
|
+
<Button onClick={() => setCount(count + 1)}>Increment</Button>
|
|
46
|
+
</VStack>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### With Complex Values
|
|
52
|
+
|
|
53
|
+
```tsx live
|
|
54
|
+
function Example() {
|
|
55
|
+
const [user, setUser] = useState({ name: 'John', age: 25 });
|
|
56
|
+
const previousUser = usePreviousValue(user);
|
|
57
|
+
|
|
58
|
+
const updateAge = () => {
|
|
59
|
+
setUser((prev) => ({ ...prev, age: prev.age + 1 }));
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<VStack gap={3} alignItems="start">
|
|
64
|
+
<VStack gap={1}>
|
|
65
|
+
<TextHeadline>Name: {user.name}</TextHeadline>
|
|
66
|
+
<TextHeadline>Age: {user.age}</TextHeadline>
|
|
67
|
+
<TextHeadline>Previous age: {previousUser?.age ?? 'None'}</TextHeadline>
|
|
68
|
+
</VStack>
|
|
69
|
+
<Button onClick={updateAge}>Add Year</Button>
|
|
70
|
+
</VStack>
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|