@campxdev/react-native-blueprint 0.1.23 → 0.1.24
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/global.css +3 -3
- package/lib/global.css +1 -1
- package/lib/module/assets/icons/Image.png +0 -0
- package/lib/module/components/DataDisplay/Avatar/Avatar.js +1 -1
- package/lib/module/components/DataDisplay/Avatar/Avatar.js.map +1 -1
- package/lib/module/components/DataDisplay/Banner/Banner.figma.js +17 -3
- package/lib/module/components/DataDisplay/Banner/Banner.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/Banner/Banner.js +138 -34
- package/lib/module/components/DataDisplay/Banner/Banner.js.map +1 -1
- package/lib/module/components/DataDisplay/CalendarItem/CalendarItem.js +2 -2
- package/lib/module/components/DataDisplay/CalendarItem/CalendarItem.js.map +1 -1
- package/lib/module/components/DataDisplay/Card/Card.figma.js +11 -4
- package/lib/module/components/DataDisplay/Card/Card.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/Card/Card.js +119 -65
- package/lib/module/components/DataDisplay/Card/Card.js.map +1 -1
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.figma.js +54 -0
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.figma.js.map +1 -0
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.js +318 -0
- package/lib/module/components/DataDisplay/ChatBubble/ChatBubble.js.map +1 -0
- package/lib/module/components/DataDisplay/ChatBubble/index.js +4 -0
- package/lib/module/components/DataDisplay/ChatBubble/index.js.map +1 -0
- package/lib/module/components/DataDisplay/FeedCard/AttachmentDetails.js +69 -0
- package/lib/module/components/DataDisplay/FeedCard/AttachmentDetails.js.map +1 -0
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.figma.js +19 -17
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.js +30 -19
- package/lib/module/components/DataDisplay/FeedCard/FeedCard.js.map +1 -1
- package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js +5 -5
- package/lib/module/components/DataDisplay/Greeting/Greeting.figma.js.map +1 -1
- package/lib/module/components/DataDisplay/Greeting/Greeting.js +46 -70
- package/lib/module/components/DataDisplay/Greeting/Greeting.js.map +1 -1
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.figma.js +16 -0
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.figma.js.map +1 -0
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.js +111 -0
- package/lib/module/components/DataDisplay/ProfileCard/ProfileCard.js.map +1 -0
- package/lib/module/components/DataDisplay/ProfileCard/index.js +4 -0
- package/lib/module/components/DataDisplay/ProfileCard/index.js.map +1 -0
- package/lib/module/components/Input/Button/Button.js +77 -129
- package/lib/module/components/Input/Button/Button.js.map +1 -1
- package/lib/module/components/Navigation/Appbar/AppBar.figma.js +18 -6
- package/lib/module/components/Navigation/Appbar/AppBar.figma.js.map +1 -1
- package/lib/module/components/Navigation/Appbar/AppBar.js +36 -9
- package/lib/module/components/Navigation/Appbar/AppBar.js.map +1 -1
- package/lib/module/components/Navigation/Popover/Popover.js +1 -1
- package/lib/module/components/Navigation/Popover/Popover.js.map +1 -1
- package/lib/module/components/ui/index.js +2 -0
- package/lib/module/components/ui/index.js.map +1 -1
- package/lib/module/lib/theme.js +2 -2
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.figma.js +196 -0
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.js +255 -0
- package/lib/module/patterns/pattern-components/AccountPattern/AccountPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/AccountPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/AccountPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/CalendarPattern/CalendarPattern.figma.js +1 -1
- package/lib/module/patterns/pattern-components/CardListPattern/CardListPattern.js +2 -4
- package/lib/module/patterns/pattern-components/CardListPattern/CardListPattern.js.map +1 -1
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.figma.js +144 -0
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.js +213 -0
- package/lib/module/patterns/pattern-components/FeedPattern/FeedPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/FeedPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/FeedPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.figma.js +70 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.js +260 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/HomeFacultyPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.figma.js +82 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.js +256 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/HomeParentPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/HomeParentPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.figma.js +73 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.figma.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.js +283 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.js.map +1 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/index.js +4 -0
- package/lib/module/patterns/pattern-components/HomeStudentPattern/index.js.map +1 -0
- package/lib/module/patterns/pattern-components/index.js +5 -0
- package/lib/module/patterns/pattern-components/index.js.map +1 -1
- package/package.json +27 -1
- package/src/assets/icons/Image.png +0 -0
- package/src/components/DataDisplay/Avatar/Avatar.tsx +24 -21
- package/src/components/DataDisplay/Banner/Banner.figma.tsx +18 -3
- package/src/components/DataDisplay/Banner/Banner.tsx +153 -26
- package/src/components/DataDisplay/CalendarItem/CalendarItem.tsx +2 -2
- package/src/components/DataDisplay/Card/Card.figma.tsx +7 -3
- package/src/components/DataDisplay/Card/Card.tsx +152 -101
- package/src/components/DataDisplay/ChatBubble/ChatBubble.figma.tsx +54 -0
- package/src/components/DataDisplay/ChatBubble/ChatBubble.tsx +404 -0
- package/src/components/DataDisplay/ChatBubble/index.ts +8 -0
- package/src/components/DataDisplay/FeedCard/AttachmentDetails.tsx +96 -0
- package/src/components/DataDisplay/FeedCard/FeedCard.figma.tsx +17 -15
- package/src/components/DataDisplay/FeedCard/FeedCard.tsx +66 -35
- package/src/components/DataDisplay/Greeting/Greeting.figma.tsx +5 -5
- package/src/components/DataDisplay/Greeting/Greeting.tsx +58 -96
- package/src/components/DataDisplay/ProfileCard/ProfileCard.figma.tsx +17 -0
- package/src/components/DataDisplay/ProfileCard/ProfileCard.tsx +173 -0
- package/src/components/DataDisplay/ProfileCard/index.ts +1 -0
- package/src/components/Input/Button/Button.tsx +71 -157
- package/src/components/Navigation/Appbar/AppBar.figma.tsx +18 -6
- package/src/components/Navigation/Appbar/AppBar.tsx +58 -13
- package/src/components/Navigation/Popover/Popover.tsx +3 -3
- package/src/components/ui/index.ts +2 -0
- package/src/lib/theme.ts +2 -2
- package/src/patterns/pattern-components/AccountPattern/AccountPattern.figma.tsx +193 -0
- package/src/patterns/pattern-components/AccountPattern/AccountPattern.tsx +301 -0
- package/src/patterns/pattern-components/AccountPattern/index.ts +1 -0
- package/src/patterns/pattern-components/CalendarPattern/CalendarPattern.figma.tsx +1 -1
- package/src/patterns/pattern-components/CardListPattern/CardListPattern.tsx +4 -9
- package/src/patterns/pattern-components/FeedPattern/FeedPattern.figma.tsx +146 -0
- package/src/patterns/pattern-components/FeedPattern/FeedPattern.tsx +264 -0
- package/src/patterns/pattern-components/FeedPattern/index.ts +2 -0
- package/src/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.figma.tsx +66 -0
- package/src/patterns/pattern-components/HomeFacultyPattern/HomeFacultyPattern.tsx +326 -0
- package/src/patterns/pattern-components/HomeFacultyPattern/index.ts +2 -0
- package/src/patterns/pattern-components/HomeParentPattern/HomeParentPattern.figma.tsx +75 -0
- package/src/patterns/pattern-components/HomeParentPattern/HomeParentPattern.tsx +328 -0
- package/src/patterns/pattern-components/HomeParentPattern/index.ts +2 -0
- package/src/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.figma.tsx +66 -0
- package/src/patterns/pattern-components/HomeStudentPattern/HomeStudentPattern.tsx +355 -0
- package/src/patterns/pattern-components/HomeStudentPattern/index.ts +2 -0
- package/src/patterns/pattern-components/index.ts +5 -0
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
|
-
import { cva, type VariantProps } from 'class-variance-authority';
|
|
3
2
|
import * as React from 'react';
|
|
4
3
|
import {
|
|
5
4
|
Pressable,
|
|
6
|
-
Text as RNText,
|
|
7
5
|
View,
|
|
6
|
+
Text as RNText,
|
|
8
7
|
type GestureResponderEvent,
|
|
9
|
-
type PressableProps,
|
|
10
8
|
type StyleProp,
|
|
11
9
|
type ViewStyle,
|
|
10
|
+
type PressableProps,
|
|
12
11
|
} from 'react-native';
|
|
12
|
+
import { cssInterop } from 'nativewind';
|
|
13
13
|
import { SquircleView } from 'react-native-figma-squircle';
|
|
14
|
-
import {
|
|
14
|
+
import { cva, type VariantProps } from 'class-variance-authority';
|
|
15
|
+
|
|
16
|
+
import { cn } from '../../../lib/utils';
|
|
17
|
+
import { useThemeColors } from '../../../lib/theme';
|
|
18
|
+
|
|
19
|
+
// NativeWind interop (className -> style)
|
|
20
|
+
cssInterop(Pressable, { className: 'style' });
|
|
21
|
+
cssInterop(View, { className: 'style' });
|
|
22
|
+
cssInterop(RNText, { className: 'style' });
|
|
15
23
|
|
|
16
24
|
/**
|
|
17
25
|
* ✅ Canonical values (match Figma)
|
|
@@ -22,38 +30,31 @@ export const ButtonVariants = {
|
|
|
22
30
|
} as const;
|
|
23
31
|
|
|
24
32
|
/**
|
|
25
|
-
* Local lightweight placeholder icon
|
|
33
|
+
* Local lightweight placeholder icon (used in demos/tests)
|
|
34
|
+
* ✅ No inline styles (satisfies react-native/no-inline-styles)
|
|
26
35
|
*/
|
|
27
36
|
function DummyIcon({ testID }: { testID?: string }) {
|
|
28
|
-
return
|
|
29
|
-
<View
|
|
30
|
-
testID={testID}
|
|
31
|
-
style={{
|
|
32
|
-
width: 16,
|
|
33
|
-
height: 16,
|
|
34
|
-
borderRadius: 4,
|
|
35
|
-
backgroundColor: '#6a7282',
|
|
36
|
-
}}
|
|
37
|
-
/>
|
|
38
|
-
);
|
|
37
|
+
return <View testID={testID} className="w-4 h-4 rounded bg-text-inverse" />;
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
/**
|
|
42
|
-
* Returns squircle fill & stroke colors per variant from
|
|
41
|
+
* Returns squircle fill & stroke colors per variant from THEME tokens
|
|
43
42
|
*/
|
|
44
|
-
function useVariantSquircleParams(variant: string
|
|
43
|
+
function useVariantSquircleParams(variant: string) {
|
|
44
|
+
const colors = useThemeColors();
|
|
45
|
+
|
|
45
46
|
const map: Record<
|
|
46
47
|
string,
|
|
47
48
|
{ fillColor: string; strokeColor: string; strokeWidth: number }
|
|
48
49
|
> = {
|
|
49
50
|
default: {
|
|
50
|
-
fillColor: colors.
|
|
51
|
+
fillColor: colors.brandPrimary,
|
|
51
52
|
strokeColor: 'transparent',
|
|
52
53
|
strokeWidth: 0,
|
|
53
54
|
},
|
|
54
55
|
secondary: {
|
|
55
|
-
fillColor: colors.
|
|
56
|
-
strokeColor: colors.
|
|
56
|
+
fillColor: colors.brandSecondary,
|
|
57
|
+
strokeColor: colors.border,
|
|
57
58
|
strokeWidth: 1,
|
|
58
59
|
},
|
|
59
60
|
outline: {
|
|
@@ -81,34 +82,37 @@ function useVariantSquircleParams(variant: string, colors: any) {
|
|
|
81
82
|
return map[variant] ?? map.default;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
const CORNER_RADIUS =
|
|
85
|
-
const CORNER_SMOOTHING = 1;
|
|
85
|
+
const CORNER_RADIUS = 8; // radius-lg
|
|
86
|
+
const CORNER_SMOOTHING = 1; // maximum smoothing
|
|
86
87
|
|
|
87
88
|
const buttonVariants = cva('flex-row items-center justify-center', {
|
|
88
89
|
variants: {
|
|
89
90
|
variant: {
|
|
90
|
-
default: 'gap-2',
|
|
91
|
-
secondary: '
|
|
92
|
-
outline: '
|
|
93
|
-
ghost: '
|
|
94
|
-
destructive: '
|
|
91
|
+
default: 'gap-2 active:opacity-90',
|
|
92
|
+
secondary: 'active:opacity-90',
|
|
93
|
+
outline: 'active:opacity-90',
|
|
94
|
+
ghost: 'active:opacity-90',
|
|
95
|
+
destructive: 'active:opacity-90',
|
|
95
96
|
link: '',
|
|
96
97
|
},
|
|
97
98
|
size: {
|
|
99
|
+
// ✅ Figma-like sizing
|
|
98
100
|
default: 'py-3 px-5',
|
|
99
|
-
lg: 'py-
|
|
100
|
-
icon: 'h-10 w-10',
|
|
101
|
+
lg: 'py-5 px-6',
|
|
102
|
+
icon: 'h-10 w-10 p-3 justify-center items-center',
|
|
101
103
|
},
|
|
102
104
|
disabled: {
|
|
103
105
|
false: '',
|
|
104
106
|
true: 'opacity-50',
|
|
105
107
|
},
|
|
108
|
+
// Optional icon toggles still affect spacing correctly
|
|
106
109
|
hasIcons: {
|
|
107
110
|
false: '',
|
|
108
111
|
true: 'gap-2',
|
|
109
112
|
},
|
|
110
113
|
},
|
|
111
114
|
compoundVariants: [
|
|
115
|
+
// ✅ Link should not have forced height/padding
|
|
112
116
|
{ variant: 'link', size: 'default', className: 'h-auto p-0' },
|
|
113
117
|
{ variant: 'link', size: 'lg', className: 'h-auto p-0' },
|
|
114
118
|
{ variant: 'link', size: 'icon', className: 'h-auto p-0 w-auto' },
|
|
@@ -124,11 +128,11 @@ const buttonVariants = cva('flex-row items-center justify-center', {
|
|
|
124
128
|
const buttonTextVariants = cva('font-semibold', {
|
|
125
129
|
variants: {
|
|
126
130
|
variant: {
|
|
127
|
-
default: 'text-
|
|
131
|
+
default: 'text-text-inverse',
|
|
128
132
|
secondary: 'text-foreground',
|
|
129
133
|
outline: 'text-foreground',
|
|
130
134
|
ghost: 'text-foreground',
|
|
131
|
-
destructive: 'text-
|
|
135
|
+
destructive: 'text-primary-foreground',
|
|
132
136
|
link: 'text-primary underline',
|
|
133
137
|
},
|
|
134
138
|
size: {
|
|
@@ -148,11 +152,21 @@ const buttonTextVariants = cva('font-semibold', {
|
|
|
148
152
|
},
|
|
149
153
|
});
|
|
150
154
|
|
|
155
|
+
/**
|
|
156
|
+
* ✅ Strict rule: className must NOT be accepted as a prop.
|
|
157
|
+
* So we omit it explicitly from PressableProps.
|
|
158
|
+
*/
|
|
151
159
|
type PressablePropsWithoutClassName = Omit<PressableProps, 'style'> & {
|
|
152
160
|
className?: never;
|
|
153
161
|
};
|
|
154
162
|
|
|
155
|
-
|
|
163
|
+
/**
|
|
164
|
+
* ✅ Backward compatible types:
|
|
165
|
+
* - supports boolean disabled (new)
|
|
166
|
+
* - supports 'True'/'False' and 'true'/'false' and '1'/'0' (old)
|
|
167
|
+
* - supports capitalized variant/size (old)
|
|
168
|
+
*/
|
|
169
|
+
export type ButtonProps = PressablePropsWithoutClassName &
|
|
156
170
|
VariantProps<typeof buttonVariants> & {
|
|
157
171
|
variant?:
|
|
158
172
|
| (typeof ButtonVariants.variant)[number]
|
|
@@ -192,7 +206,7 @@ function normalizeDisabled(v: any): boolean {
|
|
|
192
206
|
return s === 'true' || s === '1';
|
|
193
207
|
}
|
|
194
208
|
|
|
195
|
-
export function
|
|
209
|
+
export function Button(props: ButtonProps) {
|
|
196
210
|
const {
|
|
197
211
|
variant,
|
|
198
212
|
size,
|
|
@@ -208,16 +222,17 @@ export function ButtonComponent(props: ButtonComponentProps) {
|
|
|
208
222
|
...rest
|
|
209
223
|
} = props;
|
|
210
224
|
|
|
211
|
-
const { colors } = useTheme();
|
|
212
|
-
|
|
213
225
|
const v = normalizeVariant(variant);
|
|
214
226
|
const s = normalizeSize(size);
|
|
215
227
|
const d = normalizeDisabled(disabled);
|
|
216
228
|
|
|
229
|
+
// ✅ icon button must be square and must NOT show label (prevents long button)
|
|
217
230
|
const isIconOnly = s === 'icon';
|
|
231
|
+
|
|
232
|
+
// spacing only when icons exist
|
|
218
233
|
const hasIcons = Boolean(showLeftIcon || showRightIcon);
|
|
219
234
|
|
|
220
|
-
const squircleParams = useVariantSquircleParams(v
|
|
235
|
+
const squircleParams = useVariantSquircleParams(v);
|
|
221
236
|
|
|
222
237
|
const handlePress = React.useCallback(
|
|
223
238
|
(e: GestureResponderEvent) => {
|
|
@@ -227,100 +242,9 @@ export function ButtonComponent(props: ButtonComponentProps) {
|
|
|
227
242
|
[d, onPress]
|
|
228
243
|
);
|
|
229
244
|
|
|
230
|
-
// Get text color based on variant
|
|
231
|
-
const getTextColor = () => {
|
|
232
|
-
switch (v) {
|
|
233
|
-
case 'default':
|
|
234
|
-
return colors.primaryForeground;
|
|
235
|
-
case 'secondary':
|
|
236
|
-
return colors.secondaryForeground;
|
|
237
|
-
case 'outline':
|
|
238
|
-
return colors.foreground;
|
|
239
|
-
case 'ghost':
|
|
240
|
-
return colors.foreground;
|
|
241
|
-
case 'destructive':
|
|
242
|
-
return colors.destructiveForeground;
|
|
243
|
-
case 'link':
|
|
244
|
-
return colors.primary;
|
|
245
|
-
default:
|
|
246
|
-
return colors.primaryForeground;
|
|
247
|
-
}
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
// Get size styles
|
|
251
|
-
const getSizeStyles = () => {
|
|
252
|
-
switch (s) {
|
|
253
|
-
case 'lg':
|
|
254
|
-
return { height: 52, paddingHorizontal: 16 };
|
|
255
|
-
case 'icon':
|
|
256
|
-
return { height: 40, width: 40 };
|
|
257
|
-
case 'default':
|
|
258
|
-
default:
|
|
259
|
-
return { height: 48, paddingHorizontal: 16 };
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const sizeStyles = getSizeStyles();
|
|
264
|
-
|
|
265
|
-
if (v === 'link') {
|
|
266
|
-
// Link variant doesn't use SquircleView
|
|
267
|
-
return (
|
|
268
|
-
<Pressable
|
|
269
|
-
testID={testID ?? 'button'}
|
|
270
|
-
accessibilityRole="button"
|
|
271
|
-
accessibilityState={{ disabled: d }}
|
|
272
|
-
disabled={d}
|
|
273
|
-
onPress={handlePress}
|
|
274
|
-
style={[
|
|
275
|
-
{
|
|
276
|
-
flexDirection: 'row',
|
|
277
|
-
alignItems: 'center',
|
|
278
|
-
justifyContent: 'center',
|
|
279
|
-
opacity: d ? 0.5 : 1,
|
|
280
|
-
},
|
|
281
|
-
style,
|
|
282
|
-
]}
|
|
283
|
-
{...rest}
|
|
284
|
-
>
|
|
285
|
-
{showLeftIcon ? (
|
|
286
|
-
leftIcon ? (
|
|
287
|
-
leftIcon
|
|
288
|
-
) : (
|
|
289
|
-
<DummyIcon testID="button-left-icon" />
|
|
290
|
-
)
|
|
291
|
-
) : null}
|
|
292
|
-
|
|
293
|
-
{!isIconOnly ? (
|
|
294
|
-
<RNText
|
|
295
|
-
testID="button-label"
|
|
296
|
-
style={{
|
|
297
|
-
color: getTextColor(),
|
|
298
|
-
fontSize: s === 'lg' ? 16 : 14,
|
|
299
|
-
fontWeight: '600',
|
|
300
|
-
textDecorationLine: 'underline',
|
|
301
|
-
}}
|
|
302
|
-
numberOfLines={1}
|
|
303
|
-
ellipsizeMode="tail"
|
|
304
|
-
>
|
|
305
|
-
{children}
|
|
306
|
-
</RNText>
|
|
307
|
-
) : null}
|
|
308
|
-
|
|
309
|
-
{showRightIcon ? (
|
|
310
|
-
rightIcon ? (
|
|
311
|
-
rightIcon
|
|
312
|
-
) : (
|
|
313
|
-
<DummyIcon testID="button-right-icon" />
|
|
314
|
-
)
|
|
315
|
-
) : null}
|
|
316
|
-
</Pressable>
|
|
317
|
-
);
|
|
318
|
-
}
|
|
319
|
-
|
|
320
245
|
return (
|
|
321
246
|
<View style={style}>
|
|
322
247
|
<SquircleView
|
|
323
|
-
style={sizeStyles}
|
|
324
248
|
squircleParams={{
|
|
325
249
|
cornerRadius: CORNER_RADIUS,
|
|
326
250
|
cornerSmoothing: CORNER_SMOOTHING,
|
|
@@ -333,32 +257,26 @@ export function ButtonComponent(props: ButtonComponentProps) {
|
|
|
333
257
|
accessibilityState={{ disabled: d }}
|
|
334
258
|
disabled={d}
|
|
335
259
|
onPress={handlePress}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
260
|
+
className={cn(
|
|
261
|
+
buttonVariants({
|
|
262
|
+
variant: v,
|
|
263
|
+
size: s,
|
|
264
|
+
disabled: d,
|
|
265
|
+
hasIcons,
|
|
266
|
+
})
|
|
267
|
+
)}
|
|
344
268
|
{...rest}
|
|
345
269
|
>
|
|
346
|
-
{showLeftIcon
|
|
347
|
-
leftIcon
|
|
348
|
-
|
|
349
|
-
) : (
|
|
350
|
-
<DummyIcon testID="button-left-icon" />
|
|
351
|
-
)
|
|
352
|
-
) : null}
|
|
270
|
+
{showLeftIcon
|
|
271
|
+
? leftIcon || <DummyIcon testID="button-left-icon" />
|
|
272
|
+
: null}
|
|
353
273
|
|
|
354
274
|
{!isIconOnly ? (
|
|
355
275
|
<RNText
|
|
356
276
|
testID="button-label"
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
fontWeight: '600',
|
|
361
|
-
}}
|
|
277
|
+
className={cn(
|
|
278
|
+
buttonTextVariants({ variant: v, size: s, disabled: d })
|
|
279
|
+
)}
|
|
362
280
|
numberOfLines={1}
|
|
363
281
|
ellipsizeMode="tail"
|
|
364
282
|
>
|
|
@@ -366,19 +284,15 @@ export function ButtonComponent(props: ButtonComponentProps) {
|
|
|
366
284
|
</RNText>
|
|
367
285
|
) : null}
|
|
368
286
|
|
|
369
|
-
{showRightIcon
|
|
370
|
-
rightIcon
|
|
371
|
-
|
|
372
|
-
) : (
|
|
373
|
-
<DummyIcon testID="button-right-icon" />
|
|
374
|
-
)
|
|
375
|
-
) : null}
|
|
287
|
+
{showRightIcon
|
|
288
|
+
? rightIcon || <DummyIcon testID="button-right-icon" />
|
|
289
|
+
: null}
|
|
376
290
|
</Pressable>
|
|
377
291
|
</SquircleView>
|
|
378
292
|
</View>
|
|
379
293
|
);
|
|
380
294
|
}
|
|
381
295
|
|
|
382
|
-
|
|
296
|
+
Button.displayName = 'Button';
|
|
383
297
|
|
|
384
|
-
export {
|
|
298
|
+
export { buttonTextVariants, buttonVariants };
|
|
@@ -21,9 +21,11 @@ const FIGMA_URL =
|
|
|
21
21
|
*/
|
|
22
22
|
figma.connect(AppBar, FIGMA_URL, {
|
|
23
23
|
props: {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
type: figma.enum('type', {
|
|
25
|
+
'context': 'context',
|
|
26
|
+
'brand': 'brand',
|
|
27
|
+
'brand+switcher': 'brand+switcher',
|
|
28
|
+
'context+switcher': 'context+switcher',
|
|
27
29
|
}),
|
|
28
30
|
showLeading: figma.boolean('Show Leading'),
|
|
29
31
|
showTrailing: figma.boolean('Show Trailing'),
|
|
@@ -37,11 +39,20 @@ figma.connect(AppBar, FIGMA_URL, {
|
|
|
37
39
|
search: 'search',
|
|
38
40
|
}),
|
|
39
41
|
}),
|
|
40
|
-
logo: figma.
|
|
42
|
+
logo: figma.nestedProps('Logo', {
|
|
43
|
+
mode: figma.enum('mode', {
|
|
44
|
+
light: 'light',
|
|
45
|
+
dark: 'dark',
|
|
46
|
+
}),
|
|
47
|
+
brand: figma.enum('brand', {
|
|
48
|
+
campx: 'campx',
|
|
49
|
+
winnify: 'winnify',
|
|
50
|
+
}),
|
|
51
|
+
}),
|
|
41
52
|
},
|
|
42
53
|
example: (props) => (
|
|
43
54
|
<AppBar
|
|
44
|
-
|
|
55
|
+
type={props.type}
|
|
45
56
|
title={props.title}
|
|
46
57
|
subtitle={props.subtitle}
|
|
47
58
|
showLeading={props.showLeading}
|
|
@@ -49,9 +60,10 @@ figma.connect(AppBar, FIGMA_URL, {
|
|
|
49
60
|
showSubtitle={props.showSubtitle}
|
|
50
61
|
showHeaderBlock={props.showHeaderBlock}
|
|
51
62
|
headerType={props.headerType.type}
|
|
63
|
+
logoMode={props.logo.mode}
|
|
64
|
+
logoBrand={props.logo.brand}
|
|
52
65
|
onLeadingPress={() => {}}
|
|
53
66
|
onTrailingPress={() => {}}
|
|
54
67
|
/>
|
|
55
68
|
),
|
|
56
69
|
});
|
|
57
|
-
i;
|
|
@@ -30,10 +30,16 @@ const Pressable = RNPressable as any;
|
|
|
30
30
|
* --------------------------------------------------- */
|
|
31
31
|
|
|
32
32
|
export type AppBarVariant = 'default' | 'home';
|
|
33
|
+
export type AppBarType =
|
|
34
|
+
| 'context'
|
|
35
|
+
| 'brand'
|
|
36
|
+
| 'brand+switcher'
|
|
37
|
+
| 'context+switcher';
|
|
33
38
|
export type HeaderBlockType = 'tabs' | 'search';
|
|
34
39
|
|
|
35
40
|
export interface AppBarProps {
|
|
36
41
|
variant?: AppBarVariant;
|
|
42
|
+
type?: AppBarType;
|
|
37
43
|
|
|
38
44
|
title?: string;
|
|
39
45
|
subtitle?: string;
|
|
@@ -51,9 +57,13 @@ export interface AppBarProps {
|
|
|
51
57
|
leadingIcon?: React.ReactNode;
|
|
52
58
|
trailingIcon?: React.ReactNode;
|
|
53
59
|
|
|
54
|
-
/** For home variant logo */
|
|
60
|
+
/** For home variant logo or brand type */
|
|
55
61
|
logoSource?: ImageSourcePropType;
|
|
56
62
|
|
|
63
|
+
/** Avatar for switcher types (brand+switcher, context+switcher) */
|
|
64
|
+
switcherAvatar?: React.ReactNode;
|
|
65
|
+
onSwitcherPress?: () => void;
|
|
66
|
+
|
|
57
67
|
/** Whether to wrap with SafeAreaView for status bar */
|
|
58
68
|
useSafeArea?: boolean;
|
|
59
69
|
|
|
@@ -90,6 +100,7 @@ function HeaderBlock({ type }: { type: 'tabs' | 'search' }) {
|
|
|
90
100
|
export function AppBar(props: AppBarProps) {
|
|
91
101
|
const {
|
|
92
102
|
variant = 'default',
|
|
103
|
+
type = 'context',
|
|
93
104
|
title = 'Page Title',
|
|
94
105
|
subtitle = 'This is the page Subtitle',
|
|
95
106
|
|
|
@@ -107,6 +118,8 @@ export function AppBar(props: AppBarProps) {
|
|
|
107
118
|
trailingIcon,
|
|
108
119
|
|
|
109
120
|
logoSource,
|
|
121
|
+
switcherAvatar,
|
|
122
|
+
onSwitcherPress,
|
|
110
123
|
|
|
111
124
|
useSafeArea = true,
|
|
112
125
|
|
|
@@ -116,6 +129,8 @@ export function AppBar(props: AppBarProps) {
|
|
|
116
129
|
const { colorScheme } = useColorScheme();
|
|
117
130
|
const isDark = colorScheme === 'dark';
|
|
118
131
|
const isHome = variant === 'home';
|
|
132
|
+
const isBrandType = type === 'brand' || type === 'brand+switcher';
|
|
133
|
+
const hasSwitcher = type === 'brand+switcher' || type === 'context+switcher';
|
|
119
134
|
|
|
120
135
|
const content = (
|
|
121
136
|
<View
|
|
@@ -139,7 +154,22 @@ export function AppBar(props: AppBarProps) {
|
|
|
139
154
|
</Pressable>
|
|
140
155
|
)}
|
|
141
156
|
|
|
142
|
-
{
|
|
157
|
+
{/* Logo for brand+switcher (on left side) */}
|
|
158
|
+
{type === 'brand+switcher' && (
|
|
159
|
+
<View testID="appbar-logo-left">
|
|
160
|
+
{logoSource ? (
|
|
161
|
+
<Image
|
|
162
|
+
source={logoSource}
|
|
163
|
+
resizeMode="contain"
|
|
164
|
+
className="w-8 h-8"
|
|
165
|
+
/>
|
|
166
|
+
) : (
|
|
167
|
+
<View className="w-8 h-8 bg-surface-subtle rounded-lg" />
|
|
168
|
+
)}
|
|
169
|
+
</View>
|
|
170
|
+
)}
|
|
171
|
+
|
|
172
|
+
{!isBrandType && (
|
|
143
173
|
<View className="gap-1">
|
|
144
174
|
<Text
|
|
145
175
|
testID="appbar-title"
|
|
@@ -160,8 +190,8 @@ export function AppBar(props: AppBarProps) {
|
|
|
160
190
|
)}
|
|
161
191
|
</View>
|
|
162
192
|
|
|
163
|
-
{/* CENTER (Home logo) */}
|
|
164
|
-
{isHome && (
|
|
193
|
+
{/* CENTER (Home logo or Brand logo - only for 'brand' type) */}
|
|
194
|
+
{(isHome || type === 'brand') && (
|
|
165
195
|
<View
|
|
166
196
|
testID="appbar-logo"
|
|
167
197
|
className="flex-1 items-center justify-center"
|
|
@@ -179,15 +209,30 @@ export function AppBar(props: AppBarProps) {
|
|
|
179
209
|
)}
|
|
180
210
|
|
|
181
211
|
{/* RIGHT */}
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
212
|
+
<View className="flex-row items-center gap-3">
|
|
213
|
+
{showTrailing && (
|
|
214
|
+
<Pressable
|
|
215
|
+
testID="appbar-trailing"
|
|
216
|
+
onPress={onTrailingPress}
|
|
217
|
+
accessibilityRole="button"
|
|
218
|
+
>
|
|
219
|
+
{trailingIcon ?? <View className="w-4 h-4" />}
|
|
220
|
+
</Pressable>
|
|
221
|
+
)}
|
|
222
|
+
{hasSwitcher && (
|
|
223
|
+
<Pressable
|
|
224
|
+
testID="appbar-switcher"
|
|
225
|
+
onPress={onSwitcherPress}
|
|
226
|
+
className="flex-row items-center gap-2 px-2 py-1 rounded-full border border-border-default"
|
|
227
|
+
accessibilityRole="button"
|
|
228
|
+
>
|
|
229
|
+
{switcherAvatar ?? (
|
|
230
|
+
<View className="w-8 h-8 bg-surface-subtle rounded-full" />
|
|
231
|
+
)}
|
|
232
|
+
<View className="w-4 h-4" />
|
|
233
|
+
</Pressable>
|
|
234
|
+
)}
|
|
235
|
+
</View>
|
|
191
236
|
</View>
|
|
192
237
|
|
|
193
238
|
{/* HEADER BLOCK */}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
import * as React from 'react';
|
|
3
|
-
import {
|
|
3
|
+
import { View, Text, type StyleProp, type ViewStyle } from 'react-native';
|
|
4
4
|
|
|
5
5
|
import { Button } from '../../Input/Button/Button';
|
|
6
6
|
import {
|
|
7
|
-
PopoverContainer,
|
|
8
|
-
PopoverContent,
|
|
9
7
|
Popover as PopoverPrimitive,
|
|
10
8
|
PopoverTrigger,
|
|
9
|
+
PopoverContent,
|
|
10
|
+
PopoverContainer,
|
|
11
11
|
} from '../../Layout/PopoverContainer/Popover-Container';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -30,6 +30,7 @@ export * from '../DataDisplay/Banner/Banner';
|
|
|
30
30
|
export * from '../DataDisplay/BannerRow/BannerRow';
|
|
31
31
|
export * from '../DataDisplay/CalendarItem/CalendarItem';
|
|
32
32
|
export * from '../DataDisplay/Card/Card';
|
|
33
|
+
export * from '../DataDisplay/ChatBubble/ChatBubble';
|
|
33
34
|
export * from '../DataDisplay/Chips/Chips';
|
|
34
35
|
export * from '../DataDisplay/ChipsRow/ChipsRow';
|
|
35
36
|
export * from '../DataDisplay/DataCard/DataCard';
|
|
@@ -37,6 +38,7 @@ export * from '../DataDisplay/Datalist/Datalist';
|
|
|
37
38
|
export * from '../DataDisplay/DataListItem/DataListItem';
|
|
38
39
|
export * from '../DataDisplay/FeedCard/FeedCard';
|
|
39
40
|
export * from '../DataDisplay/Greeting/Greeting';
|
|
41
|
+
export * from '../DataDisplay/ProfileCard/ProfileCard';
|
|
40
42
|
export * from '../DataDisplay/MonthCalendar/MonthCalendar';
|
|
41
43
|
export * from '../DataDisplay/Separator/Separator';
|
|
42
44
|
export * from '../DataDisplay/Skeleton/Skeleton';
|
package/src/lib/theme.ts
CHANGED
|
@@ -46,8 +46,8 @@ export const THEME = {
|
|
|
46
46
|
accentForeground: 'hsl(0, 0%, 100%)', // #FFFFFF
|
|
47
47
|
|
|
48
48
|
// === 6. BORDERS ===
|
|
49
|
-
border: 'hsl(
|
|
50
|
-
input: 'hsl(
|
|
49
|
+
border: 'hsl(210, 13%, 80%)', // #CBD5E1
|
|
50
|
+
input: 'hsl(210, 13%, 80%)', // #CBD5E1
|
|
51
51
|
ring: 'hsl(200, 13%, 11%)', // #161A1D - Same as primary
|
|
52
52
|
|
|
53
53
|
// === 7. HIGHLIGHTS ===
|