Skip to content

Commit

Permalink
feat(hiccup-css): add attrib fn, at-rules, quoted fns, decl value arrays
Browse files Browse the repository at this point in the history
- quoted functions map keywords in root-level rules to fns
  (useful for pure JSON definitions, where fns are not possible)
- add @import, @Keyframes, @media, @namespace, @supports fns
- refactor @media & @supports to use generic `conditional()`
- add attrib selector fns
- add support for declaration value arrays (converted to string,
  first level joined w/ `,` and inner arrays joined w/ ` `
- add/update re-exports
  • Loading branch information
postspectacular committed Mar 3, 2018
1 parent e687230 commit ebbc491
Show file tree
Hide file tree
Showing 12 changed files with 96 additions and 16 deletions.
3 changes: 3 additions & 0 deletions packages/hiccup-css/src/api.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
export type RuleFn = (acc: string[], opts: CSSOpts) => string[];

export interface Format {
rules: string;
ruleSep: string;
Expand All @@ -10,6 +12,7 @@ export interface Format {

export interface CSSOpts {
format: Format;
fns: any;
autoprefix: string[] | Set<string>;
vendors: string[];
depth: number;
Expand Down
7 changes: 7 additions & 0 deletions packages/hiccup-css/src/attribs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const $ = (op) => (id: string, x: string | number, caseSensitve = false) => `[${id}${op}="${x}"${caseSensitve ? " i" : ""}]`;
export const withAttrib = (id: string) => `[${id}]`;
export const attribEq = $("");
export const attribIncl = $("~");
export const attribPrefix = $("^");
export const attribSuffix = $("$");
export const attribContains = $("*");
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { CSSOpts } from "./api";
import { CSSOpts, RuleFn } from "./api";
import { _css } from "./css";
import { indent } from "./utils";

export function mediaQuery(cond, rules: any[]) {
export function conditional(type: string, cond: string, rules: any[]): RuleFn {
return (acc: string[], opts: CSSOpts) => {
const space = indent(opts);
acc.push(`${space}@media(${cond})${opts.format.declStart}`);
acc.push(`${space}${type}(${cond})${opts.format.declStart}`);
opts.depth++;
_css(acc, [], rules, opts);
opts.depth--;
Expand Down
27 changes: 21 additions & 6 deletions packages/hiccup-css/src/css.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,14 @@ const xfSel = ((a, b) => (x) => a(b(x)))(
);

export function css(rules: any, opts?: Partial<CSSOpts>) {
opts = { format: COMPACT, autoprefix: new Set(), vendors: DEFAULT_VENDORS, depth: 0, ...opts };
opts = {
format: COMPACT,
autoprefix: new Set(),
vendors: DEFAULT_VENDORS,
fns: {},
depth: 0,
...opts
};
if (isArray(opts.autoprefix)) {
opts.autoprefix = new Set(opts.autoprefix);
}
Expand All @@ -36,16 +43,20 @@ export function css(rules: any, opts?: Partial<CSSOpts>) {
export function _css(acc: string[], parent: any[], rules: any[], opts: CSSOpts) {
const n = rules.length;
const sel: string[] = [];
let curr: any;
let curr: any, isFn;
for (let i = 0; i < n; i++) {
const r = rules[i];
if (isArray(r)) {
_css(acc, makeSelector(parent, sel), r, opts);
} else if (isFunction(r)) {
} else if ((isFn = isFunction(r)) || opts.fns[r]) {
if (parent.length === 0) {
r(acc, opts);
} else {
return opts.fns[r] ?
opts.fns[r].apply(null, rules.slice(i + 1))(acc, opts) :
r(acc, opts);
} else if (isFn) {
sel.push(r());
} else {
throw new Error(`quoted fn ('${r}') only allowed @ root level`);
}
} else if (isPlainObject(r)) {
curr = Object.assign(curr || {}, r);
Expand All @@ -61,6 +72,7 @@ export function _css(acc: string[], parent: any[], rules: any[], opts: CSSOpts)

export function formatDecls(rules: any, opts: CSSOpts) {
const f = opts.format;
const prefixes = <Set<string>>opts.autoprefix;
const space = indent(opts, opts.depth + 1);
const acc = [];
for (let r in rules) {
Expand All @@ -69,7 +81,10 @@ export function formatDecls(rules: any, opts: CSSOpts) {
if (isFunction(val)) {
val = val(rules);
}
if ((<Set<string>>opts.autoprefix).has(r)) {
if (isArray(val)) {
val = val.map((v) => isArray(v) ? v.join(" ") : v).join(f.ruleSep);
}
if (prefixes.has(r)) {
for (let v of opts.vendors) {
acc.push(`${space}${v}${r}:${f.valSep}${val};`);
}
Expand Down
10 changes: 10 additions & 0 deletions packages/hiccup-css/src/import.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export function at_import(url: string, ...queries: string[]) {
return (acc, _) => {
if (queries.length === 0) {
acc.push(`@import url(${url});`);
} else {
acc.push(`@import url(${url}) ${queries.join(" ")};`);
}
return acc;
}
}
8 changes: 7 additions & 1 deletion packages/hiccup-css/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
export * from "./api";
export * from "./attribs";
export * from "./conditional";
export * from "./css";
export * from "./import";
export * from "./keyframes";
export * from "./media-query";
export * from "./media";
export * from "./namespace";
export * from "./quoted-functions";
export * from "./supports";
6 changes: 3 additions & 3 deletions packages/hiccup-css/src/keyframes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { CSSOpts } from "./api";
import { formatDecls } from "./css";
import { indent } from "./utils";

export function keyframes(id: string, stops: any);
export function keyframes(id: string, from: any, to: any);
export function keyframes(id: string, ...args: any[]) {
export function at_keyframes(id: string, stops: any);
export function at_keyframes(id: string, from: any, to: any);
export function at_keyframes(id: string, ...args: any[]) {
const stops = args.length === 1 ? args[0] : { from: args[0], to: args[1] };
return (acc: string[], opts: CSSOpts) => {
const outer = indent(opts);
Expand Down
6 changes: 6 additions & 0 deletions packages/hiccup-css/src/media.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { RuleFn } from "./api";
import { conditional } from "./conditional";

export function at_media(cond, rules: any[]): RuleFn {
return conditional("@media", cond, rules);
}
12 changes: 12 additions & 0 deletions packages/hiccup-css/src/namespace.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function at_namespace(url: string);
export function at_namespace(prefix: string, url: string);
export function at_namespace(...args: string[]) {
return (acc, _) => {
if (args.length === 1) {
acc.push(`@namespace url(${args[0]});`);
} else {
acc.push(`@namespace ${args[0]} url(${args[1]});`);
}
return acc;
}
}
13 changes: 13 additions & 0 deletions packages/hiccup-css/src/quoted-functions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { at_import } from "./import";
import { at_keyframes } from "./keyframes";
import { at_media } from "./media";
import { at_namespace } from "./namespace";
import { at_supports } from "./supports";

export const QUOTED_FNS = {
"@import": at_import,
"@keyframes": at_keyframes,
"@media": at_media,
"@namespace": at_namespace,
"@supports": at_supports,
};
6 changes: 6 additions & 0 deletions packages/hiccup-css/src/supports.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { RuleFn } from "./api";
import { conditional } from "./conditional";

export function at_supports(cond, rules: any[]): RuleFn {
return conditional("@supports", cond, rules);
}
8 changes: 5 additions & 3 deletions packages/hiccup-css/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { css, PRETTY } from "../src";
const rules = {
a: { color: "red" },
b: { border: 0 },
f: { foo: (rules) => rules.bar, bar: 1 }
};

describe("hiccup-css", () => {
Expand All @@ -13,6 +14,7 @@ describe("hiccup-css", () => {
assert.equal(css("a"), undefined);
assert.equal(css({}), "");
assert.equal(css(rules.a), "color:red;");
assert.equal(css(rules.f), "foo:1;bar:1;");
});

it("simple", () => {
Expand Down Expand Up @@ -54,13 +56,13 @@ describe("hiccup-css", () => {
assert.equal(
css(
["#id",
["h1", {}, {}],
["h1", rules.a, rules.b],
["h2", "h3",
["div", {}],
["div", rules.b],
["[attr]",
["span", rules.a]]]],
{ format: PRETTY }),
"#id h1 {\n\n}\n\n#id h2 div, #id h3 div {\n\n}\n\n#id h2[attr] span, #id h3[attr] span {\n color: red;\n}\n"
"#id h1 {\n color: red;\n border: 0;\n}\n\n#id h2 div, #id h3 div {\n border: 0;\n}\n\n#id h2[attr] span, #id h3[attr] span {\n color: red;\n}\n"
);
});
});

0 comments on commit ebbc491

Please sign in to comment.