feat: Lazy-load chroma/fuzzysort and add memory backend
Remove Shiggyenhancements plugin Replace eager chroma and fuzzysort imports with lazy require/cached loads to reduce startup bundle and runtime cost. Add createMemoryBackend (an in-memory storage with debounced persistence) and use it for fonts to accelerate startup. Add per-store write debouncers and change lodash import to a type-only import
This commit is contained in:
parent
8857eaf144
commit
98e65fcefe
11 changed files with 116 additions and 322 deletions
|
|
@ -36,7 +36,6 @@ export const getCorePlugins = (): CorePluginRecord => ({
|
|||
"bunny.notrack": makeLazyPlugin(() => require("./notrack")),
|
||||
"bunny.messagefix": makeLazyPlugin(() => require("./messagefix")),
|
||||
"bunny.fixembed": makeLazyPlugin(() => require("./fixembed")),
|
||||
"bunny.enhancements": makeLazyPlugin(() => require("./shiggyenhancements")),
|
||||
});
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,301 +0,0 @@
|
|||
import { defineCorePlugin } from "..";
|
||||
import { findByProps } from "@metro";
|
||||
import { logger } from "@lib/utils/logger";
|
||||
import { settings } from "@lib/api/settings";
|
||||
import { React } from "@metro/common";
|
||||
|
||||
const { TableRowGroup, TableRow, TableSwitchRow, Stack } = findByProps(
|
||||
"TableRowGroup",
|
||||
"TableRow",
|
||||
"TableSwitchRow",
|
||||
"Stack",
|
||||
);
|
||||
const { ScrollView } = require("react-native");
|
||||
|
||||
// Get ReactNative for NativeModules
|
||||
const { ReactNative } = window as any;
|
||||
const { DCDSoundManager } = ReactNative?.NativeModules || {};
|
||||
|
||||
// Sound settings type
|
||||
type SoundSettings = {
|
||||
enabled: boolean;
|
||||
probability: number;
|
||||
};
|
||||
|
||||
declare module "@lib/api/settings" {
|
||||
interface Settings {
|
||||
startupSound?: SoundSettings;
|
||||
}
|
||||
}
|
||||
|
||||
const soundUrl =
|
||||
"https://github.com/kmmiio99o/kmmiio99o.github.io/raw/refs/heads/main/music/shiggycord.mp3";
|
||||
const soundId = 6971;
|
||||
let soundDuration = -1;
|
||||
let timeoutId: NodeJS.Timeout | null = null;
|
||||
let isPlaying = false;
|
||||
let isPrepared = false;
|
||||
|
||||
// Function to prepare the sound
|
||||
const prepareSound = function (): Promise<any> {
|
||||
return new Promise(function (resolve) {
|
||||
if (!DCDSoundManager) {
|
||||
logger.error("DCDSoundManager not available");
|
||||
resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
DCDSoundManager.prepare(
|
||||
soundUrl,
|
||||
"music",
|
||||
soundId,
|
||||
function (error: any, sound: any) {
|
||||
if (error) {
|
||||
logger.error("Failed to prepare sound:", error);
|
||||
resolve(null);
|
||||
} else {
|
||||
resolve(sound);
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
// Function to play the sound
|
||||
async function playSound() {
|
||||
if (!DCDSoundManager) {
|
||||
logger.error("DCDSoundManager not available for playback");
|
||||
return;
|
||||
}
|
||||
|
||||
if (isPlaying) {
|
||||
if (timeoutId != null) clearTimeout(timeoutId);
|
||||
DCDSoundManager.stop(soundId);
|
||||
isPlaying = false;
|
||||
}
|
||||
|
||||
isPlaying = true;
|
||||
|
||||
try {
|
||||
await DCDSoundManager.play(soundId);
|
||||
|
||||
if (soundDuration > 0) {
|
||||
timeoutId = setTimeout(function () {
|
||||
isPlaying = false;
|
||||
DCDSoundManager.stop(soundId);
|
||||
timeoutId = null;
|
||||
}, soundDuration);
|
||||
}
|
||||
} catch (error) {
|
||||
logger.error("Error playing sound:", error);
|
||||
isPlaying = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we should play based on probability
|
||||
function shouldPlaySound(): boolean {
|
||||
const probability = settings.startupSound?.probability ?? 2;
|
||||
const random = Math.random() * 100;
|
||||
return random <= probability;
|
||||
}
|
||||
|
||||
export default defineCorePlugin({
|
||||
manifest: {
|
||||
id: "bunny.enhancements",
|
||||
version: "0.1.0",
|
||||
type: "plugin",
|
||||
spec: 3,
|
||||
main: "",
|
||||
display: {
|
||||
name: "Shiggy Enhancements",
|
||||
description:
|
||||
"Fixes common discord bugs because discord wont, and adds some features. (Originally Kettu Enhancements)",
|
||||
authors: [{ name: "cocobo1" }, { name: "Shiggy Team" }],
|
||||
},
|
||||
},
|
||||
|
||||
SettingsComponent() {
|
||||
const { useState, useEffect } = React;
|
||||
const [config, setConfig] = useState<SoundSettings>({
|
||||
enabled: settings.startupSound?.enabled ?? true,
|
||||
probability: settings.startupSound?.probability ?? 2,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
settings.startupSound = config;
|
||||
}, [config]);
|
||||
|
||||
const updateConfig = (
|
||||
key: keyof SoundSettings,
|
||||
value: boolean | number,
|
||||
) => {
|
||||
setConfig((prev) => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
// Get UI components including TextInput
|
||||
const {
|
||||
TableRowGroup: _TRG,
|
||||
TableRow: _TR,
|
||||
TableSwitchRow: _TSR,
|
||||
Stack: _S,
|
||||
TextInput: _TextInput,
|
||||
} = findByProps(
|
||||
"TableRowGroup",
|
||||
"TableRow",
|
||||
"TableSwitchRow",
|
||||
"Stack",
|
||||
"TextInput",
|
||||
);
|
||||
|
||||
// Fallback if table components aren't available
|
||||
if (!_TRG || !_TSR || !_TR || !_S) {
|
||||
const FallbackText =
|
||||
"Startup Sound UI unavailable (missing TableRow components).";
|
||||
return React.createElement(
|
||||
ScrollView,
|
||||
{ style: { flex: 1, padding: 12 } },
|
||||
FallbackText,
|
||||
);
|
||||
}
|
||||
|
||||
const TableRowGroup = _TRG;
|
||||
const TableRow = _TR;
|
||||
const TableSwitchRow = _TSR;
|
||||
const Stack = _S;
|
||||
const TextInput = _TextInput;
|
||||
|
||||
// Handle probability input change
|
||||
const handleProbabilityChange = (v: string) => {
|
||||
const num = parseInt(v);
|
||||
if (!isNaN(num) && num >= 0 && num <= 100) {
|
||||
updateConfig("probability", num);
|
||||
} else if (v === "") {
|
||||
updateConfig("probability", 0);
|
||||
}
|
||||
};
|
||||
|
||||
// Create settings elements
|
||||
const settingsElements = [];
|
||||
|
||||
// Startup Sound toggle with probability display
|
||||
settingsElements.push(
|
||||
React.createElement(
|
||||
TableRowGroup,
|
||||
{ title: "Startup Sound", key: "startup-sound" },
|
||||
React.createElement(TableSwitchRow, {
|
||||
label: "Enable Startup Sound",
|
||||
value: config.enabled,
|
||||
onValueChange: (v: boolean) => updateConfig("enabled", v),
|
||||
}),
|
||||
React.createElement(TableRow, {
|
||||
label: "Play Chance",
|
||||
subLabel: `Current: ${config.probability}% chance to play on startup`,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
// Probability input in its own invisible group
|
||||
if (TextInput) {
|
||||
settingsElements.push(
|
||||
React.createElement(
|
||||
TableRowGroup,
|
||||
{ title: "", key: "probability-input-group" },
|
||||
React.createElement(TextInput, {
|
||||
placeholder: "Enter probability (0-100)",
|
||||
value: config.probability.toString(),
|
||||
onChange: handleProbabilityChange,
|
||||
key: "probability-input",
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// About section
|
||||
settingsElements.push(
|
||||
React.createElement(
|
||||
TableRowGroup,
|
||||
{ title: "About", key: "about" },
|
||||
React.createElement(TableRow, {
|
||||
label: "Description",
|
||||
subLabel:
|
||||
"Shiggy Enhancements, more options, more features. Originally Kettu Enhancements with additinal features.",
|
||||
disabled: true,
|
||||
}),
|
||||
),
|
||||
);
|
||||
|
||||
return React.createElement(
|
||||
ScrollView,
|
||||
{ style: { flex: 1 } },
|
||||
React.createElement(
|
||||
Stack,
|
||||
{ spacing: 8, style: { padding: 10 } },
|
||||
...settingsElements,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
start() {
|
||||
logger.log("Shiggy Enhancements: Starting plugin");
|
||||
|
||||
// Initialize sound settings
|
||||
settings.startupSound = settings.startupSound || {
|
||||
enabled: false,
|
||||
probability: 2,
|
||||
};
|
||||
|
||||
// Check if DCDSoundManager is available
|
||||
if (!DCDSoundManager) {
|
||||
logger.error("DCDSoundManager not found - startup sound disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
// Play startup sound if enabled and probability check passes
|
||||
if (settings.startupSound.enabled && shouldPlaySound()) {
|
||||
logger.log(
|
||||
`Attempting to play startup sound (${settings.startupSound.probability}% chance)`,
|
||||
);
|
||||
|
||||
// Always prepare the sound fresh each time
|
||||
prepareSound()
|
||||
.then(function (sound) {
|
||||
if (sound) {
|
||||
isPrepared = true;
|
||||
soundDuration = sound.duration || 5000;
|
||||
logger.log(`Sound prepared, duration: ${soundDuration}ms`);
|
||||
playSound();
|
||||
logger.log(
|
||||
`Startup sound played (${settings.startupSound?.probability}% chance)`,
|
||||
);
|
||||
} else {
|
||||
logger.error("Failed to prepare sound");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
logger.error("Error in sound preparation:", error);
|
||||
});
|
||||
} else if (settings.startupSound.enabled) {
|
||||
logger.log(
|
||||
`Startup sound skipped due to probability (${settings.startupSound?.probability}% chance)`,
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
stop() {
|
||||
logger.log("Shiggy Enhancements: Stopping plugin");
|
||||
|
||||
// Stop and cleanup audio
|
||||
if (DCDSoundManager && isPlaying) {
|
||||
DCDSoundManager.stop(soundId);
|
||||
isPlaying = false;
|
||||
}
|
||||
|
||||
if (timeoutId) {
|
||||
clearTimeout(timeoutId);
|
||||
timeoutId = null;
|
||||
}
|
||||
|
||||
// Reset preparation state so it can play again next time
|
||||
isPrepared = false;
|
||||
},
|
||||
});
|
||||
|
|
@ -22,7 +22,6 @@ import {
|
|||
} from "@metro/common/components";
|
||||
import { ErrorBoundary, Search } from "@ui/components";
|
||||
import { isNotNil } from "es-toolkit";
|
||||
import fuzzysort from "fuzzysort";
|
||||
import {
|
||||
ComponentType,
|
||||
ReactNode,
|
||||
|
|
@ -181,6 +180,27 @@ export default function AddonPage<T extends object>({
|
|||
const { bottom: bottomInset } = useSafeAreaInsets();
|
||||
const navigation = NavigationNative.useNavigation();
|
||||
|
||||
// Lazy-load fuzzysort to reduce initial bundle size
|
||||
const fuzzysortRef = React.useRef<any>(null);
|
||||
const [fuzzysortReady, setFuzzysortReady] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
let mounted = true;
|
||||
import("fuzzysort")
|
||||
.then((mod) => {
|
||||
const f = (mod as any).default ?? mod;
|
||||
if (mounted) {
|
||||
fuzzysortRef.current = f;
|
||||
setFuzzysortReady(true);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
// ignore load errors
|
||||
});
|
||||
return () => {
|
||||
mounted = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (props.OptionsActionSheetComponent) {
|
||||
navigation.setOptions({
|
||||
|
|
@ -205,11 +225,13 @@ export default function AddonPage<T extends object>({
|
|||
const items = values.filter((i) => isNotNil(i) && typeof i === "object");
|
||||
if (!search && sortFn) items.sort(sortFn);
|
||||
|
||||
return fuzzysort.go(search, items, {
|
||||
if (!fuzzysortReady || !fuzzysortRef.current) return [] as any[];
|
||||
|
||||
return fuzzysortRef.current.go(search, items, {
|
||||
keys: props.searchKeywords,
|
||||
all: true,
|
||||
});
|
||||
}, [props.items, sortFn, search]);
|
||||
}, [props.items, sortFn, search, fuzzysortReady]);
|
||||
|
||||
const onInstallPress = useCallback(() => {
|
||||
if (!props.installAction) return () => {};
|
||||
|
|
|
|||
|
|
@ -11,10 +11,11 @@ import {
|
|||
Text,
|
||||
} from "@metro/common/components";
|
||||
import { showSheet } from "@ui/sheets";
|
||||
import chroma from "chroma-js";
|
||||
import { createContext, useContext, useMemo } from "react";
|
||||
import { Image, View } from "react-native";
|
||||
|
||||
const getChroma = () => require("chroma-js") as typeof import("chroma-js").default;
|
||||
|
||||
const CardContext = createContext<{
|
||||
plugin: UnifiedPluginModel;
|
||||
result: Fuzzysort.KeysResult<UnifiedPluginModel>;
|
||||
|
|
@ -22,7 +23,7 @@ const CardContext = createContext<{
|
|||
const useCardContext = () => useContext(CardContext);
|
||||
|
||||
function getHighlightColor(): import("react-native").ColorValue {
|
||||
return chroma(tokens.unsafe_rawColors.YELLOW_300).alpha(0.3).hex();
|
||||
return getChroma()(tokens.unsafe_rawColors.YELLOW_300).alpha(0.3).hex();
|
||||
}
|
||||
|
||||
function Title() {
|
||||
|
|
|
|||
|
|
@ -147,7 +147,12 @@ export const initVendettaObject = (): any => {
|
|||
return require("moment");
|
||||
},
|
||||
get chroma() {
|
||||
return require("chroma-js");
|
||||
// Lazy-load chroma-js to reduce startup cost
|
||||
const cached = (this as any)._chroma;
|
||||
if (cached) return cached;
|
||||
const loaded = require("chroma-js");
|
||||
(this as any)._chroma = loaded;
|
||||
return loaded;
|
||||
},
|
||||
get lodash() {
|
||||
return require("lodash");
|
||||
|
|
|
|||
|
|
@ -153,6 +153,8 @@ export interface StorageBackend {
|
|||
}
|
||||
|
||||
const ILLEGAL_CHARS_REGEX = /[<>:"/\\|?*]/g;
|
||||
// Debouncer map for per-store writes to disk
|
||||
const _writeDebouncers = new Map<string, any>();
|
||||
|
||||
const filePathFixer = (file: string): string => Platform.select({
|
||||
default: file,
|
||||
|
|
@ -215,6 +217,71 @@ export const createMMKVBackend = (store: string, defaultData = {}) => {
|
|||
})());
|
||||
};
|
||||
|
||||
// Lightweight in-memory backend to accelerate startup and avoid blocking IO
|
||||
// while still providing eventual persistence to the native storage.
|
||||
export const createMemoryBackend = (
|
||||
store: string,
|
||||
defaultData: any = {},
|
||||
) => {
|
||||
const mmkvPath = getMMKVPath(store);
|
||||
const defaultStr = JSON.stringify(defaultData);
|
||||
|
||||
// In-memory backing object used by the proxy immediately
|
||||
const memory: any = { ...defaultData };
|
||||
|
||||
// Load persisted data in background without blocking startup
|
||||
(async () => {
|
||||
try {
|
||||
const cached = await NativeCacheModule.getItem(store);
|
||||
if (cached) {
|
||||
const parsed = JSON.parse(cached);
|
||||
Object.assign(memory, parsed);
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
try {
|
||||
const path = `${NativeFileModule.getConstants().DocumentsDirPath}/${mmkvPath}`;
|
||||
if (await NativeFileModule.fileExists(path)) {
|
||||
const content = await NativeFileModule.readFile(path, "utf8");
|
||||
const data = JSON.parse(content);
|
||||
Object.assign(memory, data);
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
})();
|
||||
|
||||
// Hydration is intentionally omitted for stability in this rewrite
|
||||
|
||||
// Local path helper (inlined to avoid hoisting concerns)
|
||||
const fixPath = (file: string) =>
|
||||
Platform.select({ default: file, ios: NativeFileModule.saveFileToGallery ? file : `Documents/${file}` });
|
||||
|
||||
return {
|
||||
get: async () => memory,
|
||||
set: async (data: any) => {
|
||||
Object.assign(memory, data);
|
||||
// Debounced persistence to disk to avoid IO storms
|
||||
try {
|
||||
const existing = _writeDebouncers.get(store);
|
||||
if (existing) clearTimeout(existing);
|
||||
const timeout = setTimeout(async () => {
|
||||
try {
|
||||
await NativeFileModule.writeFile("documents", fixPath(mmkvPath), JSON.stringify(memory), "utf8");
|
||||
} catch {
|
||||
// ignore persistence errors to keep startup fast
|
||||
}
|
||||
}, 120);
|
||||
_writeDebouncers.set(store, timeout);
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
},
|
||||
} as unknown as StorageBackend;
|
||||
};
|
||||
|
||||
export const createFileBackend = (file: string, defaultData = {}, migratePromise?: Promise<void>): StorageBackend => {
|
||||
return {
|
||||
get: async () => {
|
||||
|
|
@ -239,4 +306,3 @@ export const createFileBackend = (file: string, defaultData = {}, migratePromise
|
|||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { awaitStorage, createMMKVBackend, createStorage, wrapSync } from "@core/vendetta/storage";
|
||||
import { awaitStorage, createMemoryBackend, createStorage, wrapSync } from "@core/vendetta/storage";
|
||||
import { clearFolder, downloadFile, fileExists, removeFile, writeFile } from "@lib/api/native/fs";
|
||||
import { safeFetch } from "@lib/utils";
|
||||
|
||||
|
|
@ -13,7 +13,8 @@ export type FontDefinition = {
|
|||
}
|
||||
|
||||
type FontStorage = Record<string, FontDefinition> & { __selected?: string; };
|
||||
export const fonts = wrapSync(createStorage<FontStorage>(createMMKVBackend("BUNNY_FONTS")));
|
||||
// Use a memory-backed storage for faster startup; persistence is still written back to disk
|
||||
export const fonts = wrapSync(createStorage<FontStorage>(createMemoryBackend("BUNNY_FONTS", {})));
|
||||
|
||||
async function writeFont(font: FontDefinition | null) {
|
||||
if (!font && font !== null) throw new Error("Arg font must be a valid object or null");
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { findByProps } from "@metro";
|
||||
import chroma from "chroma-js";
|
||||
import { omit } from "es-toolkit";
|
||||
import { Platform, processColor } from "react-native";
|
||||
|
||||
const getChroma = () => require("chroma-js") as typeof import("chroma-js").default;
|
||||
|
||||
import { colorsPref } from "./preferences";
|
||||
import { ColorManifest, InternalColorDefinition } from "./types";
|
||||
|
||||
|
|
@ -33,7 +34,7 @@ export function parseColorManifest(manifest: ColorManifest): InternalColorDefini
|
|||
} else if (typeof semanticColorValue === "string") {
|
||||
if (semanticColorValue.startsWith("#")) {
|
||||
semanticColorDefinitions[semanticColorKey] = {
|
||||
value: chroma(semanticColorValue).hex(),
|
||||
value: getChroma()(semanticColorValue).hex(),
|
||||
opacity: 1,
|
||||
};
|
||||
} else {
|
||||
|
|
@ -208,7 +209,7 @@ export function applyAndroidAlphaKeys(rawColors?: Record<string, string>) {
|
|||
for (const key in alphaMap) {
|
||||
const [colorKey, alpha] = alphaMap[key];
|
||||
if (!rawColors[colorKey]) continue;
|
||||
rawColors[key] = chroma(rawColors[colorKey]).alpha(alpha).hex();
|
||||
rawColors[key] = getChroma()(rawColors[colorKey]).alpha(alpha).hex();
|
||||
}
|
||||
|
||||
return rawColors;
|
||||
|
|
@ -221,11 +222,11 @@ export function normalizeToHex(colorString: string | undefined): string | undefi
|
|||
return "#00000000";
|
||||
}
|
||||
|
||||
if (chroma.valid(colorString)) return chroma(colorString).hex();
|
||||
if (getChroma().valid(colorString)) return getChroma()(colorString).hex();
|
||||
|
||||
const color = Number(processColor(colorString));
|
||||
|
||||
return chroma.rgb(
|
||||
return getChroma().rgb(
|
||||
color >> 16 & 0xff, // red
|
||||
color >> 8 & 0xff, // green
|
||||
color & 0xff, // blue
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { after } from "@lib/api/patcher";
|
|||
import { useObservable } from "@lib/api/storage";
|
||||
import { findInReactTree } from "@lib/utils";
|
||||
import { findByFilePathLazy } from "@metro";
|
||||
import chroma from "chroma-js";
|
||||
const getChroma = () => require("chroma-js") as typeof import("chroma-js").default;
|
||||
import { ImageBackground, StyleSheet } from "react-native";
|
||||
import { logger } from "@lib/utils/logger";
|
||||
|
||||
|
|
@ -43,7 +43,7 @@ export default function patchChatBackground() {
|
|||
|
||||
if (messagesComponent) {
|
||||
const flattened = StyleSheet.flatten(messagesComponent.props.style);
|
||||
const backgroundColor = chroma(
|
||||
const backgroundColor = getChroma()(
|
||||
flattened.backgroundColor || "black"
|
||||
).alpha(
|
||||
1 - (_colorRef.current.background?.opacity ?? 1)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import { before, instead } from "@lib/api/patcher";
|
|||
import { findByProps } from "@metro";
|
||||
import { byMutableProp } from "@metro/filters";
|
||||
import { createLazyModule } from "@metro/lazy";
|
||||
import chroma from "chroma-js";
|
||||
const getChroma = () => require("chroma-js") as typeof import("chroma-js").default;
|
||||
|
||||
const tokenReference = findByProps("SemanticColor");
|
||||
const isThemeModule = createLazyModule(byMutableProp("isThemeDark"));
|
||||
|
|
@ -67,14 +67,14 @@ export default function patchDefinitionAndResolver() {
|
|||
|
||||
if (semanticDef?.value) {
|
||||
if (semanticDef.opacity === 1) return semanticDef.value;
|
||||
return chroma(semanticDef.value).alpha(semanticDef.opacity).hex();
|
||||
return getChroma()(semanticDef.value).alpha(semanticDef.opacity).hex();
|
||||
}
|
||||
|
||||
const rawKey = colorDef.raw;
|
||||
const rawValue = rawKey ? currentRef.raw[rawKey] : undefined;
|
||||
if (rawValue) {
|
||||
// Set opacity if needed
|
||||
return (colorDef.opacity === 1) ? rawValue : chroma(rawValue).alpha(colorDef.opacity).hex();
|
||||
return (colorDef.opacity === 1) ? rawValue : getChroma()(rawValue).alpha(colorDef.opacity).hex();
|
||||
}
|
||||
|
||||
// Fallback to default
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { Nullish } from "@lib/utils/types";
|
||||
import { TextStyles, ThemeColors } from "@ui/types";
|
||||
import { Falsey } from "lodash";
|
||||
import type { Falsey } from "lodash";
|
||||
import { FC, MutableRefObject, PropsWithoutRef, ReactNode, RefObject } from "react";
|
||||
import type * as RN from "react-native";
|
||||
import { ImageSourcePropType, PressableProps } from "react-native";
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue