Skip to content

Commit 8afb32f

Browse files
authored
Merge pull request #9 from codingapi/dev
fix #8
2 parents fb91b97 + a70c30d commit 8afb32f

File tree

15 files changed

+369
-15
lines changed

15 files changed

+369
-15
lines changed

README.md

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,65 @@ export default HttpTest;
361361
362362
```
363363

364+
### 主题控制
365+
366+
```
367+
import React from "react";
368+
import Space from "@/components/Space";
369+
import {ThemeContext, ThemeProviderContext} from "../../../src";
370+
import {EventBus} from "@codingapi/ui-framework";
371+
372+
const ThemeTest = () => {
373+
374+
const themeContext = React.useContext(ThemeProviderContext);
375+
376+
const [fontSize, setFontSize] = React.useState(themeContext?.getTheme().token.contentFontSize);
377+
378+
React.useEffect(() => {
379+
EventBus.getInstance().on(ThemeContext.EVENT_CHANGE_CONTENT_FONT_SIZE, (data: string) => {
380+
setFontSize(data);
381+
});
382+
383+
return () => {
384+
EventBus.getInstance().off(ThemeContext.EVENT_CHANGE_CONTENT_FONT_SIZE);
385+
}
386+
}, [])
387+
388+
return (
389+
<>
390+
<div
391+
style={{
392+
textAlign: 'center'
393+
}}
394+
>
395+
<h1>Theme Test </h1>
396+
</div>
397+
<Space>
398+
<div>
399+
font size:{fontSize}
400+
</div>
401+
<button onClick={() => {
402+
themeContext?.setSmallFontSize();
403+
}}>small font size
404+
</button>
405+
<button
406+
onClick={() => {
407+
themeContext?.setMiddleFontSize();
408+
}}
409+
>middle font size
410+
</button>
411+
<button onClick={() => {
412+
themeContext?.setLargeFontSize();
413+
}}>large font size
414+
</button>
415+
</Space>
416+
</>
417+
)
418+
}
419+
420+
export default ThemeTest;
421+
```
422+
364423
更多实例参考: https://github.com/codingapi/ui-framework/tree/main/playground
365424

366425
## 主要特性

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@codingapi/ui-framework",
3-
"version": "0.0.36",
3+
"version": "0.0.37",
44
"description": "A UI Framework built with React and Typescript",
55
"keywords": [
66
"ui",
@@ -29,10 +29,12 @@
2929
"@types/node": "^22.15.2",
3030
"axios": "^1.9.0",
3131
"base64-js": "^1.5.1",
32+
"classnames": "^2.5.1",
3233
"jszip": "^3.10.1",
3334
"lodash": "^4.17.21",
3435
"react": "^18.3.1",
3536
"react-dom": "^18.3.1",
37+
"sass": "^1.89.0",
3638
"typescript": "^5.6.2",
3739
"web-vitals": "^2.1.4"
3840
},

playground/package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@
99
"@types/react-dom": "^18.3.0",
1010
"react": "^18.3.1",
1111
"react-dom": "^18.3.1",
12-
"sass": "^1.78.0",
13-
"sass-loader": "^16.0.1",
12+
"sass": "^1.89.0",
1413
"typescript": "^5.6.2",
1514
"web-vitals": "^2.1.4"
1615
},
@@ -39,7 +38,6 @@
3938
"jest-environment-jsdom": "^29.7.0",
4039
"mockjs": "^1.1.0",
4140
"monaco-editor-webpack-plugin": "^7.1.0",
42-
"sass": "^1.78.0",
4341
"sass-loader": "^16.0.1",
4442
"style-loader": "^4.0.0",
4543
"ts-jest": "^29.3.2",

playground/src/App.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import EventBusTest from "@/components/EventBusTest";
55
import MicroComponentTest from "@/components/MicroComponentTest";
66
import Base64Test from "@/components/Base64Test";
77
import HttpTest from "@/components/HttpTest";
8+
import ThemeTest from "@/components/ThemeTest";
89

910
const App = () => {
1011

@@ -20,6 +21,7 @@ const App = () => {
2021
<MicroComponentTest/>
2122
<Base64Test/>
2223
<HttpTest/>
24+
<ThemeTest/>
2325
</div>
2426
);
2527
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import React from "react";
2+
import Space from "@/components/Space";
3+
import {ThemeContext, ThemeProviderContext} from "../../../src";
4+
import {EventBus} from "@codingapi/ui-framework";
5+
6+
const ThemeTest = () => {
7+
8+
const themeContext = React.useContext(ThemeProviderContext);
9+
10+
const [fontSize, setFontSize] = React.useState(themeContext?.getTheme().token.contentFontSize);
11+
12+
React.useEffect(() => {
13+
EventBus.getInstance().on(ThemeContext.EVENT_CHANGE_CONTENT_FONT_SIZE, (data: string) => {
14+
setFontSize(data);
15+
});
16+
17+
return () => {
18+
EventBus.getInstance().off(ThemeContext.EVENT_CHANGE_CONTENT_FONT_SIZE);
19+
}
20+
}, [])
21+
22+
return (
23+
<>
24+
<div
25+
style={{
26+
textAlign: 'center'
27+
}}
28+
>
29+
<h1>Theme Test </h1>
30+
</div>
31+
<Space>
32+
<div>
33+
font size:{fontSize}
34+
</div>
35+
<button onClick={() => {
36+
themeContext?.setSmallFontSize();
37+
}}>small font size
38+
</button>
39+
<button
40+
onClick={() => {
41+
themeContext?.setMiddleFontSize();
42+
}}
43+
>middle font size
44+
</button>
45+
<button onClick={() => {
46+
themeContext?.setLargeFontSize();
47+
}}>large font size
48+
</button>
49+
</Space>
50+
</>
51+
)
52+
}
53+
54+
export default ThemeTest;

playground/src/index.css

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
body {
2-
margin: 0;
3-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4-
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5-
sans-serif;
6-
-webkit-font-smoothing: antialiased;
7-
-moz-osx-font-smoothing: grayscale;
1+
:root {
2+
--primary-color: #81d11c;
3+
--body-background-color: #fdfdfd;
4+
5+
--content-font-size-large: 24px;
6+
--content-font-size-middle: 16px;
7+
--content-font-size-small: 12px;
8+
9+
--content-font-size: var(--content-font-size-middle);
810
}
911

10-
code {
11-
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
12-
monospace;
12+
body {
13+
margin: 0;
14+
padding: 0;
15+
background-color: var(--body-background-color);
16+
font-size: var(--content-font-size);
1317
}

playground/src/index.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,24 @@ import ReactDOM from 'react-dom/client';
33
import './index.css';
44
import App from './App';
55
import reportWebVitals from './reportWebVitals';
6+
import {CSSUtils, ThemeConfig, ThemeProvider} from "@codingapi/ui-framework";
67

78
const root = ReactDOM.createRoot(
89
document.getElementById('root') as HTMLElement
910
);
11+
12+
const theme = {
13+
token:{
14+
colorPrimary:CSSUtils.getRootVariable('--primary-color'),
15+
contentFontSize:CSSUtils.getRootVariable('--content-font-size'),
16+
}
17+
} as ThemeConfig;
18+
1019
root.render(
1120
<React.StrictMode>
12-
<App />
21+
<ThemeProvider theme={theme}>
22+
<App />
23+
</ThemeProvider>
1324
</React.StrictMode>
1425
);
1526

src/Dispatch/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
/**
2+
* Dispatch对象,对应React的useState的dispatch函数能力
3+
*/
4+
export type Dispatch<T> = (updater: ((prevState: T) => T) | T) => void;

src/ThemeProvider/component.tsx

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import React from "react";
2+
import {ThemeContext} from "./content";
3+
import {ThemeConfig} from "./types";
4+
5+
interface ThemeProviderProps {
6+
children: React.ReactNode;
7+
theme: ThemeConfig
8+
}
9+
10+
export const ThemeProviderContext = React.createContext<ThemeContext | null>(null);
11+
12+
export const ThemeProvider: React.FC<ThemeProviderProps> = (props) => {
13+
14+
const currentTheme = React.useContext(ThemeProviderContext) || {};
15+
16+
const [theme, dispatch] = React.useState<ThemeConfig>({
17+
...currentTheme,
18+
...props.theme
19+
});
20+
21+
const themeContextRef = React.useRef<ThemeContext | null>(null);
22+
23+
if (!themeContextRef.current) {
24+
themeContextRef.current = new ThemeContext(theme, dispatch);
25+
}
26+
27+
React.useEffect(() => {
28+
themeContextRef.current?.syncTheme(theme);
29+
}, [theme]);
30+
31+
return (
32+
<ThemeProviderContext.Provider value={themeContextRef.current}>
33+
{props.children}
34+
</ThemeProviderContext.Provider>
35+
)
36+
}

src/ThemeProvider/content.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import {ThemeConfig} from "./types";
2+
import {Dispatch} from "../Dispatch";
3+
import {CSSUtils} from "../utils";
4+
import {EventBus} from "../EventBus";
5+
6+
export class ThemeContext{
7+
8+
public static EVENT_CHANGE_CONTENT_FONT_SIZE = 'theme-changeContentFontSize';
9+
public static EVENT_CHANGE_THEME = 'theme-changeTheme';
10+
11+
private theme: ThemeConfig;
12+
private readonly dispatch: Dispatch<ThemeConfig>;
13+
14+
constructor(theme: ThemeConfig,dispatch: Dispatch<ThemeConfig>) {
15+
this.theme = theme;
16+
this.dispatch = dispatch;
17+
}
18+
19+
public getTheme = () => {
20+
return this.theme;
21+
}
22+
23+
// 更新状态数据
24+
public syncTheme = (theme: ThemeConfig) => {
25+
this.theme = theme;
26+
}
27+
28+
public setLargeFontSize = () => {
29+
const fontSize = CSSUtils.getRootVariable('--content-font-size-large');
30+
CSSUtils.setRootVariable('--content-font-size', fontSize);
31+
this.setFontSize(fontSize);
32+
}
33+
34+
public setMiddleFontSize = ()=>{
35+
const fontSize = CSSUtils.getRootVariable('--content-font-size-middle');
36+
CSSUtils.setRootVariable('--content-font-size', fontSize);
37+
this.setFontSize(fontSize);
38+
}
39+
40+
public setSmallFontSize = ()=>{
41+
const fontSize = CSSUtils.getRootVariable('--content-font-size-small');
42+
CSSUtils.setRootVariable('--content-font-size', fontSize);
43+
this.setFontSize(fontSize);
44+
}
45+
46+
/**
47+
* 设置字体大小
48+
* @param fontSize
49+
*/
50+
public setFontSize = (fontSize: string) => {
51+
this.dispatch((prevState) => {
52+
return {
53+
...prevState,
54+
token: {
55+
...prevState.token,
56+
contentFontSize: fontSize
57+
}
58+
}
59+
});
60+
EventBus.getInstance().emit(ThemeContext.EVENT_CHANGE_CONTENT_FONT_SIZE, fontSize);
61+
}
62+
63+
/**
64+
* 设置主题
65+
* @param theme
66+
*/
67+
public changeTheme = (theme: ThemeConfig) => {
68+
this.dispatch((prevState) => {
69+
return {
70+
...prevState,
71+
...theme
72+
}
73+
});
74+
EventBus.getInstance().emit(ThemeContext.EVENT_CHANGE_THEME, theme);
75+
}
76+
}

src/ThemeProvider/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './content';
2+
export * from './types';
3+
export * from './component';

src/ThemeProvider/types.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
export interface ThemeConfig {
2+
token: {
3+
4+
// 主题色
5+
colorPrimary?: string;
6+
7+
// 字体大小
8+
contentFontSize?: string;
9+
10+
[key : string]: any;
11+
}
12+
}

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ export * from './EventBus';
44
export * from './Form';
55
export * from './Flow';
66
export * from './utils';
7+
export * from './Dispatch';
8+
export * from './ThemeProvider';

0 commit comments

Comments
 (0)