feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,220 @@
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import * as React from 'react';
import { Animated, StyleSheet, Pressable, View } from 'react-native';
import useLatestCallback from 'use-latest-callback';
import CardActions from './CardActions';
import CardContent from './CardContent';
import CardCover from './CardCover';
import CardTitle from './CardTitle';
import { getCardColors } from './utils';
import { useInternalTheme } from '../../core/theming';
import { forwardRef } from '../../utils/forwardRef';
import hasTouchHandler from '../../utils/hasTouchHandler';
import { splitStyles } from '../../utils/splitStyles';
import Surface from '../Surface';
/**
* A card is a sheet of material that serves as an entry point to more detailed information.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Avatar, Button, Card, Text } from 'react-native-paper';
*
* const LeftContent = props => <Avatar.Icon {...props} icon="folder" />
*
* const MyComponent = () => (
* <Card>
* <Card.Title title="Card Title" subtitle="Card Subtitle" left={LeftContent} />
* <Card.Content>
* <Text variant="titleLarge">Card title</Text>
* <Text variant="bodyMedium">Card content</Text>
* </Card.Content>
* <Card.Cover source={{ uri: 'https://picsum.photos/700' }} />
* <Card.Actions>
* <Button>Cancel</Button>
* <Button>Ok</Button>
* </Card.Actions>
* </Card>
* );
*
* export default MyComponent;
* ```
*/
const Card = ({
elevation: cardElevation = 1,
delayLongPress,
onPress,
onLongPress,
onPressOut,
onPressIn,
mode: cardMode = 'elevated',
children,
style,
contentStyle,
theme: themeOverrides,
testID = 'card',
accessible,
disabled,
...rest
}, ref) => {
const theme = useInternalTheme(themeOverrides);
const isMode = React.useCallback(modeToCompare => {
return cardMode === modeToCompare;
}, [cardMode]);
const hasPassedTouchHandler = hasTouchHandler({
onPress,
onLongPress,
onPressIn,
onPressOut
});
// Default animated value
const {
current: elevation
} = React.useRef(new Animated.Value(cardElevation));
// Dark adaptive animated value, used in case of toggling the theme,
// it prevents animating the background with native drivers inside Surface
const {
current: elevationDarkAdaptive
} = React.useRef(new Animated.Value(cardElevation));
const {
animation,
dark,
mode,
roundness,
isV3
} = theme;
const prevDarkRef = React.useRef(dark);
React.useEffect(() => {
prevDarkRef.current = dark;
});
const prevDark = prevDarkRef.current;
const isAdaptiveMode = mode === 'adaptive';
const animationDuration = 150 * animation.scale;
React.useEffect(() => {
/**
* Resets animations values if updating to dark adaptive mode,
* otherwise, any card that is in the middle of animation while
* toggling the theme will stay at that animated value until
* the next press-in
*/
if (dark && isAdaptiveMode && !prevDark) {
elevation.setValue(cardElevation);
elevationDarkAdaptive.setValue(cardElevation);
}
}, [prevDark, dark, isAdaptiveMode, cardElevation, elevation, elevationDarkAdaptive]);
const runElevationAnimation = pressType => {
if (isV3 && isMode('contained')) {
return;
}
const isPressTypeIn = pressType === 'in';
if (dark && isAdaptiveMode) {
Animated.timing(elevationDarkAdaptive, {
toValue: isPressTypeIn ? isV3 ? 2 : 8 : cardElevation,
duration: animationDuration,
useNativeDriver: false
}).start();
} else {
Animated.timing(elevation, {
toValue: isPressTypeIn ? isV3 ? 2 : 8 : cardElevation,
duration: animationDuration,
useNativeDriver: false
}).start();
}
};
const handlePressIn = useLatestCallback(e => {
onPressIn === null || onPressIn === void 0 || onPressIn(e);
runElevationAnimation('in');
});
const handlePressOut = useLatestCallback(e => {
onPressOut === null || onPressOut === void 0 || onPressOut(e);
runElevationAnimation('out');
});
const total = React.Children.count(children);
const siblings = React.Children.map(children, child => /*#__PURE__*/React.isValidElement(child) && child.type ? child.type.displayName : null);
const computedElevation = dark && isAdaptiveMode ? elevationDarkAdaptive : elevation;
const {
backgroundColor,
borderColor: themedBorderColor
} = getCardColors({
theme,
mode: cardMode
});
const flattenedStyles = StyleSheet.flatten(style) || {};
const {
borderColor = themedBorderColor
} = flattenedStyles;
const [, borderRadiusStyles] = splitStyles(flattenedStyles, style => style.startsWith('border') && style.endsWith('Radius'));
const borderRadiusCombinedStyles = {
borderRadius: (isV3 ? 3 : 1) * roundness,
...borderRadiusStyles
};
const content = /*#__PURE__*/React.createElement(View, {
style: [styles.innerContainer, contentStyle],
testID: testID
}, React.Children.map(children, (child, index) => /*#__PURE__*/React.isValidElement(child) ? /*#__PURE__*/React.cloneElement(child, {
index,
total,
siblings,
borderRadiusStyles
}) : child));
return /*#__PURE__*/React.createElement(Surface, _extends({
ref: ref,
style: [isV3 && !isMode('elevated') && {
backgroundColor
}, !isV3 && (isMode('outlined') ? styles.resetElevation : {
elevation: computedElevation
}), borderRadiusCombinedStyles, style],
theme: theme
}, isV3 && {
elevation: isMode('elevated') ? computedElevation : 0
}, {
testID: `${testID}-container`,
container: true
}, rest), isMode('outlined') && /*#__PURE__*/React.createElement(View, {
pointerEvents: "none",
testID: `${testID}-outline`,
style: [{
borderColor
}, styles.outline, borderRadiusCombinedStyles]
}), hasPassedTouchHandler ? /*#__PURE__*/React.createElement(Pressable, {
accessible: accessible,
unstable_pressDelay: 0,
disabled: disabled,
delayLongPress: delayLongPress,
onLongPress: onLongPress,
onPress: onPress,
onPressIn: handlePressIn,
onPressOut: handlePressOut
}, content) : content);
};
Card.displayName = 'Card';
const Component = forwardRef(Card);
const CardComponent = Component;
// @component ./CardContent.tsx
CardComponent.Content = CardContent;
// @component ./CardActions.tsx
CardComponent.Actions = CardActions;
// @component ./CardCover.tsx
CardComponent.Cover = CardCover;
// @component ./CardTitle.tsx
CardComponent.Title = CardTitle;
const styles = StyleSheet.create({
innerContainer: {
flexShrink: 1
},
outline: {
borderWidth: 1,
position: 'absolute',
width: '100%',
height: '100%',
zIndex: 2
},
resetElevation: {
elevation: 0
}
});
export default CardComponent;
//# sourceMappingURL=Card.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,67 @@
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { useInternalTheme } from '../../core/theming';
/**
* A component to show a list of actions inside a Card.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Card, Button } from 'react-native-paper';
*
* const MyComponent = () => (
* <Card>
* <Card.Actions>
* <Button>Cancel</Button>
* <Button>Ok</Button>
* </Card.Actions>
* </Card>
* );
*
* export default MyComponent;
* ```
*/
const CardActions = ({
theme,
style,
children,
...rest
}) => {
const {
isV3
} = useInternalTheme(theme);
const justifyContent = isV3 ? 'flex-end' : 'flex-start';
const containerStyle = [styles.container, {
justifyContent
}, style];
return /*#__PURE__*/React.createElement(View, _extends({}, rest, {
style: containerStyle
}), React.Children.map(children, (child, index) => {
if (! /*#__PURE__*/React.isValidElement(child)) {
return child;
}
const compact = !isV3 && child.props.compact !== false;
const mode = child.props.mode ?? (isV3 ? index === 0 ? 'outlined' : 'contained' : undefined);
const childStyle = [isV3 && styles.button, child.props.style];
return /*#__PURE__*/React.cloneElement(child, {
...child.props,
compact,
mode,
style: childStyle
});
}));
};
CardActions.displayName = 'Card.Actions';
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
padding: 8
},
button: {
marginLeft: 8
}
});
export default CardActions;
//# sourceMappingURL=CardActions.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","StyleSheet","View","useInternalTheme","CardActions","theme","style","children","rest","isV3","justifyContent","containerStyle","styles","container","createElement","_extends","Children","map","child","index","isValidElement","compact","props","mode","undefined","childStyle","button","cloneElement","displayName","create","flexDirection","alignItems","padding","marginLeft"],"sourceRoot":"../../../../src","sources":["components/Card/CardActions.tsx"],"mappings":";AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAAoBC,UAAU,EAAEC,IAAI,QAAmB,cAAc;AAKrE,SAASC,gBAAgB,QAAQ,oBAAoB;AAWrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,WAAW,GAAGA,CAAC;EAAEC,KAAK;EAAEC,KAAK;EAAEC,QAAQ;EAAE,GAAGC;AAAY,CAAC,KAAK;EAClE,MAAM;IAAEC;EAAK,CAAC,GAAGN,gBAAgB,CAACE,KAAK,CAAC;EAExC,MAAMK,cAAc,GAClBD,IAAI,GAAG,UAAU,GAAG,YACU;EAChC,MAAME,cAAc,GAAG,CAACC,MAAM,CAACC,SAAS,EAAE;IAAEH;EAAe,CAAC,EAAEJ,KAAK,CAAC;EAEpE,oBACEN,KAAA,CAAAc,aAAA,CAACZ,IAAI,EAAAa,QAAA,KAAKP,IAAI;IAAEF,KAAK,EAAEK;EAAe,IACnCX,KAAK,CAACgB,QAAQ,CAACC,GAAG,CAACV,QAAQ,EAAE,CAACW,KAAK,EAAEC,KAAK,KAAK;IAC9C,IAAI,eAACnB,KAAK,CAACoB,cAAc,CAAuBF,KAAK,CAAC,EAAE;MACtD,OAAOA,KAAK;IACd;IAEA,MAAMG,OAAO,GAAG,CAACZ,IAAI,IAAIS,KAAK,CAACI,KAAK,CAACD,OAAO,KAAK,KAAK;IACtD,MAAME,IAAI,GACRL,KAAK,CAACI,KAAK,CAACC,IAAI,KACfd,IAAI,GAAIU,KAAK,KAAK,CAAC,GAAG,UAAU,GAAG,WAAW,GAAIK,SAAS,CAAC;IAC/D,MAAMC,UAAU,GAAG,CAAChB,IAAI,IAAIG,MAAM,CAACc,MAAM,EAAER,KAAK,CAACI,KAAK,CAAChB,KAAK,CAAC;IAE7D,oBAAON,KAAK,CAAC2B,YAAY,CAACT,KAAK,EAAE;MAC/B,GAAGA,KAAK,CAACI,KAAK;MACdD,OAAO;MACPE,IAAI;MACJjB,KAAK,EAAEmB;IACT,CAAC,CAAC;EACJ,CAAC,CACG,CAAC;AAEX,CAAC;AAEDrB,WAAW,CAACwB,WAAW,GAAG,cAAc;AAExC,MAAMhB,MAAM,GAAGX,UAAU,CAAC4B,MAAM,CAAC;EAC/BhB,SAAS,EAAE;IACTiB,aAAa,EAAE,KAAK;IACpBC,UAAU,EAAE,QAAQ;IACpBC,OAAO,EAAE;EACX,CAAC;EACDN,MAAM,EAAE;IACNO,UAAU,EAAE;EACd;AACF,CAAC,CAAC;AAEF,eAAe7B,WAAW","ignoreList":[]}

View File

@@ -0,0 +1,77 @@
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
/**
* A component to show content inside a Card.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Card, Text } from 'react-native-paper';
*
* const MyComponent = () => (
* <Card>
* <Card.Content>
* <Text variant="titleLarge">Card title</Text>
* <Text variant="bodyMedium">Card content</Text>
* </Card.Content>
* </Card>
* );
*
* export default MyComponent;
* ```
*/
const CardContent = ({
index,
total,
siblings,
style,
...rest
}) => {
const cover = 'withInternalTheme(CardCover)';
const title = 'withInternalTheme(CardTitle)';
let contentStyle, prev, next;
if (typeof index === 'number' && siblings) {
prev = siblings[index - 1];
next = siblings[index + 1];
}
if (prev === cover && next === cover || prev === title && next === title || total === 1) {
contentStyle = styles.only;
} else if (index === 0) {
if (next === cover || next === title) {
contentStyle = styles.only;
} else {
contentStyle = styles.first;
}
} else if (typeof total === 'number' && index === total - 1) {
if (prev === cover || prev === title) {
contentStyle = styles.only;
} else {
contentStyle = styles.last;
}
} else if (prev === cover || prev === title) {
contentStyle = styles.first;
} else if (next === cover || next === title) {
contentStyle = styles.last;
}
return /*#__PURE__*/React.createElement(View, _extends({}, rest, {
style: [styles.container, contentStyle, style]
}));
};
CardContent.displayName = 'Card.Content';
const styles = StyleSheet.create({
container: {
paddingHorizontal: 16
},
first: {
paddingTop: 16
},
last: {
paddingBottom: 16
},
only: {
paddingVertical: 16
}
});
export default CardContent;
//# sourceMappingURL=CardContent.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","StyleSheet","View","CardContent","index","total","siblings","style","rest","cover","title","contentStyle","prev","next","styles","only","first","last","createElement","_extends","container","displayName","create","paddingHorizontal","paddingTop","paddingBottom","paddingVertical"],"sourceRoot":"../../../../src","sources":["components/Card/CardContent.tsx"],"mappings":";AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,UAAU,EAAaC,IAAI,QAAmB,cAAc;AAsBrE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,WAAW,GAAGA,CAAC;EAAEC,KAAK;EAAEC,KAAK;EAAEC,QAAQ;EAAEC,KAAK;EAAE,GAAGC;AAAY,CAAC,KAAK;EACzE,MAAMC,KAAK,GAAG,8BAA8B;EAC5C,MAAMC,KAAK,GAAG,8BAA8B;EAE5C,IAAIC,YAAY,EAAEC,IAAI,EAAEC,IAAI;EAE5B,IAAI,OAAOT,KAAK,KAAK,QAAQ,IAAIE,QAAQ,EAAE;IACzCM,IAAI,GAAGN,QAAQ,CAACF,KAAK,GAAG,CAAC,CAAC;IAC1BS,IAAI,GAAGP,QAAQ,CAACF,KAAK,GAAG,CAAC,CAAC;EAC5B;EAEA,IACGQ,IAAI,KAAKH,KAAK,IAAII,IAAI,KAAKJ,KAAK,IAChCG,IAAI,KAAKF,KAAK,IAAIG,IAAI,KAAKH,KAAM,IAClCL,KAAK,KAAK,CAAC,EACX;IACAM,YAAY,GAAGG,MAAM,CAACC,IAAI;EAC5B,CAAC,MAAM,IAAIX,KAAK,KAAK,CAAC,EAAE;IACtB,IAAIS,IAAI,KAAKJ,KAAK,IAAII,IAAI,KAAKH,KAAK,EAAE;MACpCC,YAAY,GAAGG,MAAM,CAACC,IAAI;IAC5B,CAAC,MAAM;MACLJ,YAAY,GAAGG,MAAM,CAACE,KAAK;IAC7B;EACF,CAAC,MAAM,IAAI,OAAOX,KAAK,KAAK,QAAQ,IAAID,KAAK,KAAKC,KAAK,GAAG,CAAC,EAAE;IAC3D,IAAIO,IAAI,KAAKH,KAAK,IAAIG,IAAI,KAAKF,KAAK,EAAE;MACpCC,YAAY,GAAGG,MAAM,CAACC,IAAI;IAC5B,CAAC,MAAM;MACLJ,YAAY,GAAGG,MAAM,CAACG,IAAI;IAC5B;EACF,CAAC,MAAM,IAAIL,IAAI,KAAKH,KAAK,IAAIG,IAAI,KAAKF,KAAK,EAAE;IAC3CC,YAAY,GAAGG,MAAM,CAACE,KAAK;EAC7B,CAAC,MAAM,IAAIH,IAAI,KAAKJ,KAAK,IAAII,IAAI,KAAKH,KAAK,EAAE;IAC3CC,YAAY,GAAGG,MAAM,CAACG,IAAI;EAC5B;EAEA,oBAAOjB,KAAA,CAAAkB,aAAA,CAAChB,IAAI,EAAAiB,QAAA,KAAKX,IAAI;IAAED,KAAK,EAAE,CAACO,MAAM,CAACM,SAAS,EAAET,YAAY,EAAEJ,KAAK;EAAE,EAAE,CAAC;AAC3E,CAAC;AAEDJ,WAAW,CAACkB,WAAW,GAAG,cAAc;AAExC,MAAMP,MAAM,GAAGb,UAAU,CAACqB,MAAM,CAAC;EAC/BF,SAAS,EAAE;IACTG,iBAAiB,EAAE;EACrB,CAAC;EACDP,KAAK,EAAE;IACLQ,UAAU,EAAE;EACd,CAAC;EACDP,IAAI,EAAE;IACJQ,aAAa,EAAE;EACjB,CAAC;EACDV,IAAI,EAAE;IACJW,eAAe,EAAE;EACnB;AACF,CAAC,CAAC;AAEF,eAAevB,WAAW","ignoreList":[]}

View File

@@ -0,0 +1,68 @@
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
import * as React from 'react';
import { Image, StyleSheet, View } from 'react-native';
import { getCardCoverStyle } from './utils';
import { useInternalTheme } from '../../core/theming';
import { grey200 } from '../../styles/themes/v2/colors';
import { splitStyles } from '../../utils/splitStyles';
/**
* A component to show a cover image inside a Card.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Card } from 'react-native-paper';
*
* const MyComponent = () => (
* <Card>
* <Card.Cover source={{ uri: 'https://picsum.photos/700' }} />
* </Card>
* );
*
* export default MyComponent;
* ```
*
* @extends Image props https://reactnative.dev/docs/image#props
*/
const CardCover = ({
index,
total,
style,
theme: themeOverrides,
...rest
}) => {
const theme = useInternalTheme(themeOverrides);
const flattenedStyles = StyleSheet.flatten(style) || {};
const [, borderRadiusStyles] = splitStyles(flattenedStyles, style => style.startsWith('border') && style.endsWith('Radius'));
const coverStyle = getCardCoverStyle({
theme,
index,
total,
borderRadiusStyles
});
return /*#__PURE__*/React.createElement(View, {
style: [styles.container, coverStyle, style]
}, /*#__PURE__*/React.createElement(Image, _extends({}, rest, {
style: [styles.image, coverStyle],
accessibilityIgnoresInvertColors: true
})));
};
CardCover.displayName = 'Card.Cover';
const styles = StyleSheet.create({
container: {
height: 195,
backgroundColor: grey200,
overflow: 'hidden'
},
image: {
flex: 1,
height: undefined,
width: undefined,
justifyContent: 'flex-end'
}
});
export default CardCover;
// @component-docs ignore-next-line
export { CardCover };
//# sourceMappingURL=CardCover.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","Image","StyleSheet","View","getCardCoverStyle","useInternalTheme","grey200","splitStyles","CardCover","index","total","style","theme","themeOverrides","rest","flattenedStyles","flatten","borderRadiusStyles","startsWith","endsWith","coverStyle","createElement","styles","container","_extends","image","accessibilityIgnoresInvertColors","displayName","create","height","backgroundColor","overflow","flex","undefined","width","justifyContent"],"sourceRoot":"../../../../src","sources":["components/Card/CardCover.tsx"],"mappings":";AAAA,OAAO,KAAKA,KAAK,MAAM,OAAO;AAC9B,SAASC,KAAK,EAAaC,UAAU,EAAEC,IAAI,QAAmB,cAAc;AAE5E,SAASC,iBAAiB,QAAQ,SAAS;AAC3C,SAASC,gBAAgB,QAAQ,oBAAoB;AACrD,SAASC,OAAO,QAAQ,+BAA+B;AAEvD,SAASC,WAAW,QAAQ,yBAAyB;AAkBrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAMC,SAAS,GAAGA,CAAC;EACjBC,KAAK;EACLC,KAAK;EACLC,KAAK;EACLC,KAAK,EAAEC,cAAc;EACrB,GAAGC;AACE,CAAC,KAAK;EACX,MAAMF,KAAK,GAAGP,gBAAgB,CAACQ,cAAc,CAAC;EAE9C,MAAME,eAAe,GAAIb,UAAU,CAACc,OAAO,CAACL,KAAK,CAAC,IAAI,CAAC,CAAe;EACtE,MAAM,GAAGM,kBAAkB,CAAC,GAAGV,WAAW,CACxCQ,eAAe,EACdJ,KAAK,IAAKA,KAAK,CAACO,UAAU,CAAC,QAAQ,CAAC,IAAIP,KAAK,CAACQ,QAAQ,CAAC,QAAQ,CAClE,CAAC;EAED,MAAMC,UAAU,GAAGhB,iBAAiB,CAAC;IACnCQ,KAAK;IACLH,KAAK;IACLC,KAAK;IACLO;EACF,CAAC,CAAC;EAEF,oBACEjB,KAAA,CAAAqB,aAAA,CAAClB,IAAI;IAACQ,KAAK,EAAE,CAACW,MAAM,CAACC,SAAS,EAAEH,UAAU,EAAET,KAAK;EAAE,gBACjDX,KAAA,CAAAqB,aAAA,CAACpB,KAAK,EAAAuB,QAAA,KACAV,IAAI;IACRH,KAAK,EAAE,CAACW,MAAM,CAACG,KAAK,EAAEL,UAAU,CAAE;IAClCM,gCAAgC;EAAA,EACjC,CACG,CAAC;AAEX,CAAC;AAEDlB,SAAS,CAACmB,WAAW,GAAG,YAAY;AACpC,MAAML,MAAM,GAAGpB,UAAU,CAAC0B,MAAM,CAAC;EAC/BL,SAAS,EAAE;IACTM,MAAM,EAAE,GAAG;IACXC,eAAe,EAAExB,OAAO;IACxByB,QAAQ,EAAE;EACZ,CAAC;EACDN,KAAK,EAAE;IACLO,IAAI,EAAE,CAAC;IACPH,MAAM,EAAEI,SAAS;IACjBC,KAAK,EAAED,SAAS;IAChBE,cAAc,EAAE;EAClB;AACF,CAAC,CAAC;AAEF,eAAe3B,SAAS;;AAExB;AACA,SAASA,SAAS","ignoreList":[]}

View File

@@ -0,0 +1,113 @@
import * as React from 'react';
import { StyleSheet, View } from 'react-native';
import { useInternalTheme } from '../../core/theming';
import Text from '../Typography/Text';
import Caption from '../Typography/v2/Caption';
import Title from '../Typography/v2/Title';
const LEFT_SIZE = 40;
/**
* A component to show a title, subtitle and an avatar inside a Card.
*
* ## Usage
* ```js
* import * as React from 'react';
* import { Avatar, Card, IconButton } from 'react-native-paper';
*
* const MyComponent = () => (
* <Card.Title
* title="Card Title"
* subtitle="Card Subtitle"
* left={(props) => <Avatar.Icon {...props} icon="folder" />}
* right={(props) => <IconButton {...props} icon="dots-vertical" onPress={() => {}} />}
* />
* );
*
* export default MyComponent;
* ```
*/
const CardTitle = ({
title,
titleStyle,
titleNumberOfLines = 1,
titleVariant = 'bodyLarge',
titleMaxFontSizeMultiplier,
subtitle,
subtitleStyle,
subtitleNumberOfLines = 1,
subtitleVariant = 'bodyMedium',
subtitleMaxFontSizeMultiplier,
left,
leftStyle,
right,
rightStyle,
style,
theme: themeOverrides
}) => {
const theme = useInternalTheme(themeOverrides);
const TitleComponent = theme.isV3 ? Text : Title;
const SubtitleComponent = theme.isV3 ? Text : Caption;
const minHeight = subtitle || left || right ? 72 : 50;
const marginBottom = subtitle ? 0 : 2;
return /*#__PURE__*/React.createElement(View, {
style: [styles.container, {
minHeight
}, style]
}, left ? /*#__PURE__*/React.createElement(View, {
style: [styles.left, leftStyle]
}, left({
size: LEFT_SIZE
})) : null, /*#__PURE__*/React.createElement(View, {
style: [styles.titles]
}, title && /*#__PURE__*/React.createElement(TitleComponent, {
style: [styles.title, {
marginBottom
}, titleStyle],
numberOfLines: titleNumberOfLines,
variant: titleVariant,
maxFontSizeMultiplier: titleMaxFontSizeMultiplier
}, title), subtitle && /*#__PURE__*/React.createElement(SubtitleComponent, {
style: [styles.subtitle, subtitleStyle],
numberOfLines: subtitleNumberOfLines,
variant: subtitleVariant,
maxFontSizeMultiplier: subtitleMaxFontSizeMultiplier
}, subtitle)), /*#__PURE__*/React.createElement(View, {
style: rightStyle
}, right ? right({
size: 24
}) : null));
};
CardTitle.displayName = 'Card.Title';
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
paddingLeft: 16
},
left: {
justifyContent: 'center',
marginRight: 16,
height: LEFT_SIZE,
width: LEFT_SIZE
},
titles: {
flex: 1,
flexDirection: 'column',
justifyContent: 'center'
},
title: {
minHeight: 30,
paddingRight: 16
},
subtitle: {
minHeight: 20,
marginVertical: 0,
paddingRight: 16
}
});
export default CardTitle;
// @component-docs ignore-next-line
export { CardTitle };
//# sourceMappingURL=CardTitle.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["React","StyleSheet","View","useInternalTheme","Text","Caption","Title","LEFT_SIZE","CardTitle","title","titleStyle","titleNumberOfLines","titleVariant","titleMaxFontSizeMultiplier","subtitle","subtitleStyle","subtitleNumberOfLines","subtitleVariant","subtitleMaxFontSizeMultiplier","left","leftStyle","right","rightStyle","style","theme","themeOverrides","TitleComponent","isV3","SubtitleComponent","minHeight","marginBottom","createElement","styles","container","size","titles","numberOfLines","variant","maxFontSizeMultiplier","displayName","create","flexDirection","alignItems","justifyContent","paddingLeft","marginRight","height","width","flex","paddingRight","marginVertical"],"sourceRoot":"../../../../src","sources":["components/Card/CardTitle.tsx"],"mappings":"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","ignoreList":[]}

View File

@@ -0,0 +1,84 @@
import color from 'color';
import { black, white } from '../../styles/themes/v2/colors';
export const getCardCoverStyle = ({
theme,
index,
total,
borderRadiusStyles
}) => {
const {
isV3,
roundness
} = theme;
if (Object.keys(borderRadiusStyles).length > 0) {
return {
borderRadius: 3 * roundness,
...borderRadiusStyles
};
}
if (isV3) {
return {
borderRadius: 3 * roundness
};
}
if (index === 0) {
if (total === 1) {
return {
borderRadius: roundness
};
}
return {
borderTopLeftRadius: roundness,
borderTopRightRadius: roundness
};
}
if (typeof total === 'number' && index === total - 1) {
return {
borderBottomLeftRadius: roundness
};
}
return undefined;
};
const getBorderColor = ({
theme
}) => {
if (theme.isV3) {
return theme.colors.outline;
}
if (theme.dark) {
return color(white).alpha(0.12).rgb().string();
}
return color(black).alpha(0.12).rgb().string();
};
const getBackgroundColor = ({
theme,
isMode
}) => {
if (theme.isV3) {
if (isMode('contained')) {
return theme.colors.surfaceVariant;
}
if (isMode('outlined')) {
return theme.colors.surface;
}
}
return undefined;
};
export const getCardColors = ({
theme,
mode
}) => {
const isMode = modeToCompare => {
return mode === modeToCompare;
};
return {
backgroundColor: getBackgroundColor({
theme,
isMode
}),
borderColor: getBorderColor({
theme
})
};
};
//# sourceMappingURL=utils.js.map

View File

@@ -0,0 +1 @@
{"version":3,"names":["color","black","white","getCardCoverStyle","theme","index","total","borderRadiusStyles","isV3","roundness","Object","keys","length","borderRadius","borderTopLeftRadius","borderTopRightRadius","borderBottomLeftRadius","undefined","getBorderColor","colors","outline","dark","alpha","rgb","string","getBackgroundColor","isMode","surfaceVariant","surface","getCardColors","mode","modeToCompare","backgroundColor","borderColor"],"sourceRoot":"../../../../src","sources":["components/Card/utils.tsx"],"mappings":"AAEA,OAAOA,KAAK,MAAM,OAAO;AAEzB,SAASC,KAAK,EAAEC,KAAK,QAAQ,+BAA+B;AAgB5D,OAAO,MAAMC,iBAAiB,GAAGA,CAAC;EAChCC,KAAK;EACLC,KAAK;EACLC,KAAK;EACLC;AAMF,CAAC,KAAK;EACJ,MAAM;IAAEC,IAAI;IAAEC;EAAU,CAAC,GAAGL,KAAK;EAEjC,IAAIM,MAAM,CAACC,IAAI,CAACJ,kBAAkB,CAAC,CAACK,MAAM,GAAG,CAAC,EAAE;IAC9C,OAAO;MACLC,YAAY,EAAE,CAAC,GAAGJ,SAAS;MAC3B,GAAGF;IACL,CAAC;EACH;EAEA,IAAIC,IAAI,EAAE;IACR,OAAO;MACLK,YAAY,EAAE,CAAC,GAAGJ;IACpB,CAAC;EACH;EAEA,IAAIJ,KAAK,KAAK,CAAC,EAAE;IACf,IAAIC,KAAK,KAAK,CAAC,EAAE;MACf,OAAO;QACLO,YAAY,EAAEJ;MAChB,CAAC;IACH;IAEA,OAAO;MACLK,mBAAmB,EAAEL,SAAS;MAC9BM,oBAAoB,EAAEN;IACxB,CAAC;EACH;EAEA,IAAI,OAAOH,KAAK,KAAK,QAAQ,IAAID,KAAK,KAAKC,KAAK,GAAG,CAAC,EAAE;IACpD,OAAO;MACLU,sBAAsB,EAAEP;IAC1B,CAAC;EACH;EAEA,OAAOQ,SAAS;AAClB,CAAC;AAED,MAAMC,cAAc,GAAGA,CAAC;EAAEd;AAAgC,CAAC,KAAK;EAC9D,IAAIA,KAAK,CAACI,IAAI,EAAE;IACd,OAAOJ,KAAK,CAACe,MAAM,CAACC,OAAO;EAC7B;EAEA,IAAIhB,KAAK,CAACiB,IAAI,EAAE;IACd,OAAOrB,KAAK,CAACE,KAAK,CAAC,CAACoB,KAAK,CAAC,IAAI,CAAC,CAACC,GAAG,CAAC,CAAC,CAACC,MAAM,CAAC,CAAC;EAChD;EACA,OAAOxB,KAAK,CAACC,KAAK,CAAC,CAACqB,KAAK,CAAC,IAAI,CAAC,CAACC,GAAG,CAAC,CAAC,CAACC,MAAM,CAAC,CAAC;AAChD,CAAC;AAED,MAAMC,kBAAkB,GAAGA,CAAC;EAC1BrB,KAAK;EACLsB;AAIF,CAAC,KAAK;EACJ,IAAItB,KAAK,CAACI,IAAI,EAAE;IACd,IAAIkB,MAAM,CAAC,WAAW,CAAC,EAAE;MACvB,OAAOtB,KAAK,CAACe,MAAM,CAACQ,cAAc;IACpC;IACA,IAAID,MAAM,CAAC,UAAU,CAAC,EAAE;MACtB,OAAOtB,KAAK,CAACe,MAAM,CAACS,OAAO;IAC7B;EACF;EACA,OAAOX,SAAS;AAClB,CAAC;AAED,OAAO,MAAMY,aAAa,GAAGA,CAAC;EAC5BzB,KAAK;EACL0B;AAIF,CAAC,KAAK;EACJ,MAAMJ,MAAM,GAAIK,aAAuB,IAAK;IAC1C,OAAOD,IAAI,KAAKC,aAAa;EAC/B,CAAC;EAED,OAAO;IACLC,eAAe,EAAEP,kBAAkB,CAAC;MAClCrB,KAAK;MACLsB;IACF,CAAC,CAAC;IACFO,WAAW,EAAEf,cAAc,CAAC;MAAEd;IAAM,CAAC;EACvC,CAAC;AACH,CAAC","ignoreList":[]}