audio支持变量

This commit is contained in:
catchonme 2019-07-04 16:24:13 +08:00
parent 0e89b87a03
commit bb6a12994c
28 changed files with 690 additions and 49 deletions

View File

@ -0,0 +1,31 @@
import React = require('react');
import {render} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:button-toolbar', async () => {
const {
container
} = render(amisRender({
type: 'button-toolbar',
name: 'button-toolbar',
label: 'button-toolbar',
buttons: [
{
type: 'button',
label: '按钮1',
},
{
type: 'button',
label: '按钮2'
}
],
className: 'show'
}, {}, makeEnv({
})));
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,44 @@
import React = require('react');
import {render, fireEvent} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:carousel', async () => {
const {
container
} = render(amisRender({
type: 'carousel',
controlsTheme: 'light',
width: '500',
height: '300',
options: [
{
image: 'https://video-react.js.org/assets/poster.png',
title: '标题',
titleClassName: 'block',
description: '描述',
descriptionClassName: 'block'
},
{
html: '<div style="width: 100%; height: 300px; background: #e3e3e3; text-align: center; line-height: 300px;">carousel data</div>'
},
{
image: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg'
}
],
className: 'show'
}, {}, makeEnv({
})));
const image = document.querySelector('div.a-Carousel-item');
fireEvent.mouseEnter(image as HTMLDivElement);
const leftArrow = document.querySelector('div.a-Carousel-leftArrow')
fireEvent.click(leftArrow as HTMLDivElement);
const rightArrow = document.querySelector('div.a-Carousel-rightArrow')
fireEvent.click(rightArrow as HTMLDivElement);
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,29 @@
import React = require('react');
import {render} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:date', async () => {
const {
container
} = render(amisRender({
type: 'date',
name: 'date',
label: 'date',
value: '1559836800',
format: 'YYYY-MM-DD',
placeholder: '请选择时间',
minDate: '1559664000',
maxDate: '1561737600',
className: 'show'
}, {}, makeEnv({
})));
const input = container.querySelector('.a-DateField');
expect(input.innerHTML).toEqual('2019-06-07');
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,53 @@
import React = require('react');
import {render} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:hbox', async () => {
const {
container
} = render(amisRender({
type: 'hbox',
columns: [
{
type: 'tpl',
tpl: 'w-xs',
className: 'bg-info',
inline: false,
columnClassName: 'w-xs'
},
{
type: 'tpl',
tpl: 'w-sm',
className: 'bg-info lter',
inline: false,
columnClassName: 'w-sm'
},
{
type: 'tpl',
tpl: 'w',
className: 'bg-info dk',
inline: false,
columnClassName: 'w'
},
{
type: 'tpl',
tpl: '平均分配',
className: 'bg-success',
inline: false
},
{
type: 'tpl',
tpl: '平均分配',
className: 'bg-primary',
inline: false
}
]
}, {}, makeEnv({
})));
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,22 @@
import React = require('react');
import {render} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:iframe', async () => {
const {
container
} = render(amisRender({
type: 'iframe',
className: 'b-a',
src: "https://www.baidu.com",
height: 500,
width: 500
}, {}, makeEnv({
})));
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,23 @@
import React = require('react');
import {render} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:image', async () => {
const {
container
} = render(amisRender({
type: 'image',
defaultImage: 'https://www.baidu.com/img/bd_logo1.png',
title: '图片',
description: '图片描述',
imageClassName: 'b',
className: 'show'
}, {}, makeEnv({
})));
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,22 @@
import React = require('react');
import {render} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:link', async () => {
const {
container
} = render(amisRender({
type: 'link',
href: 'https://www.baidu.com',
placeholder: 'link address',
className: 'show',
blank: true
}, {}, makeEnv({
})));
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,25 @@
import React = require('react');
import {render} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import { makeEnv } from '../helper';
test('Renderer:mapping', async () => {
const {
container
} = render(amisRender({
type: 'mapping',
mapping: {
1: "<span class='label label-info'>漂亮</span>",
2: "<span class='label label-success'>开心</span>",
3: "<span class='label label-danger'>惊吓</span>",
4: "<span class='label label-warning'>紧张</span>",
"*": "其他:${type}"
}
}, {}, makeEnv({
})));
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,44 @@
import React = require('react');
import {render, cleanup} from 'react-testing-library';
import '../../src/themes/default';
import {
render as amisRender
} from '../../src/index';
import {makeEnv} from '../helper';
import { clearStoresCache } from '../../src/factory';
afterEach(() => {
cleanup();
clearStoresCache();
});
test('Renderer:tabs', async () => {
const {
container
} = render(amisRender({
type: "tabs",
tabClassName: 'bg-info',
tabs: [
{
title: '基本配置',
body: '<p>tab1 内容</p>',
},
{
title: '其他配置',
controls: [
{
name: 'c',
type: 'text',
label: '文本3'
},
{
name: 'd',
type: 'text',
label: '文本4'
}
]
}
]
}, {}, makeEnv()));
expect(container).toMatchSnapshot();
});

View File

@ -0,0 +1,26 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:button-toolbar 1`] = `
<div>
<div
class="a-ButtonToolbar show"
>
<button
class="a-Button a-Button--default"
type="button"
>
<span>
按钮1
</span>
</button>
<button
class="a-Button a-Button--default"
type="button"
>
<span>
按钮2
</span>
</button>
</div>
</div>
`;

View File

@ -0,0 +1,114 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:carousel 1`] = `
<div>
<div
class="a-Carousel a-Carousel--light show"
>
<div
class="a-Carousel-container"
style="width: 500px; height: 300px;"
>
<div
class="a-Carousel-item fade in"
>
<span
class="a-TplField"
>
<div
class="image "
style="background-image: url(https://video-react.js.org/assets/poster.png)"
/>
<div
class="title block"
>
标题
</div>
<div
class="description block"
>
描述
</div>
</span>
</div>
<div
class="a-Carousel-item fade out"
>
<span
class="a-TplField"
>
<div
class="image "
style="background-image: url(https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg)"
/>
</span>
</div>
<div
class="a-Carousel-dotsControl"
>
<span
class="a-Carousel-dot is-active"
/>
<span
class="a-Carousel-dot"
/>
<span
class="a-Carousel-dot"
/>
</div>
<div
class="a-Carousel-arrowsControl"
>
<div
class="a-Carousel-leftArrow"
>
<svg
class="icon"
version="1.1"
viewBox="0 0 1024 1024"
>
<path
d="M324.211517 511.805631 787.889594 73.082583c16.19422-16.630365 16.19422-43.974704 0-60.605068-16.19422-16.630365-42.495607-16.630365-58.613976 0L235.750113 479.360302c-8.647031 8.969398-12.344775 20.934917-11.719003 32.445329-0.644735 11.90863 3.071972 23.874149 11.719003 32.824585l493.506542 466.882788c16.118369 16.649327 42.438718 16.649327 58.613976 0 16.19422-17.085471 16.19422-43.974704 0-60.605068L324.211517 511.805631"
p-id="2160"
/>
</svg>
</div>
<div
class="a-Carousel-rightArrow"
>
<svg
class="icon"
version="1.1"
viewBox="0 0 1024 1024"
>
<path
d="M311.559054 1013.77369L767.908116 512.684524 311.559054 12.234501a31.318073 31.318073 0 1 0-46.657538 41.544383L679.706197 512.684524 267.458094 969.672731a31.318073 31.318073 0 0 0 46.018393 42.183526z"
p-id="1981"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,11 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:date 1`] = `
<div>
<span
class="a-DateField show"
>
2019-06-07
</span>
</div>
`;

View File

@ -0,0 +1,55 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:hbox 1`] = `
<div>
<div
class="a-Hbox"
>
<div
class="a-Hbox-col w-xs"
>
<div
class="a-TplField bg-info"
>
w-xs
</div>
</div>
<div
class="a-Hbox-col w-sm"
>
<div
class="a-TplField bg-info lter"
>
w-sm
</div>
</div>
<div
class="a-Hbox-col w"
>
<div
class="a-TplField bg-info dk"
>
w
</div>
</div>
<div
class="a-Hbox-col"
>
<div
class="a-TplField bg-success"
>
平均分配
</div>
</div>
<div
class="a-Hbox-col"
>
<div
class="a-TplField bg-primary"
>
平均分配
</div>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,12 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:iframe 1`] = `
<div>
<iframe
class="b-a"
frameborder="0"
src="https://www.baidu.com"
style="width: 500px; height: 500px;"
/>
</div>
`;

View File

@ -0,0 +1,28 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:image 1`] = `
<div>
<div
class="a-ImageField show"
>
<img
class="b"
src="https://www.baidu.com/img/bd_logo1.png"
/>
<div
class="a-ImageField-caption"
>
<div
class="text-md"
>
图片
</div>
<span
class="a-TplField"
>
图片描述
</span>
</div>
</div>
</div>
`;

View File

@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:link 1`] = `
<div>
<a
class="a-Link show"
href="https://www.baidu.com"
target="_blank"
>
https://www.baidu.com
</a>
</div>
`;

View File

@ -0,0 +1,15 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:mapping 1`] = `
<div>
<span
class="a-MappingField"
>
<span
class="text-muted"
>
-
</span>
</span>
</div>
`;

View File

@ -0,0 +1,64 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Renderer:tabs 1`] = `
<div>
<div
class="a-Tabs"
id="0"
>
<ul
class="a-Tabs-links nav"
role="tablist"
>
<li
class="a-Tabs-link active"
role="presentation"
>
<a
aria-controls="0-pane-0"
aria-selected="true"
href="#"
id="0-tab-0"
role="tab"
>
基本配置
</a>
</li>
<li
class="a-Tabs-link"
role="presentation"
>
<a
aria-controls="0-pane-1"
aria-selected="false"
href="#"
id="0-tab-1"
role="tab"
tabindex="-1"
>
其他配置
</a>
</li>
</ul>
<div
class="a-Tabs-content tab-content"
>
<div
aria-hidden="false"
aria-labelledby="0-tab-0"
class="fade tab-pane active in"
id="0-pane-0"
role="tabpanel"
>
<span
class="a-TplField"
>
<p>
tab1 内容
</p>
</span>
</div>
</div>
</div>
</div>
`;

View File

@ -30,6 +30,8 @@ amis 页面是通过 JSON 配置出来的,是由一个一个渲染模型组成
- [Checkbox](./renderers/Form/Checkbox.md): 勾选框
- [Checkboxes](./renderers/Form/Checkboxes.md): 复选框
- [Radios](./renderers/Form/Radios.md): 单选框
- [City](./renderers/Form/City.md): 城市选择
- [Rating](./renderers/Form/Rating.md): 评分
- [Switch](./renderers/Form/Switch.md): 可选框,和 checkbox 完全等价
- [Date](./renderers/Form/Date.md): 日期类型
- [Datetime](./renderers/Form/Datetime.md): 日期时间类型
@ -58,6 +60,7 @@ amis 页面是通过 JSON 配置出来的,是由一个一个渲染模型组成
- [Static](./renderers/Static.md): 纯用来展现数据的
- [Wizard](./renderers/Wizard.md): 表单向导
- [Tpl](./renderers/Tpl.md): 支持用 JS 模板引擎来组织输出
- [Each](./renderers/Each.md): 基于现有变量循环输出渲染器
- [Plain](./renderers/Plain.md): 单纯的文字输出
- [Html](./renderers/Html.md): html, 当需要用到变量时,请用 Tpl 代替
- [Action](./renderers/Action.md): 一种特殊的渲染器,它本身是一个按钮,同时它能触发事件

View File

@ -4,7 +4,7 @@
- `type` 请设置成 `divider`
```schema:height="200" scope="form-item"
```schema:height="200"
{
"type": "divider"
}

View File

@ -106,8 +106,8 @@ todo
用来显示日期。
- `type` 请设置为 `date`
- `format` 默认为 `YYYY-MM-DD`,时间格式,请参考 moment 中的格式用法。
- `valueFormat` 默认为 `X`,时间格式,请参考 moment 中的格式用法。
- `format` 默认为 `YYYY-MM-DD`,时间格式,请参考 [moment](http://momentjs.com/) 中的格式用法。
- `valueFormat` 默认为 `X`,时间格式,请参考 [moment](http://momentjs.com/) 中的格式用法。
### Mapping(Field)

View File

@ -3,10 +3,10 @@
日期范围类型。
- `type` 请设置成 `date-range`
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 moment.
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 [moment](http://momentjs.com/).
- `inputFormat` 默认 `HH:mm` 用来配置显示的时间格式。
- `minDate` 限制最小日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `maxDate` 限制最日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `maxDate` 限制最日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- 更多配置请参考 [FormItem](./FormItem.md)
```schema:height="250" scope="form"

View File

@ -3,7 +3,7 @@
日期类型。
- `type` 请设置成 `date`
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 moment.
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 [moment](http://momentjs.com/).
- `inputFormat` 默认 `YYYY-MM-DD` 用来配置显示的时间格式。
- `placeholder` 默认 `请选择日期`
- `value` 这里面 value 需要特殊说明一下,因为支持相对值。如:
@ -11,7 +11,7 @@
- `+2days` 2 天后
- `-10week` 十周前
- `minDate` 限制最小日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `maxDate` 限制最日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `maxDate` 限制最日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
可用单位: `min`、`hour`、`day`、`week`、`month`、`year`。所有单位支持复数形式。

View File

@ -3,7 +3,7 @@
日期时间类型。
- `type` 请设置成 `datetime`
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 moment.
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 [moment](http://momentjs.com/).
- `inputFormat` 默认 `YYYY-MM-DD HH:mm:ss` 用来配置显示的时间格式。
- `placeholder` 默认 `请选择日期`
- `timeConstraints` 请参考: [react-datetime](https://github.com/YouCanBookMe/react-datetime)
@ -12,7 +12,7 @@
- `+2days` 2 天后
- `-10week` 十周前
- `minDate` 限制最小日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `maxDate` 限制最日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `maxDate` 限制最日期,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `minTime` 限制最小时间,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`
- `maxTime` 限制最大时间,可用 `${xxx}` 取值,或者输入相对时间,或者时间戳。如:`${start}`、`+3days`、`+3days+2hours`或者 `${start|default:-2days}+3days`

View File

@ -3,7 +3,7 @@
时间类型。
- `type` 请设置成 `time`
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 moment.
- `format` 默认 `X` 即时间戳格式,用来提交的时间格式。更多格式类型请参考 [moment](http://momentjs.com/).
- `inputFormat` 默认 `HH:mm` 用来配置显示的时间格式。
- `placeholder` 默认 `请选择日期`
- `timeConstraints` 请参考: [react-datetime](https://github.com/YouCanBookMe/react-datetime)

View File

@ -173,13 +173,6 @@ export default {
cb(null, makeMarkdownRenderer(doc));
}),
},
{
label: 'Divider',
path: '/docs/renderers/Form/Divider',
getComponent: (location, cb) => require(['../../docs/renderers/Form/Divider.md'], (doc) => {
cb(null, makeMarkdownRenderer(doc));
}),
},
{
label: 'Select',
path: '/docs/renderers/Form/Select',
@ -229,6 +222,13 @@ export default {
cb(null, makeMarkdownRenderer(doc));
}),
},
{
label: 'Rating',
path: '/docs/renderers/Form/Rating',
getComponent: (location, cb) => require(['../../docs/renderers/Form/Rating.md'], (doc) => {
cb(null, makeMarkdownRenderer(doc));
}),
},
{
label: 'Date',
path: '/docs/renderers/Form/Date',
@ -406,6 +406,13 @@ export default {
},
]
},
{
label: 'Divider',
path: '/docs/renderers/Divider',
getComponent: (location, cb) => require(['../../docs/renderers/Divider.md'], (doc) => {
cb(null, makeMarkdownRenderer(doc));
}),
},
{
label: 'Wizard',
path: '/docs/renderers/Wizard',

View File

@ -37,18 +37,13 @@
display: none;
}
.#{$ns}Audio--inline {
display: inline-block;
height: $Audio-height;
overflow: hidden;
}
.#{$ns}Audio {
box-sizing: border-box;
height: $Audio-height;
line-height: $Audio-lineHeight;
border: $Audio-border;
display: inline-block;
overflow: hidden;
padding-left: $Audio-item-margin;
&-rates {

View File

@ -3,6 +3,7 @@ import upperFirst = require('lodash/upperFirst');
import {Renderer, RendererProps} from '../factory';
import {autobind} from '../utils/helper';
import {volumeIcon, muteIcon, playIcon, pauseIcon} from '../components/icons';
import {resolveVariable} from '../utils/tpl-builtin';
export interface AudioProps extends RendererProps {
className?: string;
@ -31,8 +32,8 @@ export interface AudioState {
export class Audio extends React.Component<AudioProps, AudioState> {
audio: any;
progressTimeout: any;
durationTimeout: any;
progressTimeout: number;
durationTimeout: number;
static defaultProps: Pick<
AudioProps,
@ -48,7 +49,7 @@ export class Audio extends React.Component<AudioProps, AudioState> {
};
state: AudioState = {
src: this.props.value || this.props.src || '',
src: this.props.value || this.props.src || resolveVariable(this.props.name, this.props.data) || '',
isReady: false,
muted: false,
playing: false,
@ -393,30 +394,34 @@ export class Audio extends React.Component<AudioProps, AudioState> {
} = this.props;
const {muted, src} = this.state;
return (
<div className={cx('Audio', className, inline ? 'Audio--inline' : '')}>
<audio
className={cx('Audio-original')}
ref={this.audioRef}
onCanPlay={this.load}
autoPlay={autoPlay}
controls
muted={muted}
loop={loop}>
<source src={src} />
</audio>
<div className={cx('Audio-controls')}>
{controls && controls.map((control:string, index:number) => {
control = 'render' + upperFirst(control);
const method:'renderRates'|'renderPlay'|'renderTime'|'renderProcess'|'renderVolume'|'render' = control as any;
return (
<React.Fragment key={index}>
{this[method]()}
</React.Fragment>
)
})}
const body = (
<div className={cx('Audio', className)}>
<audio
className={cx('Audio-original')}
ref={this.audioRef}
onCanPlay={this.load}
autoPlay={autoPlay}
controls
muted={muted}
loop={loop}>
<source src={src} />
</audio>
<div className={cx('Audio-controls')}>
{controls && controls.map((control:string, index:number) => {
control = 'render' + upperFirst(control);
const method:'renderRates'|'renderPlay'|'renderTime'|'renderProcess'|'renderVolume'|'render' = control as any;
return (
<React.Fragment key={index}>
{this[method]()}
</React.Fragment>
)
})}
</div>
</div>
</div>
);
return (
inline ? body : <div>{body}</div>
);
}
}