Skip to content

Commit b2bd30b

Browse files
committed
feat: add basic CssVars implementation
1 parent cb88c75 commit b2bd30b

File tree

3 files changed

+160
-8
lines changed

3 files changed

+160
-8
lines changed

src/CssVars/index.ts

Lines changed: 71 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,74 @@
11
import {Component} from 'react';
2+
import {Provider, Consumer} from '../context';
3+
import {h} from '../util';
4+
import renderProp from '../util/renderProp';
25

3-
const vars = {
4-
color: 'red'
5-
};
6+
let idCnt = 0;
67

7-
// export class CssVarsProvider extends Component<any, any> {
8-
// render () {
9-
// return this.props.children;
10-
// }
11-
// }
8+
const supportsCssVariables = typeof window === 'object' && (window as any).CSS && CSS.supports && CSS.supports('--a', '0');
9+
10+
export type TVars = {[name: string]: string};
11+
12+
export interface ICssVarsProviderProps {
13+
ns?: string;
14+
prefix?: string;
15+
vars: TVars;
16+
}
17+
18+
export interface ICssVarsProviderState {
19+
}
20+
21+
export class CssVarsProvider extends Component<ICssVarsProviderProps, ICssVarsProviderState> {
22+
vars: TVars = {};
23+
24+
constructor (props, context) {
25+
super(props, context);
26+
27+
this.updateVars(props.vars);
28+
}
29+
30+
updateVars (vars: TVars) {
31+
if (supportsCssVariables) {
32+
const {prefix = ''} = this.props;
33+
const {style} = document.documentElement;
34+
35+
for (const name in vars) {
36+
const id = (idCnt++).toString(36);
37+
const varName = `---${prefix}${id}`;
38+
39+
this.vars[name] = `var(${varName})`;
40+
style.setProperty(varName, String(vars[name]));
41+
}
42+
} else {
43+
this.vars = vars;
44+
}
45+
}
46+
47+
render () {
48+
return h(Provider, {
49+
name: 'css/' + this.props.ns,
50+
value: this.vars
51+
},
52+
this.props.children
53+
);
54+
}
55+
}
56+
57+
export interface ICssVarsProps {
58+
children?: any;
59+
render?: any;
60+
component?: any;
61+
comp?: any;
62+
ns?: string;
63+
}
64+
65+
export interface ICssVarsState {
66+
}
67+
68+
export class CssVars extends Component<ICssVarsProps, ICssVarsState> {
69+
render () {
70+
return h(Consumer, {name: 'css/' + this.props.ns}, (vars) => {
71+
return renderProp(this.props, vars);
72+
});
73+
}
74+
}

src/cssvars/__story__/Example1.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import {Component, createElement as h} from 'react';
2+
import {CssVarsProvider, CssVars} from '..';
3+
4+
const Print = (props) => <pre style={{fontFamily: 'monospace'}}>{JSON.stringify(props, null, 4)}</pre>;
5+
6+
export class Example1 extends Component<any, any> {
7+
el;
8+
vars;
9+
10+
ref = (el) => {
11+
this.el = el;
12+
};
13+
14+
componentDidMount () {
15+
this.applyCssVars();
16+
}
17+
18+
componentDidUpdate () {
19+
this.applyCssVars();
20+
}
21+
22+
applyCssVars () {
23+
if (this.el && this.vars) {
24+
for (const name in this.vars) {
25+
console.log('name, this.vars[name]', name, this.vars[name]);
26+
this.el.style.setProperty(name, this.vars[name]);
27+
}
28+
}
29+
}
30+
31+
render () {
32+
return (
33+
<CssVarsProvider vars={{
34+
color: 'tomato',
35+
border: '1px solid tomato'
36+
}}>
37+
<CssVars>{(vars) => {
38+
this.vars = vars;
39+
40+
return (
41+
<div>
42+
<Print {...vars} />
43+
<button ref={this.ref}>Click me!</button>
44+
</div>
45+
);
46+
}}</CssVars>
47+
</CssVarsProvider>
48+
);
49+
}
50+
}

src/cssvars/__story__/story.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import {createElement as h} from 'react';
2+
import {storiesOf} from '@storybook/react';
3+
import {action} from '@storybook/addon-actions';
4+
import {linkTo} from '@storybook/addon-links';
5+
import ShowDocs from '../../../.storybook/ShowDocs'
6+
import {CssVarsProvider, CssVars} from '..';
7+
import {Example1} from './Example1';
8+
9+
const Print = (props) => <pre style={{fontFamily: 'monospace'}}>{JSON.stringify(props, null, 4)}</pre>;
10+
11+
storiesOf('Context/CSS Variables', module)
12+
// .add('Documentation', () => h(ShowDocs, {md: require('../../../docs/en/FocusSensor.md')}))
13+
.add('Basic example', () => <Example1 />)
14+
.add('Inline style', () =>
15+
<CssVarsProvider vars={{
16+
color: 'tomato',
17+
border: '1px solid tomato'
18+
}}>
19+
<CssVars>{(vars) =>
20+
<div>
21+
<Print {...vars} />
22+
<button style={vars}>Click me!</button>
23+
</div>
24+
}</CssVars>
25+
</CssVarsProvider>
26+
)
27+
.add('With namespace', () =>
28+
<CssVarsProvider ns='namespace' prefix='prefix-' vars={{
29+
color: 'tomato',
30+
border: '1px solid tomato'
31+
}}>
32+
<CssVars ns='namespace'>{(vars) =>
33+
<div>
34+
<Print {...vars} />
35+
<button style={vars}>Click me!</button>
36+
</div>
37+
}</CssVars>
38+
</CssVarsProvider>
39+
)

0 commit comments

Comments
 (0)