技术:反应,打字稿
我确定这是重复的,但我只是不知道如何查找...
我想为样式组件包装创建包装器...
API's reference for the package that I'm talking about
无论我在哪里创建组件,都必须这样称呼它:
import styled from 'styled-components'
const mydiv = styled.div<WhateverInterface>`
height: 20px;
`
这是我见过的唯一一种表示法,声明的末尾只有一个字符串...
无论我将一个prop传递给该特定的div,要使其覆盖默认值,我都需要执行以下操作:
import styled from 'styled-components'
const mydiv = styled.div<WhateverInterface>`
height: ${props => props.height ? props.height : '20px'};
`
我创建了一个对所有键都执行此操作的函数,因此我想为 styled。[div,select,span,etc] ...创建一个包装器。被这样称呼:
import styled from 'styled-components'
function wrapper(styleComponent, rules) {
return styledComponent`
${props => mergePropsAndDefaultRules(props, rules)}
`
}
const mydiv = wrapper(styled.div<WhateverInterface>, `
height: 20px;
`);
问题是...我不知道styled.div<WhateverInterface>
末尾的字符串如何工作,表现如何……里面的道具甚至从哪里来?
有关此字符串的任何信息将不胜感激<3
PS:如果不清楚,我随机插入我的代码mergePropsAndDefaultRules
中的函数将像这样工作:
示例:
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;
*/
答案 0 :(得分:0)
所以...感谢@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);
这不是完美的,但是我希望如果有人遇到相同的问题,它可以为您带来启发...