From 77e32aad2a48039af045e9c9ebe0ec134889625a Mon Sep 17 00:00:00 2001 From: Joseph Garrone Date: Sat, 8 Jun 2024 18:54:27 +0200 Subject: [PATCH] Make useGetClassName not a hook --- src/lib/useGetClassName.ts | 53 +++++++++++++++++++++++++++++++++----- 1 file changed, 46 insertions(+), 7 deletions(-) diff --git a/src/lib/useGetClassName.ts b/src/lib/useGetClassName.ts index 01e33215..e54365ef 100644 --- a/src/lib/useGetClassName.ts +++ b/src/lib/useGetClassName.ts @@ -1,24 +1,63 @@ import { clsx } from "keycloakify/tools/clsx"; -import { useConstCallback } from "keycloakify/tools/useConstCallback"; +import type { Param0 } from "tsafe"; + +// NOTE: Note for people trying to implement Keycloakify in other frontend +// frameworks. This can be used outside of React, useGetClassName isn't actually a hook. export function createUseClassName(params: { defaultClasses: Record; }) { const { defaultClasses } = params; + function areSameParams( + params1: Param0, + params2: Param0 + ): boolean { + if (params1.doUseDefaultCss !== params2.doUseDefaultCss) { + return false; + } + + if (params1.classes === params2.classes) { + return true; + } + + return JSON.stringify(params1.classes) === JSON.stringify(params2.classes); + } + + let cache: + | { + params: Param0; + result: ReturnType; + } + | undefined = undefined; + function useGetClassName(params: { doUseDefaultCss: boolean; classes: Partial> | undefined; - }) { - const { classes, doUseDefaultCss } = params; + }): { getClassName: (classKey: ClassKey) => string } { + // NOTE: We implement a cache here only so that getClassName can be stable across renders. + // We don't want to use useConstCallback because we want this to be useable outside of React. + use_cache: { + if (cache === undefined) { + break use_cache; + } - const getClassName = useConstCallback((classKey: ClassKey): string => { + if (!areSameParams(cache.params, params)) { + break use_cache; + } + + return cache.result; + } + + function getClassName(classKey: ClassKey): string { return clsx( classKey, - doUseDefaultCss ? defaultClasses[classKey] : undefined, - classes?.[classKey] + params.doUseDefaultCss ? defaultClasses[classKey] : undefined, + params.classes?.[classKey] ); - }); + } + + cache = { params, result: { getClassName } }; return { getClassName }; }