···99import {type Alf, applyFonts, atoms, flatten} from '#/alf'
10101111/**
1212+ * Util to calculate lineHeight from a text size atom and a leading atom
1313+ *
1414+ * Example:
1515+ * `leading(atoms.text_md, atoms.leading_normal)` // => 24
1616+ */
1717+export function leading<
1818+ Size extends {fontSize?: number},
1919+ Leading extends {lineHeight?: number},
2020+>(textSize: Size, leading: Leading) {
2121+ const size = textSize?.fontSize || atoms.text_md.fontSize
2222+ const lineHeight = leading?.lineHeight || atoms.leading_normal.lineHeight
2323+ return Math.round(size * lineHeight)
2424+}
2525+2626+/**
1227 * Ensures that `lineHeight` defaults to a relative value of `1`, or applies
1328 * other relative leading atoms.
1429 *
+8
src/alf/util/__tests__/colors.test.ts
···11import {jest} from '@jest/globals'
2233+import {logger} from '#/logger'
34import {transparentifyColor} from '../colorGeneration'
55+66+jest.mock('#/logger', () => ({
77+ logger: {warn: jest.fn()},
88+}))
49510describe('transparentifyColor', () => {
611 beforeEach(() => {
···3641 const unsupported = 'blue'
3742 const result = transparentifyColor(unsupported, 0.5)
3843 expect(result).toBe(unsupported)
4444+ expect(logger.warn).toHaveBeenCalledWith(
4545+ `Could not make '${unsupported}' transparent`,
4646+ )
3947 })
4048})
+62-1
src/alf/util/platform.ts
···11-export {android, ios, native, platform, web} from '@bsky.app/alf'
11+import {Platform} from 'react-native'
22+33+import {isAndroid, isIOS, isNative, isWeb} from '#/platform/detection'
44+55+/**
66+ * Identity function on web. Returns nothing on other platforms.
77+ *
88+ * Note: Platform splitting does not tree-shake away the other platforms,
99+ * so don't do stuff like e.g. rely on platform-specific imports. Use
1010+ * platform-split files instead.
1111+ */
1212+export function web(value: any) {
1313+ if (isWeb) {
1414+ return value
1515+ }
1616+}
1717+1818+/**
1919+ * Identity function on iOS. Returns nothing on other platforms.
2020+ *
2121+ * Note: Platform splitting does not tree-shake away the other platforms,
2222+ * so don't do stuff like e.g. rely on platform-specific imports. Use
2323+ * platform-split files instead.
2424+ */
2525+export function ios(value: any) {
2626+ if (isIOS) {
2727+ return value
2828+ }
2929+}
3030+3131+/**
3232+ * Identity function on Android. Returns nothing on other platforms..
3333+ *
3434+ * Note: Platform splitting does not tree-shake away the other platforms,
3535+ * so don't do stuff like e.g. rely on platform-specific imports. Use
3636+ * platform-split files instead.
3737+ */
3838+export function android(value: any) {
3939+ if (isAndroid) {
4040+ return value
4141+ }
4242+}
4343+4444+/**
4545+ * Identity function on iOS and Android. Returns nothing on web.
4646+ *
4747+ * Note: Platform splitting does not tree-shake away the other platforms,
4848+ * so don't do stuff like e.g. rely on platform-specific imports. Use
4949+ * platform-split files instead.
5050+ */
5151+export function native(value: any) {
5252+ if (isNative) {
5353+ return value
5454+ }
5555+}
5656+5757+/**
5858+ * Note: Platform splitting does not tree-shake away the other platforms,
5959+ * so don't do stuff like e.g. rely on platform-specific imports. Use
6060+ * platform-split files instead.
6161+ */
6262+export const platform = Platform.select
+1-1
src/alf/util/systemUI.ts
···11import * as SystemUI from 'expo-system-ui'
22-import {type Theme} from '@bsky.app/alf'
3243import {isAndroid} from '#/platform/detection'
44+import {type Theme} from '../types'
5566export function setSystemUITheme(themeType: 'theme' | 'lightbox', t: Theme) {
77 if (isAndroid) {
+13-2
src/alf/util/themeSelector.ts
···11-import {utils} from '@bsky.app/alf'
11+import {type ThemeName} from '#/alf/types'
2233-export const select = utils.select
33+export function select<T>(name: ThemeName, options: Record<ThemeName, T>) {
44+ switch (name) {
55+ case 'light':
66+ return options.light
77+ case 'dark':
88+ return options.dark || options.dim
99+ case 'dim':
1010+ return options.dim || options.dark
1111+ default:
1212+ throw new Error(`select(theme, options) received unknown theme ${name}`)
1313+ }
1414+}
+1-1
src/alf/util/useColorModeTheme.ts
···11import React from 'react'
22import {type ColorSchemeName, useColorScheme} from 'react-native'
33-import {type ThemeName} from '@bsky.app/alf'
4354import {isWeb} from '#/platform/detection'
65import {useThemePrefs} from '#/state/shell'
76import {dark, dim, light} from '#/alf/themes'
77+import {type ThemeName} from '#/alf/types'
8899export function useColorModeTheme(): ThemeName {
1010 const theme = useThemeName()
···6262 </View>
63636464 <View style={[a.gap_sm, a.pb_lg]}>
6565- <Text style={[a.text_xl, a.leading_snug, a.font_bold]}>
6565+ <Text style={[a.text_xl, a.leading_snug, a.font_heavy]}>
6666 <Trans>
6767 You must complete age assurance in order to access this screen.
6868 </Trans>
···6262 <Dialog.ScrollableInner label={_(msg`How should we open this link?`)}>
6363 <View style={[a.gap_2xl]}>
6464 <View style={[a.gap_sm]}>
6565- <Text style={[a.font_bold, a.text_2xl]}>
6565+ <Text style={[a.font_heavy, a.text_2xl]}>
6666 <Trans>How should we open this link?</Trans>
6767 </Text>
6868 <Text style={[t.atoms.text_contrast_high, a.leading_snug, a.text_md]}>
···8282 style={[
8383 t.atoms.text_contrast_medium,
8484 a.text_sm,
8585- a.font_semi_bold,
8585+ a.font_bold,
8686 ]}>
8787 {' '}
8888 </Text>
···101101 style={[
102102 t.atoms.text,
103103 a.text_sm,
104104- a.font_semi_bold,
104104+ a.font_bold,
105105 {opacity: 0.7}, // NOTE: we use opacity 0.7 instead of a color to match the color of the home pager tab bar
106106 ]}>
107107 {topic.topic}
···11import {type ReactNode} from 'react'
22import {createContext, useContext} from 'react'
33import {type TextStyle, type ViewStyle} from 'react-native'
44-import {type ThemeName} from '@bsky.app/alf'
5455+import {type ThemeName} from '#/alf/types'
66import {darkTheme, defaultTheme, dimTheme} from './themes'
7788export type ColorScheme = 'light' | 'dark'
···133133134134 return (
135135 <View style={[a.align_start]} testID="onboardingInterests">
136136- <Text style={[a.font_bold, a.text_3xl]}>
136136+ <Text style={[a.font_heavy, a.text_3xl]}>
137137 <Trans comment="Accounts suggested to the user for them to follow">
138138 Suggested for you
139139 </Trans>