From 476e5568d051c6a71f5ebee5f4c2ee887b6af3ee Mon Sep 17 00:00:00 2001 From: cha0s Date: Sat, 8 Sep 2018 22:55:42 -0500 Subject: [PATCH] chore: initial --- index.js | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 12 ++++++++ yarn.lock | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 index.js create mode 100644 package.json create mode 100644 yarn.lock diff --git a/index.js b/index.js new file mode 100644 index 0000000..9d9706d --- /dev/null +++ b/index.js @@ -0,0 +1,84 @@ + +import * as css from 'css'; +import React from 'react'; + +let newId = 0; +const map = new WeakMap(); +let sheet = null; + +// Ensure styles exist for a component. +const ensureComponentStyles = (constructor, styles) => { + + if (!window || !styles || map.has(constructor)) { + return; + } + newId += 1; + const id = newId.toString(36); + map.set(constructor, id); + + // Ensure sheet exists. + if (!sheet) { + sheet = window.document.createElement('style'); + sheet.id = 'stylist-styles'; + window.document.getElementsByTagName('head')[0].appendChild(sheet); + } + + // All rules made component-specific. + for (const style of styles) { + + const ast = css.parse(style); + ast.stylesheet.rules = mapStyleRulesTree(ast.stylesheet.rules, id); + sheet.innerHTML += css.stringify(ast); + } +} + +const mapStyleRulesTree = (rules, id) => rules.map((rule) => { + + // Recur for mediaqueries. + if ('media' === rule.type) { + rule.rules = mapStyleRulesTree(rule.rules, id); + } + + if (!rule.selectors) { + return rule; + } + + return { + ...rule, + ...{ + selectors: rule.selectors.map((rule) => + `[data-component-style="${id}"] ${rule}` + ), + }, + }; +}); + +export default function Stylist(Component, styles) { + if (!Array.isArray(styles)) { + styles = [styles]; + } + + const createRenderFunction = (constructor, markupFn) => function() { + ensureComponentStyles(constructor, styles); + + const markup = markupFn.apply(this, arguments); + const id = map.get(constructor); + if (!id) { + return markup; + } + return {markup}; + } + + if (Component.prototype.render) { + class StylistComponent extends Component { + } + StylistComponent.prototype.render = createRenderFunction( + Component, Component.prototype.render + ); + return StylistComponent; + } + else { + return createRenderFunction(Component, Component); + } +} + diff --git a/package.json b/package.json new file mode 100644 index 0000000..d66cd04 --- /dev/null +++ b/package.json @@ -0,0 +1,12 @@ +{ + "name": "contempo", + "version": "1.0.0", + "description": "Component styles from text", + "main": "index.js", + "author": "cha0s", + "license": "MIT", + "dependencies": { + "css": "^2.2.4", + "react": "^16.5.0" + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..12d3342 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,86 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +atob@^2.1.1: + version "2.1.2" + resolved "https://npm.i12e.cha0s.io/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + +css@^2.2.4: + version "2.2.4" + resolved "https://npm.i12e.cha0s.io/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" + dependencies: + inherits "^2.0.3" + source-map "^0.6.1" + source-map-resolve "^0.5.2" + urix "^0.1.0" + +decode-uri-component@^0.2.0: + version "0.2.0" + resolved "https://npm.i12e.cha0s.io/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + +inherits@^2.0.3: + version "2.0.3" + resolved "https://npm.i12e.cha0s.io/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://npm.i12e.cha0s.io/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + +loose-envify@^1.1.0, loose-envify@^1.3.1: + version "1.4.0" + resolved "https://npm.i12e.cha0s.io/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://npm.i12e.cha0s.io/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +prop-types@^15.6.2: + version "15.6.2" + resolved "https://npm.i12e.cha0s.io/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102" + dependencies: + loose-envify "^1.3.1" + object-assign "^4.1.1" + +react@^16.5.0: + version "16.5.0" + resolved "https://npm.i12e.cha0s.io/react/-/react-16.5.0.tgz#f2c1e754bf9751a549d9c6d9aca41905beb56575" + dependencies: + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.2" + schedule "^0.3.0" + +resolve-url@^0.2.1: + version "0.2.1" + resolved "https://npm.i12e.cha0s.io/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + +schedule@^0.3.0: + version "0.3.0" + resolved "https://npm.i12e.cha0s.io/schedule/-/schedule-0.3.0.tgz#1be2ab2fc2e768536269ce7326efb478d6c045e8" + dependencies: + object-assign "^4.1.1" + +source-map-resolve@^0.5.2: + version "0.5.2" + resolved "https://npm.i12e.cha0s.io/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259" + dependencies: + atob "^2.1.1" + decode-uri-component "^0.2.0" + resolve-url "^0.2.1" + source-map-url "^0.4.0" + urix "^0.1.0" + +source-map-url@^0.4.0: + version "0.4.0" + resolved "https://npm.i12e.cha0s.io/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + +source-map@^0.6.1: + version "0.6.1" + resolved "https://npm.i12e.cha0s.io/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + +urix@^0.1.0: + version "0.1.0" + resolved "https://npm.i12e.cha0s.io/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"