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,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
|
|
10
|
+
var _IconDeletebackspace = require("../../icons/components/IconDeletebackspace");
|
|
11
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
12
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
13
|
+
function shuffleArray(arr) {
|
|
14
|
+
const shuffled = [...arr];
|
|
15
|
+
for (let i = shuffled.length - 1; i > 0; i--) {
|
|
16
|
+
const j = Math.floor(Math.random() * (i + 1));
|
|
17
|
+
[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]];
|
|
18
|
+
}
|
|
19
|
+
return shuffled;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Secure numpad component for the JFS finance system.
|
|
24
|
+
*
|
|
25
|
+
* Renders a 3×4 grid of digit keys (0-9), an optional decimal key, and a
|
|
26
|
+
* backspace key. Digit positions are shuffled by default to guard against
|
|
27
|
+
* keylogging and shoulder-surfing attacks on mobile devices.
|
|
28
|
+
*
|
|
29
|
+
* @component
|
|
30
|
+
* @param {NumpadProps} props
|
|
31
|
+
*/
|
|
32
|
+
function Numpad({
|
|
33
|
+
modes = {},
|
|
34
|
+
onKeyPress,
|
|
35
|
+
showDecimal = true,
|
|
36
|
+
shuffle = true,
|
|
37
|
+
style,
|
|
38
|
+
keyStyle,
|
|
39
|
+
keyTextStyle
|
|
40
|
+
}) {
|
|
41
|
+
const foreground = (0, _figmaVariablesResolver.getVariableByName)('numpad/foreground', modes) ?? '#141414';
|
|
42
|
+
const lineHeight = (0, _figmaVariablesResolver.getVariableByName)('numpad/lineHeight', modes) ?? 32;
|
|
43
|
+
const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('numpad/fontFamily', modes) ?? 'JioType Var';
|
|
44
|
+
const fontSize = (0, _figmaVariablesResolver.getVariableByName)('numpad/fontSize', modes) ?? 32;
|
|
45
|
+
const rowGap = (0, _figmaVariablesResolver.getVariableByName)('numpad/gridRowGap/vertical', modes) ?? 12;
|
|
46
|
+
const columnGap = (0, _figmaVariablesResolver.getVariableByName)('numpad/gridColumnGap/horizontal', modes) ?? 12;
|
|
47
|
+
const digits = (0, _react.useMemo)(() => {
|
|
48
|
+
const base = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0'];
|
|
49
|
+
return shuffle ? shuffleArray(base) : base;
|
|
50
|
+
}, [shuffle]);
|
|
51
|
+
const rows = (0, _react.useMemo)(() => [digits.slice(0, 3), digits.slice(3, 6), digits.slice(6, 9), [showDecimal ? '.' : null, digits[9], 'backspace']], [digits, showDecimal]);
|
|
52
|
+
const handlePress = (0, _react.useCallback)(key => {
|
|
53
|
+
onKeyPress?.(key);
|
|
54
|
+
}, [onKeyPress]);
|
|
55
|
+
const textStyle = {
|
|
56
|
+
color: foreground,
|
|
57
|
+
fontFamily: fontFamily,
|
|
58
|
+
fontSize: fontSize,
|
|
59
|
+
lineHeight: lineHeight,
|
|
60
|
+
textAlign: 'center'
|
|
61
|
+
};
|
|
62
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
63
|
+
style: [{
|
|
64
|
+
gap: rowGap
|
|
65
|
+
}, style],
|
|
66
|
+
accessibilityRole: "none",
|
|
67
|
+
children: rows.map((row, rowIndex) => /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
68
|
+
style: {
|
|
69
|
+
flexDirection: 'row',
|
|
70
|
+
gap: columnGap
|
|
71
|
+
},
|
|
72
|
+
children: row.map((key, colIndex) => {
|
|
73
|
+
if (key === null) {
|
|
74
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
75
|
+
style: {
|
|
76
|
+
flex: 1
|
|
77
|
+
}
|
|
78
|
+
}, `empty-${colIndex}`);
|
|
79
|
+
}
|
|
80
|
+
const isBackspace = key === 'backspace';
|
|
81
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Pressable, {
|
|
82
|
+
style: ({
|
|
83
|
+
pressed
|
|
84
|
+
}) => [{
|
|
85
|
+
flex: 1,
|
|
86
|
+
justifyContent: 'center',
|
|
87
|
+
alignItems: 'center',
|
|
88
|
+
minHeight: 46
|
|
89
|
+
}, pressed && {
|
|
90
|
+
opacity: 0.4
|
|
91
|
+
}, keyStyle],
|
|
92
|
+
onPress: () => handlePress(key),
|
|
93
|
+
accessibilityRole: "button",
|
|
94
|
+
accessibilityLabel: isBackspace ? 'Backspace' : key,
|
|
95
|
+
children: isBackspace ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_IconDeletebackspace.IconDeletebackspace, {
|
|
96
|
+
width: fontSize,
|
|
97
|
+
height: fontSize,
|
|
98
|
+
fill: foreground
|
|
99
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
100
|
+
style: [textStyle, keyTextStyle],
|
|
101
|
+
children: key
|
|
102
|
+
})
|
|
103
|
+
}, `${key}-${colIndex}`);
|
|
104
|
+
})
|
|
105
|
+
}, rowIndex))
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
var _default = exports.default = Numpad;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = StatusHero;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
|
|
10
|
+
var _JFSThemeProvider = require("../../design-tokens/JFSThemeProvider");
|
|
11
|
+
var _IconCapsule = _interopRequireDefault(require("../IconCapsule/IconCapsule"));
|
|
12
|
+
var _MoneyValue = _interopRequireDefault(require("../MoneyValue/MoneyValue"));
|
|
13
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
16
|
+
/**
|
|
17
|
+
* StatusHero component that displays a hero section for payment/transaction status screens.
|
|
18
|
+
*
|
|
19
|
+
* Contains a media slot (defaults to IconCapsule + MoneyValue) and a content area
|
|
20
|
+
* with an optional title and a subtitle. All visual values are resolved from Figma
|
|
21
|
+
* design tokens via `getVariableByName`.
|
|
22
|
+
*
|
|
23
|
+
* @component
|
|
24
|
+
* @example
|
|
25
|
+
* ```tsx
|
|
26
|
+
* <StatusHero
|
|
27
|
+
* iconName="ic_confirm"
|
|
28
|
+
* value="50"
|
|
29
|
+
* currency="INR"
|
|
30
|
+
* title="You're set to make payments"
|
|
31
|
+
* subtitle="₹50 will be auto-invested daily, stay consistent & stay golden."
|
|
32
|
+
* modes={{ 'Color Mode': 'Light' }}
|
|
33
|
+
* />
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
function StatusHero({
|
|
37
|
+
renderMedia,
|
|
38
|
+
title = "You're set to make payments",
|
|
39
|
+
showTitle = true,
|
|
40
|
+
subtitle = '₹50 will be auto-invested daily,\nstay consistent & stay golden.',
|
|
41
|
+
iconName = 'ic_confirm',
|
|
42
|
+
value = '50',
|
|
43
|
+
currency = 'INR',
|
|
44
|
+
modes: propModes = {},
|
|
45
|
+
style
|
|
46
|
+
}) {
|
|
47
|
+
const {
|
|
48
|
+
modes: globalModes
|
|
49
|
+
} = (0, _JFSThemeProvider.useTokens)();
|
|
50
|
+
const modes = {
|
|
51
|
+
...globalModes,
|
|
52
|
+
...propModes
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// Container
|
|
56
|
+
const gap = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/gap', modes)) || 12;
|
|
57
|
+
const padding = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/padding', modes)) || 8;
|
|
58
|
+
|
|
59
|
+
// Media slot wrap (gap between icon and money value in default slot)
|
|
60
|
+
const slotWrapGap = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/slotWrap/gap', modes)) || 46;
|
|
61
|
+
|
|
62
|
+
// Content wrap
|
|
63
|
+
const contentWrapGap = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/contentWrap/gap', modes)) || 12;
|
|
64
|
+
|
|
65
|
+
// Title
|
|
66
|
+
const titleColor = (0, _figmaVariablesResolver.getVariableByName)('statusHero/title/foreground', modes) || '#0c0d10';
|
|
67
|
+
const titleFontSize = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/title/fontSize', modes)) || 20;
|
|
68
|
+
const titleFontFamily = (0, _figmaVariablesResolver.getVariableByName)('statusHero/title/fontFamily', modes) || 'System';
|
|
69
|
+
const titleLineHeight = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/title/lineHeight', modes)) || 22;
|
|
70
|
+
const titleFontWeight = (0, _figmaVariablesResolver.getVariableByName)('statusHero/title/fontWeight', modes) || '700';
|
|
71
|
+
|
|
72
|
+
// Body
|
|
73
|
+
const bodyColor = (0, _figmaVariablesResolver.getVariableByName)('statusHero/body/foreground', modes) || '#24262b';
|
|
74
|
+
const bodyFontSize = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/body/fontSize', modes)) || 14;
|
|
75
|
+
const bodyFontFamily = (0, _figmaVariablesResolver.getVariableByName)('statusHero/body/fontFamily', modes) || 'System';
|
|
76
|
+
const bodyLineHeight = Number((0, _figmaVariablesResolver.getVariableByName)('statusHero/body/lineHeight', modes)) || 17;
|
|
77
|
+
const bodyFontWeight = (0, _figmaVariablesResolver.getVariableByName)('statusHero/body/fontWeight', modes) || '500';
|
|
78
|
+
const containerStyle = {
|
|
79
|
+
flexDirection: 'column',
|
|
80
|
+
alignItems: 'center',
|
|
81
|
+
justifyContent: 'center',
|
|
82
|
+
gap,
|
|
83
|
+
padding
|
|
84
|
+
};
|
|
85
|
+
const defaultMediaWrapStyle = {
|
|
86
|
+
flexDirection: 'column',
|
|
87
|
+
alignItems: 'center',
|
|
88
|
+
gap: slotWrapGap
|
|
89
|
+
};
|
|
90
|
+
const contentWrapStyle = {
|
|
91
|
+
flexDirection: 'column',
|
|
92
|
+
alignItems: 'center',
|
|
93
|
+
gap: contentWrapGap
|
|
94
|
+
};
|
|
95
|
+
const titleStyle = {
|
|
96
|
+
color: titleColor,
|
|
97
|
+
fontSize: titleFontSize,
|
|
98
|
+
fontFamily: titleFontFamily,
|
|
99
|
+
lineHeight: titleLineHeight,
|
|
100
|
+
fontWeight: String(titleFontWeight),
|
|
101
|
+
textAlign: 'center'
|
|
102
|
+
};
|
|
103
|
+
const bodyStyle = {
|
|
104
|
+
color: bodyColor,
|
|
105
|
+
fontSize: bodyFontSize,
|
|
106
|
+
fontFamily: bodyFontFamily,
|
|
107
|
+
lineHeight: bodyLineHeight,
|
|
108
|
+
fontWeight: String(bodyFontWeight),
|
|
109
|
+
textAlign: 'center'
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
// Inject modes into the provided slot if it's a valid React element
|
|
113
|
+
const mediaContent = /*#__PURE__*/(0, _react.isValidElement)(renderMedia) ? /*#__PURE__*/(0, _react.cloneElement)(renderMedia, {
|
|
114
|
+
modes
|
|
115
|
+
}) : renderMedia;
|
|
116
|
+
const defaultMediaContent = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
117
|
+
style: defaultMediaWrapStyle,
|
|
118
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_IconCapsule.default, {
|
|
119
|
+
iconName: iconName,
|
|
120
|
+
modes: {
|
|
121
|
+
...modes,
|
|
122
|
+
'Icon Capsule Size': 'L',
|
|
123
|
+
Emphasis: 'High',
|
|
124
|
+
AppearanceBrand: 'Primary'
|
|
125
|
+
}
|
|
126
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_MoneyValue.default, {
|
|
127
|
+
value: value,
|
|
128
|
+
currency: currency,
|
|
129
|
+
modes: {
|
|
130
|
+
...modes,
|
|
131
|
+
Context3: 'Balance'
|
|
132
|
+
}
|
|
133
|
+
})]
|
|
134
|
+
});
|
|
135
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
136
|
+
style: [containerStyle, style],
|
|
137
|
+
children: [mediaContent ?? defaultMediaContent, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
138
|
+
style: contentWrapStyle,
|
|
139
|
+
children: [showTitle && title ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
140
|
+
style: titleStyle,
|
|
141
|
+
children: title
|
|
142
|
+
}) : null, subtitle ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
143
|
+
style: bodyStyle,
|
|
144
|
+
children: subtitle
|
|
145
|
+
}) : null]
|
|
146
|
+
})]
|
|
147
|
+
});
|
|
148
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
|
|
10
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
+
/**
|
|
13
|
+
* Individual tab item used inside the Tabs container.
|
|
14
|
+
*
|
|
15
|
+
* Supports idle and active states driven by design tokens.
|
|
16
|
+
* When active, a bottom indicator bar is shown beneath the label.
|
|
17
|
+
*
|
|
18
|
+
* @component
|
|
19
|
+
* @param {TabItemProps} props
|
|
20
|
+
*/
|
|
21
|
+
function TabItem({
|
|
22
|
+
label = 'Tab item',
|
|
23
|
+
active = false,
|
|
24
|
+
onPress,
|
|
25
|
+
modes = {},
|
|
26
|
+
style,
|
|
27
|
+
labelStyle,
|
|
28
|
+
accessibilityLabel
|
|
29
|
+
}) {
|
|
30
|
+
const paddingVertical = (0, _figmaVariablesResolver.getVariableByName)('tabItem/padding/vertical', modes) ?? 8;
|
|
31
|
+
const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('tabItem/label/fontFamily', modes) ?? 'JioType Var';
|
|
32
|
+
const fontSize = (0, _figmaVariablesResolver.getVariableByName)('tabItem/label/size', modes) ?? 14;
|
|
33
|
+
const lineHeight = (0, _figmaVariablesResolver.getVariableByName)('tabItem/label/lineHeight', modes) ?? 17;
|
|
34
|
+
const idleLabelColor = (0, _figmaVariablesResolver.getVariableByName)('tabItem/idle/label/color', modes) ?? '#303338';
|
|
35
|
+
const activeLabelColor = (0, _figmaVariablesResolver.getVariableByName)('tabItem/active/label/color', modes) ?? '#cea15a';
|
|
36
|
+
const labelColor = active ? activeLabelColor : idleLabelColor;
|
|
37
|
+
const containerStyle = {
|
|
38
|
+
flexDirection: 'column',
|
|
39
|
+
alignItems: 'center',
|
|
40
|
+
justifyContent: 'center',
|
|
41
|
+
paddingVertical
|
|
42
|
+
};
|
|
43
|
+
const textStyle = {
|
|
44
|
+
color: labelColor,
|
|
45
|
+
fontFamily,
|
|
46
|
+
fontSize,
|
|
47
|
+
lineHeight,
|
|
48
|
+
fontWeight: '500'
|
|
49
|
+
};
|
|
50
|
+
const indicatorStyle = {
|
|
51
|
+
position: 'absolute',
|
|
52
|
+
bottom: 0,
|
|
53
|
+
left: 0,
|
|
54
|
+
right: 0,
|
|
55
|
+
height: 2,
|
|
56
|
+
backgroundColor: activeLabelColor,
|
|
57
|
+
borderRadius: 1
|
|
58
|
+
};
|
|
59
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.Pressable, {
|
|
60
|
+
style: ({
|
|
61
|
+
pressed
|
|
62
|
+
}) => [containerStyle, pressed && {
|
|
63
|
+
opacity: 0.7
|
|
64
|
+
}, style],
|
|
65
|
+
onPress: onPress,
|
|
66
|
+
accessibilityRole: "tab",
|
|
67
|
+
accessibilityState: {
|
|
68
|
+
selected: active
|
|
69
|
+
},
|
|
70
|
+
accessibilityLabel: accessibilityLabel ?? label,
|
|
71
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
72
|
+
style: [textStyle, labelStyle],
|
|
73
|
+
children: label
|
|
74
|
+
}), active && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
75
|
+
style: indicatorStyle
|
|
76
|
+
})]
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
var _default = exports.default = TabItem;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "TabItem", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function () {
|
|
9
|
+
return _TabItem.default;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
exports.default = void 0;
|
|
13
|
+
var _react = _interopRequireDefault(require("react"));
|
|
14
|
+
var _reactNative = require("react-native");
|
|
15
|
+
var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
|
|
16
|
+
var _TabItem = _interopRequireDefault(require("./TabItem"));
|
|
17
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
18
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
19
|
+
/**
|
|
20
|
+
* Tabs container component that lays out TabItem children horizontally.
|
|
21
|
+
*
|
|
22
|
+
* The "Tab items" slot maps to React children — each child should be a
|
|
23
|
+
* `<TabItem>` element. The `modes` prop is automatically forwarded to
|
|
24
|
+
* every TabItem child so theming is consistent.
|
|
25
|
+
*
|
|
26
|
+
* @component
|
|
27
|
+
* @param {TabsProps} props
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```tsx
|
|
31
|
+
* const [activeIndex, setActiveIndex] = useState(0);
|
|
32
|
+
*
|
|
33
|
+
* <Tabs modes={{ 'Color Mode': 'Light' }}>
|
|
34
|
+
* <TabItem label="Tab 1" active={activeIndex === 0} onPress={() => setActiveIndex(0)} />
|
|
35
|
+
* <TabItem label="Tab 2" active={activeIndex === 1} onPress={() => setActiveIndex(1)} />
|
|
36
|
+
* <TabItem label="Tab 3" active={activeIndex === 2} onPress={() => setActiveIndex(2)} />
|
|
37
|
+
* </Tabs>
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
function Tabs({
|
|
41
|
+
children,
|
|
42
|
+
modes = {},
|
|
43
|
+
scrollable = false,
|
|
44
|
+
style
|
|
45
|
+
}) {
|
|
46
|
+
const gap = (0, _figmaVariablesResolver.getVariableByName)('tabs/gap', modes) ?? 16;
|
|
47
|
+
const paddingTop = (0, _figmaVariablesResolver.getVariableByName)('tabs/padding/top', modes) ?? 0;
|
|
48
|
+
const paddingBottom = (0, _figmaVariablesResolver.getVariableByName)('tabs/padding/bottom', modes) ?? 0;
|
|
49
|
+
const paddingLeft = (0, _figmaVariablesResolver.getVariableByName)('tabs/padding/left', modes) ?? 0;
|
|
50
|
+
const paddingRight = (0, _figmaVariablesResolver.getVariableByName)('tabs/padding/right', modes) ?? 0;
|
|
51
|
+
|
|
52
|
+
// Forward modes to all TabItem children
|
|
53
|
+
const enhancedChildren = _react.default.Children.map(children, child => {
|
|
54
|
+
if (/*#__PURE__*/_react.default.isValidElement(child) && child.type === _TabItem.default) {
|
|
55
|
+
const childElement = child;
|
|
56
|
+
return /*#__PURE__*/_react.default.cloneElement(childElement, {
|
|
57
|
+
modes: {
|
|
58
|
+
...modes,
|
|
59
|
+
...(childElement.props.modes ?? {})
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return child;
|
|
64
|
+
});
|
|
65
|
+
const containerStyle = {
|
|
66
|
+
flexDirection: 'row',
|
|
67
|
+
gap,
|
|
68
|
+
paddingTop,
|
|
69
|
+
paddingBottom,
|
|
70
|
+
paddingLeft,
|
|
71
|
+
paddingRight
|
|
72
|
+
};
|
|
73
|
+
if (scrollable) {
|
|
74
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.ScrollView, {
|
|
75
|
+
horizontal: true,
|
|
76
|
+
showsHorizontalScrollIndicator: false,
|
|
77
|
+
accessibilityRole: "tablist",
|
|
78
|
+
contentContainerStyle: [containerStyle, style],
|
|
79
|
+
children: enhancedChildren
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
83
|
+
style: [containerStyle, style],
|
|
84
|
+
accessibilityRole: "tablist",
|
|
85
|
+
children: enhancedChildren
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
var _default = exports.default = Tabs;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _reactNativeReanimated = _interopRequireWildcard(require("react-native-reanimated"));
|
|
10
|
+
var _figmaVariablesResolver = require("../../design-tokens/figma-variables-resolver");
|
|
11
|
+
var _useToast = require("./useToast");
|
|
12
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
14
|
+
const ANIMATION_DURATION = 250;
|
|
15
|
+
function Toast({
|
|
16
|
+
id,
|
|
17
|
+
title,
|
|
18
|
+
timeout = 4000,
|
|
19
|
+
onClose,
|
|
20
|
+
modes = {},
|
|
21
|
+
placement = 'bottom',
|
|
22
|
+
style
|
|
23
|
+
}) {
|
|
24
|
+
const timerRef = (0, _react.useRef)(null);
|
|
25
|
+
(0, _react.useEffect)(() => {
|
|
26
|
+
if (timeout <= 0) return;
|
|
27
|
+
timerRef.current = setTimeout(() => (0, _useToast.closeToast)(id), timeout);
|
|
28
|
+
return () => {
|
|
29
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
30
|
+
};
|
|
31
|
+
}, [id, timeout]);
|
|
32
|
+
const backgroundColor = (0, _figmaVariablesResolver.getVariableByName)('toast/background', modes) || '#303338';
|
|
33
|
+
const foreground = (0, _figmaVariablesResolver.getVariableByName)('toast/foreground', modes) || '#ffffff';
|
|
34
|
+
const fontSize = (0, _figmaVariablesResolver.getVariableByName)('toast/fontSize', modes) || 14;
|
|
35
|
+
const fontFamily = (0, _figmaVariablesResolver.getVariableByName)('toast/fontFamily', modes) || undefined;
|
|
36
|
+
const fontWeight = (0, _figmaVariablesResolver.getVariableByName)('toast/fontWeight', modes) || '500';
|
|
37
|
+
const lineHeight = (0, _figmaVariablesResolver.getVariableByName)('toast/lineHeight', modes) || 18;
|
|
38
|
+
const radius = (0, _figmaVariablesResolver.getVariableByName)('toast/radius', modes) || 14;
|
|
39
|
+
const paddingHorizontal = (0, _figmaVariablesResolver.getVariableByName)('toast/padding/horizontal', modes) || 16;
|
|
40
|
+
const paddingVertical = (0, _figmaVariablesResolver.getVariableByName)('toast/padding/vertical', modes) || 14;
|
|
41
|
+
const gap = (0, _figmaVariablesResolver.getVariableByName)('toast/gap', modes) || 8;
|
|
42
|
+
const borderWidth = (0, _figmaVariablesResolver.getVariableByName)('toast/border/size', modes) || 1;
|
|
43
|
+
const borderColor = (0, _figmaVariablesResolver.getVariableByName)('toast/border/color', modes) || 'rgba(255,255,255,0.1)';
|
|
44
|
+
const shadowBlurPrimary = (0, _figmaVariablesResolver.getVariableByName)('toast/shadow/primary/blur', modes) || 48;
|
|
45
|
+
const shadowOffsetYPrimary = (0, _figmaVariablesResolver.getVariableByName)('toast/shadow/primary/offsetY', modes) || 16;
|
|
46
|
+
const shadowColorPrimary = (0, _figmaVariablesResolver.getVariableByName)('toast/shadow/primary/color', modes) || 'rgba(13,13,15,0.16)';
|
|
47
|
+
const enterAnimation = placement === 'top' ? _reactNativeReanimated.SlideInUp.duration(ANIMATION_DURATION) : _reactNativeReanimated.SlideInDown.duration(ANIMATION_DURATION);
|
|
48
|
+
const containerStyle = {
|
|
49
|
+
backgroundColor,
|
|
50
|
+
borderRadius: radius,
|
|
51
|
+
paddingHorizontal,
|
|
52
|
+
paddingVertical,
|
|
53
|
+
gap,
|
|
54
|
+
borderWidth,
|
|
55
|
+
borderColor,
|
|
56
|
+
shadowColor: shadowColorPrimary,
|
|
57
|
+
shadowOffset: {
|
|
58
|
+
width: 0,
|
|
59
|
+
height: shadowOffsetYPrimary
|
|
60
|
+
},
|
|
61
|
+
shadowOpacity: 1,
|
|
62
|
+
shadowRadius: shadowBlurPrimary / 2,
|
|
63
|
+
elevation: 8
|
|
64
|
+
};
|
|
65
|
+
const textStyle = {
|
|
66
|
+
color: foreground,
|
|
67
|
+
fontSize,
|
|
68
|
+
fontFamily,
|
|
69
|
+
fontWeight: String(fontWeight),
|
|
70
|
+
lineHeight
|
|
71
|
+
};
|
|
72
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNativeReanimated.default.View, {
|
|
73
|
+
entering: enterAnimation,
|
|
74
|
+
exiting: _reactNativeReanimated.FadeOut.duration(ANIMATION_DURATION),
|
|
75
|
+
style: [styles.toast, containerStyle, style],
|
|
76
|
+
accessibilityRole: "alert",
|
|
77
|
+
accessibilityLiveRegion: "assertive",
|
|
78
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
79
|
+
style: textStyle,
|
|
80
|
+
numberOfLines: 2,
|
|
81
|
+
children: title
|
|
82
|
+
})
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
const styles = _reactNative.StyleSheet.create({
|
|
86
|
+
toast: {
|
|
87
|
+
alignSelf: 'center',
|
|
88
|
+
maxWidth: '90%',
|
|
89
|
+
minWidth: 200,
|
|
90
|
+
overflow: 'hidden'
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
var _default = exports.default = Toast;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _reactNativeSafeAreaContext = require("react-native-safe-area-context");
|
|
10
|
+
var _useToast = require("./useToast");
|
|
11
|
+
var _Toast = _interopRequireDefault(require("./Toast"));
|
|
12
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
13
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
14
|
+
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
15
|
+
function ToastProvider({
|
|
16
|
+
children,
|
|
17
|
+
maxVisibleToasts = 3,
|
|
18
|
+
placement = 'bottom',
|
|
19
|
+
modes
|
|
20
|
+
}) {
|
|
21
|
+
const {
|
|
22
|
+
toasts
|
|
23
|
+
} = (0, _useToast.useToast)();
|
|
24
|
+
const insets = (0, _reactNativeSafeAreaContext.useSafeAreaInsets)();
|
|
25
|
+
const visibleToasts = (0, _react.useMemo)(() => toasts.slice(-maxVisibleToasts), [toasts, maxVisibleToasts]);
|
|
26
|
+
const regionStyle = (0, _react.useMemo)(() => [styles.region, placement === 'top' ? {
|
|
27
|
+
top: insets.top + 8
|
|
28
|
+
} : {
|
|
29
|
+
bottom: insets.bottom + 8
|
|
30
|
+
}], [placement, insets.top, insets.bottom]);
|
|
31
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
32
|
+
style: styles.container,
|
|
33
|
+
children: [children, visibleToasts.length > 0 && /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
34
|
+
style: regionStyle,
|
|
35
|
+
pointerEvents: "box-none",
|
|
36
|
+
children: visibleToasts.map(entry => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Toast.default, {
|
|
37
|
+
id: entry.id,
|
|
38
|
+
title: entry.title,
|
|
39
|
+
timeout: entry.timeout,
|
|
40
|
+
onClose: entry.onClose,
|
|
41
|
+
modes: entry.modes ?? modes,
|
|
42
|
+
placement: placement
|
|
43
|
+
}, entry.id))
|
|
44
|
+
})]
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const styles = _reactNative.StyleSheet.create({
|
|
48
|
+
container: {
|
|
49
|
+
flex: 1
|
|
50
|
+
},
|
|
51
|
+
region: {
|
|
52
|
+
position: 'absolute',
|
|
53
|
+
left: 0,
|
|
54
|
+
right: 0,
|
|
55
|
+
alignItems: 'center',
|
|
56
|
+
gap: 8,
|
|
57
|
+
zIndex: 9999,
|
|
58
|
+
pointerEvents: 'box-none'
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
var _default = exports.default = ToastProvider;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.addToast = addToast;
|
|
7
|
+
exports.closeAll = closeAll;
|
|
8
|
+
exports.closeToast = closeToast;
|
|
9
|
+
exports.useToast = useToast;
|
|
10
|
+
var _react = require("react");
|
|
11
|
+
let idCounter = 0;
|
|
12
|
+
let toasts = [];
|
|
13
|
+
const listeners = new Set();
|
|
14
|
+
function emit() {
|
|
15
|
+
for (const listener of listeners) {
|
|
16
|
+
listener();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function getSnapshot() {
|
|
20
|
+
return toasts;
|
|
21
|
+
}
|
|
22
|
+
function subscribe(listener) {
|
|
23
|
+
listeners.add(listener);
|
|
24
|
+
return () => {
|
|
25
|
+
listeners.delete(listener);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function addToast(options) {
|
|
29
|
+
const id = `toast-${++idCounter}`;
|
|
30
|
+
const entry = {
|
|
31
|
+
id,
|
|
32
|
+
title: options.title,
|
|
33
|
+
timeout: options.timeout ?? 4000,
|
|
34
|
+
onClose: options.onClose,
|
|
35
|
+
modes: options.modes
|
|
36
|
+
};
|
|
37
|
+
toasts = [...toasts, entry];
|
|
38
|
+
emit();
|
|
39
|
+
return id;
|
|
40
|
+
}
|
|
41
|
+
function closeToast(id) {
|
|
42
|
+
const entry = toasts.find(t => t.id === id);
|
|
43
|
+
toasts = toasts.filter(t => t.id !== id);
|
|
44
|
+
emit();
|
|
45
|
+
entry?.onClose?.();
|
|
46
|
+
}
|
|
47
|
+
function closeAll() {
|
|
48
|
+
const prev = toasts;
|
|
49
|
+
toasts = [];
|
|
50
|
+
emit();
|
|
51
|
+
prev.forEach(t => t.onClose?.());
|
|
52
|
+
}
|
|
53
|
+
function useToast() {
|
|
54
|
+
const queue = (0, _react.useSyncExternalStore)(subscribe, getSnapshot, getSnapshot);
|
|
55
|
+
return {
|
|
56
|
+
toasts: queue,
|
|
57
|
+
addToast: (0, _react.useCallback)(addToast, []),
|
|
58
|
+
closeToast: (0, _react.useCallback)(closeToast, []),
|
|
59
|
+
closeAll: (0, _react.useCallback)(closeAll, [])
|
|
60
|
+
};
|
|
61
|
+
}
|