cascading-color-systems
Advanced tools
Comparing version 0.1.0-beta.12 to 0.1.0-beta.13
# Changelog | ||
## 0.1.0-beta.13 - 2020/6/30 | ||
- NEW: All form inputs & buttons are now optional | ||
- NEW: Support radio-inputs for `light`/`dark`/`auto` modes: | ||
- `[data-ccs-input="light-mode"]` | ||
- `[data-ccs-input="dark-mode"]` | ||
- `[data-ccs-input="auto-mode"]` | ||
- NEW: Optionally unset theme-related user values when changing themes: | ||
- Add `unset-values` to theme input: `[data-ccs-input="theme unset-values"]` | ||
- INTERNAL: Upgrade dev dependencies | ||
## 0.1.0-beta.12 - 2020/6/23 | ||
@@ -4,0 +15,0 @@ |
205
dist.js
@@ -22,10 +22,13 @@ (function (global, factory) { | ||
function _default() { | ||
// elements | ||
// root elements | ||
const root = document.querySelector('[data-ccs="root"]'); | ||
const themeMenu = document.querySelector('[data-ccs="menu"]'); | ||
const modeToggle = document.querySelector('[data-ccs-input="mode"]'); | ||
const unsetBtn = document.querySelector('[data-ccs-input="unset"]'); // elements | ||
const invertBtn = document.querySelector('[data-ccs-input="mode"]'); | ||
const modeLight = document.querySelector('[data-ccs-input="light-mode"]'); | ||
const modeDark = document.querySelector('[data-ccs-input="dark-mode"]'); | ||
const modeAuto = document.querySelector('[data-ccs-input="auto-mode"]'); | ||
const unsetBtn = document.querySelector('[data-ccs-input="unset"]'); // controls | ||
const selectElements = { | ||
theme: document.querySelector('[data-ccs-input="theme"]'), | ||
const controls = { | ||
theme: document.querySelector('[data-ccs-input~="theme"]'), | ||
hue: document.querySelector('[data-ccs-input="hue"]'), | ||
@@ -35,37 +38,32 @@ sat: document.querySelector('[data-ccs-input="saturation"]'), | ||
contrast: document.querySelector('[data-ccs-input="contrast"]') | ||
}; | ||
const showUnsetBtn = (show = true) => { | ||
if (unsetBtn) { | ||
show ? unsetBtn.removeAttribute("hidden") : unsetBtn.setAttribute("hidden", ""); | ||
} | ||
}; // attributes | ||
const attrs = { | ||
theme: 'data-ccs-theme' | ||
theme: "data-ccs-theme" | ||
}; // properties | ||
const props = { | ||
hue: '--ccs-prime--user', | ||
sat: '--ccs-s--user', | ||
light: '--ccs-l--user', | ||
contrast: '--ccs-contrast--user', | ||
mode: '--ccs-mode--user' | ||
hue: "--ccs-prime--user", | ||
sat: "--ccs-s--user", | ||
light: "--ccs-l--user", | ||
contrast: "--ccs-contrast--user", | ||
mode: "--ccs-mode--user" | ||
}; // local storage | ||
const store = { | ||
theme: 'ccsTheme', | ||
mode: 'ccsMode', | ||
hue: 'ccsHue', | ||
sat: 'ccsSat', | ||
light: 'ccsLight', | ||
contrast: 'ccsContrast' | ||
}; // clear all settings | ||
const clearColors = () => { | ||
setValue('theme', selectElements.theme.getAttribute('data-default'), false); | ||
Object.keys(store).forEach(type => localStorage.removeItem(store[type])); | ||
Object.keys(props).forEach(prop => root.style.removeProperty(props[prop])); | ||
Object.keys(selectElements).forEach(type => { | ||
const el = selectElements[type]; | ||
selectElements[type].value = el.getAttribute('data-default'); | ||
}); | ||
unsetBtn.setAttribute('hidden', ''); | ||
theme: "ccsTheme", | ||
mode: "ccsMode", | ||
hue: "ccsHue", | ||
sat: "ccsSat", | ||
light: "ccsLight", | ||
contrast: "ccsContrast" | ||
}; // set a value | ||
const setValue = (type, to, toStore = true) => { | ||
@@ -81,14 +79,91 @@ if (to) { | ||
localStorage.setItem(store[type], to); | ||
unsetBtn.removeAttribute('hidden'); | ||
showUnsetBtn(); | ||
} | ||
} | ||
}; // toggle mode | ||
}; | ||
const clearProps = (sub = null) => Object.keys(props).forEach(prop => { | ||
if (!sub || sub.includes(prop)) { | ||
root.style.removeProperty(props[prop]); | ||
} | ||
}); | ||
const getMode = () => { | ||
return Number(getComputedStyle(root).getPropertyValue('--ccs-mode').trim()); | ||
const clearStore = (sub = null) => Object.keys(store).forEach(type => { | ||
if (!sub || sub.includes(type)) { | ||
localStorage.removeItem(store[type]); | ||
} | ||
}); | ||
const resetControls = (sub = null) => Object.keys(controls).forEach(type => { | ||
if (!sub || sub.includes(type)) { | ||
const el = controls[type]; | ||
if (el) { | ||
el.value = el.getAttribute("data-default"); | ||
} | ||
} | ||
}); | ||
const subTheme = ["hue", "sat", "light", "contrast"]; | ||
const setSelection = (type, selection) => { | ||
const unsetTheme = controls.theme && controls.theme.dataset.ccsInput && controls.theme.dataset.ccsInput.includes("unset-values"); | ||
if (type === "theme" && unsetTheme) { | ||
clearProps(subTheme); | ||
clearStore(subTheme); | ||
resetControls(subTheme); | ||
} | ||
setValue(type, selection); | ||
}; // clear all settings on reset | ||
const unset = () => { | ||
if (controls.theme) { | ||
setValue("theme", controls.theme.getAttribute("data-default"), false); | ||
} | ||
clearStore(); | ||
clearProps(); | ||
resetControls(); | ||
showUnsetBtn(false); | ||
if (modeAuto) { | ||
modeAuto.checked = true; | ||
} | ||
}; // modes | ||
const getMode = () => parseInt(getComputedStyle(root).getPropertyValue("--ccs-mode").trim(), 10); | ||
const changeMode = scheme => { | ||
const schemeDict = { | ||
light: 1, | ||
dark: -1, | ||
auto: 0 | ||
}; | ||
const setting = schemeDict[scheme]; | ||
if (setting) { | ||
setValue("mode", setting); | ||
} else { | ||
// if auto, remove mode props from root and store | ||
clearStore(["mode"]); | ||
clearProps(["mode"]); | ||
} | ||
}; | ||
const changeMode = () => { | ||
setValue('mode', getMode() * -1, true); | ||
const toggleMode = () => { | ||
const modeDict = { | ||
1: modeLight, | ||
[-1]: modeDark | ||
}; | ||
const mode = getMode(); | ||
setValue("mode", mode * -1); | ||
const modeBtn = modeDict[mode * -1]; | ||
if (modeBtn) { | ||
modeBtn.checked = true; | ||
} | ||
}; // initialize everything | ||
@@ -98,7 +173,28 @@ | ||
const initMenu = () => { | ||
themeMenu.removeAttribute('hidden'); | ||
if (themeMenu) { | ||
themeMenu.removeAttribute("hidden"); | ||
} | ||
}; | ||
const initMode = () => { | ||
let to = localStorage.getItem(store.mode); | ||
if (to) { | ||
const modeDict = { | ||
1: modeLight, | ||
[-1]: modeDark | ||
}; | ||
const modeBtn = modeDict[to]; | ||
setValue("mode", to); | ||
if (modeBtn) { | ||
modeBtn.checked = true; | ||
} | ||
} else if (modeAuto) { | ||
modeAuto.checked = true; | ||
} | ||
}; | ||
const initValue = type => { | ||
selectElements[type].setAttribute('data-default', selectElements[type].value); | ||
controls[type].setAttribute("data-default", controls[type].value); | ||
const to = localStorage.getItem(store[type]); | ||
@@ -108,30 +204,25 @@ | ||
setValue(type, to, false); | ||
selectElements[type].value = to; | ||
unsetBtn.removeAttribute('hidden'); | ||
controls[type].value = to; | ||
showUnsetBtn(); | ||
} | ||
}; | ||
/* init defaults */ | ||
const initMode = () => { | ||
let to = localStorage.getItem(store.mode); | ||
if (to) { | ||
setValue('mode', to); | ||
unsetBtn.removeAttribute('hidden'); | ||
} | ||
}; // init & events | ||
window.onload = initMenu(); | ||
window.onload = initMode(); | ||
/* attach event listeners */ | ||
document.onload = initMenu(); | ||
document.onload = initMode(); | ||
modeToggle.addEventListener('click', () => changeMode()); | ||
unsetBtn.addEventListener('click', () => clearColors()); | ||
Object.keys(selectElements).forEach(type => { | ||
if (selectElements[type]) { | ||
document.onload = initValue(type); | ||
selectElements[type].addEventListener('input', () => setValue(type, selectElements[type].value)); | ||
invertBtn && invertBtn.addEventListener("click", toggleMode); | ||
modeLight && modeLight.addEventListener("change", () => changeMode("light")); | ||
modeDark && modeDark.addEventListener("change", () => changeMode("dark")); | ||
modeAuto && modeAuto.addEventListener("change", () => changeMode("auto")); | ||
unsetBtn && unsetBtn.addEventListener("click", unset); | ||
Object.keys(controls).forEach(type => { | ||
if (controls[type]) { | ||
window.onload = initValue(type); | ||
controls[type].addEventListener("change", e => setSelection(type, e.target.value)); | ||
} | ||
}); | ||
} | ||
; | ||
}); |
213
index.js
export default function () { | ||
// elements | ||
// root elements | ||
const root = document.querySelector('[data-ccs="root"]'); | ||
const themeMenu = document.querySelector('[data-ccs="menu"]'); | ||
const modeToggle = document.querySelector('[data-ccs-input="mode"]'); | ||
const invertBtn = document.querySelector('[data-ccs-input="mode"]'); | ||
const modeLight = document.querySelector('[data-ccs-input="light-mode"]'); | ||
const modeDark = document.querySelector('[data-ccs-input="dark-mode"]'); | ||
const modeAuto = document.querySelector('[data-ccs-input="auto-mode"]'); | ||
const unsetBtn = document.querySelector('[data-ccs-input="unset"]'); | ||
// elements | ||
const selectElements = { | ||
theme: document.querySelector('[data-ccs-input="theme"]'), | ||
// controls | ||
const controls = { | ||
theme: document.querySelector('[data-ccs-input~="theme"]'), | ||
hue: document.querySelector('[data-ccs-input="hue"]'), | ||
@@ -17,5 +20,13 @@ sat: document.querySelector('[data-ccs-input="saturation"]'), | ||
const showUnsetBtn = (show = true) => { | ||
if (unsetBtn) { | ||
show | ||
? unsetBtn.removeAttribute("hidden") | ||
: unsetBtn.setAttribute("hidden", ""); | ||
} | ||
}; | ||
// attributes | ||
const attrs = { | ||
theme: 'data-ccs-theme', | ||
theme: "data-ccs-theme", | ||
}; | ||
@@ -25,7 +36,7 @@ | ||
const props = { | ||
hue: '--ccs-prime--user', | ||
sat: '--ccs-s--user', | ||
light: '--ccs-l--user', | ||
contrast: '--ccs-contrast--user', | ||
mode: '--ccs-mode--user', | ||
hue: "--ccs-prime--user", | ||
sat: "--ccs-s--user", | ||
light: "--ccs-l--user", | ||
contrast: "--ccs-contrast--user", | ||
mode: "--ccs-mode--user", | ||
}; | ||
@@ -35,22 +46,10 @@ | ||
const store = { | ||
theme: 'ccsTheme', | ||
mode: 'ccsMode', | ||
hue: 'ccsHue', | ||
sat: 'ccsSat', | ||
light: 'ccsLight', | ||
contrast: 'ccsContrast', | ||
theme: "ccsTheme", | ||
mode: "ccsMode", | ||
hue: "ccsHue", | ||
sat: "ccsSat", | ||
light: "ccsLight", | ||
contrast: "ccsContrast", | ||
}; | ||
// clear all settings | ||
const clearColors = () => { | ||
setValue('theme', selectElements.theme.getAttribute('data-default'), false); | ||
Object.keys(store).forEach(type => localStorage.removeItem(store[type])); | ||
Object.keys(props).forEach(prop => root.style.removeProperty(props[prop])); | ||
Object.keys(selectElements).forEach(type => { | ||
const el = selectElements[type]; | ||
selectElements[type].value = el.getAttribute('data-default'); | ||
}); | ||
unsetBtn.setAttribute('hidden', ''); | ||
}; | ||
// set a value | ||
@@ -67,3 +66,3 @@ const setValue = (type, to, toStore = true) => { | ||
localStorage.setItem(store[type], to); | ||
unsetBtn.removeAttribute('hidden'); | ||
showUnsetBtn(); | ||
} | ||
@@ -73,54 +72,140 @@ } | ||
// toggle mode | ||
const getMode = () => { | ||
return Number( | ||
getComputedStyle(root) | ||
.getPropertyValue('--ccs-mode') | ||
.trim(), | ||
); | ||
const clearProps = (sub = null) => | ||
Object.keys(props).forEach((prop) => { | ||
if (!sub || sub.includes(prop)) { | ||
root.style.removeProperty(props[prop]); | ||
} | ||
}); | ||
const clearStore = (sub = null) => | ||
Object.keys(store).forEach((type) => { | ||
if (!sub || sub.includes(type)) { | ||
localStorage.removeItem(store[type]); | ||
} | ||
}); | ||
const resetControls = (sub = null) => | ||
Object.keys(controls).forEach((type) => { | ||
if (!sub || sub.includes(type)) { | ||
const el = controls[type]; | ||
if (el) { | ||
el.value = el.getAttribute("data-default"); | ||
} | ||
} | ||
}); | ||
const subTheme = ["hue", "sat", "light", "contrast"]; | ||
const setSelection = (type, selection) => { | ||
const unsetTheme = | ||
controls.theme && | ||
controls.theme.dataset.ccsInput && | ||
controls.theme.dataset.ccsInput.includes("unset-values"); | ||
if (type === "theme" && unsetTheme) { | ||
clearProps(subTheme); | ||
clearStore(subTheme); | ||
resetControls(subTheme); | ||
} | ||
setValue(type, selection); | ||
}; | ||
const changeMode = () => { | ||
setValue('mode', getMode() * -1, true); | ||
// clear all settings on reset | ||
const unset = () => { | ||
if (controls.theme) { | ||
setValue("theme", controls.theme.getAttribute("data-default"), false); | ||
} | ||
clearStore(); | ||
clearProps(); | ||
resetControls(); | ||
showUnsetBtn(false); | ||
if (modeAuto) { | ||
modeAuto.checked = true; | ||
} | ||
}; | ||
// initialize everything | ||
const initMenu = () => { | ||
themeMenu.removeAttribute('hidden'); | ||
// modes | ||
const getMode = () => | ||
parseInt(getComputedStyle(root).getPropertyValue("--ccs-mode").trim(), 10); | ||
const changeMode = (scheme) => { | ||
const schemeDict = { | ||
light: 1, | ||
dark: -1, | ||
auto: 0, | ||
}; | ||
const setting = schemeDict[scheme]; | ||
if (setting) { | ||
setValue("mode", setting); | ||
} else { | ||
// if auto, remove mode props from root and store | ||
clearStore(["mode"]); | ||
clearProps(["mode"]); | ||
} | ||
}; | ||
const initValue = type => { | ||
selectElements[type].setAttribute('data-default', selectElements[type].value); | ||
const toggleMode = () => { | ||
const modeDict = { | ||
1: modeLight, | ||
[-1]: modeDark, | ||
}; | ||
const mode = getMode(); | ||
setValue("mode", mode * -1); | ||
const modeBtn = modeDict[mode * -1]; | ||
if (modeBtn) { | ||
modeBtn.checked = true; | ||
} | ||
}; | ||
const to = localStorage.getItem(store[type]); | ||
if (to) { | ||
setValue(type, to, false); | ||
selectElements[type].value = to; | ||
unsetBtn.removeAttribute('hidden'); | ||
// initialize everything | ||
const initMenu = () => { | ||
if (themeMenu) { | ||
themeMenu.removeAttribute("hidden"); | ||
} | ||
}; | ||
const initMode = () => { | ||
let to = localStorage.getItem(store.mode); | ||
if (to) { | ||
setValue('mode', to); | ||
unsetBtn.removeAttribute('hidden'); | ||
const modeDict = { | ||
1: modeLight, | ||
[-1]: modeDark, | ||
}; | ||
const modeBtn = modeDict[to]; | ||
setValue("mode", to); | ||
if (modeBtn) { | ||
modeBtn.checked = true; | ||
} | ||
} else if (modeAuto) { | ||
modeAuto.checked = true; | ||
} | ||
}; | ||
const initValue = (type) => { | ||
controls[type].setAttribute("data-default", controls[type].value); | ||
const to = localStorage.getItem(store[type]); | ||
if (to) { | ||
setValue(type, to, false); | ||
controls[type].value = to; | ||
showUnsetBtn(); | ||
} | ||
}; | ||
// init & events | ||
document.onload = initMenu(); | ||
document.onload = initMode(); | ||
modeToggle.addEventListener('click', () => changeMode()); | ||
unsetBtn.addEventListener('click', () => clearColors()); | ||
/* init defaults */ | ||
window.onload = initMenu(); | ||
window.onload = initMode(); | ||
Object.keys(selectElements).forEach(type => { | ||
if (selectElements[type]) { | ||
document.onload = initValue(type); | ||
selectElements[type].addEventListener('input', () => | ||
setValue(type, selectElements[type].value), | ||
/* attach event listeners */ | ||
invertBtn && invertBtn.addEventListener("click", toggleMode); | ||
modeLight && modeLight.addEventListener("change", () => changeMode("light")); | ||
modeDark && modeDark.addEventListener("change", () => changeMode("dark")); | ||
modeAuto && modeAuto.addEventListener("change", () => changeMode("auto")); | ||
unsetBtn && unsetBtn.addEventListener("click", unset); | ||
Object.keys(controls).forEach((type) => { | ||
if (controls[type]) { | ||
window.onload = initValue(type); | ||
controls[type].addEventListener("change", (e) => | ||
setSelection(type, e.target.value) | ||
); | ||
} | ||
}); | ||
}; | ||
} |
{ | ||
"name": "cascading-color-systems", | ||
"version": "0.1.0-beta.12", | ||
"version": "0.1.0-beta.13", | ||
"description": "generate dynamic color palettes with custom properties", | ||
"title": "Cascading Color Systems", | ||
"title": "Cascading Colors", | ||
"main": "dist.js", | ||
@@ -19,5 +19,5 @@ "module": "index.js", | ||
"devDependencies": { | ||
"@babel/cli": "^7.10.3", | ||
"@babel/core": "^7.10.3", | ||
"@babel/plugin-transform-modules-umd": "^7.10.1", | ||
"@babel/cli": "^7.10.4", | ||
"@babel/core": "^7.10.4", | ||
"@babel/plugin-transform-modules-umd": "^7.10.4", | ||
"cssremedy": "^0.1.0-beta.2", | ||
@@ -32,6 +32,6 @@ "sass": "^1.26.9", | ||
"build-js": "yarn babel index.js --out-file dist.js", | ||
"build-site": "sass site/sass/styles.scss site/css/styles.css", | ||
"build": "yarn build-sass && yarn build-docs && yarn build-js && yarn build-site", | ||
"build-demo": "sass demo/sass/styles.scss demo/css/styles.css", | ||
"build": "yarn build-sass && yarn build-docs && yarn build-js && yarn build-demo", | ||
"commit": "yarn build", | ||
"watch": "sass --watch site/sass/:site/css/" | ||
"watch": "sass --watch demo/sass/:demo/css/" | ||
}, | ||
@@ -38,0 +38,0 @@ "files": [ |
@@ -1,2 +0,2 @@ | ||
# Cascading Color Systems | ||
# Cascading Colors | ||
@@ -147,3 +147,3 @@ [Demo Site](https://cascading-colors.netlify.app/) | ||
the calculated hue for each color, | ||
afterresolving user-settings, theme-settings, and global configuration | ||
after resolving user-settings, theme-settings, and global configuration | ||
- `--ccs-contrast`: | ||
@@ -271,16 +271,44 @@ the calculated contrast range | ||
We provide several hooks for the JS to use | ||
### HTML Attributes | ||
We provide several attributes | ||
that can be used to build | ||
a user-interface for changing colors. | ||
The `root` attribute is required: | ||
- `[data-ccs="root"]`: | ||
where user settings should be applied | ||
#### General Controls: | ||
- `[data-ccs="menu"]`: | ||
if you hide the settings by default, | ||
we'll show them when the JS is available | ||
- `[data-ccs-input="mode"]`: | ||
a button to toggle light/dark modes | ||
You can hide the settings menu and unset buttons by default, | ||
and we'll show them when the JS is available | ||
- `[data-ccs-input="unset"]`: | ||
a button to unset all user preferences | ||
A button to unset all user preferences | ||
and clear related local storage | ||
- `[data-ccs-input="theme"]`: | ||
Allow users to select from available `theme` options | ||
#### Light/Dark Mode: | ||
Mode can be toggled with a button: | ||
- `[data-ccs-input="mode"]`: | ||
A button to toggle light/dark modes | ||
Or mode can be set explicitly using radio inputs: | ||
- `[data-ccs-input="light-mode"]`: | ||
Set light mode when checked | ||
- `[data-ccs-input="dark-mode"]`: | ||
Set dark mode when checked | ||
- `[data-ccs-input="auto-mode"]`: | ||
Unset explicit mode when checked, | ||
and fallback on browser/operating-system settings | ||
#### Themes & Values: | ||
- `[data-ccs-input~="theme"]`: | ||
Allow users to select from available `theme` options. | ||
Add `unset-values` to revert all other theme values | ||
when changing themes. | ||
- `[data-ccs-input="hue"]`: | ||
@@ -295,7 +323,7 @@ Allow users to change the primary hue | ||
Themes can also use the `[data-ccs-field]` on wrappers, | ||
to show and hide inputs/labels directly in the CSS | ||
based on a given theme. | ||
Themes can also use `[data-ccs-field]` attributes | ||
with the values above | ||
to show and hide inputs/labels based on a given theme. | ||
For example, a high-contrast theme | ||
might not accept `contrast` input: | ||
might not accept user `contrast` input: | ||
@@ -302,0 +330,0 @@ ```scss |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
647281
1076
333
0