chore: page 的 style 里针对 backgroundImage 自动加上 url (#3581)

This commit is contained in:
吴多益 2022-02-15 16:23:46 +08:00 committed by GitHub
parent 2a5fbc588c
commit 97820a1075
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 158 additions and 42 deletions

23
__mocks__/monaco.ts Normal file
View File

@ -0,0 +1,23 @@
/**
* monaco mock
*/
export const languages = {
register: function (language: any) {},
setMonarchTokensProvider: function (name: any, tokens: any) {},
registerCompletionItemProvider: function (name: any, provider: any) {}
};
export const editor = {
defineTheme: function (name: any, theme: any) {},
create: function (name: any, theme: any) {
return {
onDidChangeModelDecorations: () => {
return {
dispose: () => {}
};
},
dispose: () => {}
};
}
};

View File

@ -4,7 +4,6 @@ exports[`Renderer:Page 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -89,7 +88,6 @@ exports[`Renderer:Page classNames 1`] = `
<div <div
className="cxd-Page cxd-Page--withSidebar" className="cxd-Page cxd-Page--withSidebar"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-aside cxd-Page-aside--withWidth aside-class-name" className="cxd-Page-aside cxd-Page-aside--withWidth aside-class-name"
@ -1056,7 +1054,6 @@ exports[`Renderer:Page initApi 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -1090,7 +1087,6 @@ exports[`Renderer:Page initApi error show Message 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -1140,7 +1136,6 @@ exports[`Renderer:Page initApi reFetch when condition changes 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -1174,7 +1169,6 @@ exports[`Renderer:Page initApi reFetch when condition changes 2`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2120,7 +2114,6 @@ exports[`Renderer:Page initApi show loading 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2154,7 +2147,6 @@ exports[`Renderer:Page initApi show loading 2`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2188,7 +2180,6 @@ exports[`Renderer:Page initApi silentPolling 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2222,7 +2213,6 @@ exports[`Renderer:Page initApi silentPolling 2`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2256,7 +2246,6 @@ exports[`Renderer:Page initApi silentPolling 3`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2284,7 +2273,6 @@ exports[`Renderer:Page initApi silentPolling 4`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2312,7 +2300,6 @@ exports[`Renderer:Page initData 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2340,7 +2327,6 @@ exports[`Renderer:Page initFetchOn trigger initApi fetch when condition becomes
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2374,7 +2360,6 @@ exports[`Renderer:Page location query 1`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"
@ -2402,7 +2387,6 @@ exports[`Renderer:Page location query 2`] = `
<div <div
className="cxd-Page" className="cxd-Page"
onClick={[Function]} onClick={[Function]}
style={Object {}}
> >
<div <div
className="cxd-Page-content" className="cxd-Page-content"

View File

@ -0,0 +1,41 @@
import '../../src/utils/tpl.ts';
import '../../src/utils/tpl-builtin';
import '../../src/utils/tpl-lodash';
import {buildStyle} from '../../src/utils/style';
test('style var background', () => {
expect(
buildStyle('${style}', {
style: {
backgroundImage: 'http://www.example.com/a.png'
}
})
).toEqual({
backgroundImage: 'url("http://www.example.com/a.png")'
});
expect(
buildStyle(
{
backgroundImage: 'http://www.example.com/a.png'
},
{}
)
).toEqual({
backgroundImage: 'url("http://www.example.com/a.png")'
});
});
test('style case', () => {
expect(
buildStyle(
{
'font-size': '10'
},
{}
)
).toEqual({
fontSize: '10'
});
});

View File

@ -8,6 +8,7 @@ import {BaseSchema, SchemaExpression} from '../Schema';
import {evalExpression} from '../utils/tpl'; import {evalExpression} from '../utils/tpl';
import {resolveVariable, resolveVariableAndFilter} from '../utils/tpl-builtin'; import {resolveVariable, resolveVariableAndFilter} from '../utils/tpl-builtin';
import {ClassNamesFn} from '../theme'; import {ClassNamesFn} from '../theme';
import {buildStyle} from '../utils/style';
/** /**
* Badge * Badge
@ -91,6 +92,8 @@ export class Badge extends React.Component<BadgeProps, object> {
const {classnames: cx, badge, data} = this.props; const {classnames: cx, badge, data} = this.props;
let {mode = 'dot', level = 'danger', style} = badge as BadgeSchema; let {mode = 'dot', level = 'danger', style} = badge as BadgeSchema;
const customStyle = buildStyle(style, data);
if (typeof level === 'string' && level[0] === '$') { if (typeof level === 'string' && level[0] === '$') {
level = resolveVariableAndFilter(level, data); level = resolveVariableAndFilter(level, data);
} }
@ -100,7 +103,7 @@ export class Badge extends React.Component<BadgeProps, object> {
return ( return (
<span <span
className={cx('Badge-dot', `Badge--${position}`, `Badge--${level}`)} className={cx('Badge-dot', `Badge--${position}`, `Badge--${level}`)}
style={{...offsetStyle, ...sizeStyle, ...style}} style={{...offsetStyle, ...sizeStyle, ...customStyle}}
> >
{animationElement} {animationElement}
</span> </span>
@ -113,7 +116,7 @@ export class Badge extends React.Component<BadgeProps, object> {
`Badge--${position}`, `Badge--${position}`,
`Badge--${level}` `Badge--${level}`
)} )}
style={{...offsetStyle, ...sizeStyle, ...style}} style={{...offsetStyle, ...sizeStyle, ...customStyle}}
> >
{text} {text}
{animationElement} {animationElement}
@ -132,7 +135,7 @@ export class Badge extends React.Component<BadgeProps, object> {
`Badge-ribbon--${position}`, `Badge-ribbon--${position}`,
`Badge--${level}` `Badge--${level}`
)} )}
style={{...sizeStyle, ...style}} style={{...sizeStyle, ...customStyle}}
> >
{text} {text}
{animationElement} {animationElement}

View File

@ -1,6 +1,7 @@
import React from 'react'; import React from 'react';
import {isClickOnInput} from '../utils/helper'; import {isClickOnInput} from '../utils/helper';
import {ClassNamesFn, themeable, ThemeProps} from '../theme'; import {ClassNamesFn, themeable, ThemeProps} from '../theme';
import {buildStyle} from '../utils/style';
export interface CardProps extends ThemeProps { export interface CardProps extends ThemeProps {
className?: string; className?: string;
headerClassName?: string; headerClassName?: string;
@ -29,6 +30,7 @@ export interface CardProps extends ThemeProps {
secondary?: string | JSX.Element; secondary?: string | JSX.Element;
onClick?: (e: React.MouseEvent<HTMLDivElement>) => void; onClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
classnames: ClassNamesFn; classnames: ClassNamesFn;
data?: any;
} }
export class Card extends React.Component<CardProps> { export class Card extends React.Component<CardProps> {
@ -88,7 +90,8 @@ export class Card extends React.Component<CardProps> {
descriptionPlaceholder, descriptionPlaceholder,
secondary, secondary,
avatar, avatar,
avatarText avatarText,
data
} = this.props; } = this.props;
let heading = null; let heading = null;
@ -111,7 +114,7 @@ export class Card extends React.Component<CardProps> {
) : avatarText ? ( ) : avatarText ? (
<span <span
className={cx('Card-avtarText', avatarTextClassName)} className={cx('Card-avtarText', avatarTextClassName)}
style={avatarTextStyle} style={buildStyle(avatarTextStyle, data)}
> >
{avatarText} {avatarText}
</span> </span>

View File

@ -2,6 +2,7 @@ import React from 'react';
import {Renderer, RendererProps} from '../factory'; import {Renderer, RendererProps} from '../factory';
import {BaseSchema, SchemaClassName, SchemaCollection} from '../Schema'; import {BaseSchema, SchemaClassName, SchemaCollection} from '../Schema';
import {SchemaNode} from '../types'; import {SchemaNode} from '../types';
import {buildStyle} from '../utils/style';
/** /**
* Container * Container
@ -80,14 +81,18 @@ export default class Container<T> extends React.Component<
wrapperComponent, wrapperComponent,
size, size,
classnames: cx, classnames: cx,
style style,
data
} = this.props; } = this.props;
const Component = const Component =
(wrapperComponent as keyof JSX.IntrinsicElements) || 'div'; (wrapperComponent as keyof JSX.IntrinsicElements) || 'div';
return ( return (
<Component className={cx('Container', className)} style={style}> <Component
className={cx('Container', className)}
style={buildStyle(style, data)}
>
{this.renderBody()} {this.renderBody()}
</Component> </Component>
); );

View File

@ -31,6 +31,7 @@ import {SchemaRemark} from './Remark';
import {onAction} from 'mobx-state-tree'; import {onAction} from 'mobx-state-tree';
import mapValues from 'lodash/mapValues'; import mapValues from 'lodash/mapValues';
import {resolveVariable} from '../utils/tpl-builtin'; import {resolveVariable} from '../utils/tpl-builtin';
import {buildStyle} from '../utils/style';
/** /**
* *
@ -722,10 +723,7 @@ export default class Page extends React.Component<PageProps> {
? ~regions.indexOf('aside') ? ~regions.indexOf('aside')
: aside && (!Array.isArray(aside) || aside.length); : aside && (!Array.isArray(aside) || aside.length);
let styleVar = const styleVar = buildStyle(style, data);
typeof style === 'string'
? resolveVariable(style, data) || {}
: mapValues(style, s => resolveVariable(s, data) || s);
return ( return (
<div <div

View File

@ -7,6 +7,7 @@ import {Renderer, RendererProps} from '../factory';
import {BaseSchema, SchemaExpression, SchemaObject, SchemaTpl} from '../Schema'; import {BaseSchema, SchemaExpression, SchemaObject, SchemaTpl} from '../Schema';
import {resolveVariableAndFilter} from '../utils/tpl-builtin'; import {resolveVariableAndFilter} from '../utils/tpl-builtin';
import {visibilityFilter} from '../utils/helper'; import {visibilityFilter} from '../utils/helper';
import {buildStyle} from '../utils/style';
export type PropertyItemProps = { export type PropertyItemProps = {
/** /**
@ -167,7 +168,8 @@ export default class Property extends React.Component<PropertyProps, object> {
contentStyle, contentStyle,
labelStyle, labelStyle,
separator = ': ', separator = ': ',
mode = 'table' mode = 'table',
data
} = this.props; } = this.props;
return rows.map((row, key) => { return rows.map((row, key) => {
return ( return (
@ -175,10 +177,12 @@ export default class Property extends React.Component<PropertyProps, object> {
{row.map((property, index) => { {row.map((property, index) => {
return mode === 'table' ? ( return mode === 'table' ? (
<React.Fragment key={`item-${index}`}> <React.Fragment key={`item-${index}`}>
<th style={labelStyle}>{render('label', property.label)}</th> <th style={buildStyle(labelStyle, data)}>
{render('label', property.label)}
</th>
<td <td
colSpan={property.span + property.span - 1} // 需要再补上 th 所占的列数 colSpan={property.span + property.span - 1} // 需要再补上 th 所占的列数
style={contentStyle} style={buildStyle(contentStyle, data)}
> >
{render('content', property.content)} {render('content', property.content)}
</td> </td>
@ -186,10 +190,10 @@ export default class Property extends React.Component<PropertyProps, object> {
) : ( ) : (
<td <td
colSpan={property.span} colSpan={property.span}
style={contentStyle} style={buildStyle(contentStyle, data)}
key={`item-${index}`} key={`item-${index}`}
> >
<span style={labelStyle}> <span style={buildStyle(labelStyle, data)}>
{render('label', property.label)} {render('label', property.label)}
</span> </span>
{separator} {separator}
@ -210,6 +214,7 @@ export default class Property extends React.Component<PropertyProps, object> {
classnames: cx, classnames: cx,
className, className,
titleStyle, titleStyle,
data,
mode = 'table' mode = 'table'
} = this.props; } = this.props;
@ -218,7 +223,7 @@ export default class Property extends React.Component<PropertyProps, object> {
return ( return (
<div <div
className={cx('Property', `Property--${mode}`, className)} className={cx('Property', `Property--${mode}`, className)}
style={style} style={buildStyle(style, data)}
> >
<table> <table>
{title ? ( {title ? (
@ -226,7 +231,7 @@ export default class Property extends React.Component<PropertyProps, object> {
<tr> <tr>
<th <th
colSpan={mode === 'table' ? column + column : column} colSpan={mode === 'table' ? column + column : column}
style={titleStyle} style={buildStyle(titleStyle, data)}
> >
{title} {title}
</th> </th>

View File

@ -6,6 +6,7 @@ import {anyChanged, getPropValue} from '../utils/helper';
import {escapeHtml} from '../utils/tpl-builtin'; import {escapeHtml} from '../utils/tpl-builtin';
import {BaseSchema, SchemaTpl} from '../Schema'; import {BaseSchema, SchemaTpl} from '../Schema';
import {BadgeSchema, withBadge} from '../components/Badge'; import {BadgeSchema, withBadge} from '../components/Badge';
import {buildStyle} from '../utils/style';
/** /**
* tpl * tpl
@ -115,7 +116,8 @@ export class Tpl extends React.Component<TplProps, object> {
wrapperComponent, wrapperComponent,
inline, inline,
classnames: cx, classnames: cx,
style style,
data
} = this.props; } = this.props;
const Component = wrapperComponent || (inline ? 'span' : 'div'); const Component = wrapperComponent || (inline ? 'span' : 'div');
@ -123,7 +125,7 @@ export class Tpl extends React.Component<TplProps, object> {
<Component <Component
ref={this.htmlRef} ref={this.htmlRef}
className={cx('TplField', className)} className={cx('TplField', className)}
style={style} style={buildStyle(style, data)}
> >
<span>{this.getContent()}</span> <span>{this.getContent()}</span>
</Component> </Component>

View File

@ -4,6 +4,7 @@ import {BaseSchema, SchemaCollection} from '../Schema';
import {resolveVariable} from '../utils/tpl-builtin'; import {resolveVariable} from '../utils/tpl-builtin';
import {SchemaNode} from '../types'; import {SchemaNode} from '../types';
import mapValues from 'lodash/mapValues'; import mapValues from 'lodash/mapValues';
import {buildStyle} from '../utils/style';
/** /**
* Wrapper * Wrapper
@ -65,11 +66,6 @@ export default class Wrapper extends React.Component<WrapperProps, object> {
return this.renderBody(); return this.renderBody();
} }
let styleVar =
typeof style === 'string'
? resolveVariable(style, data) || {}
: mapValues(style, s => resolveVariable(s, data) || s);
return ( return (
<div <div
className={cx( className={cx(
@ -77,7 +73,7 @@ export default class Wrapper extends React.Component<WrapperProps, object> {
size && size !== 'none' ? `Wrapper--${size}` : '', size && size !== 'none' ? `Wrapper--${size}` : '',
className className
)} )}
style={styleVar} style={buildStyle(style, data)}
> >
{this.renderBody()} {this.renderBody()}
</div> </div>

56
src/utils/style.ts Normal file
View File

@ -0,0 +1,56 @@
/**
* helper
*/
import {resolveVariableAndFilter} from './tpl-builtin';
import mapValues from 'lodash/mapValues';
import camelCase from 'lodash/camelCase';
function autoAddImageURL(image: string) {
// 只支持单个的情况,并简单滤掉 linear-gradient 等情况
if (
typeof image === 'string' &&
image.indexOf(',') === -1 &&
image.indexOf('(') === -1
) {
return `url("${image}")`;
}
return image;
}
/**
* style
* 1.
* 2. font-size fontSize
* 3. image url
*/
export function buildStyle(style: any, data: any) {
if (!style) {
return style;
}
let styleVar =
typeof style === 'string'
? resolveVariableAndFilter(style, data, '| raw') || {}
: mapValues(style, s => resolveVariableAndFilter(s, data, '| raw') || s);
Object.keys(styleVar).forEach((key: string) => {
if (key.indexOf('-') !== -1) {
styleVar[camelCase(key)] = styleVar[key];
delete styleVar[key];
}
});
if (styleVar.backgroundImage) {
styleVar.backgroundImage = autoAddImageURL(styleVar.backgroundImage);
}
if (styleVar.borderImage) {
styleVar.borderImage = autoAddImageURL(styleVar.borderImage);
}
if (styleVar.listStyleImage) {
styleVar.listStyleImage = autoAddImageURL(styleVar.listStyleImage);
}
return styleVar;
}