august-design-system
Version:
A comprehensive React Native design system following Apple Human Interface Guidelines
1,220 lines (1,209 loc) • 26.9 kB
JavaScript
import { createContext, useMemo, useState, useEffect, useContext } from 'react';
import { StyleSheet, useWindowDimensions, AccessibilityInfo } from 'react-native';
// src/design-system/hooks/useThemedStyles.ts
// src/design-system/tokens/colors.ts
var palette = {
// Gray scale - iOS system grays
gray: {
50: "#F2F2F7",
100: "#E5E5EA",
200: "#D1D1D6",
300: "#C7C7CC",
400: "#AEAEB2",
500: "#8E8E93"},
// System colors - iOS standard palette
// Light mode values
red: {
light: "#FF3B30"},
orange: {
light: "#FF9500"},
yellow: {
light: "#FFCC00"},
green: {
light: "#34C759"},
mint: {
light: "#00C7BE"},
teal: {
light: "#30B0C7"},
cyan: {
light: "#32ADE6"},
blue: {
light: "#007AFF"},
indigo: {
light: "#5856D6"},
purple: {
light: "#AF52DE"},
pink: {
light: "#FF2D55"},
brown: {
light: "#A2845E"}
};
var lightColors = {
// Background colors - iOS grouped table view style layering
background: {
primary: "#FFFFFF",
secondary: "#F2F2F7",
tertiary: "#FFFFFF",
grouped: "#F2F2F7",
groupedSecondary: "#FFFFFF",
groupedTertiary: "#F2F2F7"
},
// Label colors - for text content
label: {
primary: "#000000",
// 100% black
secondary: "rgba(60, 60, 67, 0.6)",
// 60% opacity
tertiary: "rgba(60, 60, 67, 0.3)",
// 30% opacity
quaternary: "rgba(60, 60, 67, 0.18)"
// 18% opacity
},
// Fill colors - for thin and small shapes
fill: {
primary: "rgba(120, 120, 128, 0.2)",
secondary: "rgba(120, 120, 128, 0.16)",
tertiary: "rgba(118, 118, 128, 0.12)",
quaternary: "rgba(116, 116, 128, 0.08)"
},
// Separator colors
separator: {
opaque: "#C6C6C8",
nonOpaque: "rgba(60, 60, 67, 0.36)"
},
// System colors - Apple standard
system: {
red: palette.red.light,
orange: palette.orange.light,
yellow: palette.yellow.light,
green: palette.green.light,
mint: palette.mint.light,
teal: palette.teal.light,
cyan: palette.cyan.light,
blue: palette.blue.light,
indigo: palette.indigo.light,
purple: palette.purple.light,
pink: palette.pink.light,
brown: palette.brown.light,
gray: palette.gray[500],
gray2: palette.gray[400],
gray3: palette.gray[300],
gray4: palette.gray[200],
gray5: palette.gray[100],
gray6: palette.gray[50]
},
// Semantic colors - functional meaning
semantic: {
success: palette.green.light,
warning: palette.orange.light,
error: palette.red.light,
info: palette.blue.light
},
// Interactive colors
interactive: {
tint: palette.blue.light,
tintPressed: "#0062CC",
// Darkened blue for pressed state
tintDisabled: "rgba(0, 122, 255, 0.3)",
destructive: palette.red.light,
destructivePressed: "#CC2F26"
},
// Material/Blur backgrounds - approximated for non-blur fallback
material: {
thin: "rgba(255, 255, 255, 0.6)",
regular: "rgba(255, 255, 255, 0.72)",
thick: "rgba(255, 255, 255, 0.85)",
chrome: "rgba(247, 247, 247, 0.8)"
}
};
// src/design-system/tokens/typography.ts
var fontFamily = {
regular: "System",
medium: "System",
semibold: "System",
bold: "System",
heavy: "System",
monospace: "Menlo",
// Falls back to platform monospace
rounded: "System"
// SF Pro Rounded on iOS
};
var typography = {
// ==========================================================================
// DISPLAY STYLES
// Large, prominent text for titles and headers
// ==========================================================================
/**
* Large Title - Used for main screen titles in navigation bars.
* iOS: 34pt Regular
*/
largeTitle: {
fontFamily: fontFamily.regular,
fontSize: 34,
lineHeight: 41,
// 1.2x
letterSpacing: 0.37,
fontWeight: "400"
},
/**
* Title 1 - Primary content titles.
* iOS: 28pt Regular
*/
title1: {
fontFamily: fontFamily.regular,
fontSize: 28,
lineHeight: 34,
// 1.21x
letterSpacing: 0.36,
fontWeight: "400"
},
/**
* Title 2 - Secondary titles.
* iOS: 22pt Regular
*/
title2: {
fontFamily: fontFamily.regular,
fontSize: 22,
lineHeight: 28,
// 1.27x
letterSpacing: 0.35,
fontWeight: "400"
},
/**
* Title 3 - Tertiary titles.
* iOS: 20pt Regular
*/
title3: {
fontFamily: fontFamily.regular,
fontSize: 20,
lineHeight: 25,
// 1.25x
letterSpacing: 0.38,
fontWeight: "400"
},
// ==========================================================================
// HEADLINE STYLES
// For section headers and emphasized text
// ==========================================================================
/**
* Headline - Section headers, emphasized body text.
* iOS: 17pt Semibold
*/
headline: {
fontFamily: fontFamily.semibold,
fontSize: 17,
lineHeight: 22,
// 1.29x
letterSpacing: -0.41,
fontWeight: "600"
},
/**
* Subheadline - Subordinate section headers.
* iOS: 15pt Regular
*/
subheadline: {
fontFamily: fontFamily.regular,
fontSize: 15,
lineHeight: 20,
// 1.33x
letterSpacing: -0.24,
fontWeight: "400"
},
// ==========================================================================
// BODY STYLES
// Primary reading text
// ==========================================================================
/**
* Body - Primary reading text throughout the app.
* iOS: 17pt Regular
*/
body: {
fontFamily: fontFamily.regular,
fontSize: 17,
lineHeight: 22,
// 1.29x
letterSpacing: -0.41,
fontWeight: "400"
},
/**
* Callout - Secondary text that's slightly smaller than body.
* iOS: 16pt Regular
*/
callout: {
fontFamily: fontFamily.regular,
fontSize: 16,
lineHeight: 21,
// 1.31x
letterSpacing: -0.32,
fontWeight: "400"
},
// ==========================================================================
// SUPPORTING STYLES
// Smaller text for captions, footnotes, and labels
// ==========================================================================
/**
* Footnote - Smaller supporting text.
* iOS: 13pt Regular
*/
footnote: {
fontFamily: fontFamily.regular,
fontSize: 13,
lineHeight: 18,
// 1.38x
letterSpacing: -0.08,
fontWeight: "400"
},
/**
* Caption 1 - Primary caption style.
* iOS: 12pt Regular
*/
caption1: {
fontFamily: fontFamily.regular,
fontSize: 12,
lineHeight: 16,
// 1.33x
letterSpacing: 0,
fontWeight: "400"
},
/**
* Caption 2 - Secondary caption style (smallest).
* iOS: 11pt Regular
*/
caption2: {
fontFamily: fontFamily.regular,
fontSize: 11,
lineHeight: 13,
// 1.18x
letterSpacing: 0.07,
fontWeight: "400"
}
};
function withWeight(style, weight) {
return {
...style,
fontWeight: weight
};
}
function emphasized(style) {
return withWeight(style, "600");
}
({
bodyEmphasis: emphasized(typography.body),
calloutEmphasis: emphasized(typography.callout),
footnoteEmphasis: emphasized(typography.footnote),
caption1Emphasis: emphasized(typography.caption1),
subheadlineEmphasis: emphasized(typography.subheadline)
});
// src/design-system/tokens/spacing.ts
var spacing = {
// Base scale
none: 0,
xxs: 2,
xs: 4,
sm: 8,
md: 12,
lg: 16,
xl: 20,
xxl: 24,
xxxl: 32,
xxxxl: 40,
xxxxxl: 48,
// Semantic spacing - Inset (padding)
// Used for content padding inside containers
inset: {
none: 0,
xs: 4,
sm: 8,
md: 12,
lg: 16,
// Standard content inset
xl: 20
},
// Semantic spacing - Stack (vertical)
// Used for vertical spacing between elements
stack: {
none: 0,
xs: 4,
sm: 8,
// Tight grouping
md: 12,
lg: 16,
// Standard section spacing
xl: 24
// Large section spacing
},
// Semantic spacing - Inline (horizontal)
// Used for horizontal spacing between elements
inline: {
none: 0,
xs: 4,
sm: 8,
// Icon to text spacing
md: 12,
lg: 16,
// Standard element spacing
xl: 24
}
};
// src/design-system/tokens/radius.ts
var radius = {
none: 0,
xs: 4,
sm: 8,
md: 12,
lg: 16,
xl: 20,
xxl: 24,
full: 9999
};
({
/**
* Button corner radius (matches iOS default).
*/
button: radius.sm,
/**
* Small button corner radius.
*/
buttonSmall: radius.xs,
/**
* Card corner radius.
*/
card: radius.md,
/**
* Input field corner radius.
*/
input: radius.sm,
/**
* Modal/Dialog corner radius.
*/
modal: radius.lg,
/**
* Bottom sheet corner radius.
*/
sheet: radius.xl,
/**
* Image thumbnail radius.
*/
thumbnail: radius.sm,
/**
* Avatar (circular) radius.
*/
avatar: radius.full,
/**
* Badge/Chip radius.
*/
badge: radius.full,
/**
* Pill button radius.
*/
pill: radius.full,
/**
* Tag/Label radius.
*/
tag: radius.xs,
/**
* Toast notification radius.
*/
toast: radius.md,
/**
* Tooltip radius.
*/
tooltip: radius.sm,
/**
* Popover radius.
*/
popover: radius.md,
/**
* Search bar radius.
*/
searchBar: radius.sm,
/**
* Segment control radius.
*/
segmentControl: radius.sm,
/**
* Slider track radius.
*/
slider: radius.full,
/**
* Progress bar radius.
*/
progressBar: radius.full
});
// src/design-system/tokens/shadows.ts
var shadowColors = {
light: "rgba(0, 0, 0, 1)"};
var lightShadows = {
/**
* No shadow.
*/
none: {
shadowColor: shadowColors.light,
shadowOffset: { width: 0, height: 0 },
shadowOpacity: 0,
shadowRadius: 0,
elevation: 0
},
/**
* Extra small shadow - subtle lift.
* Use for: Subtle hover states, pressed buttons.
*/
xs: {
shadowColor: shadowColors.light,
shadowOffset: { width: 0, height: 1 },
shadowOpacity: 0.04,
shadowRadius: 2,
elevation: 1
},
/**
* Small shadow - light elevation.
* Use for: Cards, list items, buttons.
*/
sm: {
shadowColor: shadowColors.light,
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.08,
shadowRadius: 4,
elevation: 2
},
/**
* Medium shadow - standard elevation.
* Use for: Dropdown menus, popovers, floating action buttons.
*/
md: {
shadowColor: shadowColors.light,
shadowOffset: { width: 0, height: 4 },
shadowOpacity: 0.12,
shadowRadius: 8,
elevation: 4
},
/**
* Large shadow - prominent elevation.
* Use for: Modals, dialogs, navigation overlays.
*/
lg: {
shadowColor: shadowColors.light,
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.15,
shadowRadius: 16,
elevation: 8
},
/**
* Extra large shadow - high elevation.
* Use for: Bottom sheets, side panels.
*/
xl: {
shadowColor: shadowColors.light,
shadowOffset: { width: 0, height: 12 },
shadowOpacity: 0.18,
shadowRadius: 24,
elevation: 12
},
/**
* XXL shadow - maximum elevation.
* Use for: Full-screen overlays, critical modals.
*/
xxl: {
shadowColor: shadowColors.light,
shadowOffset: { width: 0, height: 16 },
shadowOpacity: 0.22,
shadowRadius: 32,
elevation: 16
}
};
({
/**
* Card shadow.
*/
card: lightShadows.sm,
/**
* Button shadow (when elevated).
*/
button: lightShadows.xs,
/**
* Pressed button shadow (reduced).
*/
buttonPressed: lightShadows.none,
/**
* Floating action button shadow.
*/
fab: lightShadows.md,
/**
* Dropdown/Popover shadow.
*/
dropdown: lightShadows.md,
/**
* Modal/Dialog shadow.
*/
modal: lightShadows.lg,
/**
* Bottom sheet shadow.
*/
sheet: lightShadows.xl,
/**
* Toast notification shadow.
*/
toast: lightShadows.md,
/**
* Navigation header shadow.
*/
header: lightShadows.xs,
/**
* Tab bar shadow.
*/
tabBar: lightShadows.xs
});
// src/design-system/tokens/animation.ts
var duration = {
instant: 0,
fastest: 50,
faster: 100,
fast: 150,
normal: 250,
slow: 350,
slower: 500,
slowest: 700
};
var easing = {
/**
* Linear - constant speed (rarely used for UI).
*/
linear: [0, 0, 1, 1],
/**
* Ease In - slow start, fast end.
* Use for: Elements leaving the screen.
*/
easeIn: [0.42, 0, 1, 1],
/**
* Ease Out - fast start, slow end.
* Use for: Elements entering the screen.
* This is the most common easing for iOS-style animations.
*/
easeOut: [0, 0, 0.58, 1],
/**
* Ease In Out - slow start and end.
* Use for: Elements that start and end on screen.
*/
easeInOut: [0.42, 0, 0.58, 1],
/**
* Default spring - balanced, natural feel.
* iOS default animation spring characteristics.
* Use for: Most interactive animations.
*/
spring: {
damping: 15,
stiffness: 150,
mass: 1
},
/**
* Gentle spring - soft, slow settling.
* Use for: Subtle movements, floating elements.
*/
springGentle: {
damping: 20,
stiffness: 100,
mass: 1
},
/**
* Bouncy spring - energetic, playful feel.
* Use for: Emphasis, celebrations, playful interactions.
* Use sparingly to avoid overwhelming users.
*/
springBouncy: {
damping: 10,
stiffness: 200,
mass: 1
}
};
var animation = {
duration,
easing
};
var animationPresets = {
/**
* Button press feedback.
*/
buttonPress: {
duration: duration.faster,
easing: easing.easeOut
},
/**
* Button release feedback.
*/
buttonRelease: {
duration: duration.fast,
easing: easing.spring
},
/**
* Modal/Sheet appear.
*/
modalEnter: {
duration: duration.normal,
easing: easing.spring
},
/**
* Modal/Sheet dismiss.
*/
modalExit: {
duration: duration.fast,
easing: easing.easeIn
},
/**
* Page/Screen transition.
*/
pageTransition: {
duration: duration.slow,
easing: easing.easeInOut
},
/**
* Fade in content.
*/
fadeIn: {
duration: duration.normal,
easing: easing.easeOut
},
/**
* Fade out content.
*/
fadeOut: {
duration: duration.fast,
easing: easing.easeIn
},
/**
* Slide in from bottom.
*/
slideInUp: {
duration: duration.normal,
easing: easing.spring
},
/**
* Slide out to bottom.
*/
slideOutDown: {
duration: duration.fast,
easing: easing.easeIn
},
/**
* Scale up (appearing).
*/
scaleIn: {
duration: duration.normal,
easing: easing.springBouncy
},
/**
* Scale down (disappearing).
*/
scaleOut: {
duration: duration.fast,
easing: easing.easeIn
},
/**
* Expand/Collapse accordion.
*/
expand: {
duration: duration.normal,
easing: easing.easeInOut
},
/**
* Switch/Toggle animation.
*/
toggle: {
duration: duration.fast,
easing: easing.spring
},
/**
* Skeleton loading shimmer.
*/
skeleton: {
duration: duration.slowest,
easing: easing.linear
},
/**
* Toast notification appear.
*/
toastEnter: {
duration: duration.normal,
easing: easing.springBouncy
},
/**
* Toast notification dismiss.
*/
toastExit: {
duration: duration.fast,
easing: easing.easeIn
},
/**
* Haptic feedback timing.
*/
haptic: {
duration: duration.instant,
easing: easing.linear
}
};
var reducedMotionPresets = {
/**
* Replaces spring/bouncy animations with simple fade.
*/
default: {
duration: duration.fast,
easing: easing.easeOut
},
/**
* Replaces sliding animations with fade.
*/
slide: {
duration: duration.faster,
easing: easing.easeOut
},
/**
* Replaces scale animations with fade.
*/
scale: {
duration: duration.faster,
easing: easing.easeOut
},
/**
* Instant change (no animation).
*/
instant: {
duration: duration.instant,
easing: easing.linear
}
};
// src/design-system/tokens/sizes.ts
var sizes = {
// Touch targets - Apple HIG minimum 44pt
touchTarget: {
/**
* Minimum touch target size (44pt).
* Required by Apple HIG for all interactive elements.
*/
minimum: 44,
/**
* Comfortable touch target (48pt).
* Recommended for frequently used actions.
*/
comfortable: 48,
/**
* Spacious touch target (56pt).
* For primary actions and accessibility.
*/
spacious: 56
},
// Icon sizes
icon: {
/**
* Extra small icon (12pt).
* Use for: Inline badges, tiny indicators.
*/
xs: 12,
/**
* Small icon (16pt).
* Use for: Inline text icons, compact UI.
*/
sm: 16,
/**
* Medium icon (20pt).
* Use for: Standard inline icons.
*/
md: 20,
/**
* Large icon (24pt).
* Use for: Navigation icons, tab bar icons.
*/
lg: 24,
/**
* Extra large icon (32pt).
* Use for: Featured icons, prominent actions.
*/
xl: 32,
/**
* XXL icon (40pt).
* Use for: Illustrations, large feature icons.
*/
xxl: 40
},
// Avatar sizes
avatar: {
/**
* Extra small avatar (24pt).
* Use for: Inline mentions, compact lists.
*/
xs: 24,
/**
* Small avatar (32pt).
* Use for: Comments, messaging.
*/
sm: 32,
/**
* Medium avatar (40pt).
* Use for: Standard list items.
*/
md: 40,
/**
* Large avatar (56pt).
* Use for: Profile cards, detailed lists.
*/
lg: 56,
/**
* Extra large avatar (72pt).
* Use for: Profile headers.
*/
xl: 72,
/**
* XXL avatar (96pt).
* Use for: Profile pages, settings.
*/
xxl: 96
},
// Button heights
button: {
/**
* Small button (32pt).
* Use for: Compact UI, inline actions.
* Note: May not meet touch target minimum.
*/
sm: 32,
/**
* Medium button (44pt) - DEFAULT.
* Use for: Standard buttons.
* Meets Apple HIG minimum touch target.
*/
md: 44,
/**
* Large button (50pt).
* Use for: Primary actions, CTAs.
*/
lg: 50,
/**
* Extra large button (56pt).
* Use for: Hero actions, onboarding.
*/
xl: 56
},
// Input heights
input: {
/**
* Small input (36pt).
* Use for: Compact forms, filters.
*/
sm: 36,
/**
* Medium input (44pt) - DEFAULT.
* Use for: Standard form inputs.
* Meets Apple HIG minimum touch target.
*/
md: 44,
/**
* Large input (52pt).
* Use for: Search bars, prominent inputs.
*/
lg: 52
}
};
var zIndex = {
/**
* Base level - standard content.
*/
base: 0,
/**
* Dropdown level - menus, selects.
*/
dropdown: 1e3,
/**
* Sticky level - headers, navigation.
*/
sticky: 1100,
/**
* Overlay level - background overlays.
*/
overlay: 1200,
/**
* Modal level - dialogs, sheets.
*/
modal: 1300,
/**
* Popover level - tooltips, popovers.
*/
popover: 1400,
/**
* Tooltip level - floating hints.
*/
tooltip: 1500,
/**
* Toast level - notifications (highest).
*/
toast: 1600
};
var breakpoints = {
/**
* Extra small - small phones.
*/
xs: 0,
/**
* Small - standard phones (iPhone SE+).
* iPhone SE: 375pt width.
*/
sm: 375,
/**
* Medium - large phones (iPhone Pro Max).
* iPhone Pro Max: 428pt width.
*/
md: 428,
/**
* Large - small tablets (iPad Mini).
* iPad Mini portrait: 744pt width.
*/
lg: 744,
/**
* Extra large - large tablets (iPad Pro).
* iPad Pro portrait: 1024pt width.
*/
xl: 1024
};
var opacity = {
/**
* Fully transparent.
*/
transparent: 0,
/**
* Disabled state opacity.
* iOS uses 0.3-0.4 for disabled elements.
*/
disabled: 0.38,
/**
* Medium opacity - overlays, secondary elements.
*/
medium: 0.6,
/**
* High opacity - emphasized content.
*/
high: 0.87,
/**
* Fully opaque.
*/
opaque: 1
};
// src/design-system/theme/defaultTheme.ts
var lightTheme = {
name: "August Light",
mode: "light",
colors: lightColors,
typography,
fontFamily,
spacing,
radius,
shadows: lightShadows,
animation,
sizes,
zIndex,
breakpoints,
opacity
};
var defaultContextValue = {
theme: lightTheme,
colorMode: "light",
colorModePreference: "system",
toggleColorMode: () => {
console.warn("ThemeProvider not found in component tree");
},
setColorMode: () => {
console.warn("ThemeProvider not found in component tree");
},
isDark: false,
isLight: true
};
var ThemeContext = createContext(defaultContextValue);
function useTheme() {
const context = useContext(ThemeContext);
if (context === defaultContextValue) {
console.warn(
"useTheme must be used within a ThemeProvider. Falling back to default light theme."
);
}
return context;
}
// src/design-system/hooks/useThemedStyles.ts
function useThemedStyles(styleCreator) {
const { theme } = useTheme();
return useMemo(() => {
const rawStyles = styleCreator(theme);
return StyleSheet.create(rawStyles);
}, [theme, styleCreator]);
}
function useThemedStyle(styleCreator) {
const { theme } = useTheme();
return useMemo(() => styleCreator(theme), [theme, styleCreator]);
}
function createThemedStyles(styleCreator) {
return function useStyles() {
return useThemedStyles(styleCreator);
};
}
function combineStyles(...styles) {
return styles.filter(Boolean);
}
function conditionalStyle(condition, trueStyle, falseStyle) {
if (condition) return trueStyle;
return falseStyle;
}
function useBreakpoint() {
const { width } = useWindowDimensions();
const { theme } = useTheme();
const { breakpoints: breakpoints2 } = theme;
return useMemo(() => {
if (width >= breakpoints2.xl) return "xl";
if (width >= breakpoints2.lg) return "lg";
if (width >= breakpoints2.md) return "md";
if (width >= breakpoints2.sm) return "sm";
return "xs";
}, [width, breakpoints2]);
}
function useResponsiveValue(value) {
const breakpoint = useBreakpoint();
return useMemo(() => {
if (typeof value !== "object" || value === null || Array.isArray(value)) {
return value;
}
const responsiveValue = value;
const breakpointOrder = ["xl", "lg", "md", "sm", "xs"];
const currentIndex = breakpointOrder.indexOf(breakpoint);
for (let i = currentIndex; i < breakpointOrder.length; i++) {
const bp = breakpointOrder[i];
if (bp in responsiveValue && responsiveValue[bp] !== void 0) {
return responsiveValue[bp];
}
}
for (const bp of breakpointOrder) {
if (bp in responsiveValue && responsiveValue[bp] !== void 0) {
return responsiveValue[bp];
}
}
return void 0;
}, [value, breakpoint]);
}
function useDeviceType() {
const breakpoint = useBreakpoint();
return breakpoint === "lg" || breakpoint === "xl" ? "tablet" : "phone";
}
function useIsBreakpoint(targetBreakpoint) {
const { width } = useWindowDimensions();
const { theme } = useTheme();
return width >= theme.breakpoints[targetBreakpoint];
}
function useScreenDimensions() {
const { width, height } = useWindowDimensions();
return useMemo(
() => ({
width,
height,
isPortrait: height >= width,
isLandscape: width > height,
aspectRatio: width / height
}),
[width, height]
);
}
function responsiveStyle(styles) {
const breakpointOrder = ["xl", "lg", "md", "sm", "xs"];
return (breakpoint) => {
const currentIndex = breakpointOrder.indexOf(breakpoint);
for (let i = currentIndex; i < breakpointOrder.length; i++) {
const bp = breakpointOrder[i];
if (bp in styles && styles[bp] !== void 0) {
return styles[bp];
}
}
return void 0;
};
}
function useReducedMotion() {
const [reducedMotion, setReducedMotion] = useState(false);
useEffect(() => {
AccessibilityInfo.isReduceMotionEnabled().then(setReducedMotion);
const subscription = AccessibilityInfo.addEventListener(
"reduceMotionChanged",
setReducedMotion
);
return () => {
subscription.remove();
};
}, []);
return reducedMotion;
}
function useAccessibleAnimation(preset) {
const prefersReducedMotion = useReducedMotion();
return useMemo(() => {
if (prefersReducedMotion) {
return {
duration: reducedMotionPresets.default.duration,
useNativeDriver: true,
isReduced: true
};
}
return {
duration: animationPresets[preset].duration,
useNativeDriver: true,
isReduced: false
};
}, [preset, prefersReducedMotion]);
}
function useScreenReader() {
const [screenReaderEnabled, setScreenReaderEnabled] = useState(false);
useEffect(() => {
AccessibilityInfo.isScreenReaderEnabled().then(setScreenReaderEnabled);
const subscription = AccessibilityInfo.addEventListener(
"screenReaderChanged",
setScreenReaderEnabled
);
return () => {
subscription.remove();
};
}, []);
return screenReaderEnabled;
}
function useBoldText() {
const [boldTextEnabled, setBoldTextEnabled] = useState(false);
useEffect(() => {
AccessibilityInfo.isBoldTextEnabled().then(setBoldTextEnabled);
const subscription = AccessibilityInfo.addEventListener(
"boldTextChanged",
setBoldTextEnabled
);
return () => {
subscription.remove();
};
}, []);
return boldTextEnabled;
}
function useDynamicType() {
const { fontScale } = useWindowDimensions();
return fontScale;
}
function useScaledTypography(baseStyle, options = {}) {
const { maxScale = 2, minScale = 0.8 } = options;
const fontScale = useDynamicType();
return useMemo(() => {
const clampedScale = Math.min(Math.max(fontScale, minScale), maxScale);
return {
...baseStyle,
fontSize: Math.round(baseStyle.fontSize * clampedScale),
lineHeight: Math.round(baseStyle.lineHeight * clampedScale)
};
}, [baseStyle, fontScale, maxScale, minScale]);
}
function useHighContrast() {
const boldTextEnabled = useBoldText();
return boldTextEnabled;
}
function announceForAccessibility(message) {
AccessibilityInfo.announceForAccessibility(message);
}
function setAccessibilityFocus(reactTag) {
if (reactTag) {
AccessibilityInfo.setAccessibilityFocus(reactTag);
}
}
export { announceForAccessibility, combineStyles, conditionalStyle, createThemedStyles, responsiveStyle, setAccessibilityFocus, useAccessibleAnimation, useBoldText, useBreakpoint, useDeviceType, useDynamicType, useHighContrast, useIsBreakpoint, useReducedMotion, useResponsiveValue, useScaledTypography, useScreenDimensions, useScreenReader, useThemedStyle, useThemedStyles };
//# sourceMappingURL=index.mjs.map
//# sourceMappingURL=index.mjs.map