@principal-ade/industry-theme 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/cjs/ThemeProvider.d.ts +19 -0
  2. package/dist/cjs/ThemeProvider.d.ts.map +1 -0
  3. package/dist/cjs/ThemeShowcase.d.ts +24 -0
  4. package/dist/cjs/ThemeShowcase.d.ts.map +1 -0
  5. package/dist/cjs/defaultThemes.d.ts +8 -0
  6. package/dist/cjs/defaultThemes.d.ts.map +1 -0
  7. package/dist/cjs/glassmorphismTheme.d.ts +7 -0
  8. package/dist/cjs/glassmorphismTheme.d.ts.map +1 -0
  9. package/dist/cjs/index.d.ts +130 -0
  10. package/dist/cjs/index.d.ts.map +1 -0
  11. package/dist/cjs/index.js +1798 -0
  12. package/dist/cjs/package.json +1 -0
  13. package/dist/cjs/themeHelpers.d.ts +30 -0
  14. package/dist/cjs/themeHelpers.d.ts.map +1 -0
  15. package/dist/cjs/themes.d.ts +12 -0
  16. package/dist/cjs/themes.d.ts.map +1 -0
  17. package/dist/cjs/utils.d.ts +32 -0
  18. package/dist/cjs/utils.d.ts.map +1 -0
  19. package/dist/esm/ThemeProvider.d.ts +19 -0
  20. package/dist/esm/ThemeProvider.d.ts.map +1 -0
  21. package/dist/esm/ThemeShowcase.d.ts +24 -0
  22. package/dist/esm/ThemeShowcase.d.ts.map +1 -0
  23. package/dist/esm/defaultThemes.d.ts +8 -0
  24. package/dist/esm/defaultThemes.d.ts.map +1 -0
  25. package/dist/esm/glassmorphismTheme.d.ts +7 -0
  26. package/dist/esm/glassmorphismTheme.d.ts.map +1 -0
  27. package/dist/esm/index.d.ts +130 -0
  28. package/dist/esm/index.d.ts.map +1 -0
  29. package/dist/esm/index.js +1753 -0
  30. package/dist/esm/package.json +1 -0
  31. package/dist/esm/themeHelpers.d.ts +30 -0
  32. package/dist/esm/themeHelpers.d.ts.map +1 -0
  33. package/dist/esm/themes.d.ts +12 -0
  34. package/dist/esm/themes.d.ts.map +1 -0
  35. package/dist/esm/utils.d.ts +32 -0
  36. package/dist/esm/utils.d.ts.map +1 -0
  37. package/package.json +64 -0
  38. package/src/README.md +134 -0
  39. package/src/ThemeProvider.tsx +117 -0
  40. package/src/ThemeShowcase.tsx +442 -0
  41. package/src/defaultThemes.ts +369 -0
  42. package/src/glassmorphismTheme.ts +213 -0
  43. package/src/index.ts +230 -0
  44. package/src/themeHelpers.ts +106 -0
  45. package/src/themes.ts +746 -0
  46. package/src/utils.ts +135 -0
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,30 @@
1
+ import { Theme } from './index';
2
+ /**
3
+ * Override colors in a theme with type checking
4
+ */
5
+ export declare function overrideColors<T extends Theme>(theme: T, colors: Partial<T['colors']>): T;
6
+ /**
7
+ * Create a new theme by extending a base theme
8
+ */
9
+ export declare function makeTheme<T extends Theme>(baseTheme: T, overrides: Partial<{
10
+ colors: Partial<T['colors']>;
11
+ fonts: Partial<T['fonts']>;
12
+ fontSizes: T['fontSizes'];
13
+ space: T['space'];
14
+ radii: T['radii'];
15
+ }>): T;
16
+ /**
17
+ * Add a new mode to a theme
18
+ * @param theme - The theme to add the mode to
19
+ * @param modeName - The name of the new mode (e.g., 'dark', 'light', 'high-contrast')
20
+ * @param colors - Partial colors to override for this mode
21
+ * @param baseMode - Optional existing mode to extend from (defaults to base colors)
22
+ */
23
+ export declare function addMode<T extends Theme>(theme: T, modeName: string, colors: Partial<T['colors']>, baseMode?: string): T;
24
+ /**
25
+ * Get colors for a specific mode
26
+ * @param theme - The theme to get colors from
27
+ * @param mode - The mode name (returns base colors if mode doesn't exist)
28
+ */
29
+ export declare function getMode<T extends Theme>(theme: T, mode?: string): T['colors'];
30
+ //# sourceMappingURL=themeHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themeHelpers.d.ts","sourceRoot":"","sources":["../../src/themeHelpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAEhC;;GAEG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,KAAK,EAC5C,KAAK,EAAE,CAAC,EACR,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAC3B,CAAC,CAQH;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,KAAK,EACvC,SAAS,EAAE,CAAC,EACZ,SAAS,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7B,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3B,SAAS,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1B,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IAClB,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;CACnB,CAAC,GACD,CAAC,CAaH;AAED;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,KAAK,EACrC,KAAK,EAAE,CAAC,EACR,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAC5B,QAAQ,CAAC,EAAE,MAAM,GAChB,CAAC,CA6BH;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,KAAK,EACrC,KAAK,EAAE,CAAC,EACR,IAAI,CAAC,EAAE,MAAM,GACZ,CAAC,CAAC,QAAQ,CAAC,CASb"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Collection of available themes for PrincipleMD
3
+ */
4
+ import { Theme } from './index';
5
+ export { glassmorphismTheme } from './glassmorphismTheme';
6
+ export { defaultMarkdownTheme, defaultEditorTheme, defaultTerminalTheme, } from './defaultThemes';
7
+ export declare const regalTheme: Theme;
8
+ export declare const terminalTheme: Theme;
9
+ export declare const matrixTheme: Theme;
10
+ export declare const matrixMinimalTheme: Theme;
11
+ export declare const slateTheme: Theme;
12
+ //# sourceMappingURL=themes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"themes.d.ts","sourceRoot":"","sources":["../../src/themes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,iBAAiB,CAAC;AAGzB,eAAO,MAAM,UAAU,EAAE,KAsIxB,CAAC;AAGF,eAAO,MAAM,aAAa,EAAE,KA6K3B,CAAC;AAGF,eAAO,MAAM,WAAW,EAAE,KA0IzB,CAAC;AAGF,eAAO,MAAM,kBAAkB,EAAE,KA0IhC,CAAC;AAGF,eAAO,MAAM,UAAU,EAAE,KAyIxB,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { Theme } from './index';
2
+ type StyleValue = string | number | StyleValue[] | {
3
+ [key: string]: StyleValue;
4
+ };
5
+ type StyleObject = Record<string, StyleValue>;
6
+ /**
7
+ * Utility functions for working with the Theme UI spec-compliant theme
8
+ */
9
+ export declare const getColor: (theme: Theme, colorKey: string) => string;
10
+ export declare const getSpace: (theme: Theme, index: number) => number;
11
+ export declare const getFontSize: (theme: Theme, index: number) => number;
12
+ export declare const getRadius: (theme: Theme, index: number) => number;
13
+ export declare const getShadow: (theme: Theme, index: number) => string;
14
+ export declare const getZIndex: (theme: Theme, index: number) => number;
15
+ export declare const responsive: (values: (string | number)[]) => object;
16
+ export declare const sx: (styles: StyleObject) => StyleObject;
17
+ export declare const createStyle: (theme: Theme, styleObj: StyleObject) => StyleObject;
18
+ export declare const mergeThemes: (baseTheme: Theme, ...overrides: Partial<Theme>[]) => Theme;
19
+ declare const _default: {
20
+ getColor: (theme: Theme, colorKey: string) => string;
21
+ getSpace: (theme: Theme, index: number) => number;
22
+ getFontSize: (theme: Theme, index: number) => number;
23
+ getRadius: (theme: Theme, index: number) => number;
24
+ getShadow: (theme: Theme, index: number) => string;
25
+ getZIndex: (theme: Theme, index: number) => number;
26
+ responsive: (values: (string | number)[]) => object;
27
+ sx: (styles: StyleObject) => StyleObject;
28
+ createStyle: (theme: Theme, styleObj: StyleObject) => StyleObject;
29
+ mergeThemes: (baseTheme: Theme, ...overrides: Partial<Theme>[]) => Theme;
30
+ };
31
+ export default _default;
32
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAGhC,KAAK,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,UAAU,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAAA;CAAE,CAAC;AACjF,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAE9C;;GAEG;AAGH,eAAO,MAAM,QAAQ,GAAI,OAAO,KAAK,EAAE,UAAU,MAAM,KAAG,MAKzD,CAAC;AAGF,eAAO,MAAM,QAAQ,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,KAAG,MAEtD,CAAC;AAGF,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,KAAG,MAEzD,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,KAAG,MAEvD,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,KAAG,MAEvD,CAAC;AAGF,eAAO,MAAM,SAAS,GAAI,OAAO,KAAK,EAAE,OAAO,MAAM,KAAG,MAEvD,CAAC;AAGF,eAAO,MAAM,UAAU,GAAI,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAG,MAUxD,CAAC;AAGF,eAAO,MAAM,EAAE,GAAI,QAAQ,WAAW,gBAAW,CAAC;AAGlD,eAAO,MAAM,WAAW,GAAI,OAAO,KAAK,EAAE,UAAU,WAAW,KAAG,WAmCjE,CAAC;AAGF,eAAO,MAAM,WAAW,GAAI,WAAW,KAAK,EAAE,GAAG,WAAW,OAAO,CAAC,KAAK,CAAC,EAAE,KAAG,KAuB9E,CAAC;;sBA9G8B,KAAK,YAAY,MAAM,KAAG,MAAM;sBAQhC,KAAK,SAAS,MAAM,KAAG,MAAM;yBAK1B,KAAK,SAAS,MAAM,KAAG,MAAM;uBAK/B,KAAK,SAAS,MAAM,KAAG,MAAM;uBAK7B,KAAK,SAAS,MAAM,KAAG,MAAM;uBAK7B,KAAK,SAAS,MAAM,KAAG,MAAM;yBAK3B,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,KAAG,MAAM;iBAapC,WAAW;yBAGH,KAAK,YAAY,WAAW,KAAG,WAAW;6BAsCtC,KAAK,gBAAgB,OAAO,CAAC,KAAK,CAAC,EAAE,KAAG,KAAK;;AAyBpF,wBAWE"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@principal-ade/industry-theme",
3
+ "version": "0.1.2",
4
+ "type": "module",
5
+ "description": "Theme components and styles for industry-themed markdown",
6
+ "main": "./dist/cjs/index.js",
7
+ "module": "./dist/esm/index.js",
8
+ "types": "./dist/esm/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/esm/index.d.ts",
12
+ "import": "./dist/esm/index.js",
13
+ "require": "./dist/cjs/index.js"
14
+ }
15
+ },
16
+ "scripts": {
17
+ "build": "npm run build:clean && npm run build:esm && npm run build:cjs && npm run build:types && npm run build:copy-package-files",
18
+ "build:clean": "rm -rf dist",
19
+ "build:esm": "bun build ./src/index.ts --outfile ./dist/esm/index.js --format esm --external react",
20
+ "build:cjs": "bun build ./src/index.ts --outfile ./dist/cjs/index.js --format cjs --external react",
21
+ "build:types": "tsc --emitDeclarationOnly --declaration --declarationMap --outDir ./dist/esm",
22
+ "build:copy-package-files": "echo '{\"type\":\"module\"}' > dist/esm/package.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json && cp -r dist/esm/*.d.ts dist/esm/*.d.ts.map dist/esm/types dist/esm/utils dist/cjs/ 2>/dev/null || true",
23
+ "dev": "npm run build --watch",
24
+ "test": "bun test",
25
+ "typecheck": "tsc --noEmit",
26
+ "lint": "eslint . --ext .ts,.tsx",
27
+ "lint:fix": "eslint . --ext .ts,.tsx --fix",
28
+ "format": "prettier --write .",
29
+ "format:check": "prettier --check .",
30
+ "clean": "rm -rf dist"
31
+ },
32
+ "keywords": [
33
+ "markdown",
34
+ "theme",
35
+ "industry"
36
+ ],
37
+ "author": "Principal ADE Team",
38
+ "license": "MIT",
39
+ "devDependencies": {
40
+ "@eslint/js": "^9.32.0",
41
+ "@types/bun": "latest",
42
+ "@types/react": "^19.1.12",
43
+ "eslint": "^9.32.0",
44
+ "eslint-config-prettier": "^10.1.8",
45
+ "eslint-import-resolver-typescript": "^4.4.4",
46
+ "eslint-plugin-import": "^2.32.0",
47
+ "prettier": "^3.6.2",
48
+ "react": ">=19.0.0",
49
+ "typescript": "^5.0.4",
50
+ "typescript-eslint": "^8.38.0"
51
+ },
52
+ "peerDependencies": {
53
+ "react": ">=19.0.0"
54
+ },
55
+ "files": [
56
+ "dist",
57
+ "src",
58
+ "README.md"
59
+ ],
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "git+https://github.com/principal-ade/industry-theme.git"
63
+ }
64
+ }
package/src/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # Theme UI Spec-Compliant Theme System
2
+
3
+ This directory contains a new Theme UI specification-compliant theme system for the PrincipleMD electron-react project.
4
+
5
+ ## Files
6
+
7
+ - **`index.ts`** - Main theme configuration following Theme UI spec
8
+ - **`ThemeProvider.tsx`** - React context provider and useTheme hook
9
+ - **`utils.ts`** - Utility functions for working with theme values
10
+ - **`README.md`** - This documentation
11
+
12
+ ## Usage
13
+
14
+ ### 1. Wrap your app with the ThemeProvider
15
+
16
+ ```tsx
17
+ import { ThemeProvider } from './theme/ThemeProvider';
18
+ import { theme } from './theme';
19
+
20
+ function App() {
21
+ return (
22
+ <ThemeProvider theme={theme} initialColorMode="light">
23
+ <YourApp />
24
+ </ThemeProvider>
25
+ );
26
+ }
27
+ ```
28
+
29
+ ### 2. Use the theme in components
30
+
31
+ ```tsx
32
+ import { useTheme } from './theme/ThemeProvider';
33
+ import { getSpace, getFontSize } from './theme/utils';
34
+
35
+ function MyComponent() {
36
+ const { theme, colorMode, toggleColorMode } = useTheme();
37
+
38
+ return (
39
+ <div
40
+ style={{
41
+ backgroundColor: theme.colors.background,
42
+ color: theme.colors.text,
43
+ padding: getSpace(theme, 4), // theme.space[4]
44
+ fontSize: getFontSize(theme, 2), // theme.fontSizes[2]
45
+ }}
46
+ >
47
+ Current mode: {colorMode}
48
+ <button onClick={toggleColorMode}>Toggle Mode</button>
49
+ </div>
50
+ );
51
+ }
52
+ ```
53
+
54
+ ### 3. Available theme properties
55
+
56
+ #### Colors
57
+
58
+ - `theme.colors.text` - Primary text color
59
+ - `theme.colors.background` - Primary background color
60
+ - `theme.colors.primary` - Primary brand color
61
+ - `theme.colors.secondary` - Secondary brand color
62
+ - `theme.colors.success` - Success state color
63
+ - `theme.colors.warning` - Warning state color
64
+ - `theme.colors.error` - Error state color
65
+ - `theme.colors.border` - Border color
66
+ - `theme.colors.backgroundSecondary` - Secondary background
67
+ - `theme.colors.textSecondary` - Secondary text color
68
+
69
+ #### Typography
70
+
71
+ - `theme.fonts.body` - Body font family
72
+ - `theme.fonts.heading` - Heading font family
73
+ - `theme.fonts.monospace` - Monospace font family
74
+ - `theme.fontSizes[0-9]` - Font size scale (12px to 96px)
75
+ - `theme.fontWeights.body` - Body font weight
76
+ - `theme.fontWeights.heading` - Heading font weight
77
+
78
+ #### Spacing & Layout
79
+
80
+ - `theme.space[0-8]` - Spacing scale (0px to 512px)
81
+ - `theme.radii[0-7]` - Border radius scale (0px to 24px)
82
+ - `theme.shadows[0-5]` - Box shadow scale
83
+ - `theme.breakpoints` - Responsive breakpoints
84
+
85
+ ### 4. Utility functions
86
+
87
+ ```tsx
88
+ import { getColor, getSpace, getFontSize, getRadius } from './theme/utils';
89
+
90
+ // Get theme values safely
91
+ const backgroundColor = getColor(theme, 'background');
92
+ const padding = getSpace(theme, 3); // theme.space[3]
93
+ const fontSize = getFontSize(theme, 2); // theme.fontSizes[2]
94
+ const borderRadius = getRadius(theme, 1); // theme.radii[1]
95
+ ```
96
+
97
+ ## Color Modes
98
+
99
+ The theme system supports automatic light/dark mode switching:
100
+
101
+ - Automatically detects system preference on first load
102
+ - Saves user preference to localStorage
103
+ - Provides `toggleColorMode()` function
104
+ - Dark mode colors are defined in `theme.colors.modes.dark`
105
+
106
+ ## Migration from old theme
107
+
108
+ The new theme maintains backward compatibility with existing color property names:
109
+
110
+ ```tsx
111
+ // Old usage (still works)
112
+ theme.colors.background;
113
+ theme.colors.primary;
114
+ theme.colors.textSecondary;
115
+
116
+ // New Theme UI spec additions
117
+ theme.fontSizes[2]; // instead of hardcoded values
118
+ theme.space[4]; // instead of hardcoded spacing
119
+ theme.radii[2]; // instead of hardcoded border radius
120
+ ```
121
+
122
+ ## Theme UI Specification Compliance
123
+
124
+ This theme follows the [Theme UI theme specification](https://theme-ui.com/theme-spec) which provides:
125
+
126
+ - Consistent scales for spacing, typography, and colors
127
+ - Responsive design support
128
+ - Component variant support
129
+ - Color mode handling
130
+ - Standard naming conventions
131
+
132
+ ## Example Component
133
+
134
+ See `ThemeExample.tsx` for a comprehensive example showing all theme features.
@@ -0,0 +1,117 @@
1
+ import React, { createContext, useContext, ReactNode, useState, useEffect } from 'react';
2
+
3
+ import { getMode } from './themeHelpers';
4
+
5
+ import { Theme, theme as defaultTheme } from './index';
6
+
7
+ // Theme context
8
+ interface ThemeContextValue {
9
+ theme: Theme;
10
+ mode?: string;
11
+ setMode: (mode: string) => void;
12
+ }
13
+
14
+ // Create a singleton context instance that persists across module boundaries
15
+ let ThemeContext: React.Context<ThemeContextValue | undefined>;
16
+
17
+ // Use a global variable to ensure single instance across all imports
18
+ const getThemeContext = () => {
19
+ if (typeof window !== 'undefined') {
20
+ // Store on window to ensure true singleton in browser
21
+ const globalWindow = window as Window & {
22
+ __principlemd_theme_context__?: React.Context<ThemeContextValue | undefined>;
23
+ };
24
+ if (!globalWindow.__principlemd_theme_context__) {
25
+ globalWindow.__principlemd_theme_context__ = createContext<ThemeContextValue | undefined>(
26
+ undefined,
27
+ );
28
+ }
29
+ return globalWindow.__principlemd_theme_context__;
30
+ } else {
31
+ // Server-side rendering or Node environment
32
+ if (!ThemeContext) {
33
+ ThemeContext = createContext<ThemeContextValue | undefined>(undefined);
34
+ }
35
+ return ThemeContext;
36
+ }
37
+ };
38
+
39
+ // Get the singleton context
40
+ const ThemeContextSingleton = getThemeContext();
41
+
42
+ // Hook to use theme
43
+ export const useTheme = (): ThemeContextValue => {
44
+ const context = useContext(ThemeContextSingleton);
45
+
46
+ if (!context) {
47
+ throw new Error('useTheme must be used within a ThemeProvider');
48
+ }
49
+ return context as ThemeContextValue;
50
+ };
51
+
52
+ // Theme provider component
53
+ interface ThemeProviderProps {
54
+ children: ReactNode;
55
+ theme?: Theme;
56
+ initialMode?: string;
57
+ }
58
+
59
+ export const ThemeProvider: React.FC<ThemeProviderProps> = ({
60
+ children,
61
+ theme: customTheme = defaultTheme,
62
+ initialMode,
63
+ }) => {
64
+ const [mode, setMode] = useState<string | undefined>(initialMode);
65
+
66
+ // Get the theme with the current mode applied
67
+ const activeTheme = React.useMemo(() => {
68
+ if (!mode || !customTheme.modes || !customTheme.modes[mode]) {
69
+ return customTheme;
70
+ }
71
+
72
+ // Apply the mode colors to the theme
73
+ return {
74
+ ...customTheme,
75
+ colors: getMode(customTheme, mode),
76
+ };
77
+ }, [customTheme, mode]);
78
+
79
+ // Load saved mode from localStorage on mount
80
+ useEffect(() => {
81
+ if (!initialMode) {
82
+ const savedMode = localStorage.getItem('principlemd-theme-mode');
83
+ if (savedMode) {
84
+ setMode(savedMode);
85
+ }
86
+ }
87
+ }, [initialMode]);
88
+
89
+ // Save mode to localStorage when it changes
90
+ useEffect(() => {
91
+ if (mode) {
92
+ localStorage.setItem('principlemd-theme-mode', mode);
93
+ } else {
94
+ localStorage.removeItem('principlemd-theme-mode');
95
+ }
96
+ }, [mode]);
97
+
98
+ const value: ThemeContextValue = {
99
+ theme: activeTheme,
100
+ mode,
101
+ setMode,
102
+ };
103
+
104
+ return <ThemeContextSingleton.Provider value={value}>{children}</ThemeContextSingleton.Provider>;
105
+ };
106
+
107
+ // Higher-order component for theme access
108
+ export const withTheme = <P extends object>(
109
+ Component: React.ComponentType<P & { theme: Theme }>,
110
+ ) => {
111
+ return (props: P) => {
112
+ const { theme } = useTheme();
113
+ return <Component {...props} theme={theme} />;
114
+ };
115
+ };
116
+
117
+ export default ThemeProvider;