@alyle/ui
Version:
Minimal Design, a set of components for Angular
354 lines • 12.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StringIdGenerator = exports.StyleCollection = exports.LylParse = void 0;
exports.resolveSelectors = resolveSelectors;
exports.lyl = lyl;
exports.st2c = st2c;
const LINE_FEED_REGEX = () => /[\n\s]*([^\n]+)/g;
const AMPERSAND_REGEX = () => /&/g;
var RuleType;
(function (RuleType) {
RuleType[RuleType["FontFace"] = 0] = "FontFace";
RuleType[RuleType["MediaQuery"] = 1] = "MediaQuery";
RuleType[RuleType["KeyFrame"] = 2] = "KeyFrame";
RuleType[RuleType["Style"] = 3] = "Style";
RuleType[RuleType["DynamicStyle"] = 4] = "DynamicStyle";
RuleType[RuleType["CompiledStyle"] = 5] = "CompiledStyle";
})(RuleType || (RuleType = {}));
/**
* Transform a lyl style block to CSS
*/
class LylParse {
constructor(_template, _className = '${_className}', _isServer,
/** Is true when used inside lyl */
_isDevMode) {
this._template = _template;
this._className = _className;
this._isServer = _isServer;
this._isDevMode = _isDevMode;
}
toCss() {
const selectors = [];
const resolvedSelectors = [];
const rules = [];
this._template
.replace(/(\/\/\s[^\n\r]*(?:[\n\r]+|$))/g, '') // remove comments
.replace(/,[\n\s]+/g, ',')
.replace(LINE_FEED_REGEX(), (_ex, fullLine) => {
if (fullLine.endsWith('{')) {
if (selectors.length === 0) {
selectors.push([this._className]);
this._createRule(rules, RuleType.Style, selectors, resolvedSelectors);
}
else {
const line_1 = fullLine.slice(0, fullLine.length - 1).trim();
if (line_1 === '@font-face') {
selectors.push(line_1);
this._createRule(rules, RuleType.FontFace, selectors, resolvedSelectors);
}
else if (line_1.startsWith('@m')) {
selectors.push(line_1);
this._createRule(rules, RuleType.MediaQuery, selectors, resolvedSelectors);
}
else if (line_1.startsWith('@k')) {
selectors.push(line_1);
this._createRule(rules, RuleType.KeyFrame, selectors, resolvedSelectors);
}
else {
selectors.push(line_1
.split(',')
.map(_ => _.trim()));
this._createRule(rules, RuleType.Style, selectors, resolvedSelectors);
}
}
}
else if (fullLine.length === 1 && fullLine === '}') {
this._removeParentSelector(rules, selectors, resolvedSelectors);
}
else if (this._isDevMode && fullLine.startsWith('/* >> ds')) {
const lin = fullLine;
this._createRuleWithResolvedSelector(rules, RuleType.DynamicStyle, selectors, resolvedSelectors, lin);
}
else if (this._isServer && fullLine.startsWith('...')) {
const content = fullLine.slice(3);
this._createRuleWithResolvedSelector(rules, RuleType.CompiledStyle, selectors, resolvedSelectors, content);
}
else {
if (fullLine) {
if (this._isDevMode && fullLine.includes('undefined')) {
return '';
}
if (this._isDevMode && fullLine.endsWith(';')) {
throw new Error(`Do not require semicolon in [${fullLine}]`);
}
if (fullLine.includes(': ')) {
fullLine = fullLine.replace(': ', ':');
}
fullLine += ';';
this._appendDeclaration(rules, RuleType.Style, fullLine);
}
}
return '';
});
return rules
.filter(rule => !rule.isEmpty)
.map(rule => {
return rule.block;
}).join('');
}
_createRule(rules, type, selectors, resolvedSelectors) {
const parentRule = resolvedSelectors[resolvedSelectors.length - 1];
const prevRule = rules[rules.length - 1];
if (prevRule && !prevRule.isReady) {
prevRule.block += `}`;
prevRule.isReady = true;
}
let selector = '';
if (type === RuleType.FontFace) {
selector = `-face`;
}
else if (type === RuleType.KeyFrame) {
selector = selectors[1];
}
else if (parentRule && parentRule.type === RuleType.KeyFrame) {
selector = selectors[selectors.length - 1][0];
}
else if (type === RuleType.MediaQuery || (parentRule && parentRule.type === RuleType.MediaQuery && prevRule && prevRule.isEmpty)) {
selector = resolveSelectors(selectors, false);
}
else {
selector = resolveSelectors(selectors, true);
}
const rule = {
selector,
block: `${selector}{`,
type: RuleType.Style,
isEmpty: true
};
resolvedSelectors.push({ selector: '', block: '', type: type, isEmpty: true });
rules.push(rule);
// If is new media query
if (type === RuleType.MediaQuery) {
// rule.block += `{`;
rule.hasMedia = true;
}
if (parentRule && parentRule.hasMedia) {
rule.hasMedia = true;
}
if (type === RuleType.KeyFrame) {
rule.isReady = true;
rule.isEmpty = false;
}
return rule;
}
_createRuleWithResolvedSelector(rules, type, selectors, resolvedSelectors, content) {
if (!content) {
return;
}
const prevRule = rules[rules.length - 1];
const parentRule = resolvedSelectors[resolvedSelectors.length - 1];
const { hasMedia } = prevRule;
let selector = '';
if (type === RuleType.MediaQuery || (parentRule && parentRule.type === RuleType.MediaQuery && prevRule && prevRule.isEmpty)) {
selector = resolveSelectors(selectors, false);
}
else {
selector = resolveSelectors(selectors, true);
}
// Close previous
if (prevRule && !prevRule.isReady) {
prevRule.block += `}`;
}
const rule = {
selector: selector,
block: ``,
type,
hasMedia,
isEmpty: false
};
if (type === RuleType.CompiledStyle) {
rule.block = transformCC(content, selector);
}
else if (type === RuleType.DynamicStyle) {
rule.block = content.replace(/\|\|\&\|\|/g, selector);
}
rule.isReady = true;
rules.push(rule);
}
_appendDeclaration(rules, _type, content) {
if (!content) {
return;
}
let prevRule = rules[rules.length - 1];
if (prevRule && prevRule.isReady) {
prevRule = {
selector: prevRule.selector,
block: `${prevRule.selector}{`,
type: prevRule.type,
hasMedia: prevRule.hasMedia,
isEmpty: false
};
rules.push(prevRule);
}
prevRule.block += content;
prevRule.isEmpty = false;
}
_removeParentSelector(rules, selectors, resolvedSelectors) {
selectors.pop();
const prevRule = rules[rules.length - 1];
const currentRule = resolvedSelectors.pop();
if (!prevRule) {
return;
}
// Close previous rule
if (!prevRule.isReady) {
prevRule.block += `}`;
prevRule.isReady = true;
}
if (currentRule && (currentRule.type === RuleType.MediaQuery || currentRule.type === RuleType.KeyFrame)) {
prevRule.block += `}`;
prevRule.isReady = true;
}
}
}
exports.LylParse = LylParse;
function transformCC(content, sel) {
content = content.replace(/\/\* >> cc[^\/\*]+\*\//g, '');
let expression = content.slice(2, content.length - 1);
expression = `st2c((${expression}), \`${sel}\`)`;
return `\${${expression}}`;
}
function resolveSelectors(selectors, ignoreMediaQuery) {
let media = null;
const sel = selectors
.filter((_) => {
if (typeof _ === 'string') {
if (!ignoreMediaQuery) {
media = _;
}
return false;
}
return !!_.filter(__ => __).length;
});
const sel2 = sel.length === 1
? sel[0].join(',')
: sel.length ? sel.reduce((prv, curr) => {
const result = prv.map(item => curr.map(cu => {
if (cu.includes('&')) {
return cu.replace(AMPERSAND_REGEX(), item);
}
return `${item} ${cu}`;
}));
return Array.prototype.concat.apply([], result);
}).join(',') : '';
if (media) {
return `${media}{${sel2}`;
}
return sel2;
}
function lyl(literals, ...placeholders) {
return (className) => {
let result = '';
// Save expressions
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) {
result += `${createUniqueCommentSelector('ds')}${st2c(placeholder, '||&||')}`;
}
}
else {
result += placeholder;
}
}
// add the last literal
result += literals[literals.length - 1];
const css = new LylParse(result, className, false, true).toCss();
return css;
};
}
function createUniqueCommentSelector(text = 'id') {
return `/* >> ${text} -- ${Math.floor(new Date().valueOf() * Math.random()).toString(36)} */`;
}
class StyleCollection {
constructor(...templates) {
this._templates = templates;
this.css = this.css.bind(this);
}
add(...templates) {
// return new StyleCollection(...[...this._templates, ...templates]);
this._templates.push(...templates);
return this;
}
/** Transform style */
setTransformer(transformer) {
this._transformer = transformer;
return this;
}
/**
* @return StyleTemplate
* @docs-private
*/
css(className) {
let lin = '';
const templates = this._templates;
for (let index = 0; index < templates.length; index++) {
let template;
if (this._transformer) {
template = ((this._transformer(templates[index])));
}
else {
template = templates[index];
}
lin += template(className);
}
return lin;
}
}
exports.StyleCollection = StyleCollection;
/**
* Transform a ...{style} to css
* For internal use purposes only
* @param fn StyleTemplate or StyleCollection
* @param className class name
*/
function st2c(fn, className) {
if (fn == null) {
return '';
}
if (fn instanceof StyleCollection) {
return fn.css(className);
}
return fn(className);
}
class StringIdGenerator {
constructor(chars = 'abcdefghijklmnopqrstuvwxyz') {
this._chars = chars;
this._nextId = [0];
}
next() {
const r = [];
for (const char of this._nextId) {
r.unshift(this._chars[char]);
}
this._increment();
return r.join('');
}
_increment() {
for (let i = 0; i < this._nextId.length; i++) {
const val = ++this._nextId[i];
if (val >= this._chars.length) {
this._nextId[i] = 0;
}
else {
return;
}
}
this._nextId.push(0);
}
}
exports.StringIdGenerator = StringIdGenerator;
//# sourceMappingURL=parse.js.map