@idealyst/components 1.0.82 → 1.0.84
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/CLAUDE.md +199 -232
- package/README.md +5 -5
- package/package.json +25 -7
- package/plugin/README.md +272 -0
- package/plugin/test-cases.jsx +112 -0
- package/plugin/web-legacy.js +320 -0
- package/plugin/web.js +422 -124
- package/src/Accordion/Accordion.native.tsx +182 -0
- package/src/Accordion/Accordion.styles.tsx +260 -0
- package/src/Accordion/Accordion.web.tsx +147 -0
- package/src/Accordion/index.native.tsx +3 -0
- package/src/Accordion/index.ts +3 -0
- package/src/Accordion/index.web.tsx +3 -0
- package/src/Accordion/types.ts +23 -0
- package/src/ActivityIndicator/ActivityIndicator.native.tsx +17 -12
- package/src/ActivityIndicator/ActivityIndicator.styles.tsx +83 -109
- package/src/ActivityIndicator/ActivityIndicator.web.tsx +23 -17
- package/src/ActivityIndicator/index.ts +5 -2
- package/src/ActivityIndicator/index.web.ts +5 -2
- package/src/ActivityIndicator/types.ts +15 -10
- package/src/Alert/Alert.native.tsx +113 -0
- package/src/Alert/Alert.styles.tsx +304 -0
- package/src/Alert/Alert.web.tsx +123 -0
- package/src/Alert/index.native.ts +5 -0
- package/src/Alert/index.ts +5 -0
- package/src/Alert/index.web.ts +5 -0
- package/src/Alert/types.ts +21 -0
- package/src/Avatar/Avatar.native.tsx +8 -6
- package/src/Avatar/Avatar.styles.tsx +64 -58
- package/src/Avatar/Avatar.web.tsx +13 -8
- package/src/Avatar/index.ts +5 -2
- package/src/Avatar/index.web.ts +5 -2
- package/src/Avatar/types.ts +19 -13
- package/src/Badge/Badge.native.tsx +59 -14
- package/src/Badge/Badge.styles.tsx +125 -139
- package/src/Badge/Badge.web.tsx +72 -16
- package/src/Badge/index.ts +5 -2
- package/src/Badge/index.web.ts +5 -2
- package/src/Badge/types.ts +23 -11
- package/src/Breadcrumb/Breadcrumb.native.tsx +225 -0
- package/src/Breadcrumb/Breadcrumb.styles.tsx +234 -0
- package/src/Breadcrumb/Breadcrumb.web.tsx +268 -0
- package/src/Breadcrumb/index.native.ts +5 -0
- package/src/Breadcrumb/index.ts +5 -0
- package/src/Breadcrumb/index.web.ts +5 -0
- package/src/Breadcrumb/types.ts +56 -0
- package/src/Button/Button.native.tsx +75 -24
- package/src/Button/Button.styles.tsx +248 -205
- package/src/Button/Button.web.tsx +82 -25
- package/src/Button/index.ts +5 -5
- package/src/Button/index.web.ts +5 -3
- package/src/Button/types.ts +32 -15
- package/src/Card/Card.native.tsx +14 -11
- package/src/Card/Card.styles.tsx +146 -220
- package/src/Card/Card.web.tsx +20 -21
- package/src/Card/index.ts +5 -5
- package/src/Card/index.web.ts +5 -3
- package/src/Card/types.ts +24 -17
- package/src/Checkbox/Checkbox.native.tsx +24 -34
- package/src/Checkbox/Checkbox.styles.tsx +223 -275
- package/src/Checkbox/Checkbox.web.tsx +30 -37
- package/src/Checkbox/index.ts +5 -5
- package/src/Checkbox/index.web.ts +5 -3
- package/src/Checkbox/types.ts +26 -20
- package/src/Chip/Chip.native.tsx +126 -0
- package/src/Chip/Chip.styles.tsx +138 -0
- package/src/Chip/Chip.web.tsx +154 -0
- package/src/Chip/index.native.ts +5 -0
- package/src/Chip/index.ts +5 -0
- package/src/Chip/index.web.ts +5 -0
- package/src/Chip/types.ts +51 -0
- package/src/Dialog/Dialog.native.tsx +65 -12
- package/src/Dialog/Dialog.styles.tsx +154 -136
- package/src/Dialog/Dialog.web.tsx +16 -11
- package/src/Dialog/index.ts +5 -2
- package/src/Dialog/index.web.ts +5 -2
- package/src/Dialog/types.ts +22 -16
- package/src/Divider/Divider.native.tsx +19 -14
- package/src/Divider/Divider.styles.tsx +273 -595
- package/src/Divider/Divider.web.tsx +19 -12
- package/src/Divider/index.ts +5 -5
- package/src/Divider/index.web.ts +5 -3
- package/src/Divider/types.ts +28 -19
- package/src/Icon/Icon.native.tsx +17 -24
- package/src/Icon/Icon.styles.tsx +64 -48
- package/src/Icon/Icon.web.tsx +14 -11
- package/src/Icon/IconSvg/IconSvg.native.tsx +42 -0
- package/src/Icon/IconSvg/IconSvg.web.tsx +40 -0
- package/src/Icon/IconSvg/index.native.ts +1 -0
- package/src/Icon/IconSvg/index.ts +1 -0
- package/src/Icon/icon-resolver.native.ts +27 -0
- package/src/Icon/icon-resolver.ts +70 -0
- package/src/Icon/index.ts +5 -5
- package/src/Icon/index.web.ts +5 -3
- package/src/Icon/types.ts +17 -11
- package/src/Image/Image.native.tsx +86 -0
- package/src/Image/Image.styles.tsx +57 -0
- package/src/Image/Image.web.tsx +92 -0
- package/src/Image/index.native.ts +5 -0
- package/src/Image/index.ts +5 -0
- package/src/Image/types.ts +21 -0
- package/src/Input/Input.native.tsx +103 -26
- package/src/Input/Input.styles.tsx +240 -177
- package/src/Input/Input.web.tsx +141 -38
- package/src/Input/index.ts +5 -5
- package/src/Input/index.web.ts +5 -3
- package/src/Input/types.ts +43 -20
- package/src/List/List.native.tsx +56 -0
- package/src/List/List.styles.tsx +257 -0
- package/src/List/List.web.tsx +43 -0
- package/src/List/ListContext.tsx +16 -0
- package/src/List/ListItem.native.tsx +111 -0
- package/src/List/ListItem.web.tsx +110 -0
- package/src/List/ListSection.native.tsx +31 -0
- package/src/List/ListSection.web.tsx +33 -0
- package/src/List/index.native.tsx +5 -0
- package/src/List/index.ts +5 -0
- package/src/List/index.web.tsx +5 -0
- package/src/List/types.ts +42 -0
- package/src/Menu/Menu.native.tsx +150 -0
- package/src/Menu/Menu.styles.tsx +185 -0
- package/src/Menu/Menu.web.tsx +99 -0
- package/src/Menu/MenuItem.native.tsx +66 -0
- package/src/Menu/MenuItem.styles.tsx +119 -0
- package/src/Menu/MenuItem.web.tsx +67 -0
- package/src/Menu/index.native.ts +3 -0
- package/src/Menu/index.ts +3 -0
- package/src/Menu/index.web.ts +3 -0
- package/src/Menu/types.ts +30 -0
- package/src/Popover/Popover.native.tsx +102 -32
- package/src/Popover/Popover.styles.tsx +100 -67
- package/src/Popover/Popover.web.tsx +36 -260
- package/src/Popover/index.ts +5 -2
- package/src/Popover/index.web.ts +5 -2
- package/src/Popover/types.ts +14 -13
- package/src/Pressable/Pressable.native.tsx +7 -6
- package/src/Pressable/Pressable.web.tsx +8 -6
- package/src/Pressable/index.ts +5 -2
- package/src/Pressable/index.web.ts +5 -2
- package/src/Pressable/types.ts +11 -10
- package/src/Progress/Progress.native.tsx +179 -0
- package/src/Progress/Progress.styles.tsx +164 -0
- package/src/Progress/Progress.web.tsx +144 -0
- package/src/Progress/index.native.ts +1 -0
- package/src/Progress/index.ts +5 -0
- package/src/Progress/index.web.ts +5 -0
- package/src/Progress/types.ts +21 -0
- package/src/RadioButton/RadioButton.native.tsx +88 -0
- package/src/RadioButton/RadioButton.styles.tsx +163 -0
- package/src/RadioButton/RadioButton.web.tsx +85 -0
- package/src/RadioButton/RadioGroup.native.tsx +43 -0
- package/src/RadioButton/RadioGroup.web.tsx +49 -0
- package/src/RadioButton/index.native.ts +2 -0
- package/src/RadioButton/index.ts +2 -0
- package/src/RadioButton/index.web.ts +2 -0
- package/src/RadioButton/types.ts +29 -0
- package/src/SVGImage/SVGImage.native.tsx +9 -7
- package/src/SVGImage/SVGImage.styles.tsx +63 -55
- package/src/SVGImage/SVGImage.web.tsx +16 -13
- package/src/SVGImage/index.ts +5 -5
- package/src/SVGImage/index.web.ts +5 -2
- package/src/SVGImage/types.ts +7 -3
- package/src/Screen/Screen.native.tsx +43 -17
- package/src/Screen/Screen.styles.tsx +58 -54
- package/src/Screen/Screen.web.tsx +11 -5
- package/src/Screen/index.ts +5 -2
- package/src/Screen/index.web.ts +5 -2
- package/src/Screen/types.ts +23 -9
- package/src/Select/Select.native.tsx +347 -0
- package/src/Select/Select.styles.tsx +335 -0
- package/src/Select/Select.web.tsx +276 -0
- package/src/Select/index.native.ts +2 -0
- package/src/Select/index.ts +5 -0
- package/src/Select/index.web.ts +5 -0
- package/src/Select/types.ts +124 -0
- package/src/Skeleton/Skeleton.native.tsx +139 -0
- package/src/Skeleton/Skeleton.styles.tsx +59 -0
- package/src/Skeleton/Skeleton.web.tsx +112 -0
- package/src/Skeleton/index.native.ts +4 -0
- package/src/Skeleton/index.ts +5 -0
- package/src/Skeleton/index.web.ts +5 -0
- package/src/Skeleton/types.ts +75 -0
- package/src/Slider/Slider.native.tsx +248 -0
- package/src/Slider/Slider.styles.tsx +241 -0
- package/src/Slider/Slider.web.tsx +226 -0
- package/src/Slider/index.native.ts +3 -0
- package/src/Slider/index.ts +5 -0
- package/src/Slider/index.web.ts +5 -0
- package/src/Slider/types.ts +31 -0
- package/src/Switch/Switch.native.tsx +131 -0
- package/src/Switch/Switch.styles.tsx +169 -0
- package/src/Switch/Switch.web.tsx +121 -0
- package/src/Switch/index.native.ts +3 -0
- package/src/Switch/index.ts +5 -0
- package/src/Switch/index.web.ts +5 -0
- package/src/Switch/types.ts +21 -0
- package/src/TabBar/TabBar.native.tsx +142 -0
- package/src/TabBar/TabBar.styles.tsx +399 -0
- package/src/TabBar/TabBar.web.tsx +205 -0
- package/src/TabBar/index.native.tsx +3 -0
- package/src/TabBar/index.ts +3 -0
- package/src/TabBar/index.web.tsx +3 -0
- package/src/TabBar/types.ts +26 -0
- package/src/Table/Table.native.tsx +122 -0
- package/src/Table/Table.styles.tsx +283 -0
- package/src/Table/Table.web.tsx +112 -0
- package/src/Table/index.native.tsx +3 -0
- package/src/Table/index.ts +3 -0
- package/src/Table/index.web.tsx +3 -0
- package/src/Table/types.ts +28 -0
- package/src/Text/Text.native.tsx +12 -11
- package/src/Text/Text.styles.tsx +76 -64
- package/src/Text/Text.web.tsx +14 -9
- package/src/Text/index.ts +5 -5
- package/src/Text/index.web.ts +5 -3
- package/src/Text/types.ts +20 -13
- package/src/TextArea/TextArea.native.tsx +134 -0
- package/src/TextArea/TextArea.styles.tsx +175 -0
- package/src/TextArea/TextArea.web.tsx +156 -0
- package/src/TextArea/index.native.ts +3 -0
- package/src/TextArea/index.ts +3 -0
- package/src/TextArea/index.web.ts +3 -0
- package/src/TextArea/types.ts +30 -0
- package/src/Tooltip/Tooltip.native.tsx +165 -0
- package/src/Tooltip/Tooltip.styles.tsx +73 -0
- package/src/Tooltip/Tooltip.web.tsx +87 -0
- package/src/Tooltip/index.native.ts +3 -0
- package/src/Tooltip/index.ts +3 -0
- package/src/Tooltip/types.ts +18 -0
- package/src/Video/Video.native.tsx +105 -0
- package/src/Video/Video.styles.tsx +39 -0
- package/src/Video/Video.web.tsx +115 -0
- package/src/Video/index.native.ts +5 -0
- package/src/Video/index.ts +5 -0
- package/src/Video/types.ts +29 -0
- package/src/View/View.native.tsx +9 -14
- package/src/View/View.styles.tsx +101 -93
- package/src/View/View.web.tsx +16 -17
- package/src/View/index.ts +5 -5
- package/src/View/index.web.ts +5 -3
- package/src/View/types.ts +29 -21
- package/src/examples/AccordionExamples.tsx +126 -0
- package/src/examples/AlertExamples.tsx +280 -0
- package/src/examples/AvatarExamples.tsx +23 -23
- package/src/examples/BadgeExamples.tsx +109 -41
- package/src/examples/BreadcrumbExamples.tsx +312 -0
- package/src/examples/ButtonExamples.tsx +160 -33
- package/src/examples/CardExamples.tsx +40 -40
- package/src/examples/CheckboxExamples.tsx +12 -12
- package/src/examples/ChipExamples.tsx +197 -0
- package/src/examples/DialogExamples.tsx +22 -22
- package/src/examples/DividerExamples.tsx +49 -49
- package/src/examples/IconExamples.tsx +270 -54
- package/src/examples/ImageExamples.tsx +174 -0
- package/src/examples/InputExamples.tsx +75 -17
- package/src/examples/ListExamples.tsx +288 -0
- package/src/examples/MenuExamples.tsx +144 -0
- package/src/examples/PopoverExamples.tsx +69 -73
- package/src/examples/ProgressExamples.tsx +137 -0
- package/src/examples/RadioButtonExamples.tsx +161 -0
- package/src/examples/SVGImageExamples.tsx +19 -17
- package/src/examples/ScreenExamples.tsx +31 -31
- package/src/examples/SelectExamples.tsx +423 -0
- package/src/examples/SkeletonExamples.tsx +206 -0
- package/src/examples/SliderExamples.tsx +200 -0
- package/src/examples/SwitchExamples.tsx +182 -0
- package/src/examples/TabBarExamples.tsx +143 -0
- package/src/examples/TableExamples.tsx +280 -0
- package/src/examples/TextAreaExamples.tsx +173 -0
- package/src/examples/TextExamples.tsx +28 -32
- package/src/examples/ThemeExtensionExamples.tsx +10 -10
- package/src/examples/TooltipExamples.tsx +126 -0
- package/src/examples/VideoExamples.tsx +144 -0
- package/src/examples/ViewExamples.tsx +64 -56
- package/src/examples/index.ts +18 -3
- package/src/hooks/useMergeRefs.ts +16 -0
- package/src/hooks/useSmartPosition.native.ts +169 -0
- package/src/index.native.ts +80 -9
- package/src/index.ts +75 -1
- package/src/internal/BoundedModalContent.native.tsx +58 -0
- package/src/internal/PositionedPortal.tsx +254 -0
- package/src/internal/SafeAreaDebugOverlay.native.tsx +173 -0
- package/src/unistyles.d.ts +6 -0
- package/src/utils/buildSizeVariants.ts +16 -0
- package/src/utils/deepMerge.ts +43 -0
- package/src/utils/positionUtils.native.ts +280 -0
- package/src/utils/styleHelpers.ts +48 -0
- package/LLM-ACCESS-GUIDE.md +0 -143
- package/src/ActivityIndicator/README.md +0 -132
- package/src/Avatar/README.md +0 -139
- package/src/Badge/README.md +0 -170
- package/src/Button/Button.types.ts +0 -12
- package/src/Button/README.md +0 -262
- package/src/Card/README.md +0 -258
- package/src/Checkbox/README.md +0 -102
- package/src/Dialog/README.md +0 -210
- package/src/Divider/README.md +0 -108
- package/src/Icon/README.md +0 -81
- package/src/Input/README.md +0 -100
- package/src/SVGImage/README.md +0 -209
- package/src/Screen/README.md +0 -86
- package/src/Text/README.md +0 -94
- package/src/View/README.md +0 -107
- package/src/examples/AllExamples.tsx +0 -84
- package/src/examples/README.md +0 -136
- package/src/examples/ValidationExamples.tsx +0 -95
- package/src/examples/extendedTheme.ts +0 -329
- package/src/theme/breakpoints.ts +0 -8
- package/src/theme/colorResolver.ts +0 -218
- package/src/theme/colors.ts +0 -315
- package/src/theme/defaultThemes.ts +0 -326
- package/src/theme/index.ts +0 -188
- package/src/theme/themeBuilder.ts +0 -602
- package/src/theme/unistyles.d.ts +0 -6
- package/src/theme/variantHelpers.ts +0 -584
- package/src/theme/variants.ts +0 -56
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Screen, View, Text, Button } from '@idealyst/components';
|
|
3
|
+
import Tooltip from '../Tooltip';
|
|
4
|
+
|
|
5
|
+
export const TooltipExamples: React.FC = () => {
|
|
6
|
+
return (
|
|
7
|
+
<Screen background="primary" padding="lg">
|
|
8
|
+
<View spacing="lg">
|
|
9
|
+
<Text size="xl" weight="bold">Tooltip Examples</Text>
|
|
10
|
+
|
|
11
|
+
<View spacing="md">
|
|
12
|
+
<Text size="lg" weight="semibold">Basic Tooltip</Text>
|
|
13
|
+
<Tooltip content="This is a tooltip">
|
|
14
|
+
<Button type="outlined">Hover over me</Button>
|
|
15
|
+
</Tooltip>
|
|
16
|
+
</View>
|
|
17
|
+
|
|
18
|
+
<View spacing="md">
|
|
19
|
+
<Text size="lg" weight="semibold">Placements</Text>
|
|
20
|
+
<View spacing="sm" style={{ alignItems: 'center' }}>
|
|
21
|
+
<Tooltip content="Top tooltip" placement="top">
|
|
22
|
+
<Button type="outlined">Top</Button>
|
|
23
|
+
</Tooltip>
|
|
24
|
+
<View style={{ flexDirection: 'row', gap: 16 }}>
|
|
25
|
+
<Tooltip content="Left tooltip" placement="left">
|
|
26
|
+
<Button type="outlined">Left</Button>
|
|
27
|
+
</Tooltip>
|
|
28
|
+
<Tooltip content="Right tooltip" placement="right">
|
|
29
|
+
<Button type="outlined">Right</Button>
|
|
30
|
+
</Tooltip>
|
|
31
|
+
</View>
|
|
32
|
+
<Tooltip content="Bottom tooltip" placement="bottom">
|
|
33
|
+
<Button type="outlined">Bottom</Button>
|
|
34
|
+
</Tooltip>
|
|
35
|
+
</View>
|
|
36
|
+
</View>
|
|
37
|
+
|
|
38
|
+
<View spacing="md">
|
|
39
|
+
<Text size="lg" weight="semibold">Sizes</Text>
|
|
40
|
+
<View style={{ flexDirection: 'row', gap: 16, flexWrap: 'wrap' }}>
|
|
41
|
+
<Tooltip content="Small tooltip" size="sm">
|
|
42
|
+
<Button type="outlined" size="sm">Small</Button>
|
|
43
|
+
</Tooltip>
|
|
44
|
+
<Tooltip content="Medium tooltip" size="md">
|
|
45
|
+
<Button type="outlined" size="md">Medium</Button>
|
|
46
|
+
</Tooltip>
|
|
47
|
+
<Tooltip content="Large tooltip" size="lg">
|
|
48
|
+
<Button type="outlined" size="lg">Large</Button>
|
|
49
|
+
</Tooltip>
|
|
50
|
+
</View>
|
|
51
|
+
</View>
|
|
52
|
+
|
|
53
|
+
<View spacing="md">
|
|
54
|
+
<Text size="lg" weight="semibold">Intent Colors</Text>
|
|
55
|
+
<View style={{ flexDirection: 'row', gap: 16, flexWrap: 'wrap' }}>
|
|
56
|
+
<Tooltip content="Primary tooltip" intent="primary">
|
|
57
|
+
<Button type="contained" intent="primary">Primary</Button>
|
|
58
|
+
</Tooltip>
|
|
59
|
+
<Tooltip content="Success tooltip" intent="success">
|
|
60
|
+
<Button type="contained" intent="success">Success</Button>
|
|
61
|
+
</Tooltip>
|
|
62
|
+
<Tooltip content="Warning tooltip" intent="warning">
|
|
63
|
+
<Button type="contained" intent="warning">Warning</Button>
|
|
64
|
+
</Tooltip>
|
|
65
|
+
<Tooltip content="Error tooltip" intent="error">
|
|
66
|
+
<Button type="contained" intent="error">Error</Button>
|
|
67
|
+
</Tooltip>
|
|
68
|
+
<Tooltip content="Neutral tooltip" intent="neutral">
|
|
69
|
+
<Button type="contained" intent="neutral">Neutral</Button>
|
|
70
|
+
</Tooltip>
|
|
71
|
+
</View>
|
|
72
|
+
</View>
|
|
73
|
+
|
|
74
|
+
<View spacing="md">
|
|
75
|
+
<Text size="lg" weight="semibold">Custom Delay</Text>
|
|
76
|
+
<View style={{ flexDirection: 'row', gap: 16, flexWrap: 'wrap' }}>
|
|
77
|
+
<Tooltip content="Instant (0ms)" delay={0}>
|
|
78
|
+
<Button type="outlined">No Delay</Button>
|
|
79
|
+
</Tooltip>
|
|
80
|
+
<Tooltip content="Quick (200ms)" delay={200}>
|
|
81
|
+
<Button type="outlined">Default</Button>
|
|
82
|
+
</Tooltip>
|
|
83
|
+
<Tooltip content="Slow (1000ms)" delay={1000}>
|
|
84
|
+
<Button type="outlined">Slow</Button>
|
|
85
|
+
</Tooltip>
|
|
86
|
+
</View>
|
|
87
|
+
</View>
|
|
88
|
+
|
|
89
|
+
<View spacing="md">
|
|
90
|
+
<Text size="lg" weight="semibold">Long Content</Text>
|
|
91
|
+
<Tooltip content="This is a longer tooltip that demonstrates how the component handles multi-line content automatically">
|
|
92
|
+
<Button type="outlined">Hover for long text</Button>
|
|
93
|
+
</Tooltip>
|
|
94
|
+
</View>
|
|
95
|
+
|
|
96
|
+
<View spacing="md">
|
|
97
|
+
<Text size="lg" weight="semibold">On Text</Text>
|
|
98
|
+
<View>
|
|
99
|
+
<Tooltip content="Additional information">
|
|
100
|
+
<Text style={{ textDecorationLine: 'underline' }}>
|
|
101
|
+
Hover over this text
|
|
102
|
+
</Text>
|
|
103
|
+
</Tooltip>
|
|
104
|
+
</View>
|
|
105
|
+
</View>
|
|
106
|
+
|
|
107
|
+
<View spacing="md">
|
|
108
|
+
<Text size="lg" weight="semibold">Rich Content</Text>
|
|
109
|
+
<Tooltip
|
|
110
|
+
content={
|
|
111
|
+
<View spacing="xs">
|
|
112
|
+
<Text weight="bold">Rich Tooltip</Text>
|
|
113
|
+
<Text>With multiple lines</Text>
|
|
114
|
+
<Text>and formatting</Text>
|
|
115
|
+
</View>
|
|
116
|
+
}
|
|
117
|
+
>
|
|
118
|
+
<Button type="outlined">Rich Content</Button>
|
|
119
|
+
</Tooltip>
|
|
120
|
+
</View>
|
|
121
|
+
</View>
|
|
122
|
+
</Screen>
|
|
123
|
+
);
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
export default TooltipExamples;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Screen, View, Text } from '@idealyst/components';
|
|
3
|
+
import Video from '../Video';
|
|
4
|
+
|
|
5
|
+
export const VideoExamples: React.FC = () => {
|
|
6
|
+
return (
|
|
7
|
+
<Screen background="primary" padding="lg">
|
|
8
|
+
<View spacing="lg">
|
|
9
|
+
<Text size="xl" weight="bold">Video Examples</Text>
|
|
10
|
+
|
|
11
|
+
<View spacing="sm" style={{ padding: 12, backgroundColor: '#fff3cd', borderRadius: 8 }}>
|
|
12
|
+
<Text size="sm" weight="semibold">Note:</Text>
|
|
13
|
+
<Text size="sm">
|
|
14
|
+
On React Native, this component requires react-native-video to be installed.
|
|
15
|
+
The examples below use sample videos from the web.
|
|
16
|
+
</Text>
|
|
17
|
+
</View>
|
|
18
|
+
|
|
19
|
+
<View spacing="md">
|
|
20
|
+
<Text size="lg" weight="semibold">Basic Video with Controls</Text>
|
|
21
|
+
<Video
|
|
22
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"
|
|
23
|
+
width="100%"
|
|
24
|
+
aspectRatio={16 / 9}
|
|
25
|
+
controls={true}
|
|
26
|
+
/>
|
|
27
|
+
</View>
|
|
28
|
+
|
|
29
|
+
<View spacing="md">
|
|
30
|
+
<Text size="lg" weight="semibold">Video with Poster</Text>
|
|
31
|
+
<Video
|
|
32
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4"
|
|
33
|
+
poster="https://picsum.photos/800/450"
|
|
34
|
+
width="100%"
|
|
35
|
+
aspectRatio={16 / 9}
|
|
36
|
+
controls={true}
|
|
37
|
+
/>
|
|
38
|
+
</View>
|
|
39
|
+
|
|
40
|
+
<View spacing="md">
|
|
41
|
+
<Text size="lg" weight="semibold">Autoplay & Loop</Text>
|
|
42
|
+
<Text size="sm" color="secondary">
|
|
43
|
+
Video plays automatically and loops continuously
|
|
44
|
+
</Text>
|
|
45
|
+
<Video
|
|
46
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4"
|
|
47
|
+
width="100%"
|
|
48
|
+
aspectRatio={16 / 9}
|
|
49
|
+
autoPlay={true}
|
|
50
|
+
loop={true}
|
|
51
|
+
muted={true}
|
|
52
|
+
controls={true}
|
|
53
|
+
/>
|
|
54
|
+
</View>
|
|
55
|
+
|
|
56
|
+
<View spacing="md">
|
|
57
|
+
<Text size="lg" weight="semibold">Fixed Size</Text>
|
|
58
|
+
<Video
|
|
59
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4"
|
|
60
|
+
width={640}
|
|
61
|
+
height={360}
|
|
62
|
+
controls={true}
|
|
63
|
+
/>
|
|
64
|
+
</View>
|
|
65
|
+
|
|
66
|
+
<View spacing="md">
|
|
67
|
+
<Text size="lg" weight="semibold">Rounded Corners</Text>
|
|
68
|
+
<Video
|
|
69
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4"
|
|
70
|
+
width="100%"
|
|
71
|
+
aspectRatio={16 / 9}
|
|
72
|
+
borderRadius={16}
|
|
73
|
+
controls={true}
|
|
74
|
+
/>
|
|
75
|
+
</View>
|
|
76
|
+
|
|
77
|
+
<View spacing="md">
|
|
78
|
+
<Text size="lg" weight="semibold">Different Aspect Ratios</Text>
|
|
79
|
+
<View spacing="sm">
|
|
80
|
+
<Text size="sm" weight="medium">16:9 (Widescreen)</Text>
|
|
81
|
+
<Video
|
|
82
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4"
|
|
83
|
+
width="100%"
|
|
84
|
+
aspectRatio={16 / 9}
|
|
85
|
+
controls={true}
|
|
86
|
+
/>
|
|
87
|
+
|
|
88
|
+
<Text size="sm" weight="medium">4:3 (Standard)</Text>
|
|
89
|
+
<Video
|
|
90
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerMeltdowns.mp4"
|
|
91
|
+
width="100%"
|
|
92
|
+
aspectRatio={4 / 3}
|
|
93
|
+
controls={true}
|
|
94
|
+
/>
|
|
95
|
+
|
|
96
|
+
<Text size="sm" weight="medium">1:1 (Square)</Text>
|
|
97
|
+
<Video
|
|
98
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/Sintel.mp4"
|
|
99
|
+
width={300}
|
|
100
|
+
aspectRatio={1}
|
|
101
|
+
controls={true}
|
|
102
|
+
/>
|
|
103
|
+
</View>
|
|
104
|
+
</View>
|
|
105
|
+
|
|
106
|
+
<View spacing="md">
|
|
107
|
+
<Text size="lg" weight="semibold">Without Controls</Text>
|
|
108
|
+
<Text size="sm" color="secondary">
|
|
109
|
+
Video with controls disabled
|
|
110
|
+
</Text>
|
|
111
|
+
<Video
|
|
112
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/TearsOfSteel.mp4"
|
|
113
|
+
width="100%"
|
|
114
|
+
aspectRatio={16 / 9}
|
|
115
|
+
controls={false}
|
|
116
|
+
autoPlay={true}
|
|
117
|
+
loop={true}
|
|
118
|
+
muted={true}
|
|
119
|
+
/>
|
|
120
|
+
</View>
|
|
121
|
+
|
|
122
|
+
<View spacing="md">
|
|
123
|
+
<Text size="lg" weight="semibold">Event Handlers</Text>
|
|
124
|
+
<Text size="sm" color="secondary">
|
|
125
|
+
Check console for video events (onLoad, onPlay, onPause, onEnd)
|
|
126
|
+
</Text>
|
|
127
|
+
<Video
|
|
128
|
+
source="http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/VolkswagenGTIReview.mp4"
|
|
129
|
+
width="100%"
|
|
130
|
+
aspectRatio={16 / 9}
|
|
131
|
+
controls={true}
|
|
132
|
+
onLoad={() => console.log('Video loaded')}
|
|
133
|
+
onPlay={() => console.log('Video playing')}
|
|
134
|
+
onPause={() => console.log('Video paused')}
|
|
135
|
+
onEnd={() => console.log('Video ended')}
|
|
136
|
+
onProgress={(progress) => console.log('Progress:', progress)}
|
|
137
|
+
/>
|
|
138
|
+
</View>
|
|
139
|
+
</View>
|
|
140
|
+
</Screen>
|
|
141
|
+
);
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
export default VideoExamples;
|
|
@@ -1,107 +1,115 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
1
|
import { Screen, View, Text } from '../index';
|
|
3
2
|
|
|
4
3
|
export const ViewExamples = () => {
|
|
5
4
|
return (
|
|
6
5
|
<Screen background="primary" padding="lg">
|
|
7
6
|
<View spacing="none">
|
|
8
|
-
<Text size="
|
|
7
|
+
<Text size="lg" weight="bold" align="center">
|
|
9
8
|
View Examples
|
|
10
9
|
</Text>
|
|
11
|
-
|
|
10
|
+
|
|
12
11
|
{/* Spacing Examples */}
|
|
13
12
|
<View spacing="md">
|
|
14
|
-
<Text size="
|
|
15
|
-
<View style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap' }}>
|
|
16
|
-
<View spacing="none" background="
|
|
17
|
-
<Text size="
|
|
13
|
+
<Text size="md" weight="semibold">Spacing Variants</Text>
|
|
14
|
+
<View style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap', alignItems: 'center' }}>
|
|
15
|
+
<View spacing="none" background="secondary" border="thin">
|
|
16
|
+
<Text size="sm">None</Text>
|
|
18
17
|
</View>
|
|
19
|
-
<View spacing="xs" background="
|
|
20
|
-
<Text size="
|
|
18
|
+
<View spacing="xs" background="secondary" border="thin">
|
|
19
|
+
<Text size="sm">XS</Text>
|
|
21
20
|
</View>
|
|
22
|
-
<View spacing="sm" background="
|
|
23
|
-
<Text size="
|
|
21
|
+
<View spacing="sm" background="secondary" border="thin">
|
|
22
|
+
<Text size="sm">SM</Text>
|
|
24
23
|
</View>
|
|
25
|
-
<View spacing="md" background="
|
|
26
|
-
<Text size="
|
|
24
|
+
<View spacing="md" background="secondary" border="thin">
|
|
25
|
+
<Text size="sm">MD</Text>
|
|
27
26
|
</View>
|
|
28
|
-
<View spacing="lg" background="
|
|
29
|
-
<Text size="
|
|
27
|
+
<View spacing="lg" background="secondary" border="thin">
|
|
28
|
+
<Text size="sm">LG</Text>
|
|
30
29
|
</View>
|
|
31
|
-
<View spacing="xl" background="
|
|
32
|
-
<Text size="
|
|
30
|
+
<View spacing="xl" background="secondary" border="thin">
|
|
31
|
+
<Text size="sm">XL</Text>
|
|
33
32
|
</View>
|
|
34
33
|
</View>
|
|
35
34
|
</View>
|
|
36
35
|
|
|
37
36
|
{/* Background Examples */}
|
|
38
37
|
<View spacing="md">
|
|
39
|
-
<Text size="
|
|
38
|
+
<Text size="md" weight="semibold">Background Variants</Text>
|
|
40
39
|
<View style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap' }}>
|
|
41
|
-
<View background="transparent" border="thin" spacing="sm">
|
|
42
|
-
<Text size="
|
|
40
|
+
<View background="transparent" border="thin" spacing="sm" radius="sm">
|
|
41
|
+
<Text size="sm" color="primary">Transparent</Text>
|
|
42
|
+
</View>
|
|
43
|
+
<View background="primary" spacing="sm" radius="sm">
|
|
44
|
+
<Text size="sm" color="primary">Primary</Text>
|
|
43
45
|
</View>
|
|
44
|
-
<View background="
|
|
45
|
-
<Text size="
|
|
46
|
+
<View background="secondary" spacing="sm" radius="sm">
|
|
47
|
+
<Text size="sm" color="secondary">Secondary</Text>
|
|
46
48
|
</View>
|
|
47
|
-
<View background="
|
|
48
|
-
<Text size="
|
|
49
|
+
<View background="tertiary" spacing="sm" radius="sm">
|
|
50
|
+
<Text size="sm" color="tertiary">Tertiary</Text>
|
|
49
51
|
</View>
|
|
50
|
-
<View background="
|
|
51
|
-
<Text size="
|
|
52
|
+
<View background="inverse" spacing="sm" radius="sm">
|
|
53
|
+
<Text size="sm" color="inverse">Inverse (of primary)</Text>
|
|
54
|
+
</View>
|
|
55
|
+
<View background="inverse-secondary" spacing="sm" radius="sm">
|
|
56
|
+
<Text size="sm" color="inverse-secondary">Inverse Secondary</Text>
|
|
57
|
+
</View>
|
|
58
|
+
<View background="inverse-tertiary" spacing="sm" radius="sm">
|
|
59
|
+
<Text size="sm" color="inverse-tertiary">Inverse Tertiary</Text>
|
|
52
60
|
</View>
|
|
53
61
|
</View>
|
|
54
62
|
</View>
|
|
55
63
|
|
|
56
64
|
{/* Border Radius Examples */}
|
|
57
65
|
<View spacing="md">
|
|
58
|
-
<Text size="
|
|
66
|
+
<Text size="md" weight="semibold">Border Radius</Text>
|
|
59
67
|
<View style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap' }}>
|
|
60
|
-
<View radius="none" background="
|
|
61
|
-
<Text size="
|
|
68
|
+
<View radius="none" background="inverse" spacing="sm">
|
|
69
|
+
<Text size="sm" color="inverse">None</Text>
|
|
62
70
|
</View>
|
|
63
|
-
<View radius="xs" background="
|
|
64
|
-
<Text size="
|
|
71
|
+
<View radius="xs" background="inverse" spacing="sm">
|
|
72
|
+
<Text size="sm" color="inverse">XS</Text>
|
|
65
73
|
</View>
|
|
66
|
-
<View radius="sm" background="
|
|
67
|
-
<Text size="
|
|
74
|
+
<View radius="sm" background="inverse" spacing="sm">
|
|
75
|
+
<Text size="sm" color="inverse">SM</Text>
|
|
68
76
|
</View>
|
|
69
|
-
<View radius="md" background="
|
|
70
|
-
<Text size="
|
|
77
|
+
<View radius="md" background="inverse" spacing="sm">
|
|
78
|
+
<Text size="sm" color="inverse">MD</Text>
|
|
71
79
|
</View>
|
|
72
|
-
<View radius="lg" background="
|
|
73
|
-
<Text size="
|
|
80
|
+
<View radius="lg" background="inverse" spacing="sm">
|
|
81
|
+
<Text size="sm" color="inverse">LG</Text>
|
|
74
82
|
</View>
|
|
75
|
-
<View radius="xl" background="
|
|
76
|
-
<Text size="
|
|
83
|
+
<View radius="xl" background="inverse" spacing="sm">
|
|
84
|
+
<Text size="sm" color="inverse">XL</Text>
|
|
77
85
|
</View>
|
|
78
86
|
</View>
|
|
79
87
|
</View>
|
|
80
88
|
|
|
81
89
|
{/* Border Examples */}
|
|
82
90
|
<View spacing="md">
|
|
83
|
-
<Text size="
|
|
91
|
+
<Text size="md" weight="semibold">Border Variants</Text>
|
|
84
92
|
<View style={{ flexDirection: 'row', gap: 8, flexWrap: 'wrap' }}>
|
|
85
|
-
<View border="none" background="
|
|
86
|
-
<Text size="
|
|
93
|
+
<View border="none" background="secondary" spacing="sm" radius="sm">
|
|
94
|
+
<Text size="sm">None</Text>
|
|
87
95
|
</View>
|
|
88
|
-
<View border="thin" background="
|
|
89
|
-
<Text size="
|
|
96
|
+
<View border="thin" background="secondary" spacing="sm" radius="sm">
|
|
97
|
+
<Text size="sm">Thin</Text>
|
|
90
98
|
</View>
|
|
91
|
-
<View border="thick" background="
|
|
92
|
-
<Text size="
|
|
99
|
+
<View border="thick" background="secondary" spacing="sm" radius="sm">
|
|
100
|
+
<Text size="sm">Thick</Text>
|
|
93
101
|
</View>
|
|
94
102
|
</View>
|
|
95
103
|
</View>
|
|
96
104
|
|
|
97
105
|
{/* Layout Examples */}
|
|
98
106
|
<View spacing="md">
|
|
99
|
-
<Text size="
|
|
107
|
+
<Text size="md" weight="semibold">Layout Examples</Text>
|
|
100
108
|
<View spacing="sm" style={{ gap: 10 }}>
|
|
101
|
-
<View
|
|
102
|
-
background="
|
|
103
|
-
spacing="md"
|
|
104
|
-
radius="md"
|
|
109
|
+
<View
|
|
110
|
+
background="secondary"
|
|
111
|
+
spacing="md"
|
|
112
|
+
radius="md"
|
|
105
113
|
border="thin"
|
|
106
114
|
style={{ flexDirection: 'row', justifyContent: 'space-between' }}
|
|
107
115
|
>
|
|
@@ -109,11 +117,11 @@ export const ViewExamples = () => {
|
|
|
109
117
|
<Text>Center</Text>
|
|
110
118
|
<Text>Right</Text>
|
|
111
119
|
</View>
|
|
112
|
-
|
|
113
|
-
<View
|
|
114
|
-
background="
|
|
115
|
-
spacing="md"
|
|
116
|
-
radius="md"
|
|
120
|
+
|
|
121
|
+
<View
|
|
122
|
+
background="secondary"
|
|
123
|
+
spacing="md"
|
|
124
|
+
radius="md"
|
|
117
125
|
border="thin"
|
|
118
126
|
style={{ flexDirection: 'column', alignItems: 'center' }}
|
|
119
127
|
>
|
package/src/examples/index.ts
CHANGED
|
@@ -12,7 +12,22 @@ export { ScreenExamples } from './ScreenExamples';
|
|
|
12
12
|
export { SVGImageExamples } from './SVGImageExamples';
|
|
13
13
|
export { DialogExamples } from './DialogExamples';
|
|
14
14
|
export { PopoverExamples } from './PopoverExamples';
|
|
15
|
+
export { SelectExamples } from './SelectExamples';
|
|
16
|
+
export { SliderExamples } from './SliderExamples';
|
|
17
|
+
export { SwitchExamples } from './SwitchExamples';
|
|
18
|
+
export { RadioButtonExamples } from './RadioButtonExamples';
|
|
19
|
+
export { ProgressExamples } from './ProgressExamples';
|
|
20
|
+
export { TextAreaExamples } from './TextAreaExamples';
|
|
21
|
+
export { TabBarExamples } from './TabBarExamples';
|
|
22
|
+
export { TooltipExamples } from './TooltipExamples';
|
|
23
|
+
export { AccordionExamples } from './AccordionExamples';
|
|
24
|
+
export { ListExamples } from './ListExamples';
|
|
25
|
+
export { TableExamples } from './TableExamples';
|
|
26
|
+
export { MenuExamples } from './MenuExamples';
|
|
27
|
+
export { ImageExamples } from './ImageExamples';
|
|
28
|
+
export { VideoExamples } from './VideoExamples';
|
|
29
|
+
export { AlertExamples } from './AlertExamples';
|
|
30
|
+
export { SkeletonExamples } from './SkeletonExamples';
|
|
31
|
+
export { ChipExamples } from './ChipExamples';
|
|
32
|
+
export { BreadcrumbExamples } from './BreadcrumbExamples';
|
|
15
33
|
export { ThemeExtensionExamples } from './ThemeExtensionExamples';
|
|
16
|
-
export { extendedThemes, } from './extendedTheme';
|
|
17
|
-
export type { ExtendedColorVariant, ExtendedIntentVariant } from './extendedTheme';
|
|
18
|
-
export { AllExamples } from './AllExamples';
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Userful when workign with getWebProps and forwarding refs
|
|
3
|
+
* @param refs
|
|
4
|
+
* @returns
|
|
5
|
+
*/
|
|
6
|
+
export default function useMergeRefs<T>(...refs: React.Ref<T>[]): React.RefCallback<T> {
|
|
7
|
+
return (value: T) => {
|
|
8
|
+
refs.forEach((ref) => {
|
|
9
|
+
if (typeof ref === 'function') {
|
|
10
|
+
ref(value);
|
|
11
|
+
} else if (ref && 'current' in ref) {
|
|
12
|
+
ref.current = value;
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
};
|
|
16
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { useState, useRef, useEffect } from 'react';
|
|
2
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
3
|
+
import { calculateSmartPosition, type Placement } from '../utils/positionUtils.native';
|
|
4
|
+
|
|
5
|
+
export interface UseSmartPositionOptions {
|
|
6
|
+
placement?: Placement;
|
|
7
|
+
offset?: number;
|
|
8
|
+
maxHeight?: number;
|
|
9
|
+
matchWidth?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface SmartPosition {
|
|
13
|
+
top: number;
|
|
14
|
+
left: number;
|
|
15
|
+
width: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface SmartSize {
|
|
19
|
+
width: number;
|
|
20
|
+
height: number;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface UseSmartPositionReturn {
|
|
24
|
+
position: SmartPosition;
|
|
25
|
+
size: SmartSize;
|
|
26
|
+
isPositioned: boolean;
|
|
27
|
+
anchorRef: React.MutableRefObject<any>;
|
|
28
|
+
measureAndPosition: () => void;
|
|
29
|
+
handleLayout: (event: any) => void;
|
|
30
|
+
reset: () => void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Hook for smart positioning of modals/dropdowns with automatic flip detection
|
|
35
|
+
* and stable measurement-based positioning.
|
|
36
|
+
*
|
|
37
|
+
* This hook handles the complex two-phase rendering pattern:
|
|
38
|
+
* 1. Render invisible at initial position
|
|
39
|
+
* 2. Measure actual content size
|
|
40
|
+
* 3. Calculate final position based on measured size
|
|
41
|
+
* 4. Show once positioned and measurements are stable
|
|
42
|
+
*/
|
|
43
|
+
export const useSmartPosition = ({
|
|
44
|
+
placement = 'bottom-start',
|
|
45
|
+
offset = 8,
|
|
46
|
+
maxHeight = 300,
|
|
47
|
+
matchWidth = false,
|
|
48
|
+
}: UseSmartPositionOptions = {}): UseSmartPositionReturn => {
|
|
49
|
+
const [position, setPosition] = useState<SmartPosition>({ top: 0, left: 0, width: 0 });
|
|
50
|
+
const [size, setSize] = useState<SmartSize>({ width: 0, height: 0 });
|
|
51
|
+
const [isPositioned, setIsPositioned] = useState(false);
|
|
52
|
+
|
|
53
|
+
const anchorRef = useRef<any>(null);
|
|
54
|
+
const anchorMeasurements = useRef<{ x: number; y: number; width: number; height: number } | null>(null);
|
|
55
|
+
const previousHeightRef = useRef<number>(0);
|
|
56
|
+
const rafRef = useRef<any | null>(null);
|
|
57
|
+
const insets = useSafeAreaInsets();
|
|
58
|
+
|
|
59
|
+
// Calculate position based on anchor and content measurements
|
|
60
|
+
const calculatePosition = (x: number, y: number, width: number, height: number) => {
|
|
61
|
+
// For flip detection, use maxHeight to properly detect insufficient space
|
|
62
|
+
// But once we have a measured height, use that for tighter positioning
|
|
63
|
+
let heightForPositioning = maxHeight;
|
|
64
|
+
|
|
65
|
+
if (size.height > 0) {
|
|
66
|
+
// We have a measured height - use it if it's less than maxHeight
|
|
67
|
+
heightForPositioning = Math.min(size.height, maxHeight);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const desiredSize = {
|
|
71
|
+
width: size.width,
|
|
72
|
+
height: heightForPositioning
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// Calculate position with flip detection
|
|
76
|
+
const calculatedPosition = calculateSmartPosition(
|
|
77
|
+
{ x, y, width, height },
|
|
78
|
+
desiredSize,
|
|
79
|
+
placement,
|
|
80
|
+
offset,
|
|
81
|
+
matchWidth,
|
|
82
|
+
insets
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
setPosition({
|
|
86
|
+
top: calculatedPosition.top,
|
|
87
|
+
left: calculatedPosition.left,
|
|
88
|
+
width: calculatedPosition.width || width,
|
|
89
|
+
});
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
// Recalculate position when size changes
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (anchorMeasurements.current && size.width > 0 && size.height > 0) {
|
|
95
|
+
const { x, y, width, height } = anchorMeasurements.current;
|
|
96
|
+
calculatePosition(x, y, width, height);
|
|
97
|
+
|
|
98
|
+
// Cancel any pending RAF
|
|
99
|
+
if (rafRef.current !== null) {
|
|
100
|
+
cancelAnimationFrame(rafRef.current);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Wait for next frame to allow layout to settle before showing
|
|
104
|
+
rafRef.current = setTimeout(() => {
|
|
105
|
+
setIsPositioned(true);
|
|
106
|
+
rafRef.current = null;
|
|
107
|
+
}, 20)
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return () => {
|
|
111
|
+
if (rafRef.current !== null) {
|
|
112
|
+
clearTimeout(rafRef.current);
|
|
113
|
+
rafRef.current = null;
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
}, [size]);
|
|
117
|
+
|
|
118
|
+
// Measure anchor and set initial position
|
|
119
|
+
const measureAndPosition = () => {
|
|
120
|
+
anchorRef.current?.measureInWindow((x: number, y: number, width: number, height: number) => {
|
|
121
|
+
// Store anchor measurements for potential recalculation
|
|
122
|
+
anchorMeasurements.current = { x, y, width, height };
|
|
123
|
+
|
|
124
|
+
// Set initial position (will be adjusted after measurement)
|
|
125
|
+
setPosition({ top: y + height + offset, left: x, width });
|
|
126
|
+
setIsPositioned(false);
|
|
127
|
+
previousHeightRef.current = 0;
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// Handle layout measurement from content
|
|
132
|
+
const handleLayout = (event: any) => {
|
|
133
|
+
const { width, height } = event.nativeEvent.layout;
|
|
134
|
+
|
|
135
|
+
if (__DEV__) {
|
|
136
|
+
console.log('[useSmartPosition] onLayout:', { width, height, currentSize: size, isPositioned });
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Only update if size has changed significantly
|
|
140
|
+
if (Math.abs(width - size.width) > 1 || Math.abs(height - size.height) > 1) {
|
|
141
|
+
if (__DEV__) {
|
|
142
|
+
console.log('[useSmartPosition] Size changed, updating');
|
|
143
|
+
}
|
|
144
|
+
previousHeightRef.current = size.height;
|
|
145
|
+
setSize({ width, height });
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// Reset state (call when closing modal)
|
|
150
|
+
const reset = () => {
|
|
151
|
+
if (rafRef.current !== null) {
|
|
152
|
+
clearTimeout(rafRef.current);
|
|
153
|
+
rafRef.current = null;
|
|
154
|
+
}
|
|
155
|
+
setIsPositioned(false);
|
|
156
|
+
setSize({ width: 0, height: 0 });
|
|
157
|
+
previousHeightRef.current = 0;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
return {
|
|
161
|
+
position,
|
|
162
|
+
size,
|
|
163
|
+
isPositioned,
|
|
164
|
+
anchorRef,
|
|
165
|
+
measureAndPosition,
|
|
166
|
+
handleLayout,
|
|
167
|
+
reset,
|
|
168
|
+
};
|
|
169
|
+
};
|