Skip to content

Instantly share code, notes, and snippets.

@subtleGradient
Last active September 6, 2018 19:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save subtleGradient/a47830160afb246980b1a16e4f7458ad to your computer and use it in GitHub Desktop.
Save subtleGradient/a47830160afb246980b1a16e4f7458ad to your computer and use it in GitHub Desktop.
Sheet Mixin Demo. Shows how to use spreadable mixins to do some wacky behavior sheets stuff with React
<!doctype html>
<meta charset=utf-8>
<title>HasSheetsMixin</title>
<script src="http://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.11.0/es6-shim.min.js"></script>
<script src="http://fb.me/react-with-addons-0.11.1.js"></script>
<script src="http://fb.me/JSXTransformer-0.11.1.js"></script>
<div id="SheetsDemoRoot"></div>
<script type="text/jsx;harmony=true" src="SheetMixinDemo.jsx"></script>
/** @jsx React.DOM */
function createMergingSelector(getSheets){
return function mergeStyles(...names){
return mergeMatchingItemsFromSheets(getSheets(this, names), this, names);
};
}
function createCollectionSelector(getSheets){
return function collectStyles(...names){
return collectMatchingItemsFromSheets(getSheets(this, names), this, names);
};
}
function assignOntoThis(object){
Object.assign(this, object);
}
function mergeMatchingItemsFromSheets(sheets, component, names){
return collectMatchingItemsFromSheets(sheets, component, names, assignOntoThis, {});
}
function collectMatchingItemsFromSheets(sheets, component, names, callback, callbackThis){
if (!Array.isArray(sheets)) {
return;
}
if (callback === undefined) {
callbackThis = [];
callback = callbackThis.push;
}
for (var sheetIndex=0, sheet; sheet = sheets[sheetIndex]; sheetIndex++){
for (var nameIndex=0, name; name = names[nameIndex]; nameIndex++){
var style = typeof name == 'string' ? sheet[name] : name;
callbackThis = forEachMatchingItem(style, component, name, callback, callbackThis);
}
}
return callbackThis;
}
function forEachMatchingItem(item, component, refName, callback, callbackThis){
if (item == null) {
return callbackThis;
}
if (typeof item == 'object' && Array.isArray(item)) {
for (var itemPartsIndex=0, itemPart; itemPart = item[itemPartsIndex]; itemPartsIndex++){
callbackThis = forEachMatchingItem(itemPart, component, refName, callback, callbackThis);
}
return callbackThis;
} else if (typeof item == 'function') {
item = item(component, refName);
}
if (item == null) {
return callbackThis;
}
if (callback === undefined) {
callbackThis = [];
callback = callbackThis.push;
}
callback.call(callbackThis, item);
return callbackThis;
}
// if (__DEV__)
{
;(function(){
var global = this;
var theThis = {theThis:true}; var theComponent = {theComponent:true}; var theRefName = {theRefName:true};
var theStyle = {color:'red'};
var callbackCount = 0;
forEachMatchingItem(theStyle, theComponent, theRefName, function(style) {
callbackCount++;
console.assert(style === theStyle);
console.assert(arguments.length === 1);
console.assert(this === theThis);
}, theThis);
console.assert(callbackCount === 1);
forEachMatchingItem(theStyle, theComponent, theRefName, function(style) {
callbackCount++;
console.assert(style === theStyle);
console.assert(arguments.length === 1);
console.assert(this === global);
});
console.assert(callbackCount === 2);
}());
;(function(){
var theThis = {}; var theComponent = {}; var theRefName = {};
var theStyle = {color:'red'};
var callbackCount = 0;
var matchingStyles = forEachMatchingItem(theStyle, theComponent, theRefName);
console.assert(matchingStyles.length === 1);
forEachMatchingItem(theStyle, theComponent, theRefName, matchingStyles.push, matchingStyles);
console.assert(matchingStyles.length === 2);
forEachMatchingItem(theStyle, theComponent, theRefName, matchingStyles.push, matchingStyles);
console.assert(matchingStyles.length === 3);
}());
;(function(){
var theThis = {}; var theComponent = {}; var theRefName = {};
var theStyle = 123;
var callbackCount = 0;
var matchingStyles = forEachMatchingItem(theStyle, theComponent, theRefName);
console.assert(matchingStyles.length === 1);
matchingStyles[0] === theStyle;
}());
;(function(){
var theStyle = {theStyle:true};
var callbackCount = 0;
var matchingStyles = forEachMatchingItem(function(){callbackCount++;return theStyle});
console.assert(callbackCount === 1);
console.assert(matchingStyles.length === 1);
matchingStyles[0] === theStyle;
}());
};
////////////////////////////////////////////////////////////////////////////////
var OtherStyles = {
awesomeable: component => component.props.isAwesome ? OtherStyles.awesome : OtherStyles.notAwesome,
awesome: {
backgroundColor: 'yellow',
},
notAwesome: {
backgroundColor: 'gray',
},
hoverable: (component, ref) => component.state && component.state[ref + 'IsHovering'] && OtherStyles.awesome || undefined,
};
var DemoSheet = {
body: [
OtherStyles.awesomeable,
OtherStyles.hoverable,
],
};
var BasicBehaviors = {
// hover: {
// onMouseEnter(event){console.log(event)},
// onMouseLeave(event){console.log(event)},
// },
hover: (component, ref) => (
component['hover ' + ref] || (
component['hover ' + ref] = {
onMouseEnter(event){
var changeSet = {};
changeSet[ref + 'IsHovering'] = true;
component.setState(changeSet);
},
onMouseLeave(event){
var changeSet = {};
changeSet[ref + 'IsHovering'] = false;
component.setState(changeSet);
},
}
)
),
};
var SheetsDemoBehaviors = {
body: [
BasicBehaviors.hover,
],
};
var SheetsDemoStyles = {
body: [
OtherStyles.awesomeable,
OtherStyles.hoverable,
component => component.state && component.state.bodyIsHovering ? SheetsDemoStyles.bodyHover : SheetsDemoStyles.bodyNotHover,
{
fontSize: 28,
borderSize: 4,
borderStyle: 'solid',
},
],
bodyHover: {
borderColor: '#00FF00',
},
bodyNotHover: {
borderColor: '#0000FF',
},
};
var SheetsDemo = React.createClass({
statics: {
behaviors: [
BasicBehaviors,
SheetsDemoBehaviors,
],
styles: [
DemoSheet,
SheetsDemoStyles,
],
},
behaviors: createMergingSelector(component => component.constructor.behaviors),
mergedStylesForElement: createMergingSelector(component => component.constructor.styles),
propsForRef(ref){
var style = this.mergedStylesForElement.apply(this, arguments);
var behaviors = this.behaviors(ref);
return Object.assign({ref, style}, behaviors);
},
render(){
var ref = this.propsForRef;
return (
<div {...ref('body')}>
<b {...BasicBehaviors.hover(this, 'Hello')}>
Hello
{this.state && this.state.HelloIsHovering && 'LULZ'}
</b>
World {this.state && this.state.bodyIsHovering && 'LULZ'}
</div>
);
},
});
React.renderComponent(
<div>
<SheetsDemo />
<SheetsDemo isAwesome />
</div>,
document.getElementById('SheetsDemoRoot')
);
@subtleGradient
Copy link
Author

Hello from the future. This is REALLY hard to understand. But it's super brilliant! I love it!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment