@rific/auto-paper 0.13.3 → 0.14.0

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/dist/index.js CHANGED
@@ -51,13 +51,19 @@ __export(index_exports, {
51
51
  SEMANTIC_BASE_COLORS: () => SEMANTIC_BASE_COLORS,
52
52
  TextInput: () => TextInput,
53
53
  ThemeSettingsContext: () => ThemeSettingsContext,
54
+ createChalkboardTone: () => createChalkboardTone,
54
55
  createThemeReducer: () => createThemeReducer,
55
56
  defaultColors: () => defaultColors,
56
57
  defaultThemeSettings: () => defaultThemeSettings,
57
58
  getBlendedColor: () => getBlendedColor,
59
+ getChalkboardColor: () => getChalkboardColor,
58
60
  getColorRoles: () => getColorRoles,
59
61
  getContrastColor: () => getContrastColor,
62
+ getContrastRatio: () => getContrastRatio,
60
63
  getHex: () => getHex,
64
+ getLuminance: () => getLuminance,
65
+ getOklch: () => getOklch,
66
+ getOklchHex: () => getOklchHex,
61
67
  getRgb: () => getRgb,
62
68
  getThirdColor: () => getThirdColor,
63
69
  getTintTextColor: () => getTintTextColor,
@@ -77,6 +83,7 @@ __export(index_exports, {
77
83
  useComputedTheme: () => useComputedTheme,
78
84
  useMaskedViewModule: () => useMaskedViewModule,
79
85
  useNavBarContext: () => useNavBarContext,
86
+ usePaletteTone: () => usePaletteTone,
80
87
  usePaperDefaults: () => usePaperDefaults,
81
88
  useReanimatedModule: () => useReanimatedModule,
82
89
  useThemeBridgeProps: () => useThemeBridgeProps,
@@ -330,13 +337,13 @@ var getRgb = (value) => {
330
337
  var getHex = (value) => {
331
338
  const rgb = getRgb(value);
332
339
  if (!rgb) return null;
333
- const toHex = (n) => {
340
+ const toHex2 = (n) => {
334
341
  const hex = Math.round(n).toString(16);
335
342
  return hex.length === 1 ? "0" + hex : hex;
336
343
  };
337
- const hexString = `#${toHex(rgb.r)}${toHex(rgb.g)}${toHex(rgb.b)}`;
344
+ const hexString = `#${toHex2(rgb.r)}${toHex2(rgb.g)}${toHex2(rgb.b)}`;
338
345
  if (rgb.a !== void 0) {
339
- return `${hexString}${toHex(rgb.a * 255)}`;
346
+ return `${hexString}${toHex2(rgb.a * 255)}`;
340
347
  }
341
348
  return hexString;
342
349
  };
@@ -353,6 +360,21 @@ var getBlendedColor = (foreground, background, alpha) => {
353
360
  return getHex(`rgb(${r}, ${g}, ${b})`) ?? background;
354
361
  };
355
362
 
363
+ // src/utils/getContrastRatio.ts
364
+ var getLuminance = (value) => {
365
+ const rgb = getRgb(value);
366
+ if (!rgb) return 0;
367
+ const [r, g, b] = [rgb.r, rgb.g, rgb.b].map((channel) => {
368
+ const c = channel / 255;
369
+ return c <= 0.03928 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
370
+ });
371
+ return 0.2126 * r + 0.7152 * g + 0.0722 * b;
372
+ };
373
+ var getContrastRatio = (a, b) => {
374
+ const [lighter, darker] = [getLuminance(a), getLuminance(b)].sort((x, y) => y - x);
375
+ return (lighter + 0.05) / (darker + 0.05);
376
+ };
377
+
356
378
  // src/utils/getTonalColor.ts
357
379
  var getTonalColor = (color, lightness) => {
358
380
  const rgb = getRgb(color);
@@ -417,11 +439,13 @@ var isDarkColor = (value) => {
417
439
  };
418
440
 
419
441
  // src/utils/getColorRoles.ts
442
+ var MIN_LIGHT_ON_COLOR_CONTRAST = 2.5;
420
443
  var getColorRoles = (base, surface, containerAlpha = 0.15) => {
421
444
  const container = getBlendedColor(base, surface, containerAlpha);
445
+ const lightOnColor = getTonalColor(base, 0.95);
422
446
  return {
423
447
  color: base,
424
- onColor: getTonalColor(base, isDarkColor(base) ? 0.95 : 0.08),
448
+ onColor: getContrastRatio(lightOnColor, base) >= MIN_LIGHT_ON_COLOR_CONTRAST ? lightOnColor : getTonalColor(base, 0.08),
425
449
  container,
426
450
  onContainer: getTonalColor(base, isDarkColor(container) ? 0.92 : 0.12)
427
451
  };
@@ -501,11 +525,11 @@ function hslToHex(h, s, l) {
501
525
  g = 0;
502
526
  b = x;
503
527
  }
504
- const toHex = (value) => {
528
+ const toHex2 = (value) => {
505
529
  const hex = Math.round((value + m) * 255).toString(16);
506
530
  return hex.length === 1 ? `0${hex}` : hex;
507
531
  };
508
- return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
532
+ return `#${toHex2(r)}${toHex2(g)}${toHex2(b)}`;
509
533
  }
510
534
 
511
535
  // src/useComputedTheme.ts
@@ -518,7 +542,7 @@ var SEMANTIC_BASE_COLORS = {
518
542
  warning: "#A15C00",
519
543
  danger: "#B00020"
520
544
  };
521
- function useComputedTheme(appearance, color, harmony = "split-complementary") {
545
+ function useComputedTheme(appearance, color, harmony = "split-complementary", paletteTone) {
522
546
  const [theme, setTheme] = (0, import_react3.useState)(null);
523
547
  const primaryInput = typeof color === "string" ? color : color.primary;
524
548
  const secondaryInput = typeof color === "string" ? null : color.secondary;
@@ -551,7 +575,8 @@ function useComputedTheme(appearance, color, harmony = "split-complementary") {
551
575
  onDangerContainer: dangerRoles.onContainer
552
576
  }
553
577
  };
554
- const palette = secondaryInput !== null && tertiaryInput !== null ? { primary: normalizeExplicitColor(primaryInput), secondary: normalizeExplicitColor(secondaryInput), tertiary: normalizeExplicitColor(tertiaryInput) } : getTriadicPalette(primaryInput, harmony);
578
+ const untoned = secondaryInput !== null && tertiaryInput !== null ? { primary: normalizeExplicitColor(primaryInput), secondary: normalizeExplicitColor(secondaryInput), tertiary: normalizeExplicitColor(tertiaryInput) } : getTriadicPalette(primaryInput, harmony);
579
+ const palette = paletteTone ? { primary: paletteTone(untoned.primary, base.dark), secondary: paletteTone(untoned.secondary, base.dark), tertiary: paletteTone(untoned.tertiary, base.dark) } : untoned;
555
580
  const primaryRoles = getColorRoles(palette.primary, surface);
556
581
  _theme.colors.primary = primaryRoles.color;
557
582
  _theme.colors.onPrimary = primaryRoles.onColor;
@@ -584,7 +609,7 @@ function useComputedTheme(appearance, color, harmony = "split-complementary") {
584
609
  level5: getBlendedColor(blendedGrey, _theme.colors.surface, 0.7)
585
610
  };
586
611
  setTheme(_theme);
587
- }, [appearance, primaryInput, secondaryInput, tertiaryInput, harmony]);
612
+ }, [appearance, primaryInput, secondaryInput, tertiaryInput, harmony, paletteTone]);
588
613
  (0, import_react3.useEffect)(() => {
589
614
  computeTheme();
590
615
  }, [computeTheme]);
@@ -605,15 +630,17 @@ var ReanimatedModuleContext = (0, import_react4.createContext)(void 0);
605
630
  var useReanimatedModule = () => (0, import_react4.useContext)(ReanimatedModuleContext);
606
631
  var MaskedViewModuleContext = (0, import_react4.createContext)(void 0);
607
632
  var useMaskedViewModule = () => (0, import_react4.useContext)(MaskedViewModuleContext);
633
+ var PaletteToneContext = (0, import_react4.createContext)(void 0);
634
+ var usePaletteTone = () => (0, import_react4.useContext)(PaletteToneContext);
608
635
  var StatusBarEnabledContext = (0, import_react4.createContext)(true);
609
636
  var useStatusBarEnabled = () => (0, import_react4.useContext)(StatusBarEnabledContext);
610
- function Provider({ children, defaults, expoBlur, fontFamily, initialValue, maskedView, navigationBar, onChange, onNavBarChange, onReady, reanimated, statusBar, statusBarProps, style }) {
611
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeSettingsProvider, { initialValue, onChange, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeProviderBody, { defaults, expoBlur, fontFamily, maskedView, navigationBar, onNavBarChange, onReady, reanimated, statusBar, statusBarProps, style, children }) });
637
+ function Provider({ children, defaults, expoBlur, fontFamily, initialValue, maskedView, navigationBar, onChange, onNavBarChange, onReady, paletteTone, reanimated, statusBar, statusBarProps, style }) {
638
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeSettingsProvider, { initialValue, onChange, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ThemeProviderBody, { defaults, expoBlur, fontFamily, maskedView, navigationBar, onNavBarChange, onReady, paletteTone, reanimated, statusBar, statusBarProps, style, children }) });
612
639
  }
613
640
  var ThemeSettingsProvider = themeSettingsProvider;
614
- function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, maskedView, navigationBar, onNavBarChange, onReady, reanimated, statusBar = true, statusBarProps, style }) {
641
+ function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, maskedView, navigationBar, onNavBarChange, onReady, paletteTone, reanimated, statusBar = true, statusBarProps, style }) {
615
642
  const { settings } = useThemeSettingsInternal();
616
- const computedTheme = useComputedTheme(settings.appearance, settings.color, settings.harmony);
643
+ const computedTheme = useComputedTheme(settings.appearance, settings.color, settings.harmony, paletteTone);
617
644
  const theme = (0, import_react4.useMemo)(() => {
618
645
  if (!computedTheme) return null;
619
646
  if (!fontFamily) return computedTheme;
@@ -629,7 +656,7 @@ function ThemeProviderBody({ children, defaults, expoBlur, fontFamily, maskedVie
629
656
  if (!theme) return null;
630
657
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_react_native_paper2.Provider, { theme, children: [
631
658
  statusBar && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.StatusBar, { barStyle: theme.dark ? "light-content" : "dark-content", ...statusBarProps }),
632
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBarEnabledContext.Provider, { value: statusBar, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MaskedViewModuleContext.Provider, { value: maskedView, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper2.Portal.Host, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) }) }) }) })
659
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(StatusBarEnabledContext.Provider, { value: statusBar, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PaperDefaultsContext.Provider, { value: defaults ?? {}, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(NavBarContext.Provider, { value: { navigationBar, onNavBarChange }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(BlurModuleContext.Provider, { value: expoBlur, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReanimatedModuleContext.Provider, { value: reanimated, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MaskedViewModuleContext.Provider, { value: maskedView, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PaletteToneContext.Provider, { value: paletteTone, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native_paper2.Portal.Host, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react_native2.View, { style: [styles.flex, { backgroundColor: theme.colors.background }, style], children }) }) }) }) }) }) }) }) })
633
660
  ] });
634
661
  }
635
662
  var styles = import_react_native2.StyleSheet.create({
@@ -682,6 +709,10 @@ var AutoAppearancePicker = (props) => {
682
709
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AppearancePicker, { ...props, value: settings.appearance, onChange: (appearance) => set({ appearance }) });
683
710
  };
684
711
 
712
+ // src/components/AutoPalettePicker.tsx
713
+ var import_react10 = require("react");
714
+ var import_react_native_paper10 = require("react-native-paper");
715
+
685
716
  // src/utils/resolveSeedColor.ts
686
717
  var resolveSeedColor = (color) => typeof color === "string" ? color : color.primary;
687
718
 
@@ -932,19 +963,25 @@ var buildWedges = (weights) => {
932
963
  ];
933
964
  };
934
965
  var Pie = ({ palette, weights = defaultWeights, size = SIZE2 }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: [styles4.pie, { borderRadius: size / 2, height: size, width: size }], children: buildWedges(weights).map(({ key, rotate, share }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: [styles4.rotator, { transform: [{ rotate: `${rotate}deg` }] }], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: styles4.halfMask, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: [styles4.innerRotator, { transform: [{ rotate: `${share - 180}deg` }] }], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: [styles4.wedgeFill, { backgroundColor: palette[key] }] }) }) }) }, key)) });
935
- var PalettePicker = ({ value, onChange, harmony = "split-complementary", onHarmonyChange, weights, colors = defaultColors, blur: blurProp }) => {
966
+ var PalettePicker = ({ value, onChange, harmony = "split-complementary", onHarmonyChange, weights, colors = defaultColors, blur: blurProp, previewColor }) => {
936
967
  const blur = useBlur(blurProp);
937
968
  const { colors: themeColors } = (0, import_react_native_paper9.useTheme)();
938
969
  const [open, setOpen] = (0, import_react9.useState)(false);
939
970
  const { onLayout, size } = useSwatchSize(SIZE2);
971
+ const shade = (0, import_react9.useMemo)(
972
+ () => (palette) => previewColor ? { primary: previewColor(palette.primary), secondary: previewColor(palette.secondary), tertiary: previewColor(palette.tertiary) } : palette,
973
+ [previewColor]
974
+ );
975
+ const triggerPalette = shade(getTriadicPalette(value, harmony));
976
+ const swatchPalettes = (0, import_react9.useMemo)(() => colors.map(({ value: hex }) => shade(getTriadicPalette(hex, harmony))), [colors, harmony, shade]);
940
977
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
941
978
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper9.TouchableRipple, { onPress: () => setOpen(true), style: styles4.trigger, borderless: true, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_react_native7.View, { style: styles4.triggerContent, children: [
942
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pie, { palette: getTriadicPalette(value, harmony), weights }),
943
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { pointerEvents: "none", style: [styles4.triggerIcon, { borderRadius: SIZE2 / 2 }, getSwatchRing(value, false, themeColors.outlineVariant)], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper9.Icon, { source: "palette", size: 20, color: getContrastColor(value) }) })
979
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pie, { palette: triggerPalette, weights }),
980
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { pointerEvents: "none", style: [styles4.triggerIcon, { borderRadius: SIZE2 / 2 }, getSwatchRing(triggerPalette.primary, false, themeColors.outlineVariant)], children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper9.Icon, { source: "palette", size: 20, color: getContrastColor(triggerPalette.primary) }) })
944
981
  ] }) }),
945
982
  /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Dialog, { blur, visible: open, onDismiss: () => setOpen(false), children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(Dialog.Content, { children: [
946
983
  onHarmonyChange && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: styles4.harmonyRow, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(HarmonyPicker, { value: harmony, onChange: onHarmonyChange, showLabels: false }) }),
947
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: styles4.swatches, onLayout, children: colors.map(({ value: hex }) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
984
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { style: styles4.swatches, onLayout, children: colors.map(({ value: hex }, index) => /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
948
985
  import_react_native7.TouchableOpacity,
949
986
  {
950
987
  onPress: () => {
@@ -953,8 +990,8 @@ var PalettePicker = ({ value, onChange, harmony = "split-complementary", onHarmo
953
990
  },
954
991
  style: [styles4.swatch, { height: size, width: size }],
955
992
  children: [
956
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pie, { palette: getTriadicPalette(hex, harmony), weights, size }),
957
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { pointerEvents: "none", style: [styles4.ring, { borderRadius: size / 2 }, getSwatchRing(hex, value === hex, themeColors.outlineVariant)], children: value === hex && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper9.Icon, { source: "check", size: 20, color: getContrastColor(hex) }) })
993
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Pie, { palette: swatchPalettes[index], weights, size }),
994
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native7.View, { pointerEvents: "none", style: [styles4.ring, { borderRadius: size / 2 }, getSwatchRing(swatchPalettes[index].primary, value === hex, themeColors.outlineVariant)], children: value === hex && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_react_native_paper9.Icon, { source: "check", size: 20, color: getContrastColor(swatchPalettes[index].primary) }) })
958
995
  ]
959
996
  },
960
997
  hex
@@ -981,13 +1018,16 @@ var styles4 = import_react_native7.StyleSheet.create({
981
1018
  var import_jsx_runtime10 = require("react/jsx-runtime");
982
1019
  var AutoPalettePicker = (props) => {
983
1020
  const { settings, set } = useThemeSettings();
984
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PalettePicker, { ...props, value: resolveSeedColor(settings.color), onChange: (color) => set({ color }), harmony: settings.harmony, onHarmonyChange: (harmony) => set({ harmony }) });
1021
+ const tone = usePaletteTone();
1022
+ const { dark } = (0, import_react_native_paper10.useTheme)();
1023
+ const toned = (0, import_react10.useCallback)((color) => tone(color, dark), [tone, dark]);
1024
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PalettePicker, { ...props, value: resolveSeedColor(settings.color), onChange: (color) => set({ color }), harmony: settings.harmony, onHarmonyChange: (harmony) => set({ harmony }), previewColor: tone ? toned : void 0 });
985
1025
  };
986
1026
 
987
1027
  // src/components/BottomNavigation.tsx
988
- var import_react10 = require("react");
1028
+ var import_react11 = require("react");
989
1029
  var import_react_native8 = require("react-native");
990
- var import_react_native_paper10 = require("react-native-paper");
1030
+ var import_react_native_paper11 = require("react-native-paper");
991
1031
 
992
1032
  // src/navigation-bar.ts
993
1033
  var setNavigationBarStyle = (navigationBar, dark) => {
@@ -998,9 +1038,9 @@ var setNavigationBarStyle = (navigationBar, dark) => {
998
1038
  // src/components/BottomNavigation.tsx
999
1039
  var import_jsx_runtime11 = require("react/jsx-runtime");
1000
1040
  function useNavigationBarSync() {
1001
- const theme = (0, import_react_native_paper10.useTheme)();
1041
+ const theme = (0, import_react_native_paper11.useTheme)();
1002
1042
  const { navigationBar, onNavBarChange } = useNavBarContext();
1003
- (0, import_react10.useEffect)(() => {
1043
+ (0, import_react11.useEffect)(() => {
1004
1044
  if (import_react_native8.Platform.OS !== "android") return;
1005
1045
  if (onNavBarChange) onNavBarChange(theme.colors.surface, theme.dark);
1006
1046
  else if (navigationBar) setNavigationBarStyle(navigationBar, theme.dark);
@@ -1009,53 +1049,53 @@ function useNavigationBarSync() {
1009
1049
  function BottomNavigationComponent(props) {
1010
1050
  const defaults = usePaperDefaults();
1011
1051
  useNavigationBarSync();
1012
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper10.BottomNavigation, { ...defaults.BottomNavigation, ...props });
1052
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper11.BottomNavigation, { ...defaults.BottomNavigation, ...props });
1013
1053
  }
1014
1054
  function Bar(props) {
1015
1055
  useNavigationBarSync();
1016
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper10.BottomNavigation.Bar, { ...props });
1056
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native_paper11.BottomNavigation.Bar, { ...props });
1017
1057
  }
1018
1058
  BottomNavigationComponent.Bar = Bar;
1019
- BottomNavigationComponent.SceneMap = import_react_native_paper10.BottomNavigation?.SceneMap;
1059
+ BottomNavigationComponent.SceneMap = import_react_native_paper11.BottomNavigation?.SceneMap;
1020
1060
  var BottomNavigation = BottomNavigationComponent;
1021
1061
 
1022
1062
  // src/components/Button.tsx
1023
- var import_react_native_paper11 = require("react-native-paper");
1063
+ var import_react_native_paper12 = require("react-native-paper");
1024
1064
  var import_jsx_runtime12 = require("react/jsx-runtime");
1025
1065
  function Button(props) {
1026
1066
  const defaults = usePaperDefaults();
1027
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper11.Button, { ...defaults.Button, ...props });
1067
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_react_native_paper12.Button, { ...defaults.Button, ...props });
1028
1068
  }
1029
1069
 
1030
1070
  // src/components/Chip.tsx
1031
- var import_react_native_paper12 = require("react-native-paper");
1071
+ var import_react_native_paper13 = require("react-native-paper");
1032
1072
  var import_jsx_runtime13 = require("react/jsx-runtime");
1033
1073
  function Chip({ variant, style, selectedColor, ...props }) {
1034
1074
  const defaults = usePaperDefaults();
1035
- const { colors } = (0, import_react_native_paper12.useTheme)();
1075
+ const { colors } = (0, import_react_native_paper13.useTheme)();
1036
1076
  const variantStyle = variant === "primary" ? { backgroundColor: colors.primaryContainer } : variant === "secondary" ? { backgroundColor: colors.secondaryContainer } : variant === "tertiary" ? { backgroundColor: colors.tertiaryContainer } : variant === "surface" ? { backgroundColor: colors.surface } : void 0;
1037
1077
  const variantSelectedColor = variant === "primary" ? colors.onPrimaryContainer : variant === "secondary" ? colors.onSecondaryContainer : variant === "tertiary" ? colors.onTertiaryContainer : variant === "surface" ? colors.onSurface : void 0;
1038
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper12.Chip, { ...defaults.Chip, selectedColor: selectedColor ?? variantSelectedColor, ...props, style: [variantStyle, style] });
1078
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native_paper13.Chip, { ...defaults.Chip, selectedColor: selectedColor ?? variantSelectedColor, ...props, style: [variantStyle, style] });
1039
1079
  }
1040
1080
 
1041
1081
  // src/components/FAB.tsx
1042
- var import_react_native_paper13 = require("react-native-paper");
1082
+ var import_react_native_paper14 = require("react-native-paper");
1043
1083
  var import_jsx_runtime14 = require("react/jsx-runtime");
1044
1084
  function FAB(props) {
1045
1085
  const defaults = usePaperDefaults();
1046
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper13.FAB, { ...defaults.FAB, ...props });
1086
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_react_native_paper14.FAB, { ...defaults.FAB, ...props });
1047
1087
  }
1048
1088
 
1049
1089
  // src/components/FadingScrollView.tsx
1050
- var import_react11 = require("react");
1090
+ var import_react12 = require("react");
1051
1091
  var import_react_native9 = require("react-native");
1052
1092
  var import_jsx_runtime15 = require("react/jsx-runtime");
1053
1093
  var SCROLL_FADE_HEIGHT = 24;
1054
1094
  function FadingScrollView({ style, fadeHeight = SCROLL_FADE_HEIGHT, onScroll, onLayout, onContentSizeChange, scrollEventThrottle = 16, children, ...rest }) {
1055
1095
  const MaskedView = useMaskedViewModule();
1056
- const sizes = (0, import_react11.useRef)({ viewport: 0, content: 0, offset: 0 });
1057
- const [edges, setEdges] = (0, import_react11.useState)(NO_EDGES);
1058
- const update = (0, import_react11.useCallback)(() => {
1096
+ const sizes = (0, import_react12.useRef)({ viewport: 0, content: 0, offset: 0 });
1097
+ const [edges, setEdges] = (0, import_react12.useState)(NO_EDGES);
1098
+ const update = (0, import_react12.useCallback)(() => {
1059
1099
  const { viewport, content, offset } = sizes.current;
1060
1100
  const above = offset > 1;
1061
1101
  const below = content - viewport - offset > 1;
@@ -1129,20 +1169,20 @@ var styles5 = import_react_native9.StyleSheet.create({
1129
1169
  });
1130
1170
 
1131
1171
  // src/components/IconButton.tsx
1132
- var import_react_native_paper14 = require("react-native-paper");
1172
+ var import_react_native_paper15 = require("react-native-paper");
1133
1173
  var import_jsx_runtime16 = require("react/jsx-runtime");
1134
1174
  function IconButton({ variant, iconColor, containerColor, ...props }) {
1135
1175
  const defaults = usePaperDefaults();
1136
- const { colors } = (0, import_react_native_paper14.useTheme)();
1176
+ const { colors } = (0, import_react_native_paper15.useTheme)();
1137
1177
  const variantContainerColor = variant === "primary" ? colors.primaryContainer : variant === "secondary" ? colors.secondaryContainer : variant === "tertiary" ? colors.tertiaryContainer : variant === "surface" ? colors.surface : void 0;
1138
1178
  const variantIconColor = variant === "primary" ? colors.onPrimaryContainer : variant === "secondary" ? colors.onSecondaryContainer : variant === "tertiary" ? colors.onTertiaryContainer : variant === "surface" ? colors.onSurface : void 0;
1139
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper14.IconButton, { ...defaults.IconButton, containerColor: containerColor ?? variantContainerColor, iconColor: iconColor ?? variantIconColor, ...props });
1179
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_react_native_paper15.IconButton, { ...defaults.IconButton, containerColor: containerColor ?? variantContainerColor, iconColor: iconColor ?? variantIconColor, ...props });
1140
1180
  }
1141
1181
 
1142
1182
  // src/components/Menu.tsx
1143
- var import_react12 = require("react");
1183
+ var import_react13 = require("react");
1144
1184
  var import_react_native10 = require("react-native");
1145
- var import_react_native_paper15 = require("react-native-paper");
1185
+ var import_react_native_paper16 = require("react-native-paper");
1146
1186
  var import_jsx_runtime17 = require("react/jsx-runtime");
1147
1187
  var ANIMATION_DURATION2 = 250;
1148
1188
  var EASING = import_react_native10.Easing.bezier(0.4, 0, 0.2, 1);
@@ -1151,11 +1191,11 @@ var SHADOW_HEIGHT = [0, 1, 2, 4, 6, 8];
1151
1191
  var SHADOW_RADIUS = [0, 3, 6, 8, 10, 12];
1152
1192
  var AnimatedBlurView2 = import_react_native10.Animated.createAnimatedComponent(BlurView);
1153
1193
  var FadingBlurView = ({ blur, children, elevation, theme: themeOverrides, visible }) => {
1154
- const { animation, roundness } = (0, import_react_native_paper15.useTheme)(themeOverrides);
1155
- const [opacity] = (0, import_react12.useState)(() => new import_react_native10.Animated.Value(0));
1156
- const [closing, setClosing] = (0, import_react12.useState)(false);
1194
+ const { animation, roundness } = (0, import_react_native_paper16.useTheme)(themeOverrides);
1195
+ const [opacity] = (0, import_react13.useState)(() => new import_react_native10.Animated.Value(0));
1196
+ const [closing, setClosing] = (0, import_react13.useState)(false);
1157
1197
  if (!visible && !closing) setClosing(true);
1158
- (0, import_react12.useEffect)(() => {
1198
+ (0, import_react13.useEffect)(() => {
1159
1199
  import_react_native10.Animated.timing(opacity, { duration: animation.scale * ANIMATION_DURATION2, easing: EASING, toValue: closing ? 0 : 1, useNativeDriver: false }).start();
1160
1200
  }, [animation.scale, closing, opacity]);
1161
1201
  const shadow = elevation > 0 ? { shadowColor: "#000000", shadowOffset: { height: SHADOW_HEIGHT[elevation], width: 0 }, shadowOpacity: 0.3, shadowRadius: SHADOW_RADIUS[elevation] } : null;
@@ -1164,10 +1204,10 @@ var FadingBlurView = ({ blur, children, elevation, theme: themeOverrides, visibl
1164
1204
  var MenuComponent = ({ blur: blurProp, children, ...props }) => {
1165
1205
  const blur = useBlur(blurProp);
1166
1206
  const web = import_react_native10.Platform.OS === "web";
1167
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper15.Menu, { ...props, contentStyle: [styles6.content, web && styles6.webSurface, props.contentStyle], children: web ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FadingBlurView, { blur, elevation: props.mode === "flat" ? 0 : props.elevation ?? DEFAULT_ELEVATION, theme: props.theme, visible: props.visible, children }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BlurView, { blur, children }) });
1207
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_react_native_paper16.Menu, { ...props, contentStyle: [styles6.content, web && styles6.webSurface, props.contentStyle], children: web ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(FadingBlurView, { blur, elevation: props.mode === "flat" ? 0 : props.elevation ?? DEFAULT_ELEVATION, theme: props.theme, visible: props.visible, children }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(BlurView, { blur, children }) });
1168
1208
  };
1169
1209
  var Menu = Object.assign(MenuComponent, {
1170
- Item: import_react_native_paper15.Menu.Item
1210
+ Item: import_react_native_paper16.Menu.Item
1171
1211
  });
1172
1212
  var styles6 = import_react_native10.StyleSheet.create({
1173
1213
  content: { backgroundColor: "transparent", paddingVertical: 0 },
@@ -1175,12 +1215,12 @@ var styles6 = import_react_native10.StyleSheet.create({
1175
1215
  });
1176
1216
 
1177
1217
  // src/components/TextInput.tsx
1178
- var import_react13 = require("react");
1179
- var import_react_native_paper16 = require("react-native-paper");
1218
+ var import_react14 = require("react");
1219
+ var import_react_native_paper17 = require("react-native-paper");
1180
1220
  var import_jsx_runtime18 = require("react/jsx-runtime");
1181
- var TextInput = (0, import_react13.forwardRef)(function TextInput2(props, ref) {
1221
+ var TextInput = (0, import_react14.forwardRef)(function TextInput2(props, ref) {
1182
1222
  const defaults = usePaperDefaults();
1183
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper16.TextInput, { ref, ...defaults.TextInput, ...props });
1223
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(import_react_native_paper17.TextInput, { ref, ...defaults.TextInput, ...props });
1184
1224
  });
1185
1225
 
1186
1226
  // src/redux/themeSlice.ts
@@ -1205,16 +1245,99 @@ var selectThemeColor = themeSlice.selectors.selectColor;
1205
1245
  var selectThemeHarmony = themeSlice.selectors.selectHarmony;
1206
1246
 
1207
1247
  // src/useTheme.ts
1208
- var import_react_native_paper17 = require("react-native-paper");
1209
- var useAutoPaperTheme = () => (0, import_react_native_paper17.useTheme)();
1248
+ var import_react_native_paper18 = require("react-native-paper");
1249
+ var useAutoPaperTheme = () => (0, import_react_native_paper18.useTheme)();
1210
1250
 
1211
1251
  // src/useThemeBridgeProps.ts
1212
- var import_react14 = require("react");
1252
+ var import_react15 = require("react");
1213
1253
  function useThemeBridgeProps(props) {
1214
1254
  const { initialValue, onChange, onReady } = props;
1215
- return (0, import_react14.useMemo)(() => ({ initialValue, onChange, onReady }), [initialValue, onChange, onReady]);
1255
+ return (0, import_react15.useMemo)(() => ({ initialValue, onChange, onReady }), [initialValue, onChange, onReady]);
1216
1256
  }
1217
1257
 
1258
+ // src/utils/getOklch.ts
1259
+ var toLinear = (c) => c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
1260
+ var toGamma = (c) => c <= 31308e-7 ? 12.92 * c : 1.055 * c ** (1 / 2.4) - 0.055;
1261
+ var linearToOklab = ([r, g, b]) => {
1262
+ const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
1263
+ const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
1264
+ const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
1265
+ return [0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s, 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s, 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s];
1266
+ };
1267
+ var oklabToLinear = ([L, a, b]) => {
1268
+ const l = (L + 0.3963377774 * a + 0.2158037573 * b) ** 3;
1269
+ const m = (L - 0.1055613458 * a - 0.0638541728 * b) ** 3;
1270
+ const s = (L - 0.0894841775 * a - 1.291485548 * b) ** 3;
1271
+ return [4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s, -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s, -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s];
1272
+ };
1273
+ var inGamut = (rgb) => rgb.every((v) => v >= -1e-6 && v <= 1 + 1e-6);
1274
+ var clamp01 = (v) => Math.min(1, Math.max(0, v));
1275
+ var toHex = (rgb) => `#${rgb.map(
1276
+ (v) => Math.round(clamp01(toGamma(clamp01(v))) * 255).toString(16).padStart(2, "0")
1277
+ ).join("")}`;
1278
+ var getOklch = (value) => {
1279
+ const rgb = getRgb(value);
1280
+ if (!rgb) return null;
1281
+ const [l, a, b] = linearToOklab([toLinear(rgb.r / 255), toLinear(rgb.g / 255), toLinear(rgb.b / 255)]);
1282
+ return { l, c: Math.hypot(a, b), h: (Math.atan2(b, a) * 180 / Math.PI + 360) % 360 };
1283
+ };
1284
+ var getOklchHex = ({ l, c, h }) => {
1285
+ const lightness = Math.min(1, Math.max(0, l));
1286
+ const radians = h * Math.PI / 180;
1287
+ const atChroma = (chroma) => oklabToLinear([lightness, chroma * Math.cos(radians), chroma * Math.sin(radians)]);
1288
+ const direct = atChroma(Math.max(0, c));
1289
+ if (inGamut(direct)) return toHex(direct);
1290
+ let low = 0;
1291
+ let high = c;
1292
+ for (let i = 0; i < 24; i++) {
1293
+ const mid = (low + high) / 2;
1294
+ if (inGamut(atChroma(mid))) low = mid;
1295
+ else high = mid;
1296
+ }
1297
+ return toHex(atChroma(low));
1298
+ };
1299
+
1300
+ // src/utils/getChalkboardColor.ts
1301
+ var MARKER = { maxLightness: 0.6, chroma: 0.85 };
1302
+ var CHALK = { lightness: 0.86, lift: 0.5, chroma: 0.8, minLuminance: 0.5 };
1303
+ var CACHE_LIMIT = 512;
1304
+ var createChalkboardTone = (options = {}) => {
1305
+ const marker = { ...MARKER, ...options.marker };
1306
+ const chalk = { ...CHALK, ...options.chalk };
1307
+ const cache = /* @__PURE__ */ new Map();
1308
+ const toMarker = (color) => {
1309
+ const oklch = getOklch(color);
1310
+ if (!oklch) return color;
1311
+ return getOklchHex({ l: Math.min(oklch.l, marker.maxLightness), c: oklch.c * marker.chroma, h: oklch.h });
1312
+ };
1313
+ const toChalk = (color) => {
1314
+ const oklch = getOklch(color);
1315
+ if (!oklch) return color;
1316
+ const c = oklch.c * chalk.chroma;
1317
+ const lifted = oklch.l < chalk.lightness ? oklch.l + (chalk.lightness - oklch.l) * chalk.lift : oklch.l;
1318
+ const result = getOklchHex({ l: lifted, c, h: oklch.h });
1319
+ if (getLuminance(result) >= chalk.minLuminance) return result;
1320
+ let low = lifted;
1321
+ let high = 1;
1322
+ for (let i = 0; i < 20; i++) {
1323
+ const mid = (low + high) / 2;
1324
+ if (getLuminance(getOklchHex({ l: mid, c, h: oklch.h })) >= chalk.minLuminance) high = mid;
1325
+ else low = mid;
1326
+ }
1327
+ return getOklchHex({ l: high, c, h: oklch.h });
1328
+ };
1329
+ return (color, dark) => {
1330
+ const key = `${dark ? "d" : "l"}${color}`;
1331
+ const cached = cache.get(key);
1332
+ if (cached !== void 0) return cached;
1333
+ const result = dark ? toChalk(color) : toMarker(color);
1334
+ if (cache.size >= CACHE_LIMIT) cache.clear();
1335
+ cache.set(key, result);
1336
+ return result;
1337
+ };
1338
+ };
1339
+ var getChalkboardColor = createChalkboardTone();
1340
+
1218
1341
  // src/utils/getThirdColor.ts
1219
1342
  function rgbToHsl(r, g, b) {
1220
1343
  r /= 255;
@@ -1319,13 +1442,19 @@ var getTintTextColor = (tintColor, backdropColor, tintOpacity) => {
1319
1442
  SEMANTIC_BASE_COLORS,
1320
1443
  TextInput,
1321
1444
  ThemeSettingsContext,
1445
+ createChalkboardTone,
1322
1446
  createThemeReducer,
1323
1447
  defaultColors,
1324
1448
  defaultThemeSettings,
1325
1449
  getBlendedColor,
1450
+ getChalkboardColor,
1326
1451
  getColorRoles,
1327
1452
  getContrastColor,
1453
+ getContrastRatio,
1328
1454
  getHex,
1455
+ getLuminance,
1456
+ getOklch,
1457
+ getOklchHex,
1329
1458
  getRgb,
1330
1459
  getThirdColor,
1331
1460
  getTintTextColor,
@@ -1345,6 +1474,7 @@ var getTintTextColor = (tintColor, backdropColor, tintOpacity) => {
1345
1474
  useComputedTheme,
1346
1475
  useMaskedViewModule,
1347
1476
  useNavBarContext,
1477
+ usePaletteTone,
1348
1478
  usePaperDefaults,
1349
1479
  useReanimatedModule,
1350
1480
  useThemeBridgeProps,