-
-
Notifications
You must be signed in to change notification settings - Fork 151
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hiccup-css): add package @thi.ng/hiccup-css
- Loading branch information
1 parent
92fb7b0
commit 3a4cf1e
Showing
7 changed files
with
267 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
node_modules | ||
yarn.lock | ||
*.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# @thi.ng/hiccup-css | ||
|
||
[![npm (scoped)](https://img.shields.io/npm/v/@thi.ng/hiccup-css.svg)](https://www.npmjs.com/package/@thi.ng/hiccup-css) | ||
|
||
## About | ||
|
||
CSS as nested data structures. | ||
|
||
## Installation | ||
|
||
``` | ||
yarn add @thi.ng/hiccup-css | ||
``` | ||
|
||
## Usage examples | ||
|
||
```typescript | ||
import { css, FORMATS } from "@thi.ng/hiccup-css"; | ||
|
||
css(["#foo", | ||
{ background: "#eee" }, | ||
["h1", { "font-size": "2em" }, ["small", { color: "#999"}]], | ||
["h2", "h3", [".title", { "font-weight": 700 }]]], | ||
FORMATS.pretty); | ||
``` | ||
|
||
```css | ||
#foo h1 small { | ||
color:#999; | ||
} | ||
#foo h1 { | ||
font-size:2em; | ||
} | ||
#foo h2 .title, #foo h3 .title { | ||
font-weight:700; | ||
} | ||
#foo { | ||
background:#eee; | ||
} | ||
``` | ||
|
||
## Authors | ||
|
||
- Karsten Schmidt | ||
|
||
## License | ||
|
||
© 2018 Karsten Schmidt // Apache Software License 2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
{ | ||
"name": "@thi.ng/hiccup-css", | ||
"version": "0.0.1", | ||
"description": "CSS as nested data structures", | ||
"main": "./index.js", | ||
"typings": "./index.d.ts", | ||
"repository": "https://github.com/thi-ng/umbrella", | ||
"author": "Karsten Schmidt <k+npm@thi.ng>", | ||
"license": "Apache-2.0", | ||
"scripts": { | ||
"build": "yarn clean && tsc --declaration", | ||
"clean": "rm -rf *.js *.d.ts .nyc_output build coverage doc", | ||
"cover": "yarn test && nyc report --reporter=lcov", | ||
"doc": "node_modules/.bin/typedoc --mode modules --out doc src", | ||
"pub": "yarn build && yarn publish --access public", | ||
"test": "rm -rf build && tsc -p test && nyc mocha build/test/*.js" | ||
}, | ||
"devDependencies": { | ||
"@types/mocha": "^2.2.48", | ||
"@types/node": "^9.4.6", | ||
"mocha": "^5.0.0", | ||
"nyc": "^11.4.1", | ||
"ts-loader": "^3.5.0", | ||
"typedoc": "^0.10.0", | ||
"typescript": "^2.7.2", | ||
"webpack": "^3.11.0" | ||
}, | ||
"dependencies": { | ||
"@thi.ng/api": "^2.0.3", | ||
"@thi.ng/transducers": "^1.6.1" | ||
}, | ||
"keywords": [ | ||
"clojure", | ||
"components", | ||
"ES6", | ||
"hiccup", | ||
"html", | ||
"iterators", | ||
"json", | ||
"serialization", | ||
"svg", | ||
"template", | ||
"typescript", | ||
"xml" | ||
], | ||
"publishConfig": { | ||
"access": "public" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { IObjectOf } from "@thi.ng/api/api"; | ||
import { isArray } from "@thi.ng/checks/is-array"; | ||
import { isPlainObject } from "@thi.ng/checks/is-plain-object"; | ||
import { transduce } from "@thi.ng/transducers/transduce"; | ||
import { permutations } from "@thi.ng/transducers/iter/permutations"; | ||
import { str } from "@thi.ng/transducers/rfn/str"; | ||
import { flatten } from "@thi.ng/transducers/xform/flatten"; | ||
import { map } from "@thi.ng/transducers/xform/map"; | ||
|
||
export interface Format { | ||
rules: string; | ||
ruleSep: string; | ||
decls: string; | ||
declsStart: string; | ||
declEnd: string; | ||
indent: string; | ||
} | ||
|
||
const NO_SPACES = ":["; | ||
|
||
export const FORMATS: IObjectOf<Format> = { | ||
min: { rules: "", ruleSep: ",", decls: "", declsStart: "{", declEnd: "}", indent: "" }, | ||
pretty: { rules: "\n", ruleSep: ", ", decls: "\n", declsStart: " {\n", declEnd: "\n}", indent: " " }, | ||
}; | ||
|
||
const xfSel = ((a, b) => (x) => a(b(x)))( | ||
flatten(), | ||
map((x: string) => NO_SPACES.indexOf(x.charAt(0)) >= 0 ? x : " " + x) | ||
); | ||
|
||
export function css(rules: any, fmt = FORMATS.min) { | ||
if (isArray(rules)) { | ||
return _css([], [], rules, fmt).join(fmt.rules); | ||
} | ||
if (isPlainObject(rules)) { | ||
return format(rules, fmt); | ||
} | ||
} | ||
|
||
function _css(acc: string[], parent: any[], rules: any[], fmt: Format) { | ||
const n = rules.length; | ||
const sel: string[] = []; | ||
let curr: any; | ||
for (let i = 0; i < n; i++) { | ||
const r = rules[i]; | ||
if (isArray(r)) { | ||
_css(acc, makeSelector(parent, sel), r, fmt); | ||
} else if (isPlainObject(r)) { | ||
curr = Object.assign(curr || {}, r); | ||
} else { | ||
sel.push(r); | ||
} | ||
} | ||
if (curr) { | ||
acc.push(formatRule(parent, sel, curr, fmt)); | ||
} | ||
return acc; | ||
} | ||
|
||
function format(rules: any, fmt: Format) { | ||
const acc = []; | ||
for (let r in rules) { | ||
if (rules.hasOwnProperty(r)) { | ||
acc.push(`${fmt.indent}${r}:${rules[r]};`); | ||
} | ||
} | ||
return acc.join(fmt.decls); | ||
} | ||
|
||
function makeSelector(parent: any[], curr: any[]) { | ||
return parent.length ? [...permutations(parent, curr)] : curr; | ||
} | ||
|
||
function formatRule(parent: any[], sel: any[], curr: any, fmt: Format) { | ||
return transduce( | ||
map((sel: any[]) => transduce(xfSel, str(), isArray(sel) ? sel : [sel]).trim()), | ||
str(fmt.ruleSep), | ||
makeSelector(parent, sel)) | ||
+ fmt.declsStart | ||
+ format(curr, fmt) | ||
+ fmt.declEnd; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import * as assert from "assert"; | ||
|
||
import { css, FORMATS } from "../src"; | ||
|
||
const rules = { | ||
a: { color: "red" }, | ||
b: { border: 0 }, | ||
}; | ||
|
||
describe("hiccup-css", () => { | ||
|
||
it("rules only", () => { | ||
assert.equal(css("a"), undefined); | ||
assert.equal(css({}), ""); | ||
assert.equal(css(rules.a), "color:red;"); | ||
}); | ||
|
||
it("simple", () => { | ||
assert.equal(css(["a"]), ""); | ||
assert.equal(css(["a", rules.a]), "a{color:red;}"); | ||
assert.equal( | ||
css([["a", rules.a], ["b", rules.b]]), | ||
"a{color:red;}b{border:0;}" | ||
); | ||
assert.equal( | ||
css(["a", "b", rules.a, rules.b]), | ||
"a,b{color:red;border:0;}" | ||
); | ||
}); | ||
|
||
it("nested", () => { | ||
assert.equal( | ||
css(["a", [":link", rules.a], [":visited", rules.b]]), | ||
"a:link{color:red;}a:visited{border:0;}" | ||
); | ||
assert.equal( | ||
css(["p", ["a", [":link", rules.a], [":visited", rules.b]]]), | ||
"p a:link{color:red;}p a:visited{border:0;}" | ||
); | ||
assert.equal( | ||
css( | ||
["#id", | ||
["h1", {}, {}], | ||
["h2", "h3", | ||
["div", {}], | ||
["[attr]", | ||
["span", rules.a]]]] | ||
), | ||
"#id h1{}#id h2 div,#id h3 div{}#id h2[attr] span,#id h3[attr] span{color:red;}" | ||
); | ||
}); | ||
|
||
it("pretty", () => { | ||
assert.equal( | ||
css( | ||
["#id", | ||
["h1", {}, {}], | ||
["h2", "h3", | ||
["div", {}], | ||
["[attr]", | ||
["span", rules.a]]]], | ||
FORMATS.pretty), | ||
"#id h1 {\n\n}\n#id h2 div, #id h3 div {\n\n}\n#id h2[attr] span, #id h3[attr] span {\n color:red;\n}" | ||
); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"extends": "../../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "../build" | ||
}, | ||
"include": [ | ||
"./**/*.ts", | ||
"../src/**/*.ts" | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
{ | ||
"extends": "../../tsconfig.json", | ||
"compilerOptions": { | ||
"outDir": "." | ||
}, | ||
"include": [ | ||
"./src/**/*.ts" | ||
] | ||
} |