diff --git a/demo/DemoApp.tsx b/demo/DemoApp.tsx index 337c509..ad72cbf 100644 --- a/demo/DemoApp.tsx +++ b/demo/DemoApp.tsx @@ -39,6 +39,7 @@ import {Await, useAsync} from "../src/Async"; import {NotifyErrorsBoundary} from "../src/Components/Errors/NotifyErrorsBoundary"; import {DemoFailingComponent, DemoResetComponent} from "./DemoFailingComponent"; import {Tip} from "../src/Components/Tips/Tip"; +import {useKernelApplicationData} from "../src/KernelContext"; export function DemoApp() { @@ -73,6 +74,8 @@ export function DemoApp() const [failingComponentsCount, setFailingComponentsCount] = useState(0); + const [kernelApplicationData, setKernelApplicationData] = useKernelApplicationData("customData", ""); + return ( @@ -609,6 +612,23 @@ export function DemoApp() +

+ Global states +

+ + + + + + + + +
); } diff --git a/demo/DemoSubapp.tsx b/demo/DemoSubapp.tsx index d42b2a2..0132755 100644 --- a/demo/DemoSubapp.tsx +++ b/demo/DemoSubapp.tsx @@ -1,6 +1,7 @@ import React from "react"; import {Subapp, useSubapp} from "../src/Components/Subapps/Subapps"; import {Card} from "../src/Components/Card"; +import {useKernelApplicationData} from "../src/KernelContext"; /** * A demo Subapp component. @@ -10,6 +11,9 @@ export function DemoSubapp() // Get subapp close function. const {uuid, close} = useSubapp(); + // Get kernel application custom data. + const [kernelApplicationData] = useKernelApplicationData("customData", ""); + return ( @@ -17,6 +21,8 @@ export function DemoSubapp()

UUID : {uuid}

+ {kernelApplicationData &&

Kernel application data: {kernelApplicationData}

} +
diff --git a/index.ts b/index.ts index 97a20ca..bf6dbb1 100644 --- a/index.ts +++ b/index.ts @@ -49,4 +49,5 @@ export * from "./src/Components/Tips/Tip"; export * from "./src/Async"; export * from "./src/GlobalState"; +export * from "./src/KernelContext"; export * from "./src/Utils"; diff --git a/package.json b/package.json index 71f4d19..804f2e7 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "version": "1.7.1", + "version": "1.8.0", "name": "@kernelui/core", "description": "Kernel UI Core.", "scripts": { diff --git a/src/Application/Kernel.tsx b/src/Application/Kernel.tsx index 0734069..9d4e343 100644 --- a/src/Application/Kernel.tsx +++ b/src/Application/Kernel.tsx @@ -3,6 +3,7 @@ import React from "react"; import {createBrowserRouter, RouterProvider} from "react-router-dom"; import {CurtainsProvider} from "../Components/Curtains/Curtains"; import {NotificationsProvider} from "../Components/Notifications/Notifications"; +import {KernelContextProvider} from "../KernelContext"; /** * Main Kernel UI app component which initializes everything. @@ -14,17 +15,19 @@ export function Kernel({header, footer, router}: { }) { return ( - - - - {header} - - {footer} - - - + + + + + {header} + + {footer} + + + + ); } diff --git a/src/KernelContext.tsx b/src/KernelContext.tsx new file mode 100644 index 0000000..d763a72 --- /dev/null +++ b/src/KernelContext.tsx @@ -0,0 +1,111 @@ +import React, {useCallback, useContext, useMemo, useState} from "react"; + +/** + * Application data setter function type. + */ +export type ApplicationDataSetter = (identifier: IdentifierType, value: ValueType) => void; + +/** + * Application data dispatcher function type. + */ +export type KernelApplicationDataDispatcher = (value: ValueType) => void; + +/** + * Kernel application data type. + */ +export type KernelApplicationData = Record; + +/** + * Kernel context data. + */ +export interface KernelContextData +{ + application: { + data: KernelApplicationData; + setData: ApplicationDataSetter; + }; +} + +/** + * React Kernel context. + */ +export const KernelContext = React.createContext({ + application: { + data: {}, + setData: () => {}, + }, +}); + +/** + * Kernel context provider. + */ +export function KernelContextProvider({children}: React.PropsWithChildren<{}>) +{ + // Kernel application data initialization. + const [kernelApplicationData, setKernelApplicationData] = useState({}); + + /** + * Change application data function. + */ + const changeApplicationData = useCallback((applicationUpdate: Partial) => { + setKernelApplicationData({ + ...kernelApplicationData, + ...applicationUpdate, + }); + }, [kernelApplicationData, setKernelApplicationData]); + + /** + * Application data setter function. + */ + const applicationDataSetter = useCallback((identifier: string, data: any) => ( + changeApplicationData({ + [identifier]: data, + }) + ), [changeApplicationData]); + + // Initialize kernel context value. + const kernelContextValue = useMemo(() => ({ + application: { + data: kernelApplicationData, + setData: applicationDataSetter, + }, + }), [kernelApplicationData, applicationDataSetter]); + + return ( + + {children} + + ); +} + +/** + * Get kernel context data. + */ +export function useKernelContext(): KernelContextData +{ + return useContext(KernelContext); +} + +/** + * Initialize or get kernel application data with given identifier. + * @param identifier Application data identifier. + * @param initialValue Application data initial value. + */ +export function useKernelApplicationData(identifier: string, initialValue: T): [T, KernelApplicationDataDispatcher] +{ + /** + * Get kernel context. + */ + const kernelContext = useKernelContext(); + + /** + * Function to set application data. + */ + const setApplicationData = useCallback( + (newValue: T) => kernelContext.application.setData(identifier, newValue), + [kernelContext.application.setData] + ); + + // Return kernel application data. + return [kernelContext.application.data?.[identifier] ?? initialValue, setApplicationData]; +}