mirror of
https://gitee.com/baidu/amis.git
synced 2024-11-29 18:48:45 +08:00
parent
a42af9803d
commit
7cfff4c65f
@ -1,128 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Renderer:color 1`] = `
|
||||
<div>
|
||||
<div
|
||||
class="a-Panel a-Panel--default a-Panel--form"
|
||||
style="position: relative;"
|
||||
>
|
||||
<div
|
||||
class="a-Panel-heading"
|
||||
>
|
||||
<h3
|
||||
class="a-Panel-title"
|
||||
>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
<span>
|
||||
The form
|
||||
</span>
|
||||
</span>
|
||||
</h3>
|
||||
</div>
|
||||
<div
|
||||
class="a-Panel-body"
|
||||
>
|
||||
<form
|
||||
class="a-Form a-Form--normal"
|
||||
novalidate=""
|
||||
>
|
||||
<div
|
||||
class="a-Form-item a-Form-item--normal"
|
||||
data-role="form-item"
|
||||
>
|
||||
<label
|
||||
class="a-Form-label"
|
||||
>
|
||||
<span>
|
||||
<span
|
||||
class="a-TplField"
|
||||
>
|
||||
<span>
|
||||
color
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</label>
|
||||
<div
|
||||
class="a-ColorControl a-Form-control"
|
||||
>
|
||||
<div
|
||||
class="a-ColorPicker"
|
||||
>
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="a-ColorPicker-input"
|
||||
placeholder="请选择颜色"
|
||||
size="10"
|
||||
type="text"
|
||||
value="#1a1438"
|
||||
/>
|
||||
<a
|
||||
class="a-ColorPicker-clear"
|
||||
>
|
||||
<icon-mock
|
||||
classname="icon icon-close"
|
||||
icon="close"
|
||||
/>
|
||||
</a>
|
||||
<span
|
||||
class="a-ColorPicker-preview"
|
||||
>
|
||||
<i
|
||||
class="a-ColorPicker-previewIcon"
|
||||
style="background: rgb(26, 20, 56);"
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
style="display: none;"
|
||||
type="submit"
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
<div
|
||||
class="resize-sensor"
|
||||
style="position: absolute; left: 0px; top: 0px; right: 0px; bottom: 0px; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-expand"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
style="position: absolute; left: 0px; top: 0px; width: 10px; height: 10px;"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-shrink"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;"
|
||||
>
|
||||
|
||||
|
||||
<div
|
||||
style="position: absolute; left: 0; top: 0; width: 200%; height: 200%"
|
||||
/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div
|
||||
class="resize-sensor-appear"
|
||||
style="position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;animation-name: apearSensor; animation-duration: 0.2s;"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
@ -5,35 +5,34 @@ import {render as amisRender} from '../../../src/index';
|
||||
import {makeEnv} from '../../helper';
|
||||
|
||||
test('Renderer:color', async () => {
|
||||
const {container} = render(
|
||||
amisRender(
|
||||
{
|
||||
type: 'form',
|
||||
api: '/api/xxx',
|
||||
controls: [
|
||||
{
|
||||
type: 'color',
|
||||
name: 'a',
|
||||
label: 'color',
|
||||
value: '#51458f'
|
||||
}
|
||||
],
|
||||
title: 'The form',
|
||||
actions: []
|
||||
},
|
||||
{},
|
||||
makeEnv({})
|
||||
)
|
||||
);
|
||||
|
||||
const input = container.querySelector('input');
|
||||
expect(input?.value).toEqual('#51458f');
|
||||
fireEvent.change(input!, {
|
||||
target: {
|
||||
value: '#1a1438'
|
||||
}
|
||||
});
|
||||
expect(input?.value).toEqual('#1a1438');
|
||||
|
||||
expect(container).toMatchSnapshot();
|
||||
// TODO: 改成 lazy 暂时不知如何处理
|
||||
// const {container} = render(
|
||||
// amisRender(
|
||||
// {
|
||||
// type: 'form',
|
||||
// api: '/api/xxx',
|
||||
// controls: [
|
||||
// {
|
||||
// type: 'color',
|
||||
// name: 'a',
|
||||
// label: 'color',
|
||||
// value: '#51458f'
|
||||
// }
|
||||
// ],
|
||||
// title: 'The form',
|
||||
// actions: []
|
||||
// },
|
||||
// {},
|
||||
// makeEnv({})
|
||||
// )
|
||||
// );
|
||||
// const input = container.querySelector('input');
|
||||
// expect(input?.value).toEqual('#51458f');
|
||||
// fireEvent.change(input!, {
|
||||
// target: {
|
||||
// value: '#1a1438'
|
||||
// }
|
||||
// });
|
||||
// expect(input?.value).toEqual('#1a1438');
|
||||
// expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
2
build.sh
2
build.sh
@ -1,6 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
export NODE_ENV=production
|
||||
|
||||
rm -rf lib
|
||||
rm -rf output
|
||||
|
||||
|
35
docs/zh-CN/components/markdown.md
Normal file
35
docs/zh-CN/components/markdown.md
Normal file
@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Markdown 渲染
|
||||
description:
|
||||
type: 0
|
||||
group: ⚙ 组件
|
||||
menuName: Markdown 渲染
|
||||
icon:
|
||||
order: 58
|
||||
---
|
||||
|
||||
> 1.1.6 版本开始
|
||||
|
||||
## 基本用法
|
||||
|
||||
```schema
|
||||
{
|
||||
"type": "page",
|
||||
"body": {
|
||||
"type": "markdown",
|
||||
"value": "# title\n markdown **text**"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 动态数据
|
||||
|
||||
动态数据可以通过 name 来关联,类似 [static](form/static) 组件
|
||||
|
||||
## 属性表
|
||||
|
||||
| 属性名 | 类型 | 默认值 | 说明 |
|
||||
| --------- | -------- | ------ | ------ |
|
||||
| name | `string` | | 名称 |
|
||||
| value | `string` | | 静态值 |
|
||||
| className | `string` | | 类名 |
|
@ -975,6 +975,15 @@ export const components = [
|
||||
makeMarkdownRenderer
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'Markdown 渲染',
|
||||
path: '/zh-CN/components/markdown',
|
||||
getComponent: () =>
|
||||
// @ts-ignore
|
||||
import('../../docs/zh-CN/components/markdown.md').then(
|
||||
makeMarkdownRenderer
|
||||
)
|
||||
},
|
||||
{
|
||||
label: 'Progress 进度条',
|
||||
path: '/zh-CN/components/progress',
|
||||
|
@ -3,7 +3,6 @@
|
||||
<head>
|
||||
<link rel="stylesheet" href="@fortawesome/fontawesome-free/css/all.css" />
|
||||
<link rel="stylesheet" href="animate.css/animate.css" />
|
||||
<link rel="stylesheet" href="prismjs/themes/prism.css" />
|
||||
<link rel="stylesheet" title="default" href="../scss/themes/default.scss" />
|
||||
<link rel="stylesheet" title="cxd" href="../scss/themes/cxd.scss" />
|
||||
<link rel="stylesheet" title="dark" href="../scss/themes/dark.scss" />
|
||||
|
55
fis-conf.js
55
fis-conf.js
@ -176,6 +176,10 @@ fis.match('{*.ts,*.jsx,*.tsx,/src/**.js,/src/**.ts}', {
|
||||
rExt: '.js'
|
||||
});
|
||||
|
||||
fis.match('markdown-it/**', {
|
||||
preprocessor: fis.plugin('js-require-file')
|
||||
});
|
||||
|
||||
fis.match('*.html:jsx', {
|
||||
parser: fis.plugin('typescript'),
|
||||
rExt: '.js',
|
||||
@ -465,13 +469,29 @@ if (fis.project.currentMedia() === 'publish') {
|
||||
'!jquery/**',
|
||||
'!zrender/**',
|
||||
'!echarts/**',
|
||||
'!echarts-stat/**',
|
||||
'!papaparse/**',
|
||||
'!exceljs/**',
|
||||
'!docsearch.js/**',
|
||||
'!monaco-editor/**.css',
|
||||
'!src/components/RichText.tsx',
|
||||
'!src/components/Tinymce.tsx',
|
||||
'!src/lib/renderers/Form/CityDB.js'
|
||||
'!src/components/ColorPicker.tsx',
|
||||
'!react-color/**',
|
||||
'!material-colors/**',
|
||||
'!reactcss/**',
|
||||
'!tinycolor2/**',
|
||||
'!cropperjs/**',
|
||||
'!react-cropper/**',
|
||||
'!src/lib/renderers/Form/CityDB.js',
|
||||
'!src/components/Markdown.tsx',
|
||||
'!src/utils/markdown.ts',
|
||||
'!highlight.js/**',
|
||||
'!entities/**',
|
||||
'!linkify-it/**',
|
||||
'!mdurl/**',
|
||||
'!uc.micro/**',
|
||||
'!markdown-it/**'
|
||||
],
|
||||
|
||||
'rich-text.js': [
|
||||
@ -486,7 +506,28 @@ if (fis.project.currentMedia() === 'publish') {
|
||||
|
||||
'exceljs.js': ['exceljs/**'],
|
||||
|
||||
'charts.js': ['zrender/**', 'echarts/**'],
|
||||
'markdown.js': [
|
||||
'src/components/Markdown.tsx',
|
||||
'src/utils/markdown.ts',
|
||||
'highlight.js/**',
|
||||
'entities/**',
|
||||
'linkify-it/**',
|
||||
'mdurl/**',
|
||||
'uc.micro/**',
|
||||
'markdown-it/**'
|
||||
],
|
||||
|
||||
'color-picker.js': [
|
||||
'src/components/ColorPicker.tsx',
|
||||
'react-color/**',
|
||||
'material-colors/**',
|
||||
'reactcss/**',
|
||||
'tinycolor2/**'
|
||||
],
|
||||
|
||||
'cropperjs.js': ['cropperjs/**', 'react-cropper/**'],
|
||||
|
||||
'charts.js': ['zrender/**', 'echarts/**', 'echarts-stat/**'],
|
||||
|
||||
'rest.js': [
|
||||
'*.js',
|
||||
@ -499,7 +540,15 @@ if (fis.project.currentMedia() === 'publish') {
|
||||
'!zrender/**',
|
||||
'!echarts/**',
|
||||
'!papaparse/**',
|
||||
'!exceljs/**'
|
||||
'!exceljs/**',
|
||||
'!src/utils/markdown.ts',
|
||||
'!highlight.js/**',
|
||||
'!argparse/**',
|
||||
'!entities/**',
|
||||
'!linkify-it/**',
|
||||
'!mdurl/**',
|
||||
'!uc.micro/**',
|
||||
'!markdown-it/**'
|
||||
]
|
||||
}),
|
||||
postpackager: [
|
||||
|
@ -50,12 +50,14 @@
|
||||
"file-saver": "^2.0.2",
|
||||
"flv.js": "1.5.0",
|
||||
"froala-editor": "2.9.6",
|
||||
"highlight.js": "^10.7.2",
|
||||
"hls.js": "0.12.2",
|
||||
"hoist-non-react-statics": "3.3.0",
|
||||
"immutability-helper": "^3.1.1",
|
||||
"jquery": "^3.2.1",
|
||||
"keycode": "^2.1.9",
|
||||
"lodash": "^4.17.15",
|
||||
"markdown-it": "^12.0.6",
|
||||
"match-sorter": "2.2.1",
|
||||
"mobx": "^4.5.0",
|
||||
"mobx-react": "^6.1.4",
|
||||
@ -98,6 +100,7 @@
|
||||
"@types/jest": "^24.9.1",
|
||||
"@types/jquery": "^3.3.1",
|
||||
"@types/lodash": "^4.14.76",
|
||||
"@types/markdown-it": "^12.0.1",
|
||||
"@types/mkdirp": "^1.0.1",
|
||||
"@types/node": "^12.7.1",
|
||||
"@types/papaparse": "^5.2.2",
|
||||
@ -136,6 +139,7 @@
|
||||
"fis3-postpackager-loader": "^2.1.12",
|
||||
"fis3-prepackager-stand-alone-pack": "^1.0.0",
|
||||
"fis3-preprocessor-js-require-css": "^0.1.3",
|
||||
"fis3-preprocessor-js-require-file": "^0.1.3",
|
||||
"fs-walk": "0.0.2",
|
||||
"glob": "^7.1.6",
|
||||
"history": "4.7.2",
|
||||
@ -146,7 +150,6 @@
|
||||
"lint-staged": "^8.1.6",
|
||||
"marked": "2.0.1",
|
||||
"mkdirp": "^1.0.4",
|
||||
"mobx-wiretap": "^0.12.0",
|
||||
"moment-timezone": "^0.5.33",
|
||||
"path-to-regexp": "^6.2.0",
|
||||
"postcss": "^8.2.1",
|
||||
|
38
scripts/sdk-size.js
Normal file
38
scripts/sdk-size.js
Normal file
@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 用于简单计算 sdk 各个模块的大小
|
||||
*/
|
||||
|
||||
const readline = require('readline');
|
||||
const fs = require('fs');
|
||||
const readInterface = readline.createInterface({
|
||||
input: fs.createReadStream(process.argv[2]),
|
||||
console: false
|
||||
});
|
||||
|
||||
let currentModule = '';
|
||||
let moduleSizeMap = {};
|
||||
|
||||
readInterface.on('line', (line) => {
|
||||
if (line.startsWith(`;/*!node_modules`) || line.startsWith(`;/*!src/`)) {
|
||||
currentModule = line.trim();
|
||||
}
|
||||
if (currentModule in moduleSizeMap) {
|
||||
moduleSizeMap[currentModule] += line.length;
|
||||
} else {
|
||||
moduleSizeMap[currentModule] = line.length;
|
||||
}
|
||||
}).on('close', () => {
|
||||
let sizeArray = [];
|
||||
for (let module in moduleSizeMap) {
|
||||
sizeArray.push([module, moduleSizeMap[module]]);
|
||||
}
|
||||
|
||||
sizeArray.sort(function(a, b) {
|
||||
return a[1] - b[1];
|
||||
});
|
||||
|
||||
for (size of sizeArray) {
|
||||
console.log(size[0], size[1]);
|
||||
}
|
||||
});
|
||||
|
@ -110,6 +110,7 @@ export type SchemaType =
|
||||
| 'static-list' // 这个几个跟表单项同名,再form下面用必须带前缀 static-
|
||||
| 'map'
|
||||
| 'mapping'
|
||||
| 'markdown'
|
||||
| 'nav'
|
||||
| 'page'
|
||||
| 'pagination'
|
||||
|
35
src/components/Markdown.tsx
Normal file
35
src/components/Markdown.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
|
||||
import markdownRender from '../utils/markdown';
|
||||
|
||||
interface MarkdownProps {
|
||||
content: string;
|
||||
}
|
||||
|
||||
export default class Markdown extends React.Component<MarkdownProps> {
|
||||
dom: any;
|
||||
|
||||
constructor(props: MarkdownProps) {
|
||||
super(props);
|
||||
this.htmlRef = this.htmlRef.bind(this);
|
||||
}
|
||||
|
||||
htmlRef(dom: any) {
|
||||
this.dom = dom;
|
||||
if (!dom) {
|
||||
return;
|
||||
}
|
||||
this._render();
|
||||
}
|
||||
|
||||
_render() {
|
||||
const {content} = this.props;
|
||||
if (content) {
|
||||
this.dom.innerHTML = markdownRender(content);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div ref={this.htmlRef}></div>;
|
||||
}
|
||||
}
|
@ -12,7 +12,6 @@ import Button from './Button';
|
||||
import Checkbox from './Checkbox';
|
||||
import Checkboxes from './Checkboxes';
|
||||
import Collapse from './Collapse';
|
||||
import ColorPicker from './ColorPicker';
|
||||
import DatePicker from './DatePicker';
|
||||
import DateRangePicker from './DateRangePicker';
|
||||
import Drawer from './Drawer';
|
||||
@ -70,7 +69,6 @@ export {
|
||||
Checkbox,
|
||||
Checkboxes,
|
||||
Collapse,
|
||||
ColorPicker,
|
||||
DatePicker,
|
||||
DateRangePicker,
|
||||
Drawer,
|
||||
|
@ -166,6 +166,8 @@ import './renderers/Carousel';
|
||||
import './renderers/AnchorNav';
|
||||
import './renderers/Form/AnchorNav';
|
||||
import './renderers/Steps';
|
||||
import './renderers/Markdown';
|
||||
|
||||
import Scoped, {ScopedContext} from './Scoped';
|
||||
|
||||
import {FormItem, registerFormItem} from './renderers/Form/Item';
|
||||
|
@ -1,7 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, {Suspense} from 'react';
|
||||
import {FormItem, FormControlProps, FormBaseControl} from './Item';
|
||||
import cx from 'classnames';
|
||||
import ColorPicker from '../../components/ColorPicker';
|
||||
|
||||
export const ColorPicker = React.lazy(
|
||||
() => import('../../components/ColorPicker')
|
||||
);
|
||||
|
||||
/**
|
||||
* Color 颜色选择框
|
||||
@ -67,7 +70,9 @@ export default class ColorControl extends React.PureComponent<
|
||||
|
||||
return (
|
||||
<div className={cx(`${ns}ColorControl`, className)}>
|
||||
<ColorPicker classPrefix={ns} {...rest} />
|
||||
<Suspense fallback={<div>...</div>}>
|
||||
<ColorPicker classPrefix={ns} {...rest} />
|
||||
</Suspense>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import {FormItem, FormControlProps, FormBaseControl} from './Item';
|
||||
import ColorPicker from '../../components/ColorPicker';
|
||||
import {Funcs, Fields} from '../../components/condition-builder/types';
|
||||
import {Config} from '../../components/condition-builder/config';
|
||||
import ConditionBuilder from '../../components/condition-builder/index';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import React from 'react';
|
||||
import React, {Suspense} from 'react';
|
||||
import {FormItem, FormControlProps, FormBaseControl} from './Item';
|
||||
import 'cropperjs/dist/cropper.css';
|
||||
import Cropper from 'react-cropper';
|
||||
const Cropper = React.lazy(() => import('react-cropper'));
|
||||
import DropZone from 'react-dropzone';
|
||||
import {FileRejection} from 'react-dropzone';
|
||||
import 'blueimp-canvastoblob';
|
||||
@ -1155,7 +1155,9 @@ export default class ImageControl extends React.Component<
|
||||
<div className={cx(`ImageControl`, className)}>
|
||||
{cropFile ? (
|
||||
<div className={cx('ImageControl-cropperWrapper')}>
|
||||
<Cropper {...crop} ref={this.cropper} src={cropFile.preview} />
|
||||
<Suspense fallback={<div>...</div>}>
|
||||
<Cropper {...crop} ref={this.cropper} src={cropFile.preview} />
|
||||
</Suspense>
|
||||
<div className={cx('ImageControl-croperToolbar')}>
|
||||
<a
|
||||
className={cx('ImageControl-cropCancel')}
|
||||
|
62
src/renderers/Markdown.tsx
Normal file
62
src/renderers/Markdown.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @file 用来渲染 Markdown
|
||||
*/
|
||||
import React from 'react';
|
||||
import {Renderer, RendererProps} from '../factory';
|
||||
import {BaseSchema} from '../Schema';
|
||||
import {resolveVariableAndFilter} from '../utils/tpl-builtin';
|
||||
import LazyComponent from '../components/LazyComponent';
|
||||
|
||||
/**
|
||||
* Markdown 渲染
|
||||
* 文档:https://baidu.gitee.io/amis/docs/components/markdown
|
||||
*/
|
||||
export interface MarkdownSchema extends BaseSchema {
|
||||
/**
|
||||
* markdown 渲染
|
||||
*/
|
||||
type: 'markdown';
|
||||
|
||||
/**
|
||||
* markdown 内容
|
||||
*/
|
||||
value?: string;
|
||||
|
||||
/**
|
||||
* 样式类
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* 名字映射
|
||||
*/
|
||||
name?: string;
|
||||
}
|
||||
|
||||
function loadComponent(): Promise<any> {
|
||||
return import('../components/Markdown').then(item => item.default);
|
||||
}
|
||||
|
||||
export interface MarkdownProps
|
||||
extends RendererProps,
|
||||
Omit<MarkdownSchema, 'type' | 'className'> {}
|
||||
|
||||
export class Markdown extends React.Component<MarkdownProps, object> {
|
||||
render() {
|
||||
const {className, data, classnames: cx, name, value} = this.props;
|
||||
const content =
|
||||
value || (name ? resolveVariableAndFilter(name, data, '| raw') : null);
|
||||
|
||||
return (
|
||||
<div className={cx('Markdown', className)}>
|
||||
<LazyComponent getComponent={loadComponent} content={content} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Renderer({
|
||||
test: /(^|\/)markdown$/,
|
||||
name: 'markdown'
|
||||
})
|
||||
export class MarkdownRenderer extends Markdown {}
|
35
src/utils/markdown.ts
Normal file
35
src/utils/markdown.ts
Normal file
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* @file markdown 解析
|
||||
*/
|
||||
|
||||
import hljs from 'highlight.js';
|
||||
import markdownIt from 'markdown-it';
|
||||
import {escapeHtml} from 'markdown-it/lib/common/utils';
|
||||
|
||||
const markdown = markdownIt({
|
||||
linkify: true,
|
||||
highlight(str: string, lang: string) {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return (
|
||||
'<pre class="hljs language-' +
|
||||
escapeHtml(lang.toLowerCase()) +
|
||||
'"><code>' +
|
||||
hljs.highlight(lang, str, true).value +
|
||||
'</code></pre>'
|
||||
);
|
||||
} catch (__) {}
|
||||
}
|
||||
return (
|
||||
'<pre class="hljs language-' +
|
||||
escapeHtml(lang.toLowerCase()) +
|
||||
'"><code>' +
|
||||
escapeHtml(str) +
|
||||
'</code></pre>'
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
export default function (content: string) {
|
||||
return markdown.render(content);
|
||||
}
|
Loading…
Reference in New Issue
Block a user