jfs-components 0.0.42 → 0.0.44
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/lib/commonjs/components/Button/Button.js +15 -1
- package/lib/commonjs/components/Checkbox/Checkbox.js +208 -0
- package/lib/commonjs/components/MoneyValue/MoneyValue.js +81 -49
- package/lib/commonjs/components/NoteInput/NoteInput.js +120 -0
- package/lib/commonjs/components/NoteInput/index.js +13 -0
- package/lib/commonjs/components/Numpad/Numpad.js +108 -0
- package/lib/commonjs/components/StatusHero/StatusHero.js +148 -0
- package/lib/commonjs/components/Tabs/TabItem.js +79 -0
- package/lib/commonjs/components/Tabs/Tabs.js +88 -0
- package/lib/commonjs/components/Toast/Toast.js +93 -0
- package/lib/commonjs/components/Toast/ToastProvider.js +61 -0
- package/lib/commonjs/components/Toast/useToast.js +61 -0
- package/lib/commonjs/components/index.js +81 -0
- package/lib/commonjs/design-tokens/JFS Variables-variables-full.json +1 -1
- package/lib/commonjs/icons/registry.js +1 -1
- package/lib/module/components/Button/Button.js +14 -1
- package/lib/module/components/Checkbox/Checkbox.js +205 -0
- package/lib/module/components/MoneyValue/MoneyValue.js +81 -49
- package/lib/module/components/NoteInput/NoteInput.js +115 -0
- package/lib/module/components/NoteInput/index.js +3 -0
- package/lib/module/components/Numpad/Numpad.js +103 -0
- package/lib/module/components/StatusHero/StatusHero.js +142 -0
- package/lib/module/components/Tabs/TabItem.js +74 -0
- package/lib/module/components/Tabs/Tabs.js +78 -0
- package/lib/module/components/Toast/Toast.js +88 -0
- package/lib/module/components/Toast/ToastProvider.js +55 -0
- package/lib/module/components/Toast/useToast.js +54 -0
- package/lib/module/components/index.js +10 -1
- package/lib/module/design-tokens/JFS Variables-variables-full.json +1 -1
- package/lib/module/icons/registry.js +1 -1
- package/lib/typescript/src/components/Button/Button.d.ts +6 -1
- package/lib/typescript/src/components/Checkbox/Checkbox.d.ts +30 -0
- package/lib/typescript/src/components/MoneyValue/MoneyValue.d.ts +18 -26
- package/lib/typescript/src/components/NoteInput/NoteInput.d.ts +23 -0
- package/lib/typescript/src/components/NoteInput/index.d.ts +3 -0
- package/lib/typescript/src/components/Numpad/Numpad.d.ts +35 -0
- package/lib/typescript/src/components/StatusHero/StatusHero.d.ts +47 -0
- package/lib/typescript/src/components/Tabs/TabItem.d.ts +29 -0
- package/lib/typescript/src/components/Tabs/Tabs.d.ts +44 -0
- package/lib/typescript/src/components/Toast/Toast.d.ts +14 -0
- package/lib/typescript/src/components/Toast/ToastProvider.d.ts +11 -0
- package/lib/typescript/src/components/Toast/useToast.d.ts +24 -0
- package/lib/typescript/src/components/index.d.ts +9 -0
- package/lib/typescript/src/icons/registry.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/Button/Button.tsx +14 -1
- package/src/components/Checkbox/Checkbox.tsx +238 -0
- package/src/components/MoneyValue/MoneyValue.tsx +134 -79
- package/src/components/NoteInput/NoteInput.tsx +146 -0
- package/src/components/NoteInput/index.ts +2 -0
- package/src/components/Numpad/Numpad.tsx +162 -0
- package/src/components/StatusHero/StatusHero.tsx +156 -0
- package/src/components/Tabs/TabItem.tsx +96 -0
- package/src/components/Tabs/Tabs.tsx +105 -0
- package/src/components/Toast/Toast.tsx +105 -0
- package/src/components/Toast/ToastProvider.tsx +75 -0
- package/src/components/Toast/useToast.ts +80 -0
- package/src/components/index.ts +9 -0
- package/src/design-tokens/JFS Variables-variables-full.json +1 -1
- package/src/icons/registry.ts +1 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { isValidElement, cloneElement } from 'react';
|
|
4
|
+
import { View, Text } from 'react-native';
|
|
5
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
|
+
import { useTokens } from '../../design-tokens/JFSThemeProvider';
|
|
7
|
+
import IconCapsule from '../IconCapsule/IconCapsule';
|
|
8
|
+
import MoneyValue from '../MoneyValue/MoneyValue';
|
|
9
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
10
|
+
/**
|
|
11
|
+
* StatusHero component that displays a hero section for payment/transaction status screens.
|
|
12
|
+
*
|
|
13
|
+
* Contains a media slot (defaults to IconCapsule + MoneyValue) and a content area
|
|
14
|
+
* with an optional title and a subtitle. All visual values are resolved from Figma
|
|
15
|
+
* design tokens via `getVariableByName`.
|
|
16
|
+
*
|
|
17
|
+
* @component
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* <StatusHero
|
|
21
|
+
* iconName="ic_confirm"
|
|
22
|
+
* value="50"
|
|
23
|
+
* currency="INR"
|
|
24
|
+
* title="You're set to make payments"
|
|
25
|
+
* subtitle="₹50 will be auto-invested daily, stay consistent & stay golden."
|
|
26
|
+
* modes={{ 'Color Mode': 'Light' }}
|
|
27
|
+
* />
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export default function StatusHero({
|
|
31
|
+
renderMedia,
|
|
32
|
+
title = "You're set to make payments",
|
|
33
|
+
showTitle = true,
|
|
34
|
+
subtitle = '₹50 will be auto-invested daily,\nstay consistent & stay golden.',
|
|
35
|
+
iconName = 'ic_confirm',
|
|
36
|
+
value = '50',
|
|
37
|
+
currency = 'INR',
|
|
38
|
+
modes: propModes = {},
|
|
39
|
+
style
|
|
40
|
+
}) {
|
|
41
|
+
const {
|
|
42
|
+
modes: globalModes
|
|
43
|
+
} = useTokens();
|
|
44
|
+
const modes = {
|
|
45
|
+
...globalModes,
|
|
46
|
+
...propModes
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// Container
|
|
50
|
+
const gap = Number(getVariableByName('statusHero/gap', modes)) || 12;
|
|
51
|
+
const padding = Number(getVariableByName('statusHero/padding', modes)) || 8;
|
|
52
|
+
|
|
53
|
+
// Media slot wrap (gap between icon and money value in default slot)
|
|
54
|
+
const slotWrapGap = Number(getVariableByName('statusHero/slotWrap/gap', modes)) || 46;
|
|
55
|
+
|
|
56
|
+
// Content wrap
|
|
57
|
+
const contentWrapGap = Number(getVariableByName('statusHero/contentWrap/gap', modes)) || 12;
|
|
58
|
+
|
|
59
|
+
// Title
|
|
60
|
+
const titleColor = getVariableByName('statusHero/title/foreground', modes) || '#0c0d10';
|
|
61
|
+
const titleFontSize = Number(getVariableByName('statusHero/title/fontSize', modes)) || 20;
|
|
62
|
+
const titleFontFamily = getVariableByName('statusHero/title/fontFamily', modes) || 'System';
|
|
63
|
+
const titleLineHeight = Number(getVariableByName('statusHero/title/lineHeight', modes)) || 22;
|
|
64
|
+
const titleFontWeight = getVariableByName('statusHero/title/fontWeight', modes) || '700';
|
|
65
|
+
|
|
66
|
+
// Body
|
|
67
|
+
const bodyColor = getVariableByName('statusHero/body/foreground', modes) || '#24262b';
|
|
68
|
+
const bodyFontSize = Number(getVariableByName('statusHero/body/fontSize', modes)) || 14;
|
|
69
|
+
const bodyFontFamily = getVariableByName('statusHero/body/fontFamily', modes) || 'System';
|
|
70
|
+
const bodyLineHeight = Number(getVariableByName('statusHero/body/lineHeight', modes)) || 17;
|
|
71
|
+
const bodyFontWeight = getVariableByName('statusHero/body/fontWeight', modes) || '500';
|
|
72
|
+
const containerStyle = {
|
|
73
|
+
flexDirection: 'column',
|
|
74
|
+
alignItems: 'center',
|
|
75
|
+
justifyContent: 'center',
|
|
76
|
+
gap,
|
|
77
|
+
padding
|
|
78
|
+
};
|
|
79
|
+
const defaultMediaWrapStyle = {
|
|
80
|
+
flexDirection: 'column',
|
|
81
|
+
alignItems: 'center',
|
|
82
|
+
gap: slotWrapGap
|
|
83
|
+
};
|
|
84
|
+
const contentWrapStyle = {
|
|
85
|
+
flexDirection: 'column',
|
|
86
|
+
alignItems: 'center',
|
|
87
|
+
gap: contentWrapGap
|
|
88
|
+
};
|
|
89
|
+
const titleStyle = {
|
|
90
|
+
color: titleColor,
|
|
91
|
+
fontSize: titleFontSize,
|
|
92
|
+
fontFamily: titleFontFamily,
|
|
93
|
+
lineHeight: titleLineHeight,
|
|
94
|
+
fontWeight: String(titleFontWeight),
|
|
95
|
+
textAlign: 'center'
|
|
96
|
+
};
|
|
97
|
+
const bodyStyle = {
|
|
98
|
+
color: bodyColor,
|
|
99
|
+
fontSize: bodyFontSize,
|
|
100
|
+
fontFamily: bodyFontFamily,
|
|
101
|
+
lineHeight: bodyLineHeight,
|
|
102
|
+
fontWeight: String(bodyFontWeight),
|
|
103
|
+
textAlign: 'center'
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// Inject modes into the provided slot if it's a valid React element
|
|
107
|
+
const mediaContent = /*#__PURE__*/isValidElement(renderMedia) ? /*#__PURE__*/cloneElement(renderMedia, {
|
|
108
|
+
modes
|
|
109
|
+
}) : renderMedia;
|
|
110
|
+
const defaultMediaContent = /*#__PURE__*/_jsxs(View, {
|
|
111
|
+
style: defaultMediaWrapStyle,
|
|
112
|
+
children: [/*#__PURE__*/_jsx(IconCapsule, {
|
|
113
|
+
iconName: iconName,
|
|
114
|
+
modes: {
|
|
115
|
+
...modes,
|
|
116
|
+
'Icon Capsule Size': 'L',
|
|
117
|
+
Emphasis: 'High',
|
|
118
|
+
AppearanceBrand: 'Primary'
|
|
119
|
+
}
|
|
120
|
+
}), /*#__PURE__*/_jsx(MoneyValue, {
|
|
121
|
+
value: value,
|
|
122
|
+
currency: currency,
|
|
123
|
+
modes: {
|
|
124
|
+
...modes,
|
|
125
|
+
Context3: 'Balance'
|
|
126
|
+
}
|
|
127
|
+
})]
|
|
128
|
+
});
|
|
129
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
130
|
+
style: [containerStyle, style],
|
|
131
|
+
children: [mediaContent ?? defaultMediaContent, /*#__PURE__*/_jsxs(View, {
|
|
132
|
+
style: contentWrapStyle,
|
|
133
|
+
children: [showTitle && title ? /*#__PURE__*/_jsx(Text, {
|
|
134
|
+
style: titleStyle,
|
|
135
|
+
children: title
|
|
136
|
+
}) : null, subtitle ? /*#__PURE__*/_jsx(Text, {
|
|
137
|
+
style: bodyStyle,
|
|
138
|
+
children: subtitle
|
|
139
|
+
}) : null]
|
|
140
|
+
})]
|
|
141
|
+
});
|
|
142
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { Pressable, Text, View } from 'react-native';
|
|
5
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
|
+
/**
|
|
8
|
+
* Individual tab item used inside the Tabs container.
|
|
9
|
+
*
|
|
10
|
+
* Supports idle and active states driven by design tokens.
|
|
11
|
+
* When active, a bottom indicator bar is shown beneath the label.
|
|
12
|
+
*
|
|
13
|
+
* @component
|
|
14
|
+
* @param {TabItemProps} props
|
|
15
|
+
*/
|
|
16
|
+
function TabItem({
|
|
17
|
+
label = 'Tab item',
|
|
18
|
+
active = false,
|
|
19
|
+
onPress,
|
|
20
|
+
modes = {},
|
|
21
|
+
style,
|
|
22
|
+
labelStyle,
|
|
23
|
+
accessibilityLabel
|
|
24
|
+
}) {
|
|
25
|
+
const paddingVertical = getVariableByName('tabItem/padding/vertical', modes) ?? 8;
|
|
26
|
+
const fontFamily = getVariableByName('tabItem/label/fontFamily', modes) ?? 'JioType Var';
|
|
27
|
+
const fontSize = getVariableByName('tabItem/label/size', modes) ?? 14;
|
|
28
|
+
const lineHeight = getVariableByName('tabItem/label/lineHeight', modes) ?? 17;
|
|
29
|
+
const idleLabelColor = getVariableByName('tabItem/idle/label/color', modes) ?? '#303338';
|
|
30
|
+
const activeLabelColor = getVariableByName('tabItem/active/label/color', modes) ?? '#cea15a';
|
|
31
|
+
const labelColor = active ? activeLabelColor : idleLabelColor;
|
|
32
|
+
const containerStyle = {
|
|
33
|
+
flexDirection: 'column',
|
|
34
|
+
alignItems: 'center',
|
|
35
|
+
justifyContent: 'center',
|
|
36
|
+
paddingVertical
|
|
37
|
+
};
|
|
38
|
+
const textStyle = {
|
|
39
|
+
color: labelColor,
|
|
40
|
+
fontFamily,
|
|
41
|
+
fontSize,
|
|
42
|
+
lineHeight,
|
|
43
|
+
fontWeight: '500'
|
|
44
|
+
};
|
|
45
|
+
const indicatorStyle = {
|
|
46
|
+
position: 'absolute',
|
|
47
|
+
bottom: 0,
|
|
48
|
+
left: 0,
|
|
49
|
+
right: 0,
|
|
50
|
+
height: 2,
|
|
51
|
+
backgroundColor: activeLabelColor,
|
|
52
|
+
borderRadius: 1
|
|
53
|
+
};
|
|
54
|
+
return /*#__PURE__*/_jsxs(Pressable, {
|
|
55
|
+
style: ({
|
|
56
|
+
pressed
|
|
57
|
+
}) => [containerStyle, pressed && {
|
|
58
|
+
opacity: 0.7
|
|
59
|
+
}, style],
|
|
60
|
+
onPress: onPress,
|
|
61
|
+
accessibilityRole: "tab",
|
|
62
|
+
accessibilityState: {
|
|
63
|
+
selected: active
|
|
64
|
+
},
|
|
65
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
66
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
67
|
+
style: [textStyle, labelStyle],
|
|
68
|
+
children: label
|
|
69
|
+
}), active && /*#__PURE__*/_jsx(View, {
|
|
70
|
+
style: indicatorStyle
|
|
71
|
+
})]
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
export default TabItem;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React from 'react';
|
|
4
|
+
import { ScrollView, View } from 'react-native';
|
|
5
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
6
|
+
import TabItem from './TabItem';
|
|
7
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
8
|
+
/**
|
|
9
|
+
* Tabs container component that lays out TabItem children horizontally.
|
|
10
|
+
*
|
|
11
|
+
* The "Tab items" slot maps to React children — each child should be a
|
|
12
|
+
* `<TabItem>` element. The `modes` prop is automatically forwarded to
|
|
13
|
+
* every TabItem child so theming is consistent.
|
|
14
|
+
*
|
|
15
|
+
* @component
|
|
16
|
+
* @param {TabsProps} props
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```tsx
|
|
20
|
+
* const [activeIndex, setActiveIndex] = useState(0);
|
|
21
|
+
*
|
|
22
|
+
* <Tabs modes={{ 'Color Mode': 'Light' }}>
|
|
23
|
+
* <TabItem label="Tab 1" active={activeIndex === 0} onPress={() => setActiveIndex(0)} />
|
|
24
|
+
* <TabItem label="Tab 2" active={activeIndex === 1} onPress={() => setActiveIndex(1)} />
|
|
25
|
+
* <TabItem label="Tab 3" active={activeIndex === 2} onPress={() => setActiveIndex(2)} />
|
|
26
|
+
* </Tabs>
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
function Tabs({
|
|
30
|
+
children,
|
|
31
|
+
modes = {},
|
|
32
|
+
scrollable = false,
|
|
33
|
+
style
|
|
34
|
+
}) {
|
|
35
|
+
const gap = getVariableByName('tabs/gap', modes) ?? 16;
|
|
36
|
+
const paddingTop = getVariableByName('tabs/padding/top', modes) ?? 0;
|
|
37
|
+
const paddingBottom = getVariableByName('tabs/padding/bottom', modes) ?? 0;
|
|
38
|
+
const paddingLeft = getVariableByName('tabs/padding/left', modes) ?? 0;
|
|
39
|
+
const paddingRight = getVariableByName('tabs/padding/right', modes) ?? 0;
|
|
40
|
+
|
|
41
|
+
// Forward modes to all TabItem children
|
|
42
|
+
const enhancedChildren = React.Children.map(children, child => {
|
|
43
|
+
if (/*#__PURE__*/React.isValidElement(child) && child.type === TabItem) {
|
|
44
|
+
const childElement = child;
|
|
45
|
+
return /*#__PURE__*/React.cloneElement(childElement, {
|
|
46
|
+
modes: {
|
|
47
|
+
...modes,
|
|
48
|
+
...(childElement.props.modes ?? {})
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
return child;
|
|
53
|
+
});
|
|
54
|
+
const containerStyle = {
|
|
55
|
+
flexDirection: 'row',
|
|
56
|
+
gap,
|
|
57
|
+
paddingTop,
|
|
58
|
+
paddingBottom,
|
|
59
|
+
paddingLeft,
|
|
60
|
+
paddingRight
|
|
61
|
+
};
|
|
62
|
+
if (scrollable) {
|
|
63
|
+
return /*#__PURE__*/_jsx(ScrollView, {
|
|
64
|
+
horizontal: true,
|
|
65
|
+
showsHorizontalScrollIndicator: false,
|
|
66
|
+
accessibilityRole: "tablist",
|
|
67
|
+
contentContainerStyle: [containerStyle, style],
|
|
68
|
+
children: enhancedChildren
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
return /*#__PURE__*/_jsx(View, {
|
|
72
|
+
style: [containerStyle, style],
|
|
73
|
+
accessibilityRole: "tablist",
|
|
74
|
+
children: enhancedChildren
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export { TabItem };
|
|
78
|
+
export default Tabs;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useEffect, useRef } from 'react';
|
|
4
|
+
import { StyleSheet, Text } from 'react-native';
|
|
5
|
+
import Animated, { FadeOut, SlideInDown, SlideInUp } from 'react-native-reanimated';
|
|
6
|
+
import { getVariableByName } from '../../design-tokens/figma-variables-resolver';
|
|
7
|
+
import { closeToast } from './useToast';
|
|
8
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
9
|
+
const ANIMATION_DURATION = 250;
|
|
10
|
+
function Toast({
|
|
11
|
+
id,
|
|
12
|
+
title,
|
|
13
|
+
timeout = 4000,
|
|
14
|
+
onClose,
|
|
15
|
+
modes = {},
|
|
16
|
+
placement = 'bottom',
|
|
17
|
+
style
|
|
18
|
+
}) {
|
|
19
|
+
const timerRef = useRef(null);
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (timeout <= 0) return;
|
|
22
|
+
timerRef.current = setTimeout(() => closeToast(id), timeout);
|
|
23
|
+
return () => {
|
|
24
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
25
|
+
};
|
|
26
|
+
}, [id, timeout]);
|
|
27
|
+
const backgroundColor = getVariableByName('toast/background', modes) || '#303338';
|
|
28
|
+
const foreground = getVariableByName('toast/foreground', modes) || '#ffffff';
|
|
29
|
+
const fontSize = getVariableByName('toast/fontSize', modes) || 14;
|
|
30
|
+
const fontFamily = getVariableByName('toast/fontFamily', modes) || undefined;
|
|
31
|
+
const fontWeight = getVariableByName('toast/fontWeight', modes) || '500';
|
|
32
|
+
const lineHeight = getVariableByName('toast/lineHeight', modes) || 18;
|
|
33
|
+
const radius = getVariableByName('toast/radius', modes) || 14;
|
|
34
|
+
const paddingHorizontal = getVariableByName('toast/padding/horizontal', modes) || 16;
|
|
35
|
+
const paddingVertical = getVariableByName('toast/padding/vertical', modes) || 14;
|
|
36
|
+
const gap = getVariableByName('toast/gap', modes) || 8;
|
|
37
|
+
const borderWidth = getVariableByName('toast/border/size', modes) || 1;
|
|
38
|
+
const borderColor = getVariableByName('toast/border/color', modes) || 'rgba(255,255,255,0.1)';
|
|
39
|
+
const shadowBlurPrimary = getVariableByName('toast/shadow/primary/blur', modes) || 48;
|
|
40
|
+
const shadowOffsetYPrimary = getVariableByName('toast/shadow/primary/offsetY', modes) || 16;
|
|
41
|
+
const shadowColorPrimary = getVariableByName('toast/shadow/primary/color', modes) || 'rgba(13,13,15,0.16)';
|
|
42
|
+
const enterAnimation = placement === 'top' ? SlideInUp.duration(ANIMATION_DURATION) : SlideInDown.duration(ANIMATION_DURATION);
|
|
43
|
+
const containerStyle = {
|
|
44
|
+
backgroundColor,
|
|
45
|
+
borderRadius: radius,
|
|
46
|
+
paddingHorizontal,
|
|
47
|
+
paddingVertical,
|
|
48
|
+
gap,
|
|
49
|
+
borderWidth,
|
|
50
|
+
borderColor,
|
|
51
|
+
shadowColor: shadowColorPrimary,
|
|
52
|
+
shadowOffset: {
|
|
53
|
+
width: 0,
|
|
54
|
+
height: shadowOffsetYPrimary
|
|
55
|
+
},
|
|
56
|
+
shadowOpacity: 1,
|
|
57
|
+
shadowRadius: shadowBlurPrimary / 2,
|
|
58
|
+
elevation: 8
|
|
59
|
+
};
|
|
60
|
+
const textStyle = {
|
|
61
|
+
color: foreground,
|
|
62
|
+
fontSize,
|
|
63
|
+
fontFamily,
|
|
64
|
+
fontWeight: String(fontWeight),
|
|
65
|
+
lineHeight
|
|
66
|
+
};
|
|
67
|
+
return /*#__PURE__*/_jsx(Animated.View, {
|
|
68
|
+
entering: enterAnimation,
|
|
69
|
+
exiting: FadeOut.duration(ANIMATION_DURATION),
|
|
70
|
+
style: [styles.toast, containerStyle, style],
|
|
71
|
+
accessibilityRole: "alert",
|
|
72
|
+
accessibilityLiveRegion: "assertive",
|
|
73
|
+
children: /*#__PURE__*/_jsx(Text, {
|
|
74
|
+
style: textStyle,
|
|
75
|
+
numberOfLines: 2,
|
|
76
|
+
children: title
|
|
77
|
+
})
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
const styles = StyleSheet.create({
|
|
81
|
+
toast: {
|
|
82
|
+
alignSelf: 'center',
|
|
83
|
+
maxWidth: '90%',
|
|
84
|
+
minWidth: 200,
|
|
85
|
+
overflow: 'hidden'
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
export default Toast;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import React, { useMemo } from 'react';
|
|
4
|
+
import { StyleSheet, View } from 'react-native';
|
|
5
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
6
|
+
import { useToast } from './useToast';
|
|
7
|
+
import Toast from './Toast';
|
|
8
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
|
+
function ToastProvider({
|
|
10
|
+
children,
|
|
11
|
+
maxVisibleToasts = 3,
|
|
12
|
+
placement = 'bottom',
|
|
13
|
+
modes
|
|
14
|
+
}) {
|
|
15
|
+
const {
|
|
16
|
+
toasts
|
|
17
|
+
} = useToast();
|
|
18
|
+
const insets = useSafeAreaInsets();
|
|
19
|
+
const visibleToasts = useMemo(() => toasts.slice(-maxVisibleToasts), [toasts, maxVisibleToasts]);
|
|
20
|
+
const regionStyle = useMemo(() => [styles.region, placement === 'top' ? {
|
|
21
|
+
top: insets.top + 8
|
|
22
|
+
} : {
|
|
23
|
+
bottom: insets.bottom + 8
|
|
24
|
+
}], [placement, insets.top, insets.bottom]);
|
|
25
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
26
|
+
style: styles.container,
|
|
27
|
+
children: [children, visibleToasts.length > 0 && /*#__PURE__*/_jsx(View, {
|
|
28
|
+
style: regionStyle,
|
|
29
|
+
pointerEvents: "box-none",
|
|
30
|
+
children: visibleToasts.map(entry => /*#__PURE__*/_jsx(Toast, {
|
|
31
|
+
id: entry.id,
|
|
32
|
+
title: entry.title,
|
|
33
|
+
timeout: entry.timeout,
|
|
34
|
+
onClose: entry.onClose,
|
|
35
|
+
modes: entry.modes ?? modes,
|
|
36
|
+
placement: placement
|
|
37
|
+
}, entry.id))
|
|
38
|
+
})]
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
const styles = StyleSheet.create({
|
|
42
|
+
container: {
|
|
43
|
+
flex: 1
|
|
44
|
+
},
|
|
45
|
+
region: {
|
|
46
|
+
position: 'absolute',
|
|
47
|
+
left: 0,
|
|
48
|
+
right: 0,
|
|
49
|
+
alignItems: 'center',
|
|
50
|
+
gap: 8,
|
|
51
|
+
zIndex: 9999,
|
|
52
|
+
pointerEvents: 'box-none'
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
export default ToastProvider;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useSyncExternalStore } from 'react';
|
|
4
|
+
let idCounter = 0;
|
|
5
|
+
let toasts = [];
|
|
6
|
+
const listeners = new Set();
|
|
7
|
+
function emit() {
|
|
8
|
+
for (const listener of listeners) {
|
|
9
|
+
listener();
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function getSnapshot() {
|
|
13
|
+
return toasts;
|
|
14
|
+
}
|
|
15
|
+
function subscribe(listener) {
|
|
16
|
+
listeners.add(listener);
|
|
17
|
+
return () => {
|
|
18
|
+
listeners.delete(listener);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export function addToast(options) {
|
|
22
|
+
const id = `toast-${++idCounter}`;
|
|
23
|
+
const entry = {
|
|
24
|
+
id,
|
|
25
|
+
title: options.title,
|
|
26
|
+
timeout: options.timeout ?? 4000,
|
|
27
|
+
onClose: options.onClose,
|
|
28
|
+
modes: options.modes
|
|
29
|
+
};
|
|
30
|
+
toasts = [...toasts, entry];
|
|
31
|
+
emit();
|
|
32
|
+
return id;
|
|
33
|
+
}
|
|
34
|
+
export function closeToast(id) {
|
|
35
|
+
const entry = toasts.find(t => t.id === id);
|
|
36
|
+
toasts = toasts.filter(t => t.id !== id);
|
|
37
|
+
emit();
|
|
38
|
+
entry?.onClose?.();
|
|
39
|
+
}
|
|
40
|
+
export function closeAll() {
|
|
41
|
+
const prev = toasts;
|
|
42
|
+
toasts = [];
|
|
43
|
+
emit();
|
|
44
|
+
prev.forEach(t => t.onClose?.());
|
|
45
|
+
}
|
|
46
|
+
export function useToast() {
|
|
47
|
+
const queue = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
48
|
+
return {
|
|
49
|
+
toasts: queue,
|
|
50
|
+
addToast: useCallback(addToast, []),
|
|
51
|
+
closeToast: useCallback(closeToast, []),
|
|
52
|
+
closeAll: useCallback(closeAll, [])
|
|
53
|
+
};
|
|
54
|
+
}
|
|
@@ -9,6 +9,7 @@ export { default as BottomNav } from './BottomNav/BottomNav';
|
|
|
9
9
|
export { default as BottomNavItem } from './BottomNavItem/BottomNavItem';
|
|
10
10
|
export { default as Button } from './Button/Button';
|
|
11
11
|
export { default as Card } from './Card/Card';
|
|
12
|
+
export { default as Checkbox } from './Checkbox/Checkbox';
|
|
12
13
|
export { default as CardFeedback } from './CardFeedback/CardFeedback';
|
|
13
14
|
export { default as Disclaimer } from './Disclaimer/Disclaimer';
|
|
14
15
|
export { default as Divider } from './Divider/Divider';
|
|
@@ -27,7 +28,9 @@ export { default as ListItem } from './ListItem/ListItem';
|
|
|
27
28
|
export { default as MediaCard } from './MediaCard/MediaCard';
|
|
28
29
|
export { default as MerchantProfile } from './MerchantProfile/MerchantProfile';
|
|
29
30
|
export { default as MoneyValue } from './MoneyValue/MoneyValue';
|
|
31
|
+
export { default as NoteInput } from './NoteInput/NoteInput';
|
|
30
32
|
export { default as NavArrow } from './NavArrow/NavArrow';
|
|
33
|
+
export { default as Numpad } from './Numpad/Numpad';
|
|
31
34
|
export { default as PageTitle } from './PageTitle/PageTitle';
|
|
32
35
|
export { default as Screen } from './Screen/Screen';
|
|
33
36
|
export { default as Section } from './Section/Section';
|
|
@@ -35,6 +38,7 @@ export { default as Stepper } from './Stepper/Stepper';
|
|
|
35
38
|
export { Step } from './Stepper/Step';
|
|
36
39
|
export { StepLabel } from './Stepper/StepLabel';
|
|
37
40
|
export { default as TextInput } from './TextInput/TextInput';
|
|
41
|
+
export { default as StatusHero } from './StatusHero/StatusHero';
|
|
38
42
|
export { default as ThreadHero } from './ThreadHero/ThreadHero';
|
|
39
43
|
export { Tooltip } from './Tooltip/Tooltip';
|
|
40
44
|
export { default as TransactionDetails } from './TransactionDetails/TransactionDetails';
|
|
@@ -51,4 +55,9 @@ export { default as ChipSelect } from './ChipSelect/ChipSelect';
|
|
|
51
55
|
export { default as InputSearch } from './InputSearch/InputSearch';
|
|
52
56
|
export { default as SupportText } from './SupportText/SupportText';
|
|
53
57
|
export { default as SupportTextIcon } from './SupportText/SupportTextIcon';
|
|
54
|
-
export { default as RadioButton } from './RadioButton/RadioButton';
|
|
58
|
+
export { default as RadioButton } from './RadioButton/RadioButton';
|
|
59
|
+
export { default as Tabs } from './Tabs/Tabs';
|
|
60
|
+
export { default as TabItem } from './Tabs/TabItem';
|
|
61
|
+
export { default as Toast } from './Toast/Toast';
|
|
62
|
+
export { default as ToastProvider } from './Toast/ToastProvider';
|
|
63
|
+
export { useToast, addToast, closeToast, closeAll } from './Toast/useToast';
|