-
Notifications
You must be signed in to change notification settings - Fork 2
/
MagicDemo.js
112 lines (100 loc) · 3.07 KB
/
MagicDemo.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import React, {useState} from 'react';
import HtmlDemo from './HtmlDemo';
import * as styles from './demo.module.css';
const MagicInput = ({name, color, type = 'text', state, updateState}) => (
<div>
<label style={{textDecorationColor: color}} htmlFor={name}>
{name}
</label>
<input
type={type}
name={name}
id={name}
value={state[name]}
style={{borderColor: color}}
onChange={e => updateState({...state, [name]: e.target.value})}
/>
</div>
);
const magicColors = [
// https://coolors.co/90f1ef-ffc2d1-9ef6a6-ffee99-ffd199-7389ae-e8b0be-e0f5a2-c1fba4-7bf1a8
'#90f1efff', // electric-blue
'#ffc2d1ff', // pink
'#9ef6a6ff', // light-green
'#ffee99ff', // green-yellow-crayola
'#ffd199ff', // deep-champagne
'#7389aeff', // shadow-blue
'#e8b0beff', // cameo-pink
'#e0f5a2ff', // key-lime
'#c1fba4ff', // mint-green
'#7bf1a8ff', // light-green-2
];
const type = value => {
if (typeof value === 'number') {
return 'number';
} else if (value.match(/#\w{3,6}/)) {
return 'color';
} else {
return 'text';
}
};
const MagicDemo = ({template, initialState = {}}) => {
// map each input to a color
const names = Object.keys(initialState);
const colorMap = names.reduce((map, name, i) => {
map[name] = magicColors[i];
return map;
}, {});
const [inputState, setInputState] = useState(initialState);
const inputs = names.map(name => (
<MagicInput
key={name}
type={type(initialState[name])}
color={colorMap[name]}
name={name}
state={inputState}
updateState={setInputState}
/>
));
let srcString = template(inputState);
let lineColors = {};
let lines = srcString.split(/\n/);
lines.forEach((line, index) => {
for (let name of names) {
let value = inputState[name];
if (value && value.toString().length > 2 && line.match(value)) {
lineColors[index + 1] = colorMap[name];
break;
}
}
});
// please excuse this hack
// it's styling the elements in the iframe with the magic colors
// it's evaluating a script in the iframe
// the script uses an xpath to find the elements with matching text :o
// and adds a border to those nodes, with the matching color
let extra = `
<script>
function highlight(value, color) {
let result = document.evaluate('//*[text()="' + value + '"]', document, null, XPathResult.ANY_TYPE);
let found = [];
while(res = result.iterateNext()) {
found.push(res);
}
found.forEach(node => {node.style.border = '4px solid ' + color})
}
${names.map(name => `highlight("${inputState[name]}", "${colorMap[name]}")`).join(';\n\t')};
</script>`;
return (
<div className={styles.magic}>
<div className={styles.label}>Playground</div>
<div className={styles.hint}>
Try changing these values. See what changes in the code and in the output.
</div>
<div className={styles.inputs}>{inputs}</div>
<HtmlDemo lineColors={lineColors} srcString={srcString} extra={extra} />
</div>
);
};
export default MagicDemo;
export {MagicInput};