@rific/auto-paper 0.13.3 → 0.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/index.d.mts +4 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.js +22 -1
- package/dist/index.mjs +20 -1
- package/package.json +2 -2
- package/src/index.ts +1 -0
- package/src/utils/getColorRoles.ts +13 -2
- package/src/utils/getContrastRatio.ts +20 -0
package/README.md
CHANGED
|
@@ -648,7 +648,7 @@ const appearance = useSelector((state: RootState) => selectThemeAppearance(state
|
|
|
648
648
|
### Color utilities
|
|
649
649
|
|
|
650
650
|
```ts
|
|
651
|
-
import { getTriadicPalette, getThirdColor, getBlendedColor, getColorRoles, getContrastColor, isDarkColor, getRgb, getHex, getTonalColor, getTintTextColor, resolveSeedColor } from '@rific/auto-paper'
|
|
651
|
+
import { getTriadicPalette, getThirdColor, getBlendedColor, getColorRoles, getContrastColor, getContrastRatio, getLuminance, isDarkColor, getRgb, getHex, getTonalColor, getTintTextColor, resolveSeedColor } from '@rific/auto-paper'
|
|
652
652
|
import type { ColorHarmony, TriadicPalette } from '@rific/auto-paper'
|
|
653
653
|
|
|
654
654
|
getTriadicPalette('#6750a4') // split-complementary (default)
|
|
@@ -661,7 +661,9 @@ getTriadicPalette('#6750a4', 'double-split')
|
|
|
661
661
|
getThirdColor('#e53935', '#1e88e5') // → '#59e52a' (hue maximally distant from both inputs; s/l averaged from both)
|
|
662
662
|
|
|
663
663
|
getBlendedColor('#ff0000', '#0000ff', 0.5) // → '#800080'
|
|
664
|
-
getColorRoles('#6750a4', '#fffbfe') // → { color, onColor, container, onContainer }: the MD3 color/onColor/container/onContainer math, generalized (this is what useComputedTheme uses internally for every role)
|
|
664
|
+
getColorRoles('#6750a4', '#fffbfe') // → { color, onColor, container, onContainer }: the MD3 color/onColor/container/onContainer math, generalized (this is what useComputedTheme uses internally for every role). onColor is light while light text reads on the color at 2.5:1, dark below that
|
|
665
|
+
getContrastRatio('#767676', '#ffffff') // → 4.54 (WCAG 2 contrast ratio, 1 to 21, either order)
|
|
666
|
+
getLuminance('#ffffff') // → 1 (WCAG 2 relative luminance, 0 for black)
|
|
665
667
|
getContrastColor('#6750a4') // → '#ffffff' (black/white pick for content sitting on a fully saturated fill)
|
|
666
668
|
isDarkColor('#6750a4') // → true
|
|
667
669
|
getRgb('coral') // → { r: 255, g: 127, b: 80 }
|
package/dist/index.d.mts
CHANGED
|
@@ -391,6 +391,9 @@ type ColorRoles = {
|
|
|
391
391
|
};
|
|
392
392
|
declare const getColorRoles: (base: string, surface: string, containerAlpha?: number) => ColorRoles;
|
|
393
393
|
|
|
394
|
+
declare const getLuminance: (value: string) => number;
|
|
395
|
+
declare const getContrastRatio: (a: string, b: string) => number;
|
|
396
|
+
|
|
394
397
|
declare const getHex: (value: string) => string | null;
|
|
395
398
|
|
|
396
399
|
type RGB = {
|
|
@@ -413,4 +416,4 @@ declare const isDarkColor: (value: string) => boolean;
|
|
|
413
416
|
|
|
414
417
|
declare const resolveSeedColor: (color: string | TriadicPalette) => string;
|
|
415
418
|
|
|
416
|
-
export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, FadingScrollView, type FadingScrollViewProps, HarmonyPicker, IconButton, type IconButtonProps, type MaskedViewModule, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, type ReanimatedModule, SCROLL_FADE_HEIGHT, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useMaskedViewModule, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
|
|
419
|
+
export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, FadingScrollView, type FadingScrollViewProps, HarmonyPicker, IconButton, type IconButtonProps, type MaskedViewModule, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, type ReanimatedModule, SCROLL_FADE_HEIGHT, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getContrastRatio, getHex, getLuminance, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useMaskedViewModule, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
|
package/dist/index.d.ts
CHANGED
|
@@ -391,6 +391,9 @@ type ColorRoles = {
|
|
|
391
391
|
};
|
|
392
392
|
declare const getColorRoles: (base: string, surface: string, containerAlpha?: number) => ColorRoles;
|
|
393
393
|
|
|
394
|
+
declare const getLuminance: (value: string) => number;
|
|
395
|
+
declare const getContrastRatio: (a: string, b: string) => number;
|
|
396
|
+
|
|
394
397
|
declare const getHex: (value: string) => string | null;
|
|
395
398
|
|
|
396
399
|
type RGB = {
|
|
@@ -413,4 +416,4 @@ declare const isDarkColor: (value: string) => boolean;
|
|
|
413
416
|
|
|
414
417
|
declare const resolveSeedColor: (color: string | TriadicPalette) => string;
|
|
415
418
|
|
|
416
|
-
export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, FadingScrollView, type FadingScrollViewProps, HarmonyPicker, IconButton, type IconButtonProps, type MaskedViewModule, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, type ReanimatedModule, SCROLL_FADE_HEIGHT, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getHex, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useMaskedViewModule, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
|
|
419
|
+
export { Appbar, type AppearanceIcons, AppearancePicker, AutoAppearancePicker, AutoPalettePicker, type AutoPaperTheme, BlurView, type BlurViewProps, BottomNavigation, Button, Chip, type ChipProps, type ColorHarmony, ColorPicker, type ColorRoles, Dialog, type DialogProps, type ExpoBlurModule, type ExpoNavigationBarModule, FAB, FadingScrollView, type FadingScrollViewProps, HarmonyPicker, IconButton, type IconButtonProps, type MaskedViewModule, Menu, type MenuProps, PalettePicker, type PaletteWeights, type PaperDefaults, Provider, type ProviderProps, type RGB, type ReanimatedModule, SCROLL_FADE_HEIGHT, SEMANTIC_BASE_COLORS, type SeedColor, type SemanticColorRoles, TextInput, type ThemeAppearance, type ThemeBridgeProps, type ThemeSettings, ThemeSettingsContext, type ThemeSettingsContextType, type ThemeState, type TriadicPalette, createThemeReducer, defaultColors, defaultThemeSettings, getBlendedColor, getColorRoles, getContrastColor, getContrastRatio, getHex, getLuminance, getRgb, getThirdColor, getTintTextColor, getTonalColor, getTriadicPalette, isDarkColor, resolveSeedColor, selectThemeAppearance, selectThemeBlur, selectThemeColor, selectThemeHarmony, themeActions, themeReducer, useAutoPaperTheme, useBlur, useBlurModule, useComputedTheme, useMaskedViewModule, useNavBarContext, usePaperDefaults, useReanimatedModule, useThemeBridgeProps, useThemeSettings };
|
package/dist/index.js
CHANGED
|
@@ -57,7 +57,9 @@ __export(index_exports, {
|
|
|
57
57
|
getBlendedColor: () => getBlendedColor,
|
|
58
58
|
getColorRoles: () => getColorRoles,
|
|
59
59
|
getContrastColor: () => getContrastColor,
|
|
60
|
+
getContrastRatio: () => getContrastRatio,
|
|
60
61
|
getHex: () => getHex,
|
|
62
|
+
getLuminance: () => getLuminance,
|
|
61
63
|
getRgb: () => getRgb,
|
|
62
64
|
getThirdColor: () => getThirdColor,
|
|
63
65
|
getTintTextColor: () => getTintTextColor,
|
|
@@ -353,6 +355,21 @@ var getBlendedColor = (foreground, background, alpha) => {
|
|
|
353
355
|
return getHex(`rgb(${r}, ${g}, ${b})`) ?? background;
|
|
354
356
|
};
|
|
355
357
|
|
|
358
|
+
// src/utils/getContrastRatio.ts
|
|
359
|
+
var getLuminance = (value) => {
|
|
360
|
+
const rgb = getRgb(value);
|
|
361
|
+
if (!rgb) return 0;
|
|
362
|
+
const [r, g, b] = [rgb.r, rgb.g, rgb.b].map((channel) => {
|
|
363
|
+
const c = channel / 255;
|
|
364
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
365
|
+
});
|
|
366
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
367
|
+
};
|
|
368
|
+
var getContrastRatio = (a, b) => {
|
|
369
|
+
const [lighter, darker] = [getLuminance(a), getLuminance(b)].sort((x, y) => y - x);
|
|
370
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
371
|
+
};
|
|
372
|
+
|
|
356
373
|
// src/utils/getTonalColor.ts
|
|
357
374
|
var getTonalColor = (color, lightness) => {
|
|
358
375
|
const rgb = getRgb(color);
|
|
@@ -417,11 +434,13 @@ var isDarkColor = (value) => {
|
|
|
417
434
|
};
|
|
418
435
|
|
|
419
436
|
// src/utils/getColorRoles.ts
|
|
437
|
+
var MIN_LIGHT_ON_COLOR_CONTRAST = 2.5;
|
|
420
438
|
var getColorRoles = (base, surface, containerAlpha = 0.15) => {
|
|
421
439
|
const container = getBlendedColor(base, surface, containerAlpha);
|
|
440
|
+
const lightOnColor = getTonalColor(base, 0.95);
|
|
422
441
|
return {
|
|
423
442
|
color: base,
|
|
424
|
-
onColor:
|
|
443
|
+
onColor: getContrastRatio(lightOnColor, base) >= MIN_LIGHT_ON_COLOR_CONTRAST ? lightOnColor : getTonalColor(base, 0.08),
|
|
425
444
|
container,
|
|
426
445
|
onContainer: getTonalColor(base, isDarkColor(container) ? 0.92 : 0.12)
|
|
427
446
|
};
|
|
@@ -1325,7 +1344,9 @@ var getTintTextColor = (tintColor, backdropColor, tintOpacity) => {
|
|
|
1325
1344
|
getBlendedColor,
|
|
1326
1345
|
getColorRoles,
|
|
1327
1346
|
getContrastColor,
|
|
1347
|
+
getContrastRatio,
|
|
1328
1348
|
getHex,
|
|
1349
|
+
getLuminance,
|
|
1329
1350
|
getRgb,
|
|
1330
1351
|
getThirdColor,
|
|
1331
1352
|
getTintTextColor,
|
package/dist/index.mjs
CHANGED
|
@@ -267,6 +267,21 @@ var getBlendedColor = (foreground, background, alpha) => {
|
|
|
267
267
|
return getHex(`rgb(${r}, ${g}, ${b})`) ?? background;
|
|
268
268
|
};
|
|
269
269
|
|
|
270
|
+
// src/utils/getContrastRatio.ts
|
|
271
|
+
var getLuminance = (value) => {
|
|
272
|
+
const rgb = getRgb(value);
|
|
273
|
+
if (!rgb) return 0;
|
|
274
|
+
const [r, g, b] = [rgb.r, rgb.g, rgb.b].map((channel) => {
|
|
275
|
+
const c = channel / 255;
|
|
276
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
|
|
277
|
+
});
|
|
278
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
279
|
+
};
|
|
280
|
+
var getContrastRatio = (a, b) => {
|
|
281
|
+
const [lighter, darker] = [getLuminance(a), getLuminance(b)].sort((x, y) => y - x);
|
|
282
|
+
return (lighter + 0.05) / (darker + 0.05);
|
|
283
|
+
};
|
|
284
|
+
|
|
270
285
|
// src/utils/getTonalColor.ts
|
|
271
286
|
var getTonalColor = (color, lightness) => {
|
|
272
287
|
const rgb = getRgb(color);
|
|
@@ -331,11 +346,13 @@ var isDarkColor = (value) => {
|
|
|
331
346
|
};
|
|
332
347
|
|
|
333
348
|
// src/utils/getColorRoles.ts
|
|
349
|
+
var MIN_LIGHT_ON_COLOR_CONTRAST = 2.5;
|
|
334
350
|
var getColorRoles = (base, surface, containerAlpha = 0.15) => {
|
|
335
351
|
const container = getBlendedColor(base, surface, containerAlpha);
|
|
352
|
+
const lightOnColor = getTonalColor(base, 0.95);
|
|
336
353
|
return {
|
|
337
354
|
color: base,
|
|
338
|
-
onColor:
|
|
355
|
+
onColor: getContrastRatio(lightOnColor, base) >= MIN_LIGHT_ON_COLOR_CONTRAST ? lightOnColor : getTonalColor(base, 0.08),
|
|
339
356
|
container,
|
|
340
357
|
onContainer: getTonalColor(base, isDarkColor(container) ? 0.92 : 0.12)
|
|
341
358
|
};
|
|
@@ -1238,7 +1255,9 @@ export {
|
|
|
1238
1255
|
getBlendedColor,
|
|
1239
1256
|
getColorRoles,
|
|
1240
1257
|
getContrastColor,
|
|
1258
|
+
getContrastRatio,
|
|
1241
1259
|
getHex,
|
|
1260
|
+
getLuminance,
|
|
1242
1261
|
getRgb,
|
|
1243
1262
|
getThirdColor,
|
|
1244
1263
|
getTintTextColor,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rific/auto-paper",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.4",
|
|
4
4
|
"description": "Adaptive react-native-paper theming: triadic palette from a seed color + system/light/dark appearance",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react-native",
|
|
@@ -69,7 +69,7 @@
|
|
|
69
69
|
},
|
|
70
70
|
"devDependencies": {
|
|
71
71
|
"@infinitetoken/eslint-config": "0.2.0",
|
|
72
|
-
"@infinitetoken/jest-config": "^0.5.
|
|
72
|
+
"@infinitetoken/jest-config": "^0.5.1",
|
|
73
73
|
"@infinitetoken/tsconfig": "^0.6.0",
|
|
74
74
|
"@react-native-masked-view/masked-view": "^0.3.2",
|
|
75
75
|
"@reduxjs/toolkit": "^2.0.0",
|
package/src/index.ts
CHANGED
|
@@ -43,6 +43,7 @@ export { useThemeSettings } from './useThemeSettings'
|
|
|
43
43
|
export { getBlendedColor } from './utils/getBlendedColor'
|
|
44
44
|
export type { ColorRoles } from './utils/getColorRoles'
|
|
45
45
|
export { getColorRoles } from './utils/getColorRoles'
|
|
46
|
+
export { getContrastRatio, getLuminance } from './utils/getContrastRatio'
|
|
46
47
|
export { getHex } from './utils/getHex'
|
|
47
48
|
export type { RGB } from './utils/getRgb'
|
|
48
49
|
export { getRgb } from './utils/getRgb'
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getBlendedColor } from './getBlendedColor'
|
|
2
|
+
import { getContrastRatio } from './getContrastRatio'
|
|
2
3
|
import { getTonalColor } from './getTonalColor'
|
|
3
4
|
import { isDarkColor } from './isDarkColor'
|
|
4
5
|
|
|
@@ -9,18 +10,28 @@ export type ColorRoles = {
|
|
|
9
10
|
onContainer: string
|
|
10
11
|
}
|
|
11
12
|
|
|
13
|
+
// The lowest contrast light text may have on a color before onColor turns dark instead. The fleet's
|
|
14
|
+
// colored buttons have always had light text, and keep it wherever it reads about as well as it does on
|
|
15
|
+
// their reds, blues and greens (2.8 to 3.1:1 for the picker's Red, Blue, Emerald and Coral); only
|
|
16
|
+
// colors light enough that it fades take dark text: the picker's Lime, Amber, Cyan and Sky (Yellow
|
|
17
|
+
// already did). Judging by the color's own darkness alone gave those near-white text that all but
|
|
18
|
+
// vanished (Jay, 2026-10-19: 1.96:1 on a light green Ready button).
|
|
19
|
+
const MIN_LIGHT_ON_COLOR_CONTRAST = 2.5
|
|
20
|
+
|
|
12
21
|
// The MD3 "color / onColor / container / onContainer" quadruple, generalized from the math
|
|
13
22
|
// useComputedTheme already uses for primary/secondary/tertiary: onColor is tuned to sit on the
|
|
14
|
-
// vivid color itself
|
|
23
|
+
// vivid color itself (light while it reads, MIN_LIGHT_ON_COLOR_CONTRAST, else dark), container is
|
|
24
|
+
// base blended toward the theme's real surface (so it inherits
|
|
15
25
|
// that surface's actual lightness rather than a fixed light/dark guess), and onContainer is tuned
|
|
16
26
|
// against the *computed* container rather than a light/dark assumption, so it stays readable
|
|
17
27
|
// whatever surface color it's handed. onContainer also reads safely directly on `surface` itself
|
|
18
28
|
// (not just on `container`), since container is only lightly blended toward it.
|
|
19
29
|
export const getColorRoles = (base: string, surface: string, containerAlpha = 0.15): ColorRoles => {
|
|
20
30
|
const container = getBlendedColor(base, surface, containerAlpha)
|
|
31
|
+
const lightOnColor = getTonalColor(base, 0.95)
|
|
21
32
|
return {
|
|
22
33
|
color: base,
|
|
23
|
-
onColor:
|
|
34
|
+
onColor: getContrastRatio(lightOnColor, base) >= MIN_LIGHT_ON_COLOR_CONTRAST ? lightOnColor : getTonalColor(base, 0.08),
|
|
24
35
|
container,
|
|
25
36
|
onContainer: getTonalColor(base, isDarkColor(container) ? 0.92 : 0.12)
|
|
26
37
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getRgb } from './getRgb'
|
|
2
|
+
|
|
3
|
+
// WCAG 2's relative luminance (0 for black, 1 for white): the same formula isDarkColor applies.
|
|
4
|
+
export const getLuminance = (value: string): number => {
|
|
5
|
+
const rgb = getRgb(value)
|
|
6
|
+
if (!rgb) return 0
|
|
7
|
+
const [r, g, b] = [rgb.r, rgb.g, rgb.b].map((channel) => {
|
|
8
|
+
const c = channel / 255
|
|
9
|
+
return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4
|
|
10
|
+
})
|
|
11
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
// WCAG 2's contrast ratio between two colors, 1 (identical) to 21 (black on white). Order doesn't matter.
|
|
15
|
+
export const getContrastRatio = (a: string, b: string): number => {
|
|
16
|
+
const [lighter, darker] = [getLuminance(a), getLuminance(b)].sort((x, y) => y - x)
|
|
17
|
+
return (lighter + 0.05) / (darker + 0.05)
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default getContrastRatio
|