Skip to content

Instantly share code, notes, and snippets.

@jjspace
Last active July 8, 2019 19:41
Show Gist options
  • Save jjspace/a370212cee9dae27e5c1313654553ed0 to your computer and use it in GitHub Desktop.
Save jjspace/a370212cee9dae27e5c1313654553ed0 to your computer and use it in GitHub Desktop.
Better DOM createElement and style
/**
* Add a new stylesheet to this page with the provided rules
* Rules should be an array of the form:
* [['selector string', { *rules object* }]]
* where rules object is:
* { property: 'value', ...}
* property names are camelCase versions of css properties
* for example the prop 'background-color' would become 'backgroundColor'
* @param {Array} rules
* @example
addStylesheet([
['h2', {
color: 'red',
backgroundColor: 'green !important',
}],
['.myclass', {
backgroundColor: 'yellow'
}]
]);
*/
const addStylesheet = (rules) => {
const styleEl = document.createElement('style');
styleEl.id = 'customSheet';
document.head.appendChild(styleEl);
const styleSheet = styleEl.sheet;
rules.forEach((rule) => {
const [selector, props] = rule;
let propStr = Object.entries(props).reduce((acc, [prop, val]) => {
return acc + prop.replace(/[A-Z]/g, (m) => '-'+m.toLowerCase()) + `:${val};`;
}, '');
styleSheet.insertRule(`${selector}{${propStr}}`, styleSheet.cssRules.length);
});
return styleSheet;
}
// Add ability to style elements with an object of styles
const styleElem = (elem, style) => {
let newElem = elem.cloneNode(true);
Object.entries(style).forEach((prop) => {
let [name,val] = prop;
// convert kebab to camelCase
name = name.replace(/\-(\w)/g, (m)=>`${m[1].toUpperCase()}`);
// set val
if (name in elem.style) {
newElem.style[name] = val;
} else {
throw new Error(`${name} is not a valid style property`);
}
});
return newElem;
}
// replace document.creatElement with function inspired by emmet
// to quickly set class, id, and inner text
const createElement = (emmetLike) => {
// extract element type, default to div
let elemTypeMatch = emmetLike.match(/^[a-zA-Z0-9-]+/);
let elemType = elemTypeMatch ? elemTypeMatch[0] : 'div';
// extract text
let textContext = '';
let textContextMatch = emmetLike.match(/\{(.+)\}/);
if (textContextMatch) {
textContext = textContextMatch[1];
emmetLike = emmetLike.replace(textContextMatch[0], '');
}
// extract id
let idMatch = emmetLike.match(/#([^\s\.\{\}]+)/);
let id = idMatch ? idMatch[1] : '';
// extract classes
let classMatch = emmetLike.match(/\.-?[_a-zA-Z]+[_a-zA-Z0-9-]*/g);
let className = classMatch ? classMatch.join('').replace(/\./g, ' ').trim() : '';
let elem = document.createElement(elemType);
if (id) { elem.id = id; }
if (className) { elem.className = className; }
if (textContext) { elem.appendChild(document.createTextNode(textContext)); }
return elem;
}
console.log(createElement(`.class.class-2#id-the-second{${'hello'}}.extra`));
console.log(createElement(`{${'hello'}}.class.class-2#id-the-second.extra`));
console.log(createElement(`.class.class-2{${'hello'}}#id-the-second.extra`));
console.log(createElement(`button.submit`))
console.log(createElement(`ul`))
console.log(createElement('p{this is some text. I like talking about things. docs are fun like object.entries}'))
console.log(createElement(`.class-1#item.class-2`))
let itemName = document.createElement('div');
itemName.className = 'item-name';
itemName.innerText = 'testing;
console.log(itemName);
console.log(createElement(`.item-name{testing}`))
let itemName2 = styleElem(itemName, {
position: 'absolute',
background: 'red',
'font-family': 'monospace',
flex: 1,
top: '30px',
});
console.log(itemName2);
console.log(itemName2.style);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment