<div id='root' ></div>
*,
*::before,
*::after {
box-sizing: border-box;
}
pre {
width: 100%;
white-space: pre-wrap;
}
body {
font-family: Arial, sans-serif;
background-color: #1a1d1d;
padding: 20px;
font-size: 0.875rem;
}
.controls-container {
display: flex;
flex-direction: column;
gap: 10px;
width: 80%;
margin: 0 auto;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
background-color: #f9f9f9;
}
.controls-container label {
display: flex;
flex-direction: column;
font-size: 16px;
color: #333;
}
.controls-container input {
margin-top: 5px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 14px;
}
.controls-container input:focus {
border-color: #007bff;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
outline: none;
}
.themed {
padding: 8px;
text-align: center;
overflow: hidden;
}
.container {
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
max-width: 30rem;
margin: auto;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
h1 {
font-size: 1rem;
}
@media screen and (max-width: 600px) {
body {
padding: 5px;
}
.container {
width: 100%;
}
}
import React, {
useState,
useRef,
useEffect,
useReducer
} from "https://esm.sh/react@18.2.0";
import ReactDOM from "https://esm.sh/react-dom@18.2.0";
const initialState = {
theme: {
background: {
color: "#ddd"
},
textColor: "#000000",
size: "100",
borderStyle: {
width: "1",
color: "#000000",
style: "solid",
radius: "5"
},
boxShadow: "0px 0px 0px 0px rgba(0,0,0,0.75)"
}
};
function styleReducer(state, action) {
switch (action.type) {
case "CHANGE_BACKGROUND_COLOR":
return {
state,
theme: {
state.theme,
background: { state.theme.background, color: action.value }
}
};
case "CHANGE_TEXT_COLOR":
return {
state,
theme: { state.theme, textColor: action.value }
};
case "CHANGE_BORDER_COLOR":
return {
state,
theme: {
state.theme,
borderStyle: { state.theme.borderStyle, color: action.value }
}
};
case "CHANGE_BORDER_RADIUS":
return {
state,
theme: {
state.theme,
borderStyle: { state.theme.borderStyle, radius: action.value }
}
};
case "CHANGE_SIZE":
return {
state,
theme: {
state.theme,
size: action.value
}
};
case "CHANGE_BOX_SHADOW":
return {
state,
theme: {
state.theme,
boxShadow: `0px 0px ${action.value}px rgba(0,0,0,0.75)`
}
};
case "CHANGE_BORDER_WIDTH":
return {
state,
theme: {
state.theme,
borderStyle: { state.theme.borderStyle, width: action.value }
}
};
default:
return state;
}
}
const toPx = (value) => `${value}px`;
function CSSPropertyEditor() {
const [state, dispatch] = useReducer(styleReducer, initialState);
const renderCount = useRef(0);
useEffect(() => {
renderCount.current += 1;
});
return (
<div className="container">
Render Count: {renderCount.current}
<div
className="themed"
style={{
backgroundColor: state.theme.background.color,
color: state.theme.textColor,
border: `${toPx(state.theme.borderStyle.width)} ${
state.theme.borderStyle.style
} ${state.theme.borderStyle.color}`,
borderRadius: toPx(state.theme.borderStyle.radius),
width: toPx(state.theme.size),
height: toPx(state.theme.size),
boxShadow: state.theme.boxShadow
}}
>
<h1>Themed Container</h1>
</div>
<div className="controls-container">
<label>
{" "}
Background color:
<input
type="color"
value={state.theme.background.color}
onChange={(e) =>
dispatch({
type: "CHANGE_BACKGROUND_COLOR",
value: e.target.value
})
}
/>
</label>
<label>
{" "}
Text color:
<input
type="color"
value={state.theme.textColor}
onChange={(e) =>
dispatch({ type: "CHANGE_TEXT_COLOR", value: e.target.value })
}
/>
</label>
<label>
{" "}
border color:
<input
type="color"
value={state.theme.borderStyle.color}
onChange={(e) =>
dispatch({ type: "CHANGE_BORDER_COLOR", value: e.target.value })
}
/>
</label>
<label>
{" "}
border Radius:
<input
type="range"
min="0"
max="100"
step="1"
value={state.theme.borderStyle.radius}
onChange={(e) =>
dispatch({ type: "CHANGE_BORDER_RADIUS", value: e.target.value })
}
/>
</label>
<label>
{" "}
Border size:
<input
type="range"
min="0"
max="100"
step="1"
value={state.theme.borderStyle.width}
onChange={(e) =>
dispatch({ type: "CHANGE_BORDER_WIDTH", value: e.target.value })
}
/>
</label>
<label>
{" "}
Size:
<input
type="range"
min="50"
max="200"
value={state.theme.size}
onChange={(e) =>
dispatch({ type: "CHANGE_SIZE", value: e.target.value })
}
/>
</label>
<label>
{" "}
Box Shadow:
<input
type="range"
min="0"
max="20"
value={parseInt(state.theme.boxShadow.split(" ")[2], 10)}
onChange={(e) =>
dispatch({ type: "CHANGE_BOX_SHADOW", value: e.target.value })
}
/>
</label>
</div>
<pre>
{JSON.stringify(
{
backgroundColor: state.theme.background.color,
color: state.theme.textColor,
border: `${state.theme.borderStyle.width} ${state.theme.borderStyle.style} ${state.theme.borderStyle.color}`,
borderRadius: toPx(state.theme.borderStyle.radius),
width: toPx(state.theme.size),
height: toPx(state.theme.size),
boxShadow: state.theme.boxShadow
},
null,
2
)}
</pre>
</div>
);
}
ReactDOM.render(<CSSPropertyEditor />, document.getElementById("root"));
View Compiled
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.