Skip to content

Instantly share code, notes, and snippets.

View ryanmorr's full-sized avatar

Ryan Morr ryanmorr

View GitHub Profile
@ryanmorr
ryanmorr / compile-tagged-template.js
Created April 2, 2024 17:05
Simple function to compile a tagged template string with a callback function
function compileTaggedTemplate(strings, values, callback) {
return strings.raw.reduce((acc, str, i) => acc + (callback(values[i - 1])) + str);
}
// Usage:
const tag = (strings, ...values) => compileTaggedTemplate(strings, values, (val) => val.toUpperCase());
console.log(tag`Capitalize ${'all'} ${'substitutions'}`); //=> Capitalize ALL SUBSTITUTIONS
@ryanmorr
ryanmorr / attempt.js
Created April 1, 2024 20:24
Wrap a try/catch block with a promise for easy error handling
function attempt(fn) {
return new Promise((resolve, reject) => {
try {
resolve(fn());
} catch(e) {
reject(e);
}
});
}
@ryanmorr
ryanmorr / create-class.js
Last active April 1, 2024 20:11
Generate a class name for a DOM element with a string, array, or object literal
// Courtesy of: https://github.com/jorgebucaran/hyperapp
function createClass(value) {
if (typeof value === 'string') {
return value;
}
let output = '';
if (Array.isArray(value)) {
for (let i = 0, len = value.length, tmp; i < len; i++) {
if ((tmp = createClass(value[i])) !== '') {
@ryanmorr
ryanmorr / styles.js
Last active April 1, 2024 20:14
Get and set CSS styles, supporting camel-case, kebab-case, and custom properties
function getStyle(el, prop) {
const style = getComputedStyle(el);
return prop.includes('-') ? style.getPropertyValue(prop) : style[prop];
}
function setStyle(el, prop, value) {
if (prop.includes('-')) {
el.style.setProperty(prop, value);
} else {
el.style[prop] = value;
@ryanmorr
ryanmorr / templit.js
Created March 29, 2024 06:27
Make a static template literal string come alive
function templit(tpl, tag) {
let exec;
return (data) => {
if (!exec) {
const vars = Object.getOwnPropertyNames(data).map((key) => `${key} = this['${key}']`);
exec = tag == null
? new Function(`var ${vars.join(',')}; return \`${tpl}\``)
: new Function('__tag', `var ${vars.join(',')}; return __tag\`${tpl}\``);
}
return tag == null ? exec.call(data) : exec.call(data, tag);
@ryanmorr
ryanmorr / sort-array.js
Last active March 29, 2024 20:09
Sort an array by string, number, or date with support for ascending and descending order
function compareDefault(a, b) {
return a - b;
}
function compareStrings(a, b) {
a = String(a).toUpperCase();
b = String(b).toUpperCase();
if (a > b) {
return 1;
}
@ryanmorr
ryanmorr / dropdown-caret.css
Created March 29, 2024 00:09
A simple pseudo-element to create a dropdown caret that scales with text in pure CSS
.dropdown-caret:after {
content: "";
display: inline-block;
width: 0;
height: 0;
margin-left: .255em;
vertical-align: middle;
border-top: .3em solid;
border-right: .3em solid transparent;
border-left: .3em solid transparent;
@ryanmorr
ryanmorr / css-unit-conversion.js
Last active March 29, 2024 00:29
A hack to get the value of a CSS style property in the provided unit
// For certain CSS properties (width, height, etc.) getComputedStyle() will return the
// "used value" (https://developer.mozilla.org/en-US/docs/Web/CSS/used_value) in pixels,
// regardless of what units it was explicitly defined with. This function allows you to
// get the value in any unit provided
function getStyleInUnit(el, prop, unit) {
let value = parseFloat(getComputedStyle(el)[prop]) || 0;
if (unit !== 'px') {
el.style[prop] = 1 + unit;
value = (1 / parseFloat(getComputedStyle(el)[prop])) * value;
@ryanmorr
ryanmorr / unload.js
Last active March 29, 2024 00:30
The MDN recommended way of executing unload code
// https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon#sending_analytics_at_the_end_of_a_session
const callbacks = [];
function unload(callback) {
callbacks.push(callback);
};
document.addEventListener('visibilitychange', () => {
if (document.visibilityState === 'hidden') {
@ryanmorr
ryanmorr / state-generator.js
Last active March 29, 2024 00:30
Simple redux-style state machine via a generator function
function *stateGenerator(state, reducer) {
let action;
while (true) {
if (action) {
state = reducer(state, action);
}
action = yield state;
}
}