@planningcenter/chat-react-native 3.13.0-rc.4 → 3.13.0-rc.5

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.
@@ -9,11 +9,15 @@ interface SpinnerProps {
9
9
  * Specifies the maximum size spinner can scale to if the device's font-size is increased.
10
10
  */
11
11
  maxFontSizeMultiplier?: number;
12
+ /**
13
+ * Specifies the minimum size spinner can scale to if the device's font-size is decreased.
14
+ */
15
+ minFontSizeMultiplier?: number;
12
16
  /**
13
17
  * Style to apply to the spinner
14
18
  */
15
19
  style?: StyleProp<ViewStyle>;
16
20
  }
17
- export declare function Spinner({ size, maxFontSizeMultiplier, style, }: SpinnerProps): React.JSX.Element;
21
+ export declare function Spinner({ size, maxFontSizeMultiplier, minFontSizeMultiplier, style, }: SpinnerProps): React.JSX.Element;
18
22
  export {};
19
23
  //# sourceMappingURL=spinner.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../../src/components/display/spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAA;AACxC,OAAO,EAAE,SAAS,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAA;AAoBrE,UAAU,YAAY;IACpB;;SAEK;IACL,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;CAC7B;AAED,wBAAgB,OAAO,CAAC,EACtB,IAAS,EACT,qBAA+C,EAC/C,KAAK,GACN,EAAE,YAAY,qBAkCd"}
1
+ {"version":3,"file":"spinner.d.ts","sourceRoot":"","sources":["../../../src/components/display/spinner.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAoB,MAAM,OAAO,CAAA;AACxC,OAAO,EAAE,SAAS,EAAoB,SAAS,EAAE,MAAM,cAAc,CAAA;AAoBrE,UAAU,YAAY;IACpB;;SAEK;IACL,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;OAEG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B;;OAEG;IACH,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAA;CAC7B;AAED,wBAAgB,OAAO,CAAC,EACtB,IAAS,EACT,qBAA+C,EAC/C,qBAA+C,EAC/C,KAAK,GACN,EAAE,YAAY,qBAkCd"}
@@ -6,8 +6,8 @@ import { useFontScale, useTheme } from '../../hooks';
6
6
  // ====== Constants ================
7
7
  // =================================
8
8
  const PREVENT_SCALING_DEFAULT = 1;
9
- export function Spinner({ size = 20, maxFontSizeMultiplier = PREVENT_SCALING_DEFAULT, style, }) {
10
- const styles = useStyles({ maxFontSizeMultiplier, size });
9
+ export function Spinner({ size = 20, maxFontSizeMultiplier = PREVENT_SCALING_DEFAULT, minFontSizeMultiplier = PREVENT_SCALING_DEFAULT, style, }) {
10
+ const styles = useStyles({ maxFontSizeMultiplier, minFontSizeMultiplier, size });
11
11
  const rotation = useSharedValue(0);
12
12
  const animatedStyle = useAnimatedStyle(() => {
13
13
  return {
@@ -33,9 +33,9 @@ export function Spinner({ size = 20, maxFontSizeMultiplier = PREVENT_SCALING_DEF
33
33
  </Animated.View>
34
34
  </View>);
35
35
  }
36
- const useStyles = ({ maxFontSizeMultiplier, size }) => {
36
+ const useStyles = ({ maxFontSizeMultiplier, minFontSizeMultiplier, size }) => {
37
37
  const { colors } = useTheme();
38
- const fontScale = useFontScale({ maxFontSizeMultiplier });
38
+ const fontScale = useFontScale({ maxFontSizeMultiplier, minFontSizeMultiplier });
39
39
  const scalableSize = size * fontScale;
40
40
  return StyleSheet.create({
41
41
  animatedContainer: {
@@ -1 +1 @@
1
- {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../../src/components/display/spinner.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect } from 'react'\nimport { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'\nimport Animated, {\n useSharedValue,\n useAnimatedStyle,\n withRepeat,\n withTiming,\n Easing,\n} from 'react-native-reanimated'\nimport { useFontScale, useTheme } from '../../hooks'\n\n// =================================\n// ====== Constants ================\n// =================================\n\nconst PREVENT_SCALING_DEFAULT = 1\n\n// =================================\n// ====== Component ================\n// =================================\n\ninterface SpinnerProps {\n /**\n * Size of the spinner in px\n * */\n size?: number\n /**\n * Specifies the maximum size spinner can scale to if the device's font-size is increased.\n */\n maxFontSizeMultiplier?: number\n /**\n * Style to apply to the spinner\n */\n style?: StyleProp<ViewStyle>\n}\n\nexport function Spinner({\n size = 20,\n maxFontSizeMultiplier = PREVENT_SCALING_DEFAULT,\n style,\n}: SpinnerProps) {\n const styles = useStyles({ maxFontSizeMultiplier, size })\n\n const rotation = useSharedValue(0)\n const animatedStyle = useAnimatedStyle(() => {\n return {\n transform: [{ rotate: `${rotation.value}deg` }],\n }\n })\n\n useEffect(() => {\n rotation.value = withRepeat(\n withTiming(360, {\n duration: 1000,\n easing: Easing.linear,\n }),\n -1 // loops animation infinitely\n )\n\n return () => {\n rotation.value = 0 // Reset rotation when Spinner unmounts\n }\n }, [rotation])\n\n return (\n <View style={style}>\n <Animated.View style={[styles.animatedContainer, animatedStyle]}>\n <View style={styles.clipping}>\n <View style={[styles.circle, styles.spinner]} />\n </View>\n <View style={[styles.circle, styles.track]} />\n </Animated.View>\n </View>\n )\n}\n\n// =================================\n// ====== Styles ===================\n// =================================\n\ninterface Styles {\n maxFontSizeMultiplier: number | undefined\n size: number\n}\n\nconst useStyles = ({ maxFontSizeMultiplier, size }: Styles) => {\n const { colors } = useTheme()\n const fontScale = useFontScale({ maxFontSizeMultiplier })\n const scalableSize = size * fontScale\n\n return StyleSheet.create({\n animatedContainer: {\n width: scalableSize,\n height: scalableSize,\n borderRadius: scalableSize / 2,\n },\n circle: {\n width: scalableSize,\n height: scalableSize,\n borderRadius: scalableSize / 2,\n borderStyle: 'solid',\n borderWidth: 3,\n },\n spinner: {\n borderColor: colors.borderColorDefaultDarkest,\n },\n track: {\n borderColor: colors.fillColorNeutral050Base,\n },\n clipping: {\n position: 'absolute',\n top: 0,\n left: 0,\n width: scalableSize / 2,\n height: scalableSize / 2,\n overflow: 'hidden',\n zIndex: 200,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"spinner.js","sourceRoot":"","sources":["../../../src/components/display/spinner.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useEffect } from 'react'\nimport { StyleProp, StyleSheet, View, ViewStyle } from 'react-native'\nimport Animated, {\n useSharedValue,\n useAnimatedStyle,\n withRepeat,\n withTiming,\n Easing,\n} from 'react-native-reanimated'\nimport { useFontScale, useTheme } from '../../hooks'\n\n// =================================\n// ====== Constants ================\n// =================================\n\nconst PREVENT_SCALING_DEFAULT = 1\n\n// =================================\n// ====== Component ================\n// =================================\n\ninterface SpinnerProps {\n /**\n * Size of the spinner in px\n * */\n size?: number\n /**\n * Specifies the maximum size spinner can scale to if the device's font-size is increased.\n */\n maxFontSizeMultiplier?: number\n /**\n * Specifies the minimum size spinner can scale to if the device's font-size is decreased.\n */\n minFontSizeMultiplier?: number\n /**\n * Style to apply to the spinner\n */\n style?: StyleProp<ViewStyle>\n}\n\nexport function Spinner({\n size = 20,\n maxFontSizeMultiplier = PREVENT_SCALING_DEFAULT,\n minFontSizeMultiplier = PREVENT_SCALING_DEFAULT,\n style,\n}: SpinnerProps) {\n const styles = useStyles({ maxFontSizeMultiplier, minFontSizeMultiplier, size })\n\n const rotation = useSharedValue(0)\n const animatedStyle = useAnimatedStyle(() => {\n return {\n transform: [{ rotate: `${rotation.value}deg` }],\n }\n })\n\n useEffect(() => {\n rotation.value = withRepeat(\n withTiming(360, {\n duration: 1000,\n easing: Easing.linear,\n }),\n -1 // loops animation infinitely\n )\n\n return () => {\n rotation.value = 0 // Reset rotation when Spinner unmounts\n }\n }, [rotation])\n\n return (\n <View style={style}>\n <Animated.View style={[styles.animatedContainer, animatedStyle]}>\n <View style={styles.clipping}>\n <View style={[styles.circle, styles.spinner]} />\n </View>\n <View style={[styles.circle, styles.track]} />\n </Animated.View>\n </View>\n )\n}\n\n// =================================\n// ====== Styles ===================\n// =================================\n\ninterface Styles {\n maxFontSizeMultiplier: number | undefined\n minFontSizeMultiplier: number | undefined\n size: number\n}\n\nconst useStyles = ({ maxFontSizeMultiplier, minFontSizeMultiplier, size }: Styles) => {\n const { colors } = useTheme()\n const fontScale = useFontScale({ maxFontSizeMultiplier, minFontSizeMultiplier })\n const scalableSize = size * fontScale\n\n return StyleSheet.create({\n animatedContainer: {\n width: scalableSize,\n height: scalableSize,\n borderRadius: scalableSize / 2,\n },\n circle: {\n width: scalableSize,\n height: scalableSize,\n borderRadius: scalableSize / 2,\n borderStyle: 'solid',\n borderWidth: 3,\n },\n spinner: {\n borderColor: colors.borderColorDefaultDarkest,\n },\n track: {\n borderColor: colors.fillColorNeutral050Base,\n },\n clipping: {\n position: 'absolute',\n top: 0,\n left: 0,\n width: scalableSize / 2,\n height: scalableSize / 2,\n overflow: 'hidden',\n zIndex: 200,\n },\n })\n}\n"]}
@@ -189,8 +189,6 @@ const useStyles = ({ size = 'md', presence = 'offline' } = {}) => {
189
189
  },
190
190
  groupLoader: {
191
191
  position: 'absolute',
192
- top: 0,
193
- left: 0,
194
192
  borderRadius: avatarDiameter,
195
193
  width: avatarDiameter,
196
194
  height: avatarDiameter,
@@ -1 +1 @@
1
- {"version":3,"file":"avatar_primitive.js","sourceRoot":"","sources":["../../../src/components/primitive/avatar_primitive.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { createContext, useContext, useEffect, useState } from 'react'\nimport { StyleSheet, View, ViewProps } from 'react-native'\nimport { useTheme } from '../../hooks'\nimport { Icon, IconString } from '../display/icon'\nimport { Image, ImageProps } from '../display/image'\nimport { Spinner } from '../display/spinner'\n\n// =================================\n// ====== Exports ==================\n// =================================\n\nconst Avatar = {\n Root: AvatarRoot,\n Image: AvatarImage,\n ImageFallback: AvatarImageFallback,\n Presence: AvatarPresence,\n Group: AvatarGroup,\n GroupLoader: AvatarGroupLoader,\n Mask: AvatarMask,\n} as const\n\ntype AvatarComponents = {\n Root: React.FC<AvatarRootProps>\n Image: React.FC<AvatarImageProps>\n ImageFallback: React.FC<AvatarImageFallbackProps>\n Presence: React.FC<AvatarPresenceProps>\n Group: React.FC<AvatarGroupProps>\n GroupLoader: React.FC<Record<string, never>>\n Mask: React.FC<AvatarMaskProps>\n}\n\nexport default Avatar as AvatarComponents\nexport type {\n AvatarImageProps,\n AvatarImageFallbackProps,\n AvatarPresenceProps,\n AvatarGroupProps,\n AvatarMaskProps,\n AvatarRootProps,\n}\n\n// =================================\n// ====== Constants & Types ========\n// =================================\n\nconst AVATAR_SIZES = {\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n} as const\n\nconst AVATAR_PRESENCE_TYPES = {\n online: 'online',\n offline: 'offline',\n} as const\n\n// Progrmatically creates type unions\ntype AvatarSize = (typeof AVATAR_SIZES)[keyof typeof AVATAR_SIZES]\ntype AvatarPresenceType = (typeof AVATAR_PRESENCE_TYPES)[keyof typeof AVATAR_PRESENCE_TYPES]\n\nconst AVATAR_PX: Record<AvatarSize, number> = {\n [AVATAR_SIZES.sm]: 24,\n [AVATAR_SIZES.md]: 32,\n [AVATAR_SIZES.lg]: 40,\n}\n\nconst AVATAR_PRESENCE_PX: Record<AvatarSize, number> = {\n [AVATAR_SIZES.sm]: 10,\n [AVATAR_SIZES.md]: 12,\n [AVATAR_SIZES.lg]: 14,\n}\n\nconst AVATAR_FALLBACK_ICON_PX: Record<AvatarSize, number> = {\n [AVATAR_SIZES.sm]: 12,\n [AVATAR_SIZES.md]: 16,\n [AVATAR_SIZES.lg]: 20,\n}\n\n// =================================\n// ====== Context ==================\n// =================================\n\ninterface AvatarContextType {\n size: AvatarSize\n allImagesLoaded: boolean\n setAllImagesLoaded: React.Dispatch<React.SetStateAction<boolean>>\n}\n\nconst AvatarContext = createContext<AvatarContextType | null>(null)\n\nfunction useAvatarContext() {\n const context = useContext(AvatarContext)\n if (!context) {\n throw new Error('Avatar components must be used within Avatar.Root')\n }\n return context\n}\n\n// =================================\n// ====== AvatarRoot ===============\n// =================================\n\ninterface AvatarRootProps {\n children: React.ReactNode\n size?: AvatarSize\n}\n\nfunction AvatarRoot({ children, size = 'md' }: AvatarRootProps) {\n const [allImagesLoaded, setAllImagesLoaded] = useState(false)\n const styles = useStyles({ size })\n\n return (\n <AvatarContext.Provider value={{ size, allImagesLoaded, setAllImagesLoaded }}>\n <View style={styles.rootContainer}>{children}</View>\n </AvatarContext.Provider>\n )\n}\n\nAvatarRoot.displayName = 'Avatar.Root'\n\n// =================================\n// ====== AvatarMask ===============\n// =================================\n\ntype AvatarMaskProps = ViewProps\n\nfunction AvatarMask({ children, ...props }: AvatarMaskProps) {\n const styles = useStyles()\n\n return (\n <View style={styles.mask} {...props}>\n {children}\n </View>\n )\n}\n\nAvatarMask.displayName = 'Avatar.Mask'\n\n// =================================\n// ====== AvatarImage ============\n// =================================\n\ninterface AvatarImageProps extends Omit<ImageProps, 'source' | 'alt'> {\n sourceUri: string\n}\n\nfunction AvatarImage({ sourceUri, ...props }: AvatarImageProps) {\n const { size } = useAvatarContext()\n\n return <Image source={{ uri: sourceUri }} loaderSize={AVATAR_PX[size]} {...props} alt=\"\" />\n}\n\nAvatarImage.displayName = 'Avatar.Image'\n\ninterface AvatarGroupImageProps {\n sourceUri: string\n style?: ImageProps['wrapperStyle']\n onLoad?: () => void\n}\n\nfunction AvatarGroupImage({ sourceUri, style, onLoad }: AvatarGroupImageProps) {\n return (\n <Image source={{ uri: sourceUri }} hideLoader wrapperStyle={style} onLoad={onLoad} alt=\"\" />\n )\n}\n\ninterface AvatarImageFallbackProps {\n name?: IconString\n}\n\nfunction AvatarImageFallback({ name = 'general.person' }: AvatarImageFallbackProps) {\n const { size } = useAvatarContext()\n const styles = useStyles()\n\n return (\n <View style={styles.fallbackContainer}>\n <Icon\n name={name}\n size={AVATAR_FALLBACK_ICON_PX[size]}\n style={styles.fallbackIcon}\n accessibilityElementsHidden={true}\n />\n </View>\n )\n}\n\nAvatarImageFallback.displayName = 'Avatar.ImageFallback'\n\n// =================================\n// ====== AvatarGroup ============\n// =================================\n\ninterface AvatarGroupProps {\n sourceUris: string[]\n}\n\ntype AvatarIndex = 0 | 1 | 2 | 3\n\nfunction AvatarGroup({ sourceUris }: AvatarGroupProps) {\n const styles = useStyles()\n const { setAllImagesLoaded } = useAvatarContext()\n const [loadingStatus, setLoadingStatus] = useState<Record<AvatarIndex, boolean>>({\n 0: false,\n 1: false,\n 2: false,\n 3: false,\n })\n const displayUris = sourceUris.slice(0, 4)\n const hasDisplayUris = displayUris.length > 0\n\n const handleImageLoaded = (index: AvatarIndex) => {\n setLoadingStatus(prev => ({\n ...prev,\n [index]: true,\n }))\n }\n\n useEffect(() => {\n const allImagesLoaded =\n hasDisplayUris &&\n displayUris.every((_, index) => loadingStatus[index as AvatarIndex] === true)\n\n setAllImagesLoaded(allImagesLoaded)\n }, [displayUris, hasDisplayUris, loadingStatus, setAllImagesLoaded])\n\n if (displayUris.length === 1) {\n return <AvatarGroupImage sourceUri={displayUris[0]} onLoad={() => handleImageLoaded(0)} />\n }\n\n if (displayUris.length === 2) {\n return (\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[0]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(0)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[1]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(1)}\n />\n </View>\n )\n }\n\n if (displayUris.length === 3) {\n return (\n <View style={styles.groupColumn}>\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[0]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(0)}\n />\n <View style={styles.groupColumn}>\n <AvatarGroupImage\n sourceUri={displayUris[1]}\n style={styles.fullWidthHalfHeight}\n onLoad={() => handleImageLoaded(1)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[2]}\n style={styles.fullWidthHalfHeight}\n onLoad={() => handleImageLoaded(2)}\n />\n </View>\n </View>\n </View>\n )\n }\n\n return (\n <View style={styles.groupColumn}>\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[0]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(0)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[1]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(1)}\n />\n </View>\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[2]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(2)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[3]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(3)}\n />\n </View>\n </View>\n )\n}\n\nAvatarGroup.displayName = 'Avatar.Group'\n\n// =================================\n// ====== AvatarGroupLoader =========\n// =================================\n\nfunction AvatarGroupLoader() {\n const { size, allImagesLoaded } = useAvatarContext()\n const styles = useStyles({ size })\n\n if (allImagesLoaded) return null\n\n return (\n <View style={styles.groupLoader}>\n <Spinner size={AVATAR_PX[size]} />\n </View>\n )\n}\n\nAvatarGroupLoader.displayName = 'Avatar.GroupLoader'\n\n// =================================\n// ====== AvatarPresence =========\n// =================================\n\ninterface AvatarPresenceProps extends ViewProps {\n presence: AvatarPresenceType\n}\n\nfunction AvatarPresence({ presence, ...props }: AvatarPresenceProps) {\n const { size } = useAvatarContext()\n const styles = useStyles({ size, presence })\n\n return <View style={styles.presence} {...props} />\n}\n\nAvatarPresence.displayName = 'Avatar.Presence'\n\n// =================================\n// ====== Styles ===================\n// =================================\n\ninterface Styles {\n size?: AvatarSize\n presence?: AvatarPresenceType\n}\n\nconst useStyles = ({ size = 'md', presence = 'offline' }: Styles = {}) => {\n const { colors } = useTheme()\n const PRESENCE_COLOR = {\n online: colors.fillColorInteractionOnlineDefault,\n offline: colors.iconColorDefaultDisabled,\n }\n const presenceDiameter = AVATAR_PRESENCE_PX[size]\n const avatarDiameter = AVATAR_PX[size]\n const groupGap = 1\n\n return StyleSheet.create({\n rootContainer: {\n height: avatarDiameter,\n width: avatarDiameter,\n },\n mask: {\n borderRadius: avatarDiameter,\n overflow: 'hidden',\n width: '100%',\n height: '100%',\n },\n presence: {\n height: presenceDiameter,\n width: presenceDiameter,\n backgroundColor: PRESENCE_COLOR[presence],\n borderColor: colors.fillColorNeutral100Inverted,\n borderWidth: 2,\n borderRadius: presenceDiameter,\n position: 'absolute',\n bottom: -1,\n right: -1,\n },\n groupLoader: {\n position: 'absolute',\n top: 0,\n left: 0,\n borderRadius: avatarDiameter,\n width: avatarDiameter,\n height: avatarDiameter,\n },\n groupColumn: {\n flex: 1,\n gap: groupGap,\n },\n groupRow: {\n flexDirection: 'row',\n flex: 1,\n gap: groupGap,\n },\n halfWidthFullHeight: {\n width: '50%',\n height: '100%',\n },\n fullWidthHalfHeight: {\n width: '100%',\n height: '50%',\n },\n fallbackContainer: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: colors.fillColorNeutral070,\n },\n fallbackIcon: {\n color: colors.iconColorDefaultDim,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"avatar_primitive.js","sourceRoot":"","sources":["../../../src/components/primitive/avatar_primitive.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAC7E,OAAO,EAAE,UAAU,EAAE,IAAI,EAAa,MAAM,cAAc,CAAA;AAC1D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EAAE,IAAI,EAAc,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,KAAK,EAAc,MAAM,kBAAkB,CAAA;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAE5C,oCAAoC;AACpC,oCAAoC;AACpC,oCAAoC;AAEpC,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,WAAW;IAClB,aAAa,EAAE,mBAAmB;IAClC,QAAQ,EAAE,cAAc;IACxB,KAAK,EAAE,WAAW;IAClB,WAAW,EAAE,iBAAiB;IAC9B,IAAI,EAAE,UAAU;CACR,CAAA;AAYV,eAAe,MAA0B,CAAA;AAUzC,oCAAoC;AACpC,oCAAoC;AACpC,oCAAoC;AAEpC,MAAM,YAAY,GAAG;IACnB,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;IACR,EAAE,EAAE,IAAI;CACA,CAAA;AAEV,MAAM,qBAAqB,GAAG;IAC5B,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,SAAS;CACV,CAAA;AAMV,MAAM,SAAS,GAA+B;IAC5C,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;IACrB,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;IACrB,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;CACtB,CAAA;AAED,MAAM,kBAAkB,GAA+B;IACrD,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;IACrB,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;IACrB,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;CACtB,CAAA;AAED,MAAM,uBAAuB,GAA+B;IAC1D,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;IACrB,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;IACrB,CAAC,YAAY,CAAC,EAAE,CAAC,EAAE,EAAE;CACtB,CAAA;AAYD,MAAM,aAAa,GAAG,aAAa,CAA2B,IAAI,CAAC,CAAA;AAEnE,SAAS,gBAAgB;IACvB,MAAM,OAAO,GAAG,UAAU,CAAC,aAAa,CAAC,CAAA;IACzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,OAAO,OAAO,CAAA;AAChB,CAAC;AAWD,SAAS,UAAU,CAAC,EAAE,QAAQ,EAAE,IAAI,GAAG,IAAI,EAAmB;IAC5D,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7D,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;IAElC,OAAO,CACL,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,kBAAkB,EAAE,CAAC,CAC3E;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,IAAI,CACrD;IAAA,EAAE,aAAa,CAAC,QAAQ,CAAC,CAC1B,CAAA;AACH,CAAC;AAED,UAAU,CAAC,WAAW,GAAG,aAAa,CAAA;AAQtC,SAAS,UAAU,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAmB;IACzD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,CAClC;MAAA,CAAC,QAAQ,CACX;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,UAAU,CAAC,WAAW,GAAG,aAAa,CAAA;AAUtC,SAAS,WAAW,CAAC,EAAE,SAAS,EAAE,GAAG,KAAK,EAAoB;IAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAA;IAEnC,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,EAAG,CAAA;AAC7F,CAAC;AAED,WAAW,CAAC,WAAW,GAAG,cAAc,CAAA;AAQxC,SAAS,gBAAgB,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAyB;IAC3E,OAAO,CACL,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,EAAE,EAAG,CAC7F,CAAA;AACH,CAAC;AAMD,SAAS,mBAAmB,CAAC,EAAE,IAAI,GAAG,gBAAgB,EAA4B;IAChF,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACnC,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAE1B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CACpC;MAAA,CAAC,IAAI,CACH,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,IAAI,CAAC,CAAC,uBAAuB,CAAC,IAAI,CAAC,CAAC,CACpC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAC3B,2BAA2B,CAAC,CAAC,IAAI,CAAC,EAEtC;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,mBAAmB,CAAC,WAAW,GAAG,sBAAsB,CAAA;AAYxD,SAAS,WAAW,CAAC,EAAE,UAAU,EAAoB;IACnD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,EAAE,kBAAkB,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACjD,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAA+B;QAC/E,CAAC,EAAE,KAAK;QACR,CAAC,EAAE,KAAK;QACR,CAAC,EAAE,KAAK;QACR,CAAC,EAAE,KAAK;KACT,CAAC,CAAA;IACF,MAAM,WAAW,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;IAC1C,MAAM,cAAc,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC,CAAA;IAE7C,MAAM,iBAAiB,GAAG,CAAC,KAAkB,EAAE,EAAE;QAC/C,gBAAgB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACxB,GAAG,IAAI;YACP,CAAC,KAAK,CAAC,EAAE,IAAI;SACd,CAAC,CAAC,CAAA;IACL,CAAC,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,eAAe,GACnB,cAAc;YACd,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,KAAoB,CAAC,KAAK,IAAI,CAAC,CAAA;QAE/E,kBAAkB,CAAC,eAAe,CAAC,CAAA;IACrC,CAAC,EAAE,CAAC,WAAW,EAAE,cAAc,EAAE,aAAa,EAAE,kBAAkB,CAAC,CAAC,CAAA;IAEpE,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,gBAAgB,CAAC,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAAG,CAAA;IAC5F,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC3B;QAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAErC;QAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAEvC;MAAA,EAAE,IAAI,CAAC,CACR,CAAA;IACH,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC9B;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC3B;UAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAErC;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC9B;YAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAErC;YAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAEvC;UAAA,EAAE,IAAI,CACR;QAAA,EAAE,IAAI,CACR;MAAA,EAAE,IAAI,CAAC,CACR,CAAA;IACH,CAAC;IAED,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC9B;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC3B;QAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAErC;QAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAEvC;MAAA,EAAE,IAAI,CACN;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC3B;QAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAErC;QAAA,CAAC,gBAAgB,CACf,SAAS,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAClC,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,EAEvC;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,WAAW,CAAC,WAAW,GAAG,cAAc,CAAA;AAExC,oCAAoC;AACpC,uCAAuC;AACvC,oCAAoC;AAEpC,SAAS,iBAAiB;IACxB,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACpD,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,CAAA;IAElC,IAAI,eAAe;QAAE,OAAO,IAAI,CAAA;IAEhC,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC9B;MAAA,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,EACjC;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,iBAAiB,CAAC,WAAW,GAAG,oBAAoB,CAAA;AAUpD,SAAS,cAAc,CAAC,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAuB;IACjE,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,EAAE,CAAA;IACnC,MAAM,MAAM,GAAG,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IAE5C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,KAAK,CAAC,EAAG,CAAA;AACpD,CAAC;AAED,cAAc,CAAC,WAAW,GAAG,iBAAiB,CAAA;AAW9C,MAAM,SAAS,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,EAAE,QAAQ,GAAG,SAAS,KAAa,EAAE,EAAE,EAAE;IACvE,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,cAAc,GAAG;QACrB,MAAM,EAAE,MAAM,CAAC,iCAAiC;QAChD,OAAO,EAAE,MAAM,CAAC,wBAAwB;KACzC,CAAA;IACD,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAA;IACjD,MAAM,cAAc,GAAG,SAAS,CAAC,IAAI,CAAC,CAAA;IACtC,MAAM,QAAQ,GAAG,CAAC,CAAA;IAElB,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,aAAa,EAAE;YACb,MAAM,EAAE,cAAc;YACtB,KAAK,EAAE,cAAc;SACtB;QACD,IAAI,EAAE;YACJ,YAAY,EAAE,cAAc;YAC5B,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,MAAM;SACf;QACD,QAAQ,EAAE;YACR,MAAM,EAAE,gBAAgB;YACxB,KAAK,EAAE,gBAAgB;YACvB,eAAe,EAAE,cAAc,CAAC,QAAQ,CAAC;YACzC,WAAW,EAAE,MAAM,CAAC,2BAA2B;YAC/C,WAAW,EAAE,CAAC;YACd,YAAY,EAAE,gBAAgB;YAC9B,QAAQ,EAAE,UAAU;YACpB,MAAM,EAAE,CAAC,CAAC;YACV,KAAK,EAAE,CAAC,CAAC;SACV;QACD,WAAW,EAAE;YACX,QAAQ,EAAE,UAAU;YACpB,YAAY,EAAE,cAAc;YAC5B,KAAK,EAAE,cAAc;YACrB,MAAM,EAAE,cAAc;SACvB;QACD,WAAW,EAAE;YACX,IAAI,EAAE,CAAC;YACP,GAAG,EAAE,QAAQ;SACd;QACD,QAAQ,EAAE;YACR,aAAa,EAAE,KAAK;YACpB,IAAI,EAAE,CAAC;YACP,GAAG,EAAE,QAAQ;SACd;QACD,mBAAmB,EAAE;YACnB,KAAK,EAAE,KAAK;YACZ,MAAM,EAAE,MAAM;SACf;QACD,mBAAmB,EAAE;YACnB,KAAK,EAAE,MAAM;YACb,MAAM,EAAE,KAAK;SACd;QACD,iBAAiB,EAAE;YACjB,IAAI,EAAE,CAAC;YACP,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,eAAe,EAAE,MAAM,CAAC,mBAAmB;SAC5C;QACD,YAAY,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,mBAAmB;SAClC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import React, { createContext, useContext, useEffect, useState } from 'react'\nimport { StyleSheet, View, ViewProps } from 'react-native'\nimport { useTheme } from '../../hooks'\nimport { Icon, IconString } from '../display/icon'\nimport { Image, ImageProps } from '../display/image'\nimport { Spinner } from '../display/spinner'\n\n// =================================\n// ====== Exports ==================\n// =================================\n\nconst Avatar = {\n Root: AvatarRoot,\n Image: AvatarImage,\n ImageFallback: AvatarImageFallback,\n Presence: AvatarPresence,\n Group: AvatarGroup,\n GroupLoader: AvatarGroupLoader,\n Mask: AvatarMask,\n} as const\n\ntype AvatarComponents = {\n Root: React.FC<AvatarRootProps>\n Image: React.FC<AvatarImageProps>\n ImageFallback: React.FC<AvatarImageFallbackProps>\n Presence: React.FC<AvatarPresenceProps>\n Group: React.FC<AvatarGroupProps>\n GroupLoader: React.FC<Record<string, never>>\n Mask: React.FC<AvatarMaskProps>\n}\n\nexport default Avatar as AvatarComponents\nexport type {\n AvatarImageProps,\n AvatarImageFallbackProps,\n AvatarPresenceProps,\n AvatarGroupProps,\n AvatarMaskProps,\n AvatarRootProps,\n}\n\n// =================================\n// ====== Constants & Types ========\n// =================================\n\nconst AVATAR_SIZES = {\n sm: 'sm',\n md: 'md',\n lg: 'lg',\n} as const\n\nconst AVATAR_PRESENCE_TYPES = {\n online: 'online',\n offline: 'offline',\n} as const\n\n// Progrmatically creates type unions\ntype AvatarSize = (typeof AVATAR_SIZES)[keyof typeof AVATAR_SIZES]\ntype AvatarPresenceType = (typeof AVATAR_PRESENCE_TYPES)[keyof typeof AVATAR_PRESENCE_TYPES]\n\nconst AVATAR_PX: Record<AvatarSize, number> = {\n [AVATAR_SIZES.sm]: 24,\n [AVATAR_SIZES.md]: 32,\n [AVATAR_SIZES.lg]: 40,\n}\n\nconst AVATAR_PRESENCE_PX: Record<AvatarSize, number> = {\n [AVATAR_SIZES.sm]: 10,\n [AVATAR_SIZES.md]: 12,\n [AVATAR_SIZES.lg]: 14,\n}\n\nconst AVATAR_FALLBACK_ICON_PX: Record<AvatarSize, number> = {\n [AVATAR_SIZES.sm]: 12,\n [AVATAR_SIZES.md]: 16,\n [AVATAR_SIZES.lg]: 20,\n}\n\n// =================================\n// ====== Context ==================\n// =================================\n\ninterface AvatarContextType {\n size: AvatarSize\n allImagesLoaded: boolean\n setAllImagesLoaded: React.Dispatch<React.SetStateAction<boolean>>\n}\n\nconst AvatarContext = createContext<AvatarContextType | null>(null)\n\nfunction useAvatarContext() {\n const context = useContext(AvatarContext)\n if (!context) {\n throw new Error('Avatar components must be used within Avatar.Root')\n }\n return context\n}\n\n// =================================\n// ====== AvatarRoot ===============\n// =================================\n\ninterface AvatarRootProps {\n children: React.ReactNode\n size?: AvatarSize\n}\n\nfunction AvatarRoot({ children, size = 'md' }: AvatarRootProps) {\n const [allImagesLoaded, setAllImagesLoaded] = useState(false)\n const styles = useStyles({ size })\n\n return (\n <AvatarContext.Provider value={{ size, allImagesLoaded, setAllImagesLoaded }}>\n <View style={styles.rootContainer}>{children}</View>\n </AvatarContext.Provider>\n )\n}\n\nAvatarRoot.displayName = 'Avatar.Root'\n\n// =================================\n// ====== AvatarMask ===============\n// =================================\n\ntype AvatarMaskProps = ViewProps\n\nfunction AvatarMask({ children, ...props }: AvatarMaskProps) {\n const styles = useStyles()\n\n return (\n <View style={styles.mask} {...props}>\n {children}\n </View>\n )\n}\n\nAvatarMask.displayName = 'Avatar.Mask'\n\n// =================================\n// ====== AvatarImage ============\n// =================================\n\ninterface AvatarImageProps extends Omit<ImageProps, 'source' | 'alt'> {\n sourceUri: string\n}\n\nfunction AvatarImage({ sourceUri, ...props }: AvatarImageProps) {\n const { size } = useAvatarContext()\n\n return <Image source={{ uri: sourceUri }} loaderSize={AVATAR_PX[size]} {...props} alt=\"\" />\n}\n\nAvatarImage.displayName = 'Avatar.Image'\n\ninterface AvatarGroupImageProps {\n sourceUri: string\n style?: ImageProps['wrapperStyle']\n onLoad?: () => void\n}\n\nfunction AvatarGroupImage({ sourceUri, style, onLoad }: AvatarGroupImageProps) {\n return (\n <Image source={{ uri: sourceUri }} hideLoader wrapperStyle={style} onLoad={onLoad} alt=\"\" />\n )\n}\n\ninterface AvatarImageFallbackProps {\n name?: IconString\n}\n\nfunction AvatarImageFallback({ name = 'general.person' }: AvatarImageFallbackProps) {\n const { size } = useAvatarContext()\n const styles = useStyles()\n\n return (\n <View style={styles.fallbackContainer}>\n <Icon\n name={name}\n size={AVATAR_FALLBACK_ICON_PX[size]}\n style={styles.fallbackIcon}\n accessibilityElementsHidden={true}\n />\n </View>\n )\n}\n\nAvatarImageFallback.displayName = 'Avatar.ImageFallback'\n\n// =================================\n// ====== AvatarGroup ============\n// =================================\n\ninterface AvatarGroupProps {\n sourceUris: string[]\n}\n\ntype AvatarIndex = 0 | 1 | 2 | 3\n\nfunction AvatarGroup({ sourceUris }: AvatarGroupProps) {\n const styles = useStyles()\n const { setAllImagesLoaded } = useAvatarContext()\n const [loadingStatus, setLoadingStatus] = useState<Record<AvatarIndex, boolean>>({\n 0: false,\n 1: false,\n 2: false,\n 3: false,\n })\n const displayUris = sourceUris.slice(0, 4)\n const hasDisplayUris = displayUris.length > 0\n\n const handleImageLoaded = (index: AvatarIndex) => {\n setLoadingStatus(prev => ({\n ...prev,\n [index]: true,\n }))\n }\n\n useEffect(() => {\n const allImagesLoaded =\n hasDisplayUris &&\n displayUris.every((_, index) => loadingStatus[index as AvatarIndex] === true)\n\n setAllImagesLoaded(allImagesLoaded)\n }, [displayUris, hasDisplayUris, loadingStatus, setAllImagesLoaded])\n\n if (displayUris.length === 1) {\n return <AvatarGroupImage sourceUri={displayUris[0]} onLoad={() => handleImageLoaded(0)} />\n }\n\n if (displayUris.length === 2) {\n return (\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[0]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(0)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[1]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(1)}\n />\n </View>\n )\n }\n\n if (displayUris.length === 3) {\n return (\n <View style={styles.groupColumn}>\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[0]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(0)}\n />\n <View style={styles.groupColumn}>\n <AvatarGroupImage\n sourceUri={displayUris[1]}\n style={styles.fullWidthHalfHeight}\n onLoad={() => handleImageLoaded(1)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[2]}\n style={styles.fullWidthHalfHeight}\n onLoad={() => handleImageLoaded(2)}\n />\n </View>\n </View>\n </View>\n )\n }\n\n return (\n <View style={styles.groupColumn}>\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[0]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(0)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[1]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(1)}\n />\n </View>\n <View style={styles.groupRow}>\n <AvatarGroupImage\n sourceUri={displayUris[2]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(2)}\n />\n <AvatarGroupImage\n sourceUri={displayUris[3]}\n style={styles.halfWidthFullHeight}\n onLoad={() => handleImageLoaded(3)}\n />\n </View>\n </View>\n )\n}\n\nAvatarGroup.displayName = 'Avatar.Group'\n\n// =================================\n// ====== AvatarGroupLoader =========\n// =================================\n\nfunction AvatarGroupLoader() {\n const { size, allImagesLoaded } = useAvatarContext()\n const styles = useStyles({ size })\n\n if (allImagesLoaded) return null\n\n return (\n <View style={styles.groupLoader}>\n <Spinner size={AVATAR_PX[size]} />\n </View>\n )\n}\n\nAvatarGroupLoader.displayName = 'Avatar.GroupLoader'\n\n// =================================\n// ====== AvatarPresence =========\n// =================================\n\ninterface AvatarPresenceProps extends ViewProps {\n presence: AvatarPresenceType\n}\n\nfunction AvatarPresence({ presence, ...props }: AvatarPresenceProps) {\n const { size } = useAvatarContext()\n const styles = useStyles({ size, presence })\n\n return <View style={styles.presence} {...props} />\n}\n\nAvatarPresence.displayName = 'Avatar.Presence'\n\n// =================================\n// ====== Styles ===================\n// =================================\n\ninterface Styles {\n size?: AvatarSize\n presence?: AvatarPresenceType\n}\n\nconst useStyles = ({ size = 'md', presence = 'offline' }: Styles = {}) => {\n const { colors } = useTheme()\n const PRESENCE_COLOR = {\n online: colors.fillColorInteractionOnlineDefault,\n offline: colors.iconColorDefaultDisabled,\n }\n const presenceDiameter = AVATAR_PRESENCE_PX[size]\n const avatarDiameter = AVATAR_PX[size]\n const groupGap = 1\n\n return StyleSheet.create({\n rootContainer: {\n height: avatarDiameter,\n width: avatarDiameter,\n },\n mask: {\n borderRadius: avatarDiameter,\n overflow: 'hidden',\n width: '100%',\n height: '100%',\n },\n presence: {\n height: presenceDiameter,\n width: presenceDiameter,\n backgroundColor: PRESENCE_COLOR[presence],\n borderColor: colors.fillColorNeutral100Inverted,\n borderWidth: 2,\n borderRadius: presenceDiameter,\n position: 'absolute',\n bottom: -1,\n right: -1,\n },\n groupLoader: {\n position: 'absolute',\n borderRadius: avatarDiameter,\n width: avatarDiameter,\n height: avatarDiameter,\n },\n groupColumn: {\n flex: 1,\n gap: groupGap,\n },\n groupRow: {\n flexDirection: 'row',\n flex: 1,\n gap: groupGap,\n },\n halfWidthFullHeight: {\n width: '50%',\n height: '100%',\n },\n fullWidthHalfHeight: {\n width: '100%',\n height: '50%',\n },\n fallbackContainer: {\n flex: 1,\n alignItems: 'center',\n justifyContent: 'center',\n backgroundColor: colors.fillColorNeutral070,\n },\n fallbackIcon: {\n color: colors.iconColorDefaultDim,\n },\n })\n}\n"]}
@@ -1,4 +1,5 @@
1
- export declare const useFontScale: ({ maxFontSizeMultiplier, }?: {
1
+ export declare const useFontScale: ({ maxFontSizeMultiplier, minFontSizeMultiplier, }?: {
2
2
  maxFontSizeMultiplier?: number;
3
+ minFontSizeMultiplier?: number;
3
4
  }) => number;
4
5
  //# sourceMappingURL=use_font_scale.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_font_scale.d.ts","sourceRoot":"","sources":["../../src/hooks/use_font_scale.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,gCAEtB;IAAE,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAAE,WAMpC,CAAA"}
1
+ {"version":3,"file":"use_font_scale.d.ts","sourceRoot":"","sources":["../../src/hooks/use_font_scale.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,YAAY,uDAGtB;IACD,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B,WAUA,CAAA"}
@@ -1,8 +1,11 @@
1
1
  import { useWindowDimensions } from 'react-native';
2
- export const useFontScale = ({ maxFontSizeMultiplier, } = {}) => {
2
+ import { clamp } from 'lodash';
3
+ export const useFontScale = ({ maxFontSizeMultiplier, minFontSizeMultiplier, } = {}) => {
3
4
  const { fontScale: nativeFontScale } = useWindowDimensions();
4
- const scaleLimit = maxFontSizeMultiplier || nativeFontScale;
5
- const fontScale = Math.min(scaleLimit, nativeFontScale);
6
- return fontScale;
5
+ // Infinity values are used to negate the scale if only one constraint is provided. This ensures that the scale is clamped to the provided constraint.
6
+ const maxFontScale = maxFontSizeMultiplier ?? Number.POSITIVE_INFINITY;
7
+ const minFontScale = minFontSizeMultiplier ?? Number.NEGATIVE_INFINITY;
8
+ const clampedScale = clamp(nativeFontScale, minFontScale, maxFontScale);
9
+ return clampedScale;
7
10
  };
8
11
  //# sourceMappingURL=use_font_scale.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_font_scale.js","sourceRoot":"","sources":["../../src/hooks/use_font_scale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAElD,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAC3B,qBAAqB,MACiB,EAAE,EAAE,EAAE;IAC5C,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,mBAAmB,EAAE,CAAA;IAC5D,MAAM,UAAU,GAAG,qBAAqB,IAAI,eAAe,CAAA;IAC3D,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,eAAe,CAAC,CAAA;IAEvD,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA","sourcesContent":["import { useWindowDimensions } from 'react-native'\n\nexport const useFontScale = ({\n maxFontSizeMultiplier,\n}: { maxFontSizeMultiplier?: number } = {}) => {\n const { fontScale: nativeFontScale } = useWindowDimensions()\n const scaleLimit = maxFontSizeMultiplier || nativeFontScale\n const fontScale = Math.min(scaleLimit, nativeFontScale)\n\n return fontScale\n}\n"]}
1
+ {"version":3,"file":"use_font_scale.js","sourceRoot":"","sources":["../../src/hooks/use_font_scale.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAE9B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,EAC3B,qBAAqB,EACrB,qBAAqB,MAInB,EAAE,EAAE,EAAE;IACR,MAAM,EAAE,SAAS,EAAE,eAAe,EAAE,GAAG,mBAAmB,EAAE,CAAA;IAE5D,sJAAsJ;IACtJ,MAAM,YAAY,GAAG,qBAAqB,IAAI,MAAM,CAAC,iBAAiB,CAAA;IACtE,MAAM,YAAY,GAAG,qBAAqB,IAAI,MAAM,CAAC,iBAAiB,CAAA;IAEtE,MAAM,YAAY,GAAG,KAAK,CAAC,eAAe,EAAE,YAAY,EAAE,YAAY,CAAC,CAAA;IAEvE,OAAO,YAAY,CAAA;AACrB,CAAC,CAAA","sourcesContent":["import { useWindowDimensions } from 'react-native'\nimport { clamp } from 'lodash'\n\nexport const useFontScale = ({\n maxFontSizeMultiplier,\n minFontSizeMultiplier,\n}: {\n maxFontSizeMultiplier?: number\n minFontSizeMultiplier?: number\n} = {}) => {\n const { fontScale: nativeFontScale } = useWindowDimensions()\n\n // Infinity values are used to negate the scale if only one constraint is provided. This ensures that the scale is clamped to the provided constraint.\n const maxFontScale = maxFontSizeMultiplier ?? Number.POSITIVE_INFINITY\n const minFontScale = minFontSizeMultiplier ?? Number.NEGATIVE_INFINITY\n\n const clampedScale = clamp(nativeFontScale, minFontScale, maxFontScale)\n\n return clampedScale\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.13.0-rc.4",
3
+ "version": "3.13.0-rc.5",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -55,5 +55,5 @@
55
55
  "react-native-url-polyfill": "^2.0.0",
56
56
  "typescript": "<5.6.0"
57
57
  },
58
- "gitHead": "b3c6396dafcf5a073c936f1e923a474e74c8a61a"
58
+ "gitHead": "1665332ab6af74c29d9630be662f0f9920a8ea2d"
59
59
  }
@@ -0,0 +1,65 @@
1
+ import { renderHook } from '@testing-library/react-native'
2
+ import { useFontScale } from '../../hooks/use_font_scale'
3
+
4
+ jest.mock('react-native', () => ({
5
+ useWindowDimensions: jest.fn(),
6
+ }))
7
+
8
+ const mockUseWindowDimensions = require('react-native').useWindowDimensions
9
+ const DEFAULT_NATIVE_FONT_SCALE = 1
10
+ const SMALL_NATIVE_FONT_SCALE = 0.8
11
+ const LARGE_NATIVE_FONT_SCALE = 3
12
+
13
+ describe('useFontScale', () => {
14
+ beforeEach(() => {
15
+ mockUseWindowDimensions.mockReturnValue({ fontScale: DEFAULT_NATIVE_FONT_SCALE })
16
+ })
17
+
18
+ afterEach(() => {
19
+ jest.clearAllMocks()
20
+ })
21
+
22
+ test('returns native font scale when no constraints provided', () => {
23
+ expect(renderHook(() => useFontScale()).result.current).toBe(DEFAULT_NATIVE_FONT_SCALE)
24
+ expect(renderHook(() => useFontScale({})).result.current).toBe(DEFAULT_NATIVE_FONT_SCALE)
25
+ })
26
+
27
+ describe('with single constraint', () => {
28
+ test('clamps to minimum when native scale is below minFontSizeMultiplier', () => {
29
+ mockUseWindowDimensions.mockReturnValue({ fontScale: SMALL_NATIVE_FONT_SCALE })
30
+ const { result } = renderHook(() => useFontScale({ minFontSizeMultiplier: 1 }))
31
+ expect(result.current).toBe(1)
32
+ })
33
+
34
+ test('clamps to maximum when native scale exceeds maxFontSizeMultiplier', () => {
35
+ mockUseWindowDimensions.mockReturnValue({ fontScale: LARGE_NATIVE_FONT_SCALE })
36
+ const { result } = renderHook(() => useFontScale({ maxFontSizeMultiplier: 2 }))
37
+ expect(result.current).toBe(2)
38
+ })
39
+ })
40
+
41
+ describe('with both constraints', () => {
42
+ test('returns native scale when within bounds', () => {
43
+ const { result } = renderHook(() =>
44
+ useFontScale({ minFontSizeMultiplier: 0.5, maxFontSizeMultiplier: 2 })
45
+ )
46
+ expect(result.current).toBe(DEFAULT_NATIVE_FONT_SCALE)
47
+ })
48
+
49
+ test('clamps to minimum when native scale is below', () => {
50
+ mockUseWindowDimensions.mockReturnValue({ fontScale: SMALL_NATIVE_FONT_SCALE })
51
+ const { result } = renderHook(() =>
52
+ useFontScale({ minFontSizeMultiplier: 1, maxFontSizeMultiplier: 2 })
53
+ )
54
+ expect(result.current).toBe(1)
55
+ })
56
+
57
+ test('clamps to maximum when native scale exceeds', () => {
58
+ mockUseWindowDimensions.mockReturnValue({ fontScale: LARGE_NATIVE_FONT_SCALE })
59
+ const { result } = renderHook(() =>
60
+ useFontScale({ minFontSizeMultiplier: 1, maxFontSizeMultiplier: 2 })
61
+ )
62
+ expect(result.current).toBe(2)
63
+ })
64
+ })
65
+ })
@@ -28,6 +28,10 @@ interface SpinnerProps {
28
28
  * Specifies the maximum size spinner can scale to if the device's font-size is increased.
29
29
  */
30
30
  maxFontSizeMultiplier?: number
31
+ /**
32
+ * Specifies the minimum size spinner can scale to if the device's font-size is decreased.
33
+ */
34
+ minFontSizeMultiplier?: number
31
35
  /**
32
36
  * Style to apply to the spinner
33
37
  */
@@ -37,9 +41,10 @@ interface SpinnerProps {
37
41
  export function Spinner({
38
42
  size = 20,
39
43
  maxFontSizeMultiplier = PREVENT_SCALING_DEFAULT,
44
+ minFontSizeMultiplier = PREVENT_SCALING_DEFAULT,
40
45
  style,
41
46
  }: SpinnerProps) {
42
- const styles = useStyles({ maxFontSizeMultiplier, size })
47
+ const styles = useStyles({ maxFontSizeMultiplier, minFontSizeMultiplier, size })
43
48
 
44
49
  const rotation = useSharedValue(0)
45
50
  const animatedStyle = useAnimatedStyle(() => {
@@ -80,12 +85,13 @@ export function Spinner({
80
85
 
81
86
  interface Styles {
82
87
  maxFontSizeMultiplier: number | undefined
88
+ minFontSizeMultiplier: number | undefined
83
89
  size: number
84
90
  }
85
91
 
86
- const useStyles = ({ maxFontSizeMultiplier, size }: Styles) => {
92
+ const useStyles = ({ maxFontSizeMultiplier, minFontSizeMultiplier, size }: Styles) => {
87
93
  const { colors } = useTheme()
88
- const fontScale = useFontScale({ maxFontSizeMultiplier })
94
+ const fontScale = useFontScale({ maxFontSizeMultiplier, minFontSizeMultiplier })
89
95
  const scalableSize = size * fontScale
90
96
 
91
97
  return StyleSheet.create({
@@ -381,8 +381,6 @@ const useStyles = ({ size = 'md', presence = 'offline' }: Styles = {}) => {
381
381
  },
382
382
  groupLoader: {
383
383
  position: 'absolute',
384
- top: 0,
385
- left: 0,
386
384
  borderRadius: avatarDiameter,
387
385
  width: avatarDiameter,
388
386
  height: avatarDiameter,
@@ -1,11 +1,20 @@
1
1
  import { useWindowDimensions } from 'react-native'
2
+ import { clamp } from 'lodash'
2
3
 
3
4
  export const useFontScale = ({
4
5
  maxFontSizeMultiplier,
5
- }: { maxFontSizeMultiplier?: number } = {}) => {
6
+ minFontSizeMultiplier,
7
+ }: {
8
+ maxFontSizeMultiplier?: number
9
+ minFontSizeMultiplier?: number
10
+ } = {}) => {
6
11
  const { fontScale: nativeFontScale } = useWindowDimensions()
7
- const scaleLimit = maxFontSizeMultiplier || nativeFontScale
8
- const fontScale = Math.min(scaleLimit, nativeFontScale)
9
12
 
10
- return fontScale
13
+ // Infinity values are used to negate the scale if only one constraint is provided. This ensures that the scale is clamped to the provided constraint.
14
+ const maxFontScale = maxFontSizeMultiplier ?? Number.POSITIVE_INFINITY
15
+ const minFontScale = minFontSizeMultiplier ?? Number.NEGATIVE_INFINITY
16
+
17
+ const clampedScale = clamp(nativeFontScale, minFontScale, maxFontScale)
18
+
19
+ return clampedScale
11
20
  }