Что это за строка в конце стилевого компонента? - PullRequest
0 голосов
/ 16 апреля 2019

Технологии: Реакция, машинопись

Я уверен, что это дубликат, но я просто не знаю, как это искать ...

Я хочу создать оболочку для пакета styled-components ...
Справочник по API для пакета, о котором я говорю

Везде, где я создаю компонент, мне нужно вызыватьэто так:

import styled from 'styled-components'

const mydiv = styled.div<WhateverInterface>`
  height: 20px;
`

Это единственное место, где я когда-либо видел такую ​​запись, где в конце объявления есть только строка ...

Куда бы я ни прошелреквизит этого конкретного div, чтобы он перезаписал значение по умолчанию, мне нужно сделать что-то вроде этого:

import styled from 'styled-components'

const mydiv = styled.div<WhateverInterface>`
  height: ${props => props.height ? props.height : '20px'};
`

Я создал функцию, которая делает это для всех ключей, поэтому я хотел бы создатьоболочка для стиля . [div, select, span и т. д.] ... функция, которая по сути будет вызываться так:

import styled from 'styled-components'

function wrapper(styleComponent, rules) {
   return styledComponent`
       ${props => mergePropsAndDefaultRules(props, rules)}
   `
}

const mydiv = wrapper(styled.div<WhateverInterface>, `
    height: 20px;
`);

Проблема в том ... Iне знаю, как эта строка, которая появляется в конце styled.div<WhateverInterface>, работает, ведет себя и т. д.откуда взялись?

Любая информация об этой строковой вещи будет высоко цениться <3 </p>


PS: если неясно, функция, которую я случайно вставил в мой код mergePropsAndDefaultRules будет работать примерно так:

  • Для каждого свойства CSS в каждом из них он будет проверять, существует ли оно в обоих ... если оно существует в обоих, установить для свойства значение в подпорках,если существует только по умолчанию, установите для свойства css значение в правилах по умолчанию, то же самое для реквизита ...

пример:

props = {
  height: '30px',
  width: '20px',  
}

defaultRules = `
   height: 20px;
   border: 1px solid black;
`
const output = mergePropsAndDefaultRules(props, defaultRules)
console.log(typeof output, output)
/* 
Output:
string,
border: 1px solid black;
height: 30px;
width: 20px;
*/

1 Ответ

0 голосов
/ 29 апреля 2019

Итак ... Я понял это благодаря комментарию @ Tholle ...


type CSSStyle = {[key: string] : (string|boolean)};

type CSSProperty = CSSStyle | {[key:string]: CSSStyle};

type Styles =  {[key: string] : CSSProperty};

interface IStyleGenerator {
    generateCSS: (props: Styles, standart: string) => string;
}

const CaseHelper = {
    snakeToCamel: s => s.replace(/(\-\w)/g, function(m){return m[1].toUpperCase();}),
    camelToSnake: c => c.replace(/([A-Z])/g, a => `-${a.toLowerCase()}`)
}

class LiberStyle implements IStyleGenerator {
    readonly defaultNamespace : string = 'standart';

    /**
     * 
     * @param propsStyle the style field from the props
     * @param standartStyle the css rules as string
     */
    generateCSS(propsStyle: Styles, standartStyle: string) : string {
        let rules = standartStyle.split('\n').map(a => a.trim()); // O(n * k);
        const defaultStyle = {};
        let namespace = this.defaultNamespace;
        defaultStyle[namespace] = {};
        const namespacePattern = /&:(\w+).+/;
        const hasDoubleMark = new RegExp(/:/);
        for(let rule of rules) {
            if(rule.length <= 0) continue;
            rule = rule.trim();
            if(rule.length <= 2) continue;
            if(rule === '}') {
                namespace = this.defaultNamespace
            } else {
                if(rule.length >= 2 && rule[0] === '&' && rule[1] === ':') {
                    namespace = rule.replace(namespacePattern, '$1');
                    defaultStyle[namespace] = {};
                } else {
                    if(!hasDoubleMark.test(rule)) continue;
                    const [key, value] = this.extractKeyValue(rule);
                    defaultStyle[namespace][key] = value;
                }
            }
        }
        const propsRemappedStyle = {};
        propsRemappedStyle[this.defaultNamespace] = {};
        Object['entries'](propsStyle).forEach(entry => {
            const [nmspace, rules] = entry;
            if(typeof rules === 'object') {
                propsRemappedStyle[nmspace] = rules
            } else {
                propsRemappedStyle[this.defaultNamespace][nmspace] = rules;
            }
        })
        return this.stringifyRules(propsRemappedStyle, defaultStyle);

    }

    /**
     * 
     *  PRIVATE METHODS ---------------------------------------------
     * 
     */


    extractKeyValue(rule : string) {
        let [key, value] = rule.split(':');
        value = value.trim();
        key = CaseHelper.snakeToCamel(key.trim());
        return [key, value.substring(0,value.length - 1)];
    }

    myInclude(array : any[], value : string) {
        let found = false;
        array.forEach((e:any) => {
            found = e === value;
            return found;
        })
        return found;
    }

    getNamespaceKeys(propKeys : any[]= [], defaultKeys : any[] = []) {
        let keys = defaultKeys.filter(style => !this.myInclude(propKeys,style));
        let ret = keys.concat(propKeys);
        // console.log({ret , propKeys, defaultKeys});
        return ret;
    }

    getKeysAndNamespace(propStyles : Styles, defaultStyles : Styles) {
        let namespacedKeys = Object.keys(propStyles)
        let namespaceMissingKeys = Object.keys(defaultStyles).filter((nmspace:string) => (!this.myInclude(namespacedKeys,nmspace) && (!this.defaultNamespace)));
        namespacedKeys = namespacedKeys.concat(namespaceMissingKeys);
        let allKeys = {};
        namespacedKeys.forEach(namespace => {
            allKeys[namespace] = this.getNamespaceKeys(Object.keys(propStyles[namespace] || {}), Object.keys(defaultStyles[namespace] || {}));
        })
        return { keys: allKeys, namespaces: namespacedKeys };
    }


     stringifyNamespace(namespace, keys, propRules, defaultRules) {
        let unifiedRules = '';
        let tab = namespace !== this.defaultNamespace ? '\t\t' : '\t'; 
        const camelToSnake = CaseHelper.camelToSnake;
        keys.forEach(key => {
            unifiedRules = `${unifiedRules}\n${tab}${camelToSnake(key)}: ${propRules[key] ? propRules[key] : defaultRules[key]};`
        });
        return namespace !== this.defaultNamespace ? `\t&:${namespace} {${unifiedRules}\n\t}` : unifiedRules;
    }

    stringifyRules(propsStyle : Styles, defaultStyle : Styles) {
        const  { keys, namespaces } = this.getKeysAndNamespace(propsStyle, defaultStyle);
        // console.log({keys, namespaces, propsStyle, defaultStyle });
        return namespaces.reduce((final, namespace) => {
            return `${final}\n${this.stringifyNamespace(namespace, keys[namespace], propsStyle[namespace], defaultStyle[namespace])}`
        }, '');
    }

}

export default new LiberStyle();

Код не идеален ... но вы можете использовать его, создавая обертку так:

import LiberStyle from './liberStyle';

interface A {
}

interface B {

}

function generic(oi) {
    return 
}

const __props__ : B = {
    style: { 
        height: '40px',
        hover: {
            color: 'red'
        }
    },
    show: true

}
/**
 * This is just a function I created to mimick styled.div because I didnt have it installed on the PC I wrote this code
 */
function styled_div<T>(staticStrings: TemplateStringsArray, ...params) {
    let merged = '';
    const size = Math.max(staticStrings.length, params.length);
    for(let i=0; i < size; i++) {
        if(staticStrings[i]) {
            merged = merged + staticStrings[i].trim();
        }
        if(params[i]) {
            if(typeof params[i] === 'function') {
                merged = merged + params[i](__props__);
            } else if(typeof params[i] === 'object') {
                merged = merged + JSON.parse(params[i]);
            } else if(typeof params[i] === 'string') {
                merged = merged + params[i].trim();
            } else {
                merged = merged + params[i];
            }
        }
    }
    return merged;
}

function merge(props, staticStrings: TemplateStringsArray, params: any[]) {
    let merged = '';
    const size = Math.max(staticStrings.length, params.length);
    for(let i=0; i < size; i++) {
        if(staticStrings[i]) {
            merged = merged + staticStrings[i].trim();
        }
        if(params[i]) {
            if(typeof params[i] === 'function') {
                merged = merged + params[i](props);
            } else if(typeof params[i] === 'object') {
                merged = merged + JSON.parse(params[i]);
            } else {
                merged = merged + params[i].trim();
            }
        }
    }
    return merged;
}


const styled = {
    div: function div<T>(staticStrings: TemplateStringsArray, ...params) {
        return styled_div<T>`
            ${props => {
                const m = merge(props, staticStrings, params);
                //console.log({ style: props.style, m});
                return LiberStyle.generateCSS(props.style,m)}
            }
        `
    },
}

const waka = styled.div<A>`
    display: ${props => props.show ? 'block' : 'none'};
    height: 20px;
    width: 30px;
`;

console.log(waka);

Это не идеально, но я надеюсь, что оно проливает свет, если у кого-то возникла такая же проблема ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...