@react-native-reusables/cli 0.0.9 → 0.0.10

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 (136) hide show
  1. package/dist/generated/components/primitives/accordion/accordion.tsx +216 -0
  2. package/dist/generated/components/primitives/accordion/accordion.web.tsx +295 -0
  3. package/dist/generated/components/primitives/accordion/index.ts +1 -0
  4. package/dist/generated/components/primitives/accordion/types.ts +45 -0
  5. package/dist/generated/components/primitives/alert-dialog/alert-dialog.tsx +237 -0
  6. package/dist/generated/components/primitives/alert-dialog/alert-dialog.web.tsx +256 -0
  7. package/dist/generated/components/primitives/alert-dialog/index.ts +1 -0
  8. package/dist/generated/components/primitives/alert-dialog/types.ts +48 -0
  9. package/dist/generated/components/primitives/aspect-ratio.tsx +23 -0
  10. package/dist/generated/components/primitives/avatar/ types.ts +10 -0
  11. package/dist/generated/components/primitives/avatar/index.tsx +95 -0
  12. package/dist/generated/components/primitives/checkbox/checkbox.tsx +101 -0
  13. package/dist/generated/components/primitives/checkbox/checkbox.web.tsx +114 -0
  14. package/dist/generated/components/primitives/checkbox/index.ts +1 -0
  15. package/dist/generated/components/primitives/checkbox/types.ts +11 -0
  16. package/dist/generated/components/primitives/collapsible/collapsible.tsx +119 -0
  17. package/dist/generated/components/primitives/collapsible/collapsible.web.tsx +157 -0
  18. package/dist/generated/components/primitives/collapsible/index.ts +1 -0
  19. package/dist/generated/components/primitives/collapsible/types.ts +18 -0
  20. package/dist/generated/components/primitives/context-menu/context-menu.tsx +626 -0
  21. package/dist/generated/components/primitives/context-menu/context-menu.web.tsx +504 -0
  22. package/dist/generated/components/primitives/context-menu/index.ts +1 -0
  23. package/dist/generated/components/primitives/context-menu/types.ts +82 -0
  24. package/dist/generated/components/primitives/dialog/dialog.tsx +211 -0
  25. package/dist/generated/components/primitives/dialog/dialog.web.tsx +197 -0
  26. package/dist/generated/components/primitives/dialog/index.ts +1 -0
  27. package/dist/generated/components/primitives/dialog/types.ts +60 -0
  28. package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.tsx +584 -0
  29. package/dist/generated/components/primitives/dropdown-menu/dropdown-menu.web.tsx +521 -0
  30. package/dist/generated/components/primitives/dropdown-menu/index.ts +1 -0
  31. package/dist/generated/components/primitives/dropdown-menu/types.ts +71 -0
  32. package/dist/generated/components/primitives/hooks/index.ts +3 -0
  33. package/dist/generated/components/primitives/hooks/useAugmentedRef.tsx +29 -0
  34. package/dist/generated/components/primitives/hooks/useControllableState.tsx +75 -0
  35. package/dist/generated/components/primitives/hooks/useRelativePosition.tsx +227 -0
  36. package/dist/generated/components/primitives/hover-card/hover-card.tsx +271 -0
  37. package/dist/generated/components/primitives/hover-card/hover-card.web.tsx +145 -0
  38. package/dist/generated/components/primitives/hover-card/index.ts +1 -0
  39. package/dist/generated/components/primitives/hover-card/types.ts +42 -0
  40. package/dist/generated/components/primitives/label/index.ts +1 -0
  41. package/dist/generated/components/primitives/label/label.tsx +31 -0
  42. package/dist/generated/components/primitives/label/label.web.tsx +36 -0
  43. package/dist/generated/components/primitives/label/types.ts +15 -0
  44. package/dist/generated/components/primitives/menubar/index.ts +1 -0
  45. package/dist/generated/components/primitives/menubar/menubar.tsx +624 -0
  46. package/dist/generated/components/primitives/menubar/menubar.web.tsx +543 -0
  47. package/dist/generated/components/primitives/menubar/types.ts +76 -0
  48. package/dist/generated/components/primitives/navigation-menu/index.ts +1 -0
  49. package/dist/generated/components/primitives/navigation-menu/navigation-menu.tsx +315 -0
  50. package/dist/generated/components/primitives/navigation-menu/navigation-menu.web.tsx +264 -0
  51. package/dist/generated/components/primitives/navigation-menu/types.ts +49 -0
  52. package/dist/generated/components/primitives/popover/index.ts +1 -0
  53. package/dist/generated/components/primitives/popover/popover.tsx +286 -0
  54. package/dist/generated/components/primitives/popover/popover.web.tsx +179 -0
  55. package/dist/generated/components/primitives/popover/types.ts +30 -0
  56. package/dist/generated/components/primitives/portal.tsx +67 -0
  57. package/dist/generated/components/primitives/progress/index.ts +1 -0
  58. package/dist/generated/components/primitives/progress/progress.tsx +59 -0
  59. package/dist/generated/components/primitives/progress/progress.web.tsx +36 -0
  60. package/dist/generated/components/primitives/progress/types.ts +7 -0
  61. package/dist/generated/components/primitives/radio-group/index.ts +1 -0
  62. package/dist/generated/components/primitives/radio-group/radio-group.tsx +116 -0
  63. package/dist/generated/components/primitives/radio-group/radio-group.web.tsx +78 -0
  64. package/dist/generated/components/primitives/radio-group/types.ts +15 -0
  65. package/dist/generated/components/primitives/select/index.ts +1 -0
  66. package/dist/generated/components/primitives/select/select.tsx +455 -0
  67. package/dist/generated/components/primitives/select/select.web.tsx +319 -0
  68. package/dist/generated/components/primitives/select/types.ts +87 -0
  69. package/dist/generated/components/primitives/separator/ types.ts +6 -0
  70. package/dist/generated/components/primitives/separator/index.tsx +23 -0
  71. package/dist/generated/components/primitives/slider/index.ts +1 -0
  72. package/dist/generated/components/primitives/slider/slider.tsx +89 -0
  73. package/dist/generated/components/primitives/slider/slider.web.tsx +67 -0
  74. package/dist/generated/components/primitives/slider/types.ts +24 -0
  75. package/dist/generated/components/primitives/slot.tsx +187 -0
  76. package/dist/generated/components/primitives/switch/index.ts +1 -0
  77. package/dist/generated/components/primitives/switch/switch.tsx +65 -0
  78. package/dist/generated/components/primitives/switch/switch.web.tsx +67 -0
  79. package/dist/generated/components/primitives/switch/types.ts +11 -0
  80. package/dist/generated/components/primitives/table.tsx +55 -0
  81. package/dist/generated/components/primitives/tabs/index.ts +1 -0
  82. package/dist/generated/components/primitives/tabs/tabs.tsx +133 -0
  83. package/dist/generated/components/primitives/tabs/tabs.web.tsx +97 -0
  84. package/dist/generated/components/primitives/tabs/types.ts +24 -0
  85. package/dist/generated/components/primitives/toast/ types.ts +7 -0
  86. package/dist/generated/components/primitives/toast/index.tsx +128 -0
  87. package/dist/generated/components/primitives/toggle/index.ts +1 -0
  88. package/dist/generated/components/primitives/toggle/toggle.tsx +37 -0
  89. package/dist/generated/components/primitives/toggle/toggle.web.tsx +26 -0
  90. package/dist/generated/components/primitives/toggle/types.ts +7 -0
  91. package/dist/generated/components/primitives/toggle-group/index.ts +1 -0
  92. package/dist/generated/components/primitives/toggle-group/toggle-group.tsx +125 -0
  93. package/dist/generated/components/primitives/toggle-group/toggle-group.web.tsx +124 -0
  94. package/dist/generated/components/primitives/toggle-group/types.ts +37 -0
  95. package/dist/generated/components/primitives/toolbar/index.ts +1 -0
  96. package/dist/generated/components/primitives/toolbar/toolbar.tsx +125 -0
  97. package/dist/generated/components/primitives/toolbar/toolbar.web.tsx +129 -0
  98. package/dist/generated/components/primitives/toolbar/types.ts +39 -0
  99. package/dist/generated/components/primitives/tooltip/index.ts +1 -0
  100. package/dist/generated/components/primitives/tooltip/tooltip.tsx +271 -0
  101. package/dist/generated/components/primitives/tooltip/tooltip.web.tsx +167 -0
  102. package/dist/generated/components/primitives/tooltip/types.ts +44 -0
  103. package/dist/generated/components/primitives/types.ts +105 -0
  104. package/dist/generated/components/primitives/utils.ts +61 -0
  105. package/dist/generated/components/ui/accordion.tsx +127 -0
  106. package/dist/generated/components/ui/alert-dialog.tsx +167 -0
  107. package/dist/generated/components/ui/aspect-ratio.tsx +5 -0
  108. package/dist/generated/components/ui/avatar.tsx +44 -0
  109. package/dist/generated/components/ui/badge.tsx +51 -0
  110. package/dist/generated/components/ui/button.tsx +88 -0
  111. package/dist/generated/components/ui/card.tsx +67 -0
  112. package/dist/generated/components/ui/checkbox.tsx +34 -0
  113. package/dist/generated/components/ui/collapsible.tsx +9 -0
  114. package/dist/generated/components/ui/context-menu.tsx +244 -0
  115. package/dist/generated/components/ui/dialog.tsx +150 -0
  116. package/dist/generated/components/ui/dropdown-menu.tsx +244 -0
  117. package/dist/generated/components/ui/hover-card.tsx +45 -0
  118. package/dist/generated/components/ui/input.tsx +26 -0
  119. package/dist/generated/components/ui/label.tsx +28 -0
  120. package/dist/generated/components/ui/menubar.tsx +260 -0
  121. package/dist/generated/components/ui/navigation-menu.tsx +177 -0
  122. package/dist/generated/components/ui/popover.tsx +39 -0
  123. package/dist/generated/components/ui/radio-group.tsx +38 -0
  124. package/dist/generated/components/ui/select.tsx +181 -0
  125. package/dist/generated/components/ui/separator.tsx +23 -0
  126. package/dist/generated/components/ui/skeleton.tsx +39 -0
  127. package/dist/generated/components/ui/switch.tsx +97 -0
  128. package/dist/generated/components/ui/table.tsx +99 -0
  129. package/dist/generated/components/ui/tabs.tsx +65 -0
  130. package/dist/generated/components/ui/text.tsx +24 -0
  131. package/dist/generated/components/ui/textarea.tsx +28 -0
  132. package/dist/generated/components/ui/toggle-group.tsx +86 -0
  133. package/dist/generated/components/ui/toggle.tsx +85 -0
  134. package/dist/generated/components/ui/tooltip.tsx +36 -0
  135. package/dist/generated/components/ui/typography.tsx +204 -0
  136. package/package.json +8 -8
@@ -0,0 +1,129 @@
1
+ import * as Toolbar from '@radix-ui/react-toolbar';
2
+ import * as React from 'react';
3
+ import { Pressable, View, type GestureResponderEvent } from 'react-native';
4
+ import * as Slot from '@rnr/slot';
5
+ import type {
6
+ PressableRef,
7
+ SlottablePressableProps,
8
+ SlottableViewProps,
9
+ ViewRef,
10
+ } from '@rnr/types';
11
+ import { ToggleGroupUtils } from '@rnr/utils';
12
+ import type { ToolbarRootProps, ToolbarToggleGroupProps, ToolbarToggleItem } from './types';
13
+
14
+ const Root = React.forwardRef<ViewRef, SlottableViewProps & ToolbarRootProps>(
15
+ ({ asChild, orientation, dir, loop, ...props }, ref) => {
16
+ const Component = asChild ? Slot.View : View;
17
+ return (
18
+ <Toolbar.Root orientation={orientation} dir={dir} loop={loop} asChild>
19
+ <Component ref={ref} {...props} />
20
+ </Toolbar.Root>
21
+ );
22
+ }
23
+ );
24
+
25
+ Root.displayName = 'RootWebToolbar';
26
+
27
+ const ToggleGroupContext = React.createContext<ToolbarToggleGroupProps | null>(null);
28
+
29
+ const ToggleGroup = React.forwardRef<ViewRef, SlottableViewProps & ToolbarToggleGroupProps>(
30
+ ({ asChild, type, value, onValueChange, disabled = false, ...viewProps }, ref) => {
31
+ const Component = asChild ? Slot.View : View;
32
+ return (
33
+ <ToggleGroupContext.Provider
34
+ value={
35
+ {
36
+ type,
37
+ value,
38
+ disabled,
39
+ onValueChange,
40
+ } as ToolbarToggleGroupProps
41
+ }
42
+ >
43
+ <Toolbar.ToggleGroup
44
+ type={type as any}
45
+ value={value as any}
46
+ onValueChange={onValueChange as any}
47
+ disabled={disabled}
48
+ asChild
49
+ >
50
+ <Component ref={ref} {...viewProps} />
51
+ </Toolbar.ToggleGroup>
52
+ </ToggleGroupContext.Provider>
53
+ );
54
+ }
55
+ );
56
+
57
+ ToggleGroup.displayName = 'ToggleGroupWebToolbar';
58
+
59
+ function useToggleGroupContext() {
60
+ const context = React.useContext(ToggleGroupContext);
61
+ if (!context) {
62
+ throw new Error(
63
+ 'ToggleGroup compound components cannot be rendered outside the ToggleGroup component'
64
+ );
65
+ }
66
+ return context;
67
+ }
68
+
69
+ const ToggleItem = React.forwardRef<PressableRef, SlottablePressableProps & ToolbarToggleItem>(
70
+ (
71
+ { asChild, value: itemValue, disabled: disabledProp = false, onPress: onPressProp, ...props },
72
+ ref
73
+ ) => {
74
+ const { type, disabled, value, onValueChange } = useToggleGroupContext();
75
+
76
+ function onPress(ev: GestureResponderEvent) {
77
+ if (disabled || disabledProp) return;
78
+ if (type === 'single') {
79
+ onValueChange(ToggleGroupUtils.getNewSingleValue(value, itemValue));
80
+ }
81
+ if (type === 'multiple') {
82
+ onValueChange(ToggleGroupUtils.getNewMultipleValue(value, itemValue));
83
+ }
84
+ onPressProp?.(ev);
85
+ }
86
+
87
+ const Component = asChild ? Slot.Pressable : Pressable;
88
+ return (
89
+ <Toolbar.ToggleItem value={itemValue} asChild>
90
+ <Component ref={ref} onPress={onPress} role='button' {...props} />
91
+ </Toolbar.ToggleItem>
92
+ );
93
+ }
94
+ );
95
+
96
+ ToggleItem.displayName = 'ToggleItemWebToolbar';
97
+
98
+ const Separator = React.forwardRef<ViewRef, SlottableViewProps>(({ asChild, ...props }, ref) => {
99
+ const Component = asChild ? Slot.View : View;
100
+ return <Component ref={ref} {...props} />;
101
+ });
102
+
103
+ Separator.displayName = 'SeparatorWebToolbar';
104
+
105
+ const Link = React.forwardRef<PressableRef, SlottablePressableProps>(
106
+ ({ asChild, ...props }, ref) => {
107
+ const Component = asChild ? Slot.Pressable : Pressable;
108
+ return (
109
+ <Toolbar.Link asChild>
110
+ <Component ref={ref} {...props} />
111
+ </Toolbar.Link>
112
+ );
113
+ }
114
+ );
115
+
116
+ Link.displayName = 'LinkWebToolbar';
117
+
118
+ const Button = React.forwardRef<PressableRef, SlottablePressableProps>(
119
+ ({ asChild, ...props }, ref) => {
120
+ const Component = asChild ? Slot.Pressable : Pressable;
121
+ return (
122
+ <Toolbar.Button asChild>
123
+ <Component ref={ref} role='button' {...props} />
124
+ </Toolbar.Button>
125
+ );
126
+ }
127
+ );
128
+
129
+ export { Button, Link, Root, Separator, ToggleGroup, ToggleItem };
@@ -0,0 +1,39 @@
1
+ interface ToolbarRootProps {
2
+ /**
3
+ * Platform: WEB ONLY
4
+ */
5
+ orientation?: 'horizontal' | 'vertical';
6
+ /**
7
+ * Platform: WEB ONLY
8
+ */
9
+ dir?: 'ltr' | 'rtl';
10
+ /**
11
+ * Platform: WEB ONLY
12
+ */
13
+ loop?: boolean;
14
+ }
15
+
16
+ type SingleToggleGroupProps = {
17
+ type: 'single';
18
+ value: string | undefined;
19
+ onValueChange: (val: string | undefined) => void;
20
+ };
21
+
22
+ type MultipleToggleGroupProps = {
23
+ type: 'multiple';
24
+ value: string[];
25
+ onValueChange: (val: string[]) => void;
26
+ };
27
+
28
+ type ToolbarToggleGroupProps = (
29
+ | SingleToggleGroupProps
30
+ | MultipleToggleGroupProps
31
+ ) & {
32
+ disabled?: boolean;
33
+ };
34
+
35
+ interface ToolbarToggleItem {
36
+ value: string;
37
+ }
38
+
39
+ export type { ToolbarToggleGroupProps, ToolbarToggleItem, ToolbarRootProps };
@@ -0,0 +1 @@
1
+ export * from './tooltip';
@@ -0,0 +1,271 @@
1
+ import * as React from 'react';
2
+ import {
3
+ BackHandler,
4
+ Pressable,
5
+ View,
6
+ type GestureResponderEvent,
7
+ type LayoutChangeEvent,
8
+ type LayoutRectangle,
9
+ } from 'react-native';
10
+ import { useControllableState, useRelativePosition, type LayoutPosition } from '@rnr/hooks';
11
+ import { Portal as RNPPortal } from '@rnr/portal';
12
+ import * as Slot from '@rnr/slot';
13
+ import type {
14
+ PositionedContentProps,
15
+ PressableRef,
16
+ SlottablePressableProps,
17
+ SlottableViewProps,
18
+ ViewRef,
19
+ } from '@rnr/types';
20
+ import type {
21
+ RootContext,
22
+ TooltipOverlayProps,
23
+ TooltipPortalProps,
24
+ TooltipRootProps,
25
+ } from './types';
26
+
27
+ interface IRootContext extends RootContext {
28
+ triggerPosition: LayoutPosition | null;
29
+ setTriggerPosition: (triggerPosition: LayoutPosition | null) => void;
30
+ contentLayout: LayoutRectangle | null;
31
+ setContentLayout: (contentLayout: LayoutRectangle | null) => void;
32
+ nativeID: string;
33
+ }
34
+
35
+ const RootContext = React.createContext<IRootContext | null>(null);
36
+
37
+ const Root = React.forwardRef<ViewRef, SlottableViewProps & TooltipRootProps>(
38
+ (
39
+ {
40
+ asChild,
41
+ defaultOpen,
42
+ open: openProp,
43
+ onOpenChange: onOpenChangeProp,
44
+ delayDuration: _delayDuration,
45
+ skipDelayDuration: _skipDelayDuration,
46
+ disableHoverableContent: _disableHoverableContent,
47
+ ...viewProps
48
+ },
49
+ ref
50
+ ) => {
51
+ const nativeID = React.useId();
52
+ const [triggerPosition, setTriggerPosition] = React.useState<LayoutPosition | null>(null);
53
+ const [contentLayout, setContentLayout] = React.useState<LayoutRectangle | null>(null);
54
+
55
+ const [open = false, onOpenChange] = useControllableState({
56
+ prop: openProp,
57
+ defaultProp: defaultOpen,
58
+ onChange: onOpenChangeProp,
59
+ });
60
+
61
+ const Component = asChild ? Slot.View : View;
62
+ return (
63
+ <RootContext.Provider
64
+ value={{
65
+ open,
66
+ onOpenChange,
67
+ contentLayout,
68
+ nativeID,
69
+ setContentLayout,
70
+ setTriggerPosition,
71
+ triggerPosition,
72
+ }}
73
+ >
74
+ <Component ref={ref} {...viewProps} />
75
+ </RootContext.Provider>
76
+ );
77
+ }
78
+ );
79
+
80
+ Root.displayName = 'RootNativeTooltip';
81
+
82
+ function useTooltipContext() {
83
+ const context = React.useContext(RootContext);
84
+ if (!context) {
85
+ throw new Error('Tooltip compound components cannot be rendered outside the Tooltip component');
86
+ }
87
+ return context;
88
+ }
89
+
90
+ const Trigger = React.forwardRef<PressableRef, SlottablePressableProps>(
91
+ ({ asChild, onPress: onPressProp, disabled = false, ...props }, ref) => {
92
+ const triggerRef = React.useRef<View>(null);
93
+ const { open, onOpenChange, setTriggerPosition } = useTooltipContext();
94
+
95
+ React.useImperativeHandle(
96
+ ref,
97
+ () => {
98
+ if (!triggerRef.current) {
99
+ return new View({});
100
+ }
101
+ return triggerRef.current;
102
+ },
103
+ [triggerRef.current]
104
+ );
105
+
106
+ function onPress(ev: GestureResponderEvent) {
107
+ if (disabled) return;
108
+ triggerRef.current?.measure((_x, _y, width, height, pageX, pageY) => {
109
+ setTriggerPosition({ width, pageX, pageY: pageY, height });
110
+ });
111
+ const newValue = !open;
112
+ onOpenChange(newValue);
113
+ onPressProp?.(ev);
114
+ }
115
+
116
+ const Component = asChild ? Slot.Pressable : Pressable;
117
+ return (
118
+ <Component
119
+ ref={triggerRef}
120
+ aria-disabled={disabled ?? undefined}
121
+ role='button'
122
+ onPress={onPress}
123
+ disabled={disabled ?? undefined}
124
+ {...props}
125
+ />
126
+ );
127
+ }
128
+ );
129
+
130
+ Trigger.displayName = 'TriggerNativeTooltip';
131
+
132
+ /**
133
+ * @warning when using a custom `<PortalHost />`, you might have to adjust the Content's sideOffset to account for nav elements like headers.
134
+ */
135
+ function Portal({ forceMount, hostName, children }: TooltipPortalProps) {
136
+ const value = useTooltipContext();
137
+
138
+ if (!value.triggerPosition) {
139
+ return null;
140
+ }
141
+
142
+ if (!forceMount) {
143
+ if (!value.open) {
144
+ return null;
145
+ }
146
+ }
147
+
148
+ return (
149
+ <RNPPortal hostName={hostName} name={`${value.nativeID}_portal`}>
150
+ <RootContext.Provider value={value}>{children}</RootContext.Provider>
151
+ </RNPPortal>
152
+ );
153
+ }
154
+
155
+ const Overlay = React.forwardRef<PressableRef, SlottablePressableProps & TooltipOverlayProps>(
156
+ ({ asChild, forceMount, onPress: OnPressProp, closeOnPress = true, ...props }, ref) => {
157
+ const { open, onOpenChange, setContentLayout, setTriggerPosition } = useTooltipContext();
158
+
159
+ function onPress(ev: GestureResponderEvent) {
160
+ if (closeOnPress) {
161
+ setTriggerPosition(null);
162
+ setContentLayout(null);
163
+ onOpenChange(false);
164
+ }
165
+ OnPressProp?.(ev);
166
+ }
167
+
168
+ if (!forceMount) {
169
+ if (!open) {
170
+ return null;
171
+ }
172
+ }
173
+
174
+ const Component = asChild ? Slot.Pressable : Pressable;
175
+ return <Component ref={ref} onPress={onPress} {...props} />;
176
+ }
177
+ );
178
+
179
+ Overlay.displayName = 'OverlayNativeTooltip';
180
+
181
+ /**
182
+ * @info `position`, `top`, `left`, and `maxWidth` style properties are controlled internally. Opt out of this behavior on native by setting `disablePositioningStyle` to `true`.
183
+ */
184
+ const Content = React.forwardRef<ViewRef, SlottableViewProps & PositionedContentProps>(
185
+ (
186
+ {
187
+ asChild = false,
188
+ forceMount,
189
+ align = 'center',
190
+ side = 'top',
191
+ sideOffset = 0,
192
+ alignOffset = 0,
193
+ avoidCollisions = true,
194
+ onLayout: onLayoutProp,
195
+ insets,
196
+ style,
197
+ disablePositioningStyle,
198
+ ...props
199
+ },
200
+ ref
201
+ ) => {
202
+ const {
203
+ open,
204
+ onOpenChange,
205
+ nativeID,
206
+ contentLayout,
207
+ setContentLayout,
208
+ setTriggerPosition,
209
+ triggerPosition,
210
+ } = useTooltipContext();
211
+
212
+ React.useEffect(() => {
213
+ const backHandler = BackHandler.addEventListener('hardwareBackPress', () => {
214
+ setTriggerPosition(null);
215
+ setContentLayout(null);
216
+ onOpenChange(false);
217
+ return true;
218
+ });
219
+
220
+ return () => {
221
+ setContentLayout(null);
222
+ backHandler.remove();
223
+ };
224
+ }, []);
225
+
226
+ const positionStyle = useRelativePosition({
227
+ align,
228
+ avoidCollisions,
229
+ triggerPosition,
230
+ contentLayout,
231
+ alignOffset,
232
+ insets,
233
+ sideOffset,
234
+ side,
235
+ disablePositioningStyle,
236
+ });
237
+
238
+ function onLayout(event: LayoutChangeEvent) {
239
+ setContentLayout(event.nativeEvent.layout);
240
+ onLayoutProp?.(event);
241
+ }
242
+
243
+ if (!forceMount) {
244
+ if (!open) {
245
+ return null;
246
+ }
247
+ }
248
+
249
+ const Component = asChild ? Slot.View : View;
250
+ return (
251
+ <Component
252
+ ref={ref}
253
+ role='tooltip'
254
+ nativeID={nativeID}
255
+ aria-modal={true}
256
+ style={[positionStyle, style]}
257
+ onLayout={onLayout}
258
+ onStartShouldSetResponder={onStartShouldSetResponder}
259
+ {...props}
260
+ />
261
+ );
262
+ }
263
+ );
264
+
265
+ Content.displayName = 'ContentNativeTooltip';
266
+
267
+ export { Content, Overlay, Portal, Root, Trigger };
268
+
269
+ function onStartShouldSetResponder() {
270
+ return true;
271
+ }
@@ -0,0 +1,167 @@
1
+ import * as Tooltip from '@radix-ui/react-tooltip';
2
+ import * as React from 'react';
3
+ import { Pressable, View, type GestureResponderEvent } from 'react-native';
4
+ import { useAugmentedRef, useControllableState } from '@rnr/hooks';
5
+ import * as Slot from '@rnr/slot';
6
+ import type {
7
+ PositionedContentProps,
8
+ PressableRef,
9
+ SlottablePressableProps,
10
+ SlottableViewProps,
11
+ ViewRef,
12
+ } from '@rnr/types';
13
+ import type {
14
+ RootContext,
15
+ TooltipOverlayProps,
16
+ TooltipPortalProps,
17
+ TooltipRootProps,
18
+ } from './types';
19
+
20
+ const RootContext = React.createContext<RootContext | null>(null);
21
+
22
+ const Root = React.forwardRef<ViewRef, SlottableViewProps & TooltipRootProps>(
23
+ (
24
+ {
25
+ asChild,
26
+ defaultOpen,
27
+ open: openProp,
28
+ onOpenChange: onOpenChangeProp,
29
+ delayDuration,
30
+ skipDelayDuration,
31
+ disableHoverableContent,
32
+ ...viewProps
33
+ },
34
+ ref
35
+ ) => {
36
+ const [open = false, onOpenChange] = useControllableState({
37
+ prop: openProp,
38
+ defaultProp: defaultOpen,
39
+ onChange: onOpenChangeProp,
40
+ });
41
+
42
+ const Component = asChild ? Slot.View : View;
43
+ return (
44
+ <RootContext.Provider value={{ open, onOpenChange }}>
45
+ <Tooltip.Provider
46
+ delayDuration={delayDuration}
47
+ skipDelayDuration={skipDelayDuration}
48
+ disableHoverableContent={disableHoverableContent}
49
+ >
50
+ <Tooltip.Root
51
+ open={open}
52
+ onOpenChange={onOpenChange}
53
+ delayDuration={delayDuration}
54
+ disableHoverableContent={disableHoverableContent}
55
+ >
56
+ <Component ref={ref} {...viewProps} />
57
+ </Tooltip.Root>
58
+ </Tooltip.Provider>
59
+ </RootContext.Provider>
60
+ );
61
+ }
62
+ );
63
+
64
+ Root.displayName = 'RootWebTooltip';
65
+
66
+ function useTooltipContext() {
67
+ const context = React.useContext(RootContext);
68
+ if (!context) {
69
+ throw new Error('Tooltip compound components cannot be rendered outside the Tooltip component');
70
+ }
71
+ return context;
72
+ }
73
+
74
+ const Trigger = React.forwardRef<PressableRef, SlottablePressableProps>(
75
+ ({ asChild, onPress: onPressProp, role: _role, disabled, ...props }, ref) => {
76
+ const augmentedRef = useAugmentedRef({ ref });
77
+ const { onOpenChange, open } = useTooltipContext();
78
+ function onPress(ev: GestureResponderEvent) {
79
+ if (onPressProp) {
80
+ onPressProp(ev);
81
+ }
82
+ onOpenChange(!open);
83
+ }
84
+
85
+ React.useLayoutEffect(() => {
86
+ if (augmentedRef.current) {
87
+ const augRef = augmentedRef.current as unknown as HTMLButtonElement;
88
+ augRef.dataset.state = open ? 'open' : 'closed';
89
+ augRef.type = 'button';
90
+ }
91
+ }, [open]);
92
+
93
+ const Component = asChild ? Slot.Pressable : Pressable;
94
+ return (
95
+ <Tooltip.Trigger disabled={disabled ?? undefined} asChild>
96
+ <Component
97
+ ref={augmentedRef}
98
+ onPress={onPress}
99
+ role='button'
100
+ disabled={disabled}
101
+ {...props}
102
+ />
103
+ </Tooltip.Trigger>
104
+ );
105
+ }
106
+ );
107
+
108
+ Trigger.displayName = 'TriggerWebTooltip';
109
+
110
+ function Portal({ forceMount, container, children }: TooltipPortalProps) {
111
+ return <Tooltip.Portal forceMount={forceMount} children={children} container={container} />;
112
+ }
113
+
114
+ const Overlay = React.forwardRef<PressableRef, SlottablePressableProps & TooltipOverlayProps>(
115
+ ({ asChild, forceMount, ...props }, ref) => {
116
+ const Component = asChild ? Slot.Pressable : Pressable;
117
+ return <Component ref={ref} {...props} />;
118
+ }
119
+ );
120
+
121
+ Overlay.displayName = 'OverlayWebTooltip';
122
+
123
+ const Content = React.forwardRef<ViewRef, SlottableViewProps & PositionedContentProps>(
124
+ (
125
+ {
126
+ asChild = false,
127
+ forceMount,
128
+ align = 'center',
129
+ side = 'top',
130
+ sideOffset = 0,
131
+ alignOffset = 0,
132
+ avoidCollisions = true,
133
+ insets: _insets,
134
+ disablePositioningStyle: _disablePositioningStyle,
135
+ onCloseAutoFocus: _onCloseAutoFocus,
136
+ onEscapeKeyDown,
137
+ onInteractOutside: _onInteractOutside,
138
+ onPointerDownOutside,
139
+ sticky,
140
+ hideWhenDetached,
141
+ ...props
142
+ },
143
+ ref
144
+ ) => {
145
+ const Component = asChild ? Slot.View : View;
146
+ return (
147
+ <Tooltip.Content
148
+ onEscapeKeyDown={onEscapeKeyDown}
149
+ onPointerDownOutside={onPointerDownOutside}
150
+ forceMount={forceMount}
151
+ align={align}
152
+ side={side}
153
+ sideOffset={sideOffset}
154
+ alignOffset={alignOffset}
155
+ avoidCollisions={avoidCollisions}
156
+ sticky={sticky}
157
+ hideWhenDetached={hideWhenDetached}
158
+ >
159
+ <Component ref={ref} {...props} />
160
+ </Tooltip.Content>
161
+ );
162
+ }
163
+ );
164
+
165
+ Content.displayName = 'ContentWebTooltip';
166
+
167
+ export { Content, Overlay, Portal, Root, Trigger };
@@ -0,0 +1,44 @@
1
+ import type { ForceMountable } from '@rnr/types';
2
+
3
+ interface RootContext extends TooltipRootProps {
4
+ open: boolean;
5
+ onOpenChange: (value: boolean) => void;
6
+ }
7
+
8
+ interface TooltipRootProps {
9
+ defaultOpen?: boolean;
10
+ open?: boolean;
11
+ onOpenChange?: (value: boolean) => void;
12
+ /**
13
+ * Platform: WEB ONLY
14
+ * @default 700
15
+ */
16
+ delayDuration?: number;
17
+ /**
18
+ * Platform: WEB ONLY
19
+ * @default 300
20
+ */
21
+ skipDelayDuration?: number;
22
+ /**
23
+ * Platform: WEB ONLY
24
+ */
25
+ disableHoverableContent?: boolean;
26
+ }
27
+
28
+ interface TooltipPortalProps extends ForceMountable {
29
+ children: React.ReactNode;
30
+ /**
31
+ * Platform: NATIVE ONLY
32
+ */
33
+ hostName?: string;
34
+ /**
35
+ * Platform: WEB ONLY
36
+ */
37
+ container?: HTMLElement | null | undefined;
38
+ }
39
+
40
+ interface TooltipOverlayProps extends ForceMountable {
41
+ closeOnPress?: boolean;
42
+ }
43
+
44
+ export type { RootContext, TooltipOverlayProps, TooltipPortalProps, TooltipRootProps };