Skip to content

Commit

Permalink
feat(lyl): support for declarations within media queries
Browse files Browse the repository at this point in the history
  • Loading branch information
Enlcxx committed Jan 9, 2020
1 parent 97f6c57 commit 8b87ffc
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 30 deletions.
84 changes: 65 additions & 19 deletions src/lib/src/parse.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,28 @@ export class LylParse {
const media = matchArray[1];
if (media !== key && val.length) {
const after = rules.get(media)!;
const newValue = after + key.replace(media + '{', '') + `{${val.join(';')}}`;
const sel = key.replace(media + '{', '');
const newValue = after + val.reduce((previous, current) => {

const last = previous[previous.length - 1];

if (current.startsWith('/* >> ds')) {
previous.push(current.replace(/\|\|\&\|\|/g, sel));
} else if (current.startsWith('/* >> cc')) {
previous.push(transformCC(current, sel));
} else {
if (Array.isArray(last)) {
last.push(current);
} else {
previous.push([current]);
}
}
return previous;
}, [] as (string | string[])[])
.map(item => Array.isArray(item) ? `${sel}{${item.join('')}}` : item).join('');
// const newValue = after
// + sel
// + `{${val.join('')}}`;
rules.set(media, [newValue]);
rules.delete(key);
}
Expand All @@ -146,17 +167,15 @@ export class LylParse {
const css: string[] = [];
const contentRendered: string[] = [];
const set = new Set<string[]>();

for (let index = 0; index < contents.length; index++) {
let content = contents[index];
const content = contents[index];
if (content) {
if (content.startsWith('/* >> ds')) {
contentRendered.push(content.replace(/\|\|\&\|\|/g, sel));
set.add(contentRendered);
} else if (content.startsWith('/* >> cc')) {
content = content.replace(/\/\* >> cc[^\/\*]+\*\//g, '');
let expression = content.slice(2, content.length - 1);
expression = `styleTemplateToString((${expression}), \`${sel}\`)`;
contentRendered.push(`\${${expression}}`);
contentRendered.push(transformCC(content, sel));
set.add(contentRendered);
} else {
// css += `${sel}{${content}}`;
Expand All @@ -183,7 +202,7 @@ export class LylParse {
// if (content.startsWith('/* >> cc')) {
// content = content.replace(/\/\* >> cc[^\/\*]+\*\//g, '');
// let variable = content.slice(2, content.length - 1);
// variable = `styleTemplateToString((${variable}), \`${sel}\`)`;
// variable = `st2c((${variable}), \`${sel}\`)`;
// return `\${${variable}}`;
// }
// // for non LylModule>
Expand Down Expand Up @@ -227,18 +246,28 @@ export class LylParse {

}

function transformCC(content: string, sel: string) {
content = content.replace(/\/\* >> cc[^\/\*]+\*\//g, '');
let expression = content.slice(2, content.length - 1);
expression = `st2c((${expression}), \`${sel}\`)`;
return `\${${expression}}`;
}

export type StyleTemplate = (className: string) => string;

export function lyl(literals: TemplateStringsArray, ...placeholders: (string | Color | StyleCollection | number | StyleTemplate | null | undefined)[]) {
export function lyl(literals: TemplateStringsArray, ...placeholders: (string | Color | StyleCollection | number | StyleTemplate | LylDeclarationBlock | null | undefined)[]) {
return (className: string) => {
let result = '';
const dsMap = new Map<string, (StyleTemplate) | StyleCollection>();
const dsMap = new Map<string, (StyleTemplate) | StyleCollection | LylDeclarationBlock>();
for (let i = 0; i < placeholders.length; i++) {
const placeholder = placeholders[i];
result += literals[i];
if (result.endsWith('...')) {
result = result.slice(0, result.length - 3);
if (typeof placeholder === 'function' || placeholder instanceof StyleCollection) {
if (typeof placeholder === 'function'
|| placeholder instanceof StyleCollection
|| Array.isArray(placeholder)
) {
const newID = createUniqueId();
dsMap.set(newID, placeholder);
result += newID;
Expand All @@ -253,13 +282,7 @@ export function lyl(literals: TemplateStringsArray, ...placeholders: (string | C
const css = result.replace(STYLE_TEMPLATE_REGEX(), (str) => {
if (dsMap.has(str)) {
const fn = dsMap.get(str)!;
let template: StyleTemplate;
if (fn instanceof StyleCollection) {
template = fn.css;
} else {
template = fn;
}
return `${createUniqueCommentSelector('ds')}${template('||&||')}`;
return `${createUniqueCommentSelector('ds')}${st2c(fn, '||&||')}`;
}
return '';
});
Expand Down Expand Up @@ -322,12 +345,35 @@ export class StyleCollection<T = any> {

}

/**
* The declaration block can an array of declarations,
* where each declaration contains a property name and value.
* If a declaration is `null` or `undefined` it will not be rendered.
* e.g.
*
* ['color:red']
*/
export type LylDeclarationBlock = (string | null | undefined)[];

export function styleTemplateToString(fn: StyleTemplate | StyleCollection | null | undefined, className: string) {
/**
* Transform a ...{style} to css
* For internal use purposes only
* @param fn StyleTemplate or StyleCollection
* @param className class name
*/
export function st2c(
fn: StyleTemplate | StyleCollection | LylDeclarationBlock | null | undefined,
className: string) {
if (fn == null) {
return '';
}
if (fn instanceof StyleCollection) {
return fn.css(className);
}
return fn ? (fn)(className) : '';
if (typeof fn === 'function') {
return (fn)(className);
}
return fn.filter((item) => !!item).join(';');
}

// export function normalizeStyleTemplate(
Expand Down
58 changes: 48 additions & 10 deletions src/lib/style-compiler/compiler.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import anyTest, { TestInterface } from 'ava';
import { hasLylStyle, styleCompiler } from './compiler';
import { styleTemplateToString, StyleCollection, lyl } from '../src/parse';
import { st2c, StyleCollection, lyl } from '../src/parse';
import * as tsNode from 'ts-node';

const test = anyTest as TestInterface<Context>;
Expand All @@ -12,7 +12,7 @@ class Context {
}\`
style('.y')`;

styleIntoObjectAsFunction = `${styleTemplateToString}\n${StyleCollection}\nconst styles = {
styleIntoObjectAsFunction = `${st2c}\n${StyleCollection}\nconst styles = {
item: () => lyl \`{
color: \${'blue'}
...\${null}
Expand All @@ -36,7 +36,7 @@ class Context {
`;

inheritanceStyle = `
${styleTemplateToString}\n
${st2c}\n
${StyleCollection}
const colorBlue = lyl \`{
color: blue
Expand Down Expand Up @@ -307,9 +307,9 @@ test(`compile complex style`, async t => {
import {
LyTheme2,
LyHostClass,
styleTemplateToString } from '@alyle/ui';
st2c } from '@alyle/ui';
const style = (className: string) => \`\${className}{color:red;}\${styleTemplateToString((
const style = (className: string) => \`\${className}{color:red;}\${st2c((
topZero), \`\${className}\`)}\`;
`);
});
Expand All @@ -321,10 +321,10 @@ test(`compile simple and complex style`, async t => {
import {
LyTheme2,
LyHostClass,
styleTemplateToString } from '@alyle/ui';
st2c } from '@alyle/ui';
const topZero = (className: string) => \`\${className}{top:0;}\`
const style = (className: string) => \`\${className}{color:red;}\${styleTemplateToString((
const style = (className: string) => \`\${className}{color:red;}\${st2c((
topZero), \`\${className}\`)}\`;
`);
});
Expand Down Expand Up @@ -367,17 +367,17 @@ import { Router, ActivatedRoute } from '@angular/router';
import {
LyTheme2,
LyHostClass,
styleTemplateToString } from '@alyle/ui';
st2c } from '@alyle/ui';
import { AUIThemeVariables } from '@app/app.module';
const zero = 0;
const topZero = (className: string) => \`\${className}{top:\${zero}px;}\`;
const colorRedAndTopZero = (className: string) => \`\${className}{color:red;}\${styleTemplateToString((item0), \`\${className}\`)}\`;
const colorRedAndTopZero = (className: string) => \`\${className}{color:red;}\${st2c((item0), \`\${className}\`)}\`;
const item2 = (className: string) => \`\${styleTemplateToString((item), \`\${className}\`)}\${className} ul{margin:0;padding:\${zero};list-style:none;}\${styleTemplateToString((item), \`\${className} ul\`)}\${className} li a{display:inline-block;}\${className} a{display:block;padding:6px \${12}px;text-decoration:none;}\${className} ul > li{list-style-type:none;}\${className} h2 + p{border-top:1px solid gray;}\${className} p ~ span{opacity:0.8;}\`;
const item2 = (className: string) => \`\${st2c((item), \`\${className}\`)}\${className} ul{margin:0;padding:\${zero};list-style:none;}\${st2c((item), \`\${className} ul\`)}\${className} li a{display:inline-block;}\${className} a{display:block;padding:6px \${12}px;text-decoration:none;}\${className} ul > li{list-style-type:none;}\${className} h2 + p{border-top:1px solid gray;}\${className} p ~ span{opacity:0.8;}\`;
`);
// tslint:enable
});
Expand Down Expand Up @@ -438,6 +438,44 @@ test(`with comments`, async t => {
t.is(css, `.y .a{color:blue;}`);
t.is(lyl `${styleContent}`('.y'), `.y .a{color:blue;}`);
});
test(`media queries with inheritance style`, async t => {
const inStyle = lyl `{
color: blue
sel {
prop: value
}
}`;
const styleContent = lyl `{
@media all {
prop: value
prop2: value2
...${inStyle}
prop3: value3
}
}`;
const css = evalScript(`
${st2c}
${StyleCollection}
const inStyle = lyl \`{
color: blue
sel {
prop: value
}
}\`;
const style = lyl \`{
@media all {
prop: value
prop2: value2
...\${inStyle}
prop3: value3
}
}\`;
style('.y');
`);
const expected = '@media all{.y{prop:value;prop2:value2;}.y{color:blue;}.y sel{prop:value;}.y{prop3:value3;}}';
t.is(css, expected);
t.is(styleContent('.y').replace(/\/\* >> ds[^\/\*]+\*\//g, ''), expected);
});

function evalScript(script: string) {
// tslint:disable-next-line: no-eval
Expand Down
2 changes: 1 addition & 1 deletion src/lib/style-compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ function updateImport(content: string, numSimpleStyles: number, numComplexStyles
const modulePath = importDeclaration.moduleSpecifier.getFullText();
if ((numSimpleStyles && numComplexStyles) || numComplexStyles) {
imports = imports.map(
imp => imp === 'lyl' ? 'styleTemplateToString' : imp);
imp => imp === 'lyl' ? 'st2c' : imp);
} else if (numSimpleStyles) {
imports = imports.filter(imp => imp !== 'lyl');
}
Expand Down

0 comments on commit 8b87ffc

Please sign in to comment.