diff --git a/.scannerwork/.sonar_lock b/.scannerwork/.sonar_lock new file mode 100644 index 0000000..e69de29 diff --git a/.scannerwork/report-task.txt b/.scannerwork/report-task.txt new file mode 100644 index 0000000..0bc3250 --- /dev/null +++ b/.scannerwork/report-task.txt @@ -0,0 +1,6 @@ +projectKey=Portal-web +serverUrl=http://localhost:9000 +serverVersion=25.12.0.117093 +dashboardUrl=http://localhost:9000/dashboard?id=Portal-web +ceTaskId=67942efc-3d1c-48c5-87bd-022c220ed6ad +ceTaskUrl=http://localhost:9000/api/ce/task?id=67942efc-3d1c-48c5-87bd-022c220ed6ad diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7083ac1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "sonarlint.connectedMode.project": { + "connectionId": "http-localhost-9000", + "projectKey": "Portal-web" + } +} \ No newline at end of file diff --git a/app/components/EmotionRegistry.tsx b/app/components/EmotionRegistry.tsx new file mode 100644 index 0000000..e8c9edb --- /dev/null +++ b/app/components/EmotionRegistry.tsx @@ -0,0 +1,95 @@ +'use client'; + +import createCache from '@emotion/cache'; +import { useServerInsertedHTML } from 'next/navigation'; +import { CacheProvider as DefaultCacheProvider } from '@emotion/react'; +import type { EmotionCache, Options as OptionsOfCreateCache } from '@emotion/cache'; +import type { ReactNode } from 'react'; +import { useState } from 'react'; +import React from 'react'; + +export type NextAppDirEmotionCacheProviderProps = { + /** This is the options passed to createCache() from 'import createCache from "@emotion/cache"' */ + options: Omit; + /** By default from 'import { CacheProvider } from "@emotion/react"' */ + CacheProvider?: (props: { + value: EmotionCache; + children: ReactNode; + }) => React.JSX.Element | null; + children: ReactNode; +}; + +// Adapted from https://github.com/garronej/tss-react/blob/main/src/next/appDir.tsx +export default function NextAppDirEmotionCacheProvider(props: NextAppDirEmotionCacheProviderProps) { + const { options, CacheProvider = DefaultCacheProvider, children } = props; + + const [registry] = useState(() => { + const cache = createCache(options); + cache.compat = true; + const prevInsert = cache.insert; + let inserted: { name: string; isGlobal: boolean }[] = []; + cache.insert = (...args) => { + const [selector, serialized] = args; + if (cache.inserted[serialized.name] === undefined) { + inserted.push({ + name: serialized.name, + isGlobal: !selector, + }); + } + return prevInsert(...args); + }; + const flush = () => { + const prevInserted = inserted; + inserted = []; + return prevInserted; + }; + return { cache, flush }; + }); + + useServerInsertedHTML(() => { + const inserted = registry.flush(); + if (inserted.length === 0) { + return null; + } + let styles = ''; + let dataEmotionAttribute = registry.cache.key; + + const globals: { + name: string; + style: string; + }[] = []; + + inserted.forEach(({ name, isGlobal }) => { + const style = registry.cache.inserted[name]; + + if (style && typeof style !== 'boolean') { + if (isGlobal) { + globals.push({ name, style }); + } else { + styles += style; + dataEmotionAttribute += ` ${name}`; + } + } + }); + + return ( + <> + {globals.map(({ name, style }) => ( +