@hero-design/rn 8.74.1 → 8.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,94 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { LayoutChangeEvent, ViewProps } from 'react-native';
3
+ import {
4
+ StyledWrapper,
5
+ StyledPrefixWrapper,
6
+ StyledSuffixWrapper,
7
+ StyledIcon,
8
+ } from './StyledFloatingIsland';
9
+ import { IconName } from '../Icon';
10
+
11
+ export interface FloatingIslandProps extends ViewProps {
12
+ /**
13
+ * Callback that is called when the floating island is pressed.
14
+ */
15
+ onPress?: () => void;
16
+ /**
17
+ * Children of the floating island.
18
+ */
19
+ children: ReactNode;
20
+ /**
21
+ * Prefix element that is displayed before the children.
22
+ */
23
+ prefix?: IconName | ReactNode;
24
+ /**
25
+ * Suffix element that is displayed after the children.
26
+ */
27
+ suffix?: IconName | ReactNode;
28
+ }
29
+
30
+ const getPrefixOrSuffix = ({
31
+ element,
32
+ isPrefix = true,
33
+ }: {
34
+ element: IconName | ReactNode;
35
+ isPrefix: boolean;
36
+ }) => {
37
+ const Wrapper = isPrefix ? StyledPrefixWrapper : StyledSuffixWrapper;
38
+ if (typeof element === 'string') {
39
+ return (
40
+ <Wrapper>
41
+ <StyledIcon
42
+ testID={`floating-island-${isPrefix ? 'prefix' : 'suffix'}-icon`}
43
+ size="small"
44
+ icon={element as IconName}
45
+ />
46
+ </Wrapper>
47
+ );
48
+ }
49
+
50
+ return <Wrapper>{element}</Wrapper>;
51
+ };
52
+
53
+ const FloatingIsland = ({
54
+ onPress,
55
+ onLayout,
56
+ style,
57
+ children,
58
+ prefix,
59
+ suffix,
60
+ ...props
61
+ }: FloatingIslandProps) => {
62
+ const [width, setWidth] = React.useState(0);
63
+
64
+ const onWrapperLayout = (event: LayoutChangeEvent) => {
65
+ setWidth(event.nativeEvent.layout.width);
66
+
67
+ onLayout?.(event);
68
+ };
69
+
70
+ return (
71
+ <StyledWrapper
72
+ {...props}
73
+ onLayout={onWrapperLayout}
74
+ disabled={!onPress}
75
+ onPress={onPress}
76
+ style={[
77
+ style,
78
+ width > 0
79
+ ? {
80
+ transform: [{ translateX: -width / 2 }],
81
+ }
82
+ : undefined,
83
+ ]}
84
+ >
85
+ {prefix && getPrefixOrSuffix({ element: prefix, isPrefix: true })}
86
+
87
+ {children}
88
+
89
+ {suffix && getPrefixOrSuffix({ element: suffix, isPrefix: false })}
90
+ </StyledWrapper>
91
+ );
92
+ };
93
+
94
+ export default FloatingIsland;
package/src/index.ts CHANGED
@@ -71,6 +71,7 @@ import {
71
71
  FlatListWithFAB,
72
72
  } from './components/AnimatedScroller';
73
73
  import Search from './components/Search';
74
+ import FloatingIsland from './components/FloatingIsland';
74
75
 
75
76
  export {
76
77
  theme,
@@ -143,6 +144,7 @@ export {
143
144
  Rate,
144
145
  RefreshControl,
145
146
  RichTextEditor,
147
+ FloatingIsland,
146
148
  };
147
149
 
148
150
  export * from './types';
@@ -590,6 +590,36 @@ exports[`theme returns correct theme object 1`] = `
590
590
  "titleMarginHorizontal": 8,
591
591
  },
592
592
  },
593
+ "floatingIsland": {
594
+ "colors": {
595
+ "wrapperBackground": "#ffffff",
596
+ },
597
+ "fontSizes": {
598
+ "iconSize": 14,
599
+ },
600
+ "radii": {
601
+ "wrapper": 999,
602
+ },
603
+ "shadows": {
604
+ "wrapper": {
605
+ "elevation": 3,
606
+ "shadowColor": "#001f23",
607
+ "shadowOffset": {
608
+ "height": 2,
609
+ "width": 0,
610
+ },
611
+ "shadowOpacity": 0.12,
612
+ "shadowRadius": 4,
613
+ },
614
+ },
615
+ "space": {
616
+ "iconPadding": 12,
617
+ "prefixMarginRight": 8,
618
+ "suffixMarginLeft": 16,
619
+ "wrapperPadding": 8,
620
+ "wrapperTop": 12,
621
+ },
622
+ },
593
623
  "icon": {
594
624
  "colors": {
595
625
  "danger": "#cb300a",
@@ -0,0 +1,31 @@
1
+ import type { GlobalTheme } from '../global';
2
+
3
+ const getFloatingIslandTheme = (theme: GlobalTheme) => {
4
+ const colors = {
5
+ wrapperBackground: theme.colors.defaultGlobalSurface,
6
+ };
7
+
8
+ const radii = {
9
+ wrapper: theme.radii.rounded,
10
+ };
11
+
12
+ const shadows = {
13
+ wrapper: theme.shadows.default,
14
+ };
15
+
16
+ const space = {
17
+ wrapperPadding: theme.space.small,
18
+ wrapperTop: theme.space.smallMedium,
19
+ prefixMarginRight: theme.space.small,
20
+ suffixMarginLeft: theme.space.medium,
21
+ iconPadding: theme.space.smallMedium,
22
+ };
23
+
24
+ const fontSizes = {
25
+ iconSize: theme.fontSizes.medium,
26
+ };
27
+
28
+ return { colors, radii, shadows, space, fontSizes };
29
+ };
30
+
31
+ export default getFloatingIslandTheme;
@@ -50,6 +50,7 @@ import getTypographyTheme from './components/typography';
50
50
  import type { GlobalTheme, Scale, SystemPalette } from './global';
51
51
  import getSearchTheme from './components/search';
52
52
  import getMapPinTheme from './components/mapPin';
53
+ import getFloatingIslandTheme from './components/floatingIsland';
53
54
 
54
55
  type Theme = GlobalTheme & {
55
56
  __hd__: {
@@ -101,6 +102,7 @@ type Theme = GlobalTheme & {
101
102
  toast: ReturnType<typeof getToastTheme>;
102
103
  toolbar: ReturnType<typeof getToolbarTheme>;
103
104
  typography: ReturnType<typeof getTypographyTheme>;
105
+ floatingIsland: ReturnType<typeof getFloatingIslandTheme>;
104
106
  };
105
107
  };
106
108
 
@@ -160,6 +162,7 @@ const getTheme = (
160
162
  toast: getToastTheme(globalTheme),
161
163
  toolbar: getToolbarTheme(globalTheme),
162
164
  typography: getTypographyTheme(globalTheme),
165
+ floatingIsland: getFloatingIslandTheme(globalTheme),
163
166
  },
164
167
  };
165
168
  };