flowbite-svelte
Version:
Flowbite components for Svelte
74 lines (73 loc) • 3.13 kB
JavaScript
import {} from "..";
import { getContext } from "svelte";
// import { dev } from "$app/environment";
// for svelte users not using sveltekit substitute the above line with the following line
const dev = import.meta.env.MODE === "development";
export function getTheme(componentKey) {
const theme = getContext("theme");
return theme?.[componentKey];
}
/**
* Warns about deprecated theme-related props and suggests modern alternatives.
*
* Shows the component name, deprecated props, migration hints, and usage location (in dev mode).
*
* @param component - Name of the component using deprecated props.
* @param names - Record of deprecated prop names and their values.
* @param replacements - Optional map of deprecated keys to their replacements (e.g., "divClass" → "div").
*/
export function warnThemeDeprecation(component, names, replacements) {
if (!dev)
return;
const nonEmptyNames = Object.keys(names).filter((name) => names[name]);
if (nonEmptyNames.length === 0)
return;
let migrationHint = "";
const usesClass = nonEmptyNames.some((name) => replacements?.[name] === "class");
const propText = usesClass ? `"classes" or "class"` : `"classes"`;
if (replacements) {
const classProps = [];
const classesObjectEntries = [];
for (const name of nonEmptyNames) {
const newKey = replacements[name];
const value = names[name];
if (!newKey || !value)
continue;
if (newKey === "class") {
classProps.push(`class="${value}"`);
}
else {
classesObjectEntries.push(`${newKey}: "${value}"`);
}
}
const hintLines = [];
if (classProps.length > 0)
hintLines.push(...classProps);
if (classesObjectEntries.length > 0) {
hintLines.push(`classes={{ ${classesObjectEntries.join(", ")} }}`);
}
if (hintLines.length > 0) {
migrationHint = `\nMigration example: ${hintLines.join(" ")}`;
}
}
// Stack trace parsing to find external caller
const stack = new Error().stack;
const externalCaller = getExternalCaller(stack);
console.warn(`⚠️ The following "${component}" props are deprecated: ${nonEmptyNames.map((n) => `"${n}"`).join(", ")}.\n` + `💡 Please use the ${propText} prop instead.${migrationHint}\n` + (externalCaller ? `🔍 Used at: ${externalCaller}` : ""));
}
// Extracts the first file in the stack trace that is NOT the current component file
function getExternalCaller(stack) {
if (!stack)
return null;
const lines = stack.split("\n").slice(2); // skip "Error" and self-call
const currentFileMatch = lines[0]?.match(/(?:\()?(.*?\.svelte):\d+:\d+\)?$/);
const currentFile = currentFileMatch?.[1];
for (const line of lines) {
const match = line.match(/(?:\()?(.*?\.svelte):\d+:\d+\)?$/);
const file = match?.[1];
if (file && file !== currentFile) {
return line.trim().replace(/^at /, ""); // Clean format
}
}
return null;
}