prettierrc 配置调整

This commit is contained in:
liaoxuezhi 2019-11-07 10:41:14 +08:00
parent ea8370e6b0
commit d5ef332151
256 changed files with 60872 additions and 55823 deletions

View File

@ -8,7 +8,7 @@ insert_final_newline = true
[**.{js,ts,tsx,scss}] [**.{js,ts,tsx,scss}]
indent_style = space indent_style = space
indent_size = 4 indent_size = 2
[*.md] [*.md]
trim_trailing_whitespace = false trim_trailing_whitespace = false

View File

@ -1,11 +1,12 @@
{ {
"printWidth": 120, "printWidth": 80,
"tabWidth": 4, "tabWidth": 2,
"useTabs": false, "useTabs": false,
"singleQuote": true, "singleQuote": true,
"semi": true, "semi": true,
"trailingComma": "none", "trailingComma": "none",
"bracketSpacing": false, "bracketSpacing": false,
"arrowParens": "avoid", "quoteProps": "consistent",
"jsxBracketSameLine": false "arrowParens": "avoid",
"jsxBracketSameLine": false
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,37 +1,40 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "音频播放器", title: '音频播放器',
"body": [ body: [
{
type: 'audio',
autoPlay: false,
rates: [1.0, 1.5, 2.0],
src:
'https://amis.bj.bcebos.com/amis/2019-7/1562137295708/chicane-poppiholla-original-radio-edit%20(1).mp3'
},
{
type: 'form',
title: '',
actions: [],
className: 'b v-middle inline w-lg h-xs',
controls: [
{ {
"type": "audio", type: 'card',
"autoPlay": false, className: 'v-middle w inline no-border',
"rates": [1.0, 1.5, 2.0], header: {
"src": "https://amis.bj.bcebos.com/amis/2019-7/1562137295708/chicane-poppiholla-original-radio-edit%20(1).mp3", title: '歌曲名称',
subTitle: '专辑名称',
description: 'description',
avatarClassName: 'pull-left thumb-md avatar m-r no-border',
avatar:
'http://hiphotos.baidu.com/fex/%70%69%63/item/c9fcc3cec3fdfc03ccabb38edd3f8794a4c22630.jpg'
}
}, },
{ {
"type": 'form', type: 'audio',
"title": '', className: 'v-middle no-border',
"actions": [], src:
"className": 'b v-middle inline w-lg h-xs', 'https://amis.bj.bcebos.com/amis/2019-7/1562137295708/chicane-poppiholla-original-radio-edit%20(1).mp3',
"controls": [ controls: ['play']
{
"type": "card",
"className": 'v-middle w inline no-border',
"header": {
"title": "歌曲名称",
"subTitle": "专辑名称",
"description": "description",
"avatarClassName": "pull-left thumb-md avatar m-r no-border",
"avatar": "http://hiphotos.baidu.com/fex/%70%69%63/item/c9fcc3cec3fdfc03ccabb38edd3f8794a4c22630.jpg"
}
},
{
"type": "audio",
"className": 'v-middle no-border',
"src": "https://amis.bj.bcebos.com/amis/2019-7/1562137295708/chicane-poppiholla-original-radio-edit%20(1).mp3",
"controls": ['play']
}
]
} }
] ]
} }
]
};

View File

@ -1,332 +1,332 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "带边栏联动", title: '带边栏联动',
aside: { aside: {
type: 'form', type: 'form',
wrapWithPanel: false, wrapWithPanel: false,
target: 'window', // location target: 'window', // location
controls: [ controls: [
{ {
type: 'tree', type: 'tree',
name: 'cat', name: 'cat',
inputClassName: 'no-border', inputClassName: 'no-border',
submitOnChange: true, submitOnChange: true,
options: [ options: [
{ {
label: '分类1', label: '分类1',
value: 'cat1' value: 'cat1'
}, },
{ {
label: '分类2', label: '分类2',
value: 'cat2' value: 'cat2'
}, },
{ {
label: '分类3', label: '分类3',
value: 'cat3' value: 'cat3'
}, },
{ {
label: '分类4', label: '分类4',
value: 'cat4' value: 'cat4'
} }
]
}
] ]
}, }
toolbar: [ ]
{ },
type: "button", toolbar: [
actionType: "dialog", {
label: "新增", type: 'button',
primary: true, actionType: 'dialog',
dialog: { label: '新增',
title: "新增", primary: true,
body: { dialog: {
type: "form", title: '新增',
name: "sample-edit-form", body: {
api: "post:/api/sample", type: 'form',
controls: [ name: 'sample-edit-form',
{ api: 'post:/api/sample',
type: "text", controls: [
name: "engine", {
label: "Engine", type: 'text',
required: true name: 'engine',
}, label: 'Engine',
{ required: true
type: "divider" },
}, {
{ type: 'divider'
type: "text", },
name: "browser", {
label: "Browser", type: 'text',
required: true name: 'browser',
}, label: 'Browser',
{ required: true
type: "divider" },
}, {
{ type: 'divider'
type: "text", },
name: "platform", {
label: "Platform(s)", type: 'text',
required: true name: 'platform',
}, label: 'Platform(s)',
{ required: true
type: "divider" },
}, {
{ type: 'divider'
type: "text", },
name: "version", {
label: "Engine version" type: 'text',
}, name: 'version',
{ label: 'Engine version'
type: "divider" },
}, {
{ type: 'divider'
type: "text", },
name: "grade", {
label: "CSS grade" type: 'text',
} name: 'grade',
] label: 'CSS grade'
}
} }
]
} }
], }
body: {
type: "crud",
draggable: true,
api: "/api/sample",
filter: {
title: "条件搜索",
submitText: "",
controls: [
{
type: "text",
name: "keywords",
placeholder: "通过关键字搜索",
addOn: {
label: "搜索",
type: "submit"
}
},
{
type: "plain",
text: "这里的表单项可以配置多个"
}
]
},
bulkActions: [
{
label: "批量删除",
actionType: "ajax",
api: "delete:/api/sample/$ids",
confirmText: "确定要批量删除?"
},
{
label: "批量修改",
actionType: "dialog",
dialog: {
title: "批量编辑",
name: "sample-bulk-edit",
body: {
type: "form",
api: "/api/sample/bulkUpdate2",
controls: [
{
type: 'hidden',
name: 'ids'
},
{
type: "text",
name: "engine",
label: "Engine"
}
]
}
}
}
],
quickSaveApi: "/api/sample/bulkUpdate",
quickSaveItemApi: "/api/sample/$id",
columns: [
{
name: "id",
label: "ID",
width: 20,
sortable: true,
type: "text",
toggled: true
},
{
name: "engine",
label: "Rendering engine",
sortable: true,
searchable: true,
type: "text",
toggled: true
},
{
name: "browser",
label: "Browser",
sortable: true,
type: "text",
toggled: true
},
{
name: "platform",
label: "Platform(s)",
sortable: true,
type: "text",
toggled: true
},
{
name: "version",
label: "Engine version",
quickEdit: true,
type: "text",
toggled: true
},
{
name: "grade",
label: "CSS grade",
quickEdit: {
mode: "inline",
type: "select",
options: ["A", "B", "C", "D", "X"],
saveImmediately: true
},
type: "text",
toggled: true
},
{
type: "operation",
label: "操作",
width: 130,
buttons: [
{
type: "button",
icon: "fa fa-eye",
actionType: "dialog",
dialog: {
title: "查看",
body: {
type: "form",
controls: [
{
type: "static",
name: "engine",
label: "Engine"
},
{
type: "divider"
},
{
type: "static",
name: "browser",
label: "Browser"
},
{
type: "divider"
},
{
type: "static",
name: "platform",
label: "Platform(s)"
},
{
type: "divider"
},
{
type: "static",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
},
{
type: "divider"
},
{
type: "html",
html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>"
}
]
}
}
},
{
type: "button",
icon: "fa fa-pencil",
actionType: "dialog",
dialog: {
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "text",
name: "grade",
label: "CSS grade"
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
toggled: true
}
]
} }
],
body: {
type: 'crud',
draggable: true,
api: '/api/sample',
filter: {
title: '条件搜索',
submitText: '',
controls: [
{
type: 'text',
name: 'keywords',
placeholder: '通过关键字搜索',
addOn: {
label: '搜索',
type: 'submit'
}
},
{
type: 'plain',
text: '这里的表单项可以配置多个'
}
]
},
bulkActions: [
{
label: '批量删除',
actionType: 'ajax',
api: 'delete:/api/sample/$ids',
confirmText: '确定要批量删除?'
},
{
label: '批量修改',
actionType: 'dialog',
dialog: {
title: '批量编辑',
name: 'sample-bulk-edit',
body: {
type: 'form',
api: '/api/sample/bulkUpdate2',
controls: [
{
type: 'hidden',
name: 'ids'
},
{
type: 'text',
name: 'engine',
label: 'Engine'
}
]
}
}
}
],
quickSaveApi: '/api/sample/bulkUpdate',
quickSaveItemApi: '/api/sample/$id',
columns: [
{
name: 'id',
label: 'ID',
width: 20,
sortable: true,
type: 'text',
toggled: true
},
{
name: 'engine',
label: 'Rendering engine',
sortable: true,
searchable: true,
type: 'text',
toggled: true
},
{
name: 'browser',
label: 'Browser',
sortable: true,
type: 'text',
toggled: true
},
{
name: 'platform',
label: 'Platform(s)',
sortable: true,
type: 'text',
toggled: true
},
{
name: 'version',
label: 'Engine version',
quickEdit: true,
type: 'text',
toggled: true
},
{
name: 'grade',
label: 'CSS grade',
quickEdit: {
mode: 'inline',
type: 'select',
options: ['A', 'B', 'C', 'D', 'X'],
saveImmediately: true
},
type: 'text',
toggled: true
},
{
type: 'operation',
label: '操作',
width: 130,
buttons: [
{
type: 'button',
icon: 'fa fa-eye',
actionType: 'dialog',
dialog: {
title: '查看',
body: {
type: 'form',
controls: [
{
type: 'static',
name: 'engine',
label: 'Engine'
},
{
type: 'divider'
},
{
type: 'static',
name: 'browser',
label: 'Browser'
},
{
type: 'divider'
},
{
type: 'static',
name: 'platform',
label: 'Platform(s)'
},
{
type: 'divider'
},
{
type: 'static',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'static',
name: 'grade',
label: 'CSS grade'
},
{
type: 'divider'
},
{
type: 'html',
html:
'<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-pencil',
actionType: 'dialog',
dialog: {
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'text',
name: 'grade',
label: 'CSS grade'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
toggled: true
}
]
}
}; };

View File

@ -1,91 +1,91 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "增删改查列类型汇总", title: '增删改查列类型汇总',
body: { body: {
type: "crud", type: 'crud',
api: "/api/mock2/crud/list", api: '/api/mock2/crud/list',
columns: [ columns: [
{ {
name: "id", name: 'id',
label: "ID", label: 'ID',
type: "text" type: 'text'
}, },
{ {
name: "audio", name: 'audio',
label: "音频", label: '音频',
type: "audio" type: 'audio'
}, },
{ {
name: "carousel", name: 'carousel',
label: "轮播图", label: '轮播图',
type: "carousel", type: 'carousel',
width: "300" width: '300'
}, },
{ {
name: "text", name: 'text',
label: "文本", label: '文本',
type: "text" type: 'text'
}, },
{ {
type: 'image', type: 'image',
label: '图片', label: '图片',
name: 'image', name: 'image',
popOver: { popOver: {
title: '查看大图', title: '查看大图',
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>' body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
} }
}, },
{ {
name: 'date', name: 'date',
type: 'date', type: 'date',
label: '日期' label: '日期'
}, },
{ {
name: "progress", name: 'progress',
label: "进度", label: '进度',
type: "progress" type: 'progress'
}, },
{ {
name: "boolean", name: 'boolean',
label: "状态", label: '状态',
type: "status" type: 'status'
}, },
{ {
name: "boolean", name: 'boolean',
label: "开关", label: '开关',
type: "switch", type: 'switch'
// readOnly: false // // readOnly: false //
}, },
{ {
name: "type", name: 'type',
label: "映射", label: '映射',
type: "mapping", type: 'mapping',
map: { map: {
"*": "其他:${type}", '*': '其他:${type}',
"1": "<span class='label label-info'>漂亮</span>", '1': "<span class='label label-info'>漂亮</span>",
"2": "<span class='label label-success'>开心</span>", '2': "<span class='label label-success'>开心</span>",
"3": "<span class='label label-danger'>惊吓</span>", '3': "<span class='label label-danger'>惊吓</span>",
"4": "<span class='label label-warning'>紧张</span>" '4': "<span class='label label-warning'>紧张</span>"
} }
}, },
{ {
name: 'list', name: 'list',
type: 'list', type: 'list',
label: 'List', label: 'List',
placeholder: '-', placeholder: '-',
size: "sm", size: 'sm',
listItem: { listItem: {
title: '${title}', title: '${title}',
subTitle: '${description}' subTitle: '${description}'
} }
}, },
{ {
name: 'json', name: 'json',
type: 'json', type: 'json',
label: 'Json' label: 'Json'
} }
] ]
} }
}; };

View File

@ -1,301 +1,301 @@
const table = { const table = {
type: "table", type: 'table',
data: [ data: [
{ {
engine: "Other browsers", engine: 'Other browsers',
browser: "All others", browser: 'All others',
platform: "-", platform: '-',
version: "-", version: '-',
grade: "U", grade: 'U',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 56, weight: 56,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Misc", engine: 'Misc',
browser: "PSP browser", browser: 'PSP browser',
platform: "PSP", platform: 'PSP',
version: "-", version: '-',
grade: "C", grade: 'C',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 55, weight: 55,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Misc", engine: 'Misc',
browser: "PSP browser", browser: 'PSP browser',
platform: "PSP", platform: 'PSP',
version: "-", version: '-',
grade: "C", grade: 'C',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 55, weight: 55,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Other browsers", engine: 'Other browsers',
browser: "All others", browser: 'All others',
platform: "-", platform: '-',
version: "-", version: '-',
grade: "U", grade: 'U',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 56, weight: 56,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Misc", engine: 'Misc',
browser: "PSP browser", browser: 'PSP browser',
platform: "PSP", platform: 'PSP',
version: "-", version: '-',
grade: "C", grade: 'C',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 55, weight: 55,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Misc", engine: 'Misc',
browser: "PSP browser", browser: 'PSP browser',
platform: "PSP", platform: 'PSP',
version: "-", version: '-',
grade: "C", grade: 'C',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 55, weight: 55,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Other browsers", engine: 'Other browsers',
browser: "All others", browser: 'All others',
platform: "-", platform: '-',
version: "-", version: '-',
grade: "U", grade: 'U',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 56, weight: 56,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Misc", engine: 'Misc',
browser: "PSP browser", browser: 'PSP browser',
platform: "PSP", platform: 'PSP',
version: "-", version: '-',
grade: "C", grade: 'C',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 55, weight: 55,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Misc", engine: 'Misc',
browser: "PSP browser", browser: 'PSP browser',
platform: "PSP", platform: 'PSP',
version: "-", version: '-',
grade: "C", grade: 'C',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 55, weight: 55,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
}, },
{ {
engine: "Other browsers", engine: 'Other browsers',
browser: "All others", browser: 'All others',
platform: "-", platform: '-',
version: "-", version: '-',
grade: "U", grade: 'U',
progress: 50, progress: 50,
status: true, status: true,
image: image:
"http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg", 'http://hiphotos.baidu.com/fex/%70%69%63/item/0d338744ebf81a4cff2f4cd6de2a6059252da694.jpg',
weight: 56, weight: 56,
others: null, others: null,
createdAt: "2017-11-17T08:47:50.000Z", createdAt: '2017-11-17T08:47:50.000Z',
updatedAt: "2017-11-17T08:47:50.000Z" updatedAt: '2017-11-17T08:47:50.000Z'
} }
].map((item, key) => ({ ].map((item, key) => ({
...item, ...item,
id: key + 1 id: key + 1
})), })),
columns: [ columns: [
{ {
name: "id", name: 'id',
label: "ID", label: 'ID',
width: 20, width: 20,
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true, toggled: true,
fixed: 'left' fixed: 'left'
}, },
{ {
name: "engine", name: 'engine',
label: "Rendering engine", label: 'Rendering engine',
sortable: true, sortable: true,
searchable: true, searchable: true,
type: "text", type: 'text',
toggled: true, toggled: true,
fixed: 'left' fixed: 'left'
}, },
{ {
name: "browser", name: 'browser',
label: "Browser", label: 'Browser',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "platform", name: 'platform',
label: "Platform(s)", label: 'Platform(s)',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "version", name: 'version',
label: "Engine version", label: 'Engine version',
quickEdit: true, quickEdit: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "grade", name: 'grade',
label: "CSS grade", label: 'CSS grade',
quickEdit: { quickEdit: {
mode: "inline", mode: 'inline',
type: "select", type: 'select',
options: ["A", "B", "C", "D", "X"], options: ['A', 'B', 'C', 'D', 'X'],
saveImmediately: true saveImmediately: true
}, },
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "browser", name: 'browser',
label: "Browser", label: 'Browser',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "platform", name: 'platform',
label: "Platform(s)", label: 'Platform(s)',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "version", name: 'version',
label: "Engine version", label: 'Engine version',
quickEdit: true, quickEdit: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "browser", name: 'browser',
label: "Browser", label: 'Browser',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "platform", name: 'platform',
label: "Platform(s)", label: 'Platform(s)',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "version", name: 'version',
label: "Engine version", label: 'Engine version',
quickEdit: true, quickEdit: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "browser", name: 'browser',
label: "Browser", label: 'Browser',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "platform", name: 'platform',
label: "Platform(s)", label: 'Platform(s)',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true, toggled: true,
fixed: 'right' fixed: 'right'
}, },
{ {
name: "version", name: 'version',
label: "Engine version", label: 'Engine version',
quickEdit: true, quickEdit: true,
type: "text", type: 'text',
toggled: true, toggled: true,
fixed: 'right' fixed: 'right'
}, }
] ]
}; };
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "固顶和列固定示例", title: '固顶和列固定示例',
remark: "bla bla bla", remark: 'bla bla bla',
body: [ body: [
table, table,
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
'<div>分割</div>', '<div>分割</div>',
table table
] ]
}; };

View File

@ -1,198 +1,198 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "开启单条底部展示功能", title: '开启单条底部展示功能',
body: { body: {
type: "crud", type: 'crud',
draggable: true, draggable: true,
api: "/api/sample", api: '/api/sample',
footable: { footable: {
expand: 'first', expand: 'first',
accordion: true accordion: true
},
columns: [
{
name: 'id',
label: 'ID',
width: 20,
sortable: true,
type: 'text',
toggled: true
},
{
name: 'engine',
label: 'Rendering engine',
sortable: true,
searchable: true,
type: 'text',
toggled: true
},
{
name: 'browser',
label: 'Browser',
sortable: true,
type: 'text',
toggled: true
},
{
name: 'platform',
label: 'Platform(s)',
sortable: true,
type: 'text',
toggled: true
},
{
name: 'version',
label: 'Engine version',
quickEdit: true,
type: 'text',
toggled: true
},
{
name: 'grade',
label: 'CSS grade',
breakpoint: '*',
quickEdit: {
mode: 'inline',
type: 'select',
options: ['A', 'B', 'C', 'D', 'X'],
inputClassName: 'w-xs',
saveImmediately: true
}, },
columns: [ type: 'text',
{ toggled: true
name: "id", },
label: "ID", {
width: 20, type: 'operation',
sortable: true, label: '操作',
type: "text", width: 100,
toggled: true breakpoint: '*',
}, buttons: [
{ {
name: "engine", type: 'button',
label: "Rendering engine", icon: 'fa fa-eye',
sortable: true, actionType: 'dialog',
searchable: true, dialog: {
type: "text", title: '查看',
toggled: true body: {
}, type: 'form',
{ controls: [
name: "browser", {
label: "Browser", type: 'static',
sortable: true, name: 'engine',
type: "text", label: 'Engine'
toggled: true },
}, {
{ type: 'divider'
name: "platform", },
label: "Platform(s)", {
sortable: true, type: 'static',
type: "text", name: 'browser',
toggled: true label: 'Browser'
}, },
{ {
name: "version", type: 'divider'
label: "Engine version", },
quickEdit: true, {
type: "text", type: 'static',
toggled: true name: 'platform',
}, label: 'Platform(s)'
{ },
name: "grade", {
label: "CSS grade", type: 'divider'
breakpoint: '*', },
quickEdit: { {
mode: "inline", type: 'static',
type: "select", name: 'version',
options: ["A", "B", "C", "D", "X"], label: 'Engine version'
inputClassName: 'w-xs', },
saveImmediately: true {
}, type: 'divider'
type: "text", },
toggled: true {
}, type: 'static',
{ name: 'grade',
type: "operation", label: 'CSS grade'
label: "操作", },
width: 100, {
breakpoint: '*', type: 'divider'
buttons: [ },
{ {
type: "button", type: 'html',
icon: "fa fa-eye", html:
actionType: "dialog", '<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
dialog: { }
title: "查看", ]
body: { }
type: "form",
controls: [
{
type: "static",
name: "engine",
label: "Engine"
},
{
type: "divider"
},
{
type: "static",
name: "browser",
label: "Browser"
},
{
type: "divider"
},
{
type: "static",
name: "platform",
label: "Platform(s)"
},
{
type: "divider"
},
{
type: "static",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
},
{
type: "divider"
},
{
type: "html",
html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>"
}
]
}
}
},
{
type: "button",
icon: "fa fa-pencil",
actionType: "drawer",
drawer: {
position: 'left',
size: 'lg',
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "select",
name: "grade",
label: "CSS grade",
options: ["A", "B", "C", "D", "X"],
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
toggled: true
} }
] },
} {
type: 'button',
icon: 'fa fa-pencil',
actionType: 'drawer',
drawer: {
position: 'left',
size: 'lg',
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'select',
name: 'grade',
label: 'CSS grade',
options: ['A', 'B', 'C', 'D', 'X']
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
toggled: true
}
]
}
}; };

View File

@ -1,221 +1,221 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "增删改查示例", title: '增删改查示例',
remark: "bla bla bla", remark: 'bla bla bla',
body: { body: {
type: "crud", type: 'crud',
api: "/api/sample", api: '/api/sample',
// api: "/api/mock2/crud/table?waitSeconds=100000", // api: "/api/mock2/crud/table?waitSeconds=100000",
mode: "cards", mode: 'cards',
defaultParams: { defaultParams: {
perPage: 12, perPage: 12
},
// fixAlignment: true,
// masonryLayout: true,
filter: {
title: '条件搜索',
submitText: '',
controls: [
{
type: 'text',
name: 'keywords',
placeholder: '通过关键字搜索',
addOn: {
label: '搜索',
type: 'submit'
}
}, },
// fixAlignment: true, {
// masonryLayout: true, type: 'plain',
filter: { text: '这只是个示例, 目前搜索对查询结果无效.'
title: "条件搜索",
submitText: "",
controls: [
{
type: "text",
name: "keywords",
placeholder: "通过关键字搜索",
addOn: {
label: "搜索",
type: "submit"
}
},
{
type: "plain",
text: "这只是个示例, 目前搜索对查询结果无效."
}
]
},
bulkActions: [
{
label: "批量删除",
actionType: "ajax",
api: "delete:/api/sample/${ids|raw}",
confirmText: "确定要批量删除?"
},
{
label: "批量修改",
actionType: "dialog",
dialog: {
title: "批量编辑",
name: "sample-bulk-edit",
body: {
type: "form",
api: "/api/sample/bulkUpdate2",
controls: [
{
type: "hidden",
name: "ids"
},
{
type: "text",
name: "engine",
label: "Engine"
}
]
}
}
}
],
quickSaveApi: "/api/sample/bulkUpdate",
quickSaveItemApi: "/api/sample/$id",
draggable: true,
card: {
header: {
title: "$engine",
subTitle: "$platform",
subTitlePlaceholder: "暂无说明",
avatar:
'<%= data.avatar || "http://bos.nj.bpc.baidu.com/showx/146bc2ce1b30f3824838f4208ad2663c" %>',
avatarClassName: "pull-left thumb b-3x m-r"
},
actions: [
{
type: "button",
label: "查看",
actionType: "dialog",
dialog: {
title: "查看",
body: {
type: "form",
controls: [
{
type: "static",
name: "engine",
label: "Engine"
},
{
type: "divider"
},
{
type: "static",
name: "browser",
label: "Browser"
},
{
type: "divider"
},
{
type: "static",
name: "platform",
label: "Platform(s)"
},
{
type: "divider"
},
{
type: "static",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
},
{
type: "divider"
},
{
type: "html",
html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>"
}
]
}
}
},
{
type: "button",
label: "编辑",
actionType: "dialog",
dialog: {
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "text",
name: "grade",
label: "CSS grade"
}
]
}
}
},
{
type: "button",
label: "删除",
actionType: "ajax",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
body: [
{
name: "engine",
label: "engine",
sortable: true,
quickEdit: true
},
{
name: "browser",
label: "Browser"
},
{
name: "platform",
label: "Platform"
},
{
name: "version",
label: "version"
}
]
} }
]
},
bulkActions: [
{
label: '批量删除',
actionType: 'ajax',
api: 'delete:/api/sample/${ids|raw}',
confirmText: '确定要批量删除?'
},
{
label: '批量修改',
actionType: 'dialog',
dialog: {
title: '批量编辑',
name: 'sample-bulk-edit',
body: {
type: 'form',
api: '/api/sample/bulkUpdate2',
controls: [
{
type: 'hidden',
name: 'ids'
},
{
type: 'text',
name: 'engine',
label: 'Engine'
}
]
}
}
}
],
quickSaveApi: '/api/sample/bulkUpdate',
quickSaveItemApi: '/api/sample/$id',
draggable: true,
card: {
header: {
title: '$engine',
subTitle: '$platform',
subTitlePlaceholder: '暂无说明',
avatar:
'<%= data.avatar || "http://bos.nj.bpc.baidu.com/showx/146bc2ce1b30f3824838f4208ad2663c" %>',
avatarClassName: 'pull-left thumb b-3x m-r'
},
actions: [
{
type: 'button',
label: '查看',
actionType: 'dialog',
dialog: {
title: '查看',
body: {
type: 'form',
controls: [
{
type: 'static',
name: 'engine',
label: 'Engine'
},
{
type: 'divider'
},
{
type: 'static',
name: 'browser',
label: 'Browser'
},
{
type: 'divider'
},
{
type: 'static',
name: 'platform',
label: 'Platform(s)'
},
{
type: 'divider'
},
{
type: 'static',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'static',
name: 'grade',
label: 'CSS grade'
},
{
type: 'divider'
},
{
type: 'html',
html:
'<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
}
]
}
}
},
{
type: 'button',
label: '编辑',
actionType: 'dialog',
dialog: {
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'text',
name: 'grade',
label: 'CSS grade'
}
]
}
}
},
{
type: 'button',
label: '删除',
actionType: 'ajax',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
body: [
{
name: 'engine',
label: 'engine',
sortable: true,
quickEdit: true
},
{
name: 'browser',
label: 'Browser'
},
{
name: 'platform',
label: 'Platform'
},
{
name: 'version',
label: 'version'
}
]
} }
}
}; };

View File

@ -1,107 +1,107 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "支持表头分组,通过在 cloumn 上设置 groupName 实现。", title: '支持表头分组,通过在 cloumn 上设置 groupName 实现。',
body: { body: {
type: "table", type: 'table',
data: { data: {
items: [ items: [
{ {
"engine": "Trident", engine: 'Trident',
"browser": "Internet Explorer 4.2", browser: 'Internet Explorer 4.2',
"platform": "Win 95+", platform: 'Win 95+',
"version": "4", version: '4',
"grade": "A" grade: 'A'
},
{
"engine": "Trident",
"browser": "Internet Explorer 4.2",
"platform": "Win 95+",
"version": "4",
"grade": "B"
},
{
"engine": "Trident",
"browser": "AOL browser (AOL desktop)",
"platform": "Win 95+",
"version": "4",
"grade": "C"
},
{
"engine": "Trident",
"browser": "AOL browser (AOL desktop)",
"platform": "Win 98",
"version": "3",
"grade": "A"
},
{
"engine": "Trident",
"browser": "AOL browser (AOL desktop)",
"platform": "Win 98",
"version": "4",
"grade": "A"
},
{
"engine": "Gecko",
"browser": "Firefox 1.0",
"platform": "Win 98+ / OSX.2+",
"version": "4",
"grade": "A"
},
{
"engine": "Gecko",
"browser": "Firefox 1.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "A"
},
{
"engine": "Gecko",
"browser": "Firefox 2.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "B"
},
{
"engine": "Gecko",
"browser": "Firefox 2.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "C"
},
{
"engine": "Gecko",
"browser": "Firefox 2.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "D"
}
]
}, },
columns: [ {
{ engine: 'Trident',
name: "engine", browser: 'Internet Explorer 4.2',
label: "Rendering engine", platform: 'Win 95+',
groupName: "A" version: '4',
}, grade: 'B'
{ },
name: "browser", {
label: "Browser", engine: 'Trident',
groupName: "A" browser: 'AOL browser (AOL desktop)',
}, platform: 'Win 95+',
{ version: '4',
name: "platform", grade: 'C'
label: "Platform(s)", },
groupName: "B" {
}, engine: 'Trident',
{ browser: 'AOL browser (AOL desktop)',
name: "version", platform: 'Win 98',
label: "Engine version", version: '3',
groupName: "B" grade: 'A'
}, },
{ {
name: "grade", engine: 'Trident',
label: "CSS grade", browser: 'AOL browser (AOL desktop)',
} platform: 'Win 98',
] version: '4',
} grade: 'A'
},
{
engine: 'Gecko',
browser: 'Firefox 1.0',
platform: 'Win 98+ / OSX.2+',
version: '4',
grade: 'A'
},
{
engine: 'Gecko',
browser: 'Firefox 1.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'A'
},
{
engine: 'Gecko',
browser: 'Firefox 2.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'B'
},
{
engine: 'Gecko',
browser: 'Firefox 2.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'C'
},
{
engine: 'Gecko',
browser: 'Firefox 2.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'D'
}
]
},
columns: [
{
name: 'engine',
label: 'Rendering engine',
groupName: 'A'
},
{
name: 'browser',
label: 'Browser',
groupName: 'A'
},
{
name: 'platform',
label: 'Platform(s)',
groupName: 'B'
},
{
name: 'version',
label: 'Engine version',
groupName: 'B'
},
{
name: 'grade',
label: 'CSS grade'
}
]
}
}; };

View File

@ -1,223 +1,228 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "增删改查示例", title: '增删改查示例',
remark: "bla bla bla", remark: 'bla bla bla',
body: { body: {
type: "crud", type: 'crud',
api: "/api/sample", api: '/api/sample',
headerToolbar: ['bulkActions', { headerToolbar: [
type: 'columns-toggler', 'bulkActions',
className: 'pull-right', {
align: 'right' type: 'columns-toggler',
}, { className: 'pull-right',
type: 'drag-toggler', align: 'right'
className: 'pull-right' },
}, { {
type: 'pagination', type: 'drag-toggler',
className: 'pull-right' className: 'pull-right'
}], },
itemActions: [ {
{ type: 'pagination',
type: "button", className: 'pull-right'
label: "查看", }
actionType: "dialog", ],
dialog: { itemActions: [
title: "查看", {
body: { type: 'button',
type: "form", label: '查看',
controls: [ actionType: 'dialog',
{ dialog: {
type: "static", title: '查看',
name: "engine", body: {
label: "Engine" type: 'form',
}, controls: [
{ {
type: "divider" type: 'static',
}, name: 'engine',
{ label: 'Engine'
type: "static", },
name: "browser", {
label: "Browser" type: 'divider'
}, },
{ {
type: "divider" type: 'static',
}, name: 'browser',
{ label: 'Browser'
type: "static", },
name: "platform", {
label: "Platform(s)" type: 'divider'
}, },
{ {
type: "divider" type: 'static',
}, name: 'platform',
{ label: 'Platform(s)'
type: "static", },
name: "version", {
label: "Engine version" type: 'divider'
}, },
{ {
type: "divider" type: 'static',
}, name: 'version',
{ label: 'Engine version'
type: "static", },
name: "grade", {
label: "CSS grade" type: 'divider'
}, },
{ {
type: "divider" type: 'static',
}, name: 'grade',
{ label: 'CSS grade'
type: "html", },
html: {
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>" type: 'divider'
} },
] {
} type: 'html',
} html:
}, '<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
{ }
type: "button", ]
label: "编辑", }
actionType: "drawer", }
drawer: { },
position: 'left', {
size: 'lg', type: 'button',
title: "编辑", label: '编辑',
body: { actionType: 'drawer',
type: "form", drawer: {
name: "sample-edit-form", position: 'left',
api: "/api/sample/$id", size: 'lg',
controls: [ title: '编辑',
{ body: {
type: "text", type: 'form',
name: "engine", name: 'sample-edit-form',
label: "Engine", api: '/api/sample/$id',
required: true controls: [
}, {
{ type: 'text',
type: "divider" name: 'engine',
}, label: 'Engine',
{ required: true
type: "text", },
name: "browser", {
label: "Browser", type: 'divider'
required: true },
}, {
{ type: 'text',
type: "divider" name: 'browser',
}, label: 'Browser',
{ required: true
type: "text", },
name: "platform", {
label: "Platform(s)", type: 'divider'
required: true },
}, {
{ type: 'text',
type: "divider" name: 'platform',
}, label: 'Platform(s)',
{ required: true
type: "text", },
name: "version", {
label: "Engine version" type: 'divider'
}, },
{ {
type: "divider" type: 'text',
}, name: 'version',
{ label: 'Engine version'
type: "select", },
name: "grade", {
label: "CSS grade", type: 'divider'
options: ["A", "B", "C", "D", "X"], },
} {
] type: 'select',
} name: 'grade',
} label: 'CSS grade',
}, options: ['A', 'B', 'C', 'D', 'X']
{ }
type: "button", ]
label: "删除", }
actionType: "ajax", }
confirmText: "您确认要删除?", },
api: "delete:/api/sample/$id" {
} type: 'button',
], label: '删除',
bulkActions: [ actionType: 'ajax',
{ confirmText: '您确认要删除?',
label: "批量删除", api: 'delete:/api/sample/$id'
actionType: "ajax", }
api: "delete:/api/sample/${ids|raw}", ],
confirmText: "确定要批量删除?", bulkActions: [
type: "button" {
}, label: '批量删除',
{ actionType: 'ajax',
label: "批量修改", api: 'delete:/api/sample/${ids|raw}',
actionType: "dialog", confirmText: '确定要批量删除?',
dialog: { type: 'button'
title: "批量编辑", },
name: "sample-bulk-edit", {
body: { label: '批量修改',
type: "form", actionType: 'dialog',
api: "/api/sample/bulkUpdate2", dialog: {
controls: [ title: '批量编辑',
{ name: 'sample-bulk-edit',
type: 'hidden', body: {
name: 'ids' type: 'form',
}, api: '/api/sample/bulkUpdate2',
{ controls: [
type: "text", {
name: "engine", type: 'hidden',
label: "Engine" name: 'ids'
} },
] {
} type: 'text',
}, name: 'engine',
type: "button" label: 'Engine'
} }
], ]
columns: [ }
{ },
name: "id", type: 'button'
label: "ID", }
width: 20, ],
sortable: true, columns: [
type: "text", {
toggled: true, name: 'id',
remark: 'Bla bla Bla' label: 'ID',
}, width: 20,
{ sortable: true,
name: "engine", type: 'text',
label: "Rendering engine", toggled: true,
sortable: true, remark: 'Bla bla Bla'
searchable: true, },
type: "text", {
toggled: true name: 'engine',
}, label: 'Rendering engine',
{ sortable: true,
name: "browser", searchable: true,
label: "Browser", type: 'text',
sortable: true, toggled: true
type: "text", },
toggled: false {
}, name: 'browser',
{ label: 'Browser',
name: "platform", sortable: true,
label: "Platform(s)", type: 'text',
sortable: true, toggled: false
type: "text", },
toggled: true {
}, name: 'platform',
{ label: 'Platform(s)',
name: "version", sortable: true,
label: "Engine version", type: 'text',
type: "text", toggled: true
toggled: true },
}, {
{ name: 'version',
name: "grade", label: 'Engine version',
label: "CSS grade", type: 'text',
type: "text", toggled: true
toggled: true },
} {
] name: 'grade',
} label: 'CSS grade',
type: 'text',
toggled: true
}
]
}
}; };

View File

@ -1,131 +1,131 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "操作并下一个", title: '操作并下一个',
"remark": "当存在下一条时,支持直接打开下一条操作。", remark: '当存在下一条时,支持直接打开下一条操作。',
"body": { body: {
"type": "crud", type: 'crud',
"title": "", title: '',
"api": "/api/sample/list", api: '/api/sample/list',
"columnsTogglable": false, columnsTogglable: false,
"columns": [ columns: [
{ {
"name": "id", name: 'id',
"label": "ID", label: 'ID',
"width": 20, width: 20,
"type": "text", type: 'text',
"toggled": true toggled: true
}, },
{ {
"name": "engine", name: 'engine',
"label": "Rendering engine", label: 'Rendering engine',
"type": "text", type: 'text',
"toggled": true toggled: true
}, },
{ {
"name": "browser", name: 'browser',
"label": "Browser", label: 'Browser',
"type": "text", type: 'text',
"toggled": true toggled: true
}, },
{ {
"type": "operation", type: 'operation',
"label": "操作", label: '操作',
"width": 130, width: 130,
"buttons": [ buttons: [
{ {
"type": "button", type: 'button',
"icon": "fa fa-pencil", icon: 'fa fa-pencil',
"actionType": "dialog", actionType: 'dialog',
"nextCondition": "true", nextCondition: 'true',
"_nextCondition": "可以设置条件比如: data.grade == \"B\"", _nextCondition: '可以设置条件比如: data.grade == "B"',
"dialog": { dialog: {
"title": "编辑", title: '编辑',
"actions": [ actions: [
{ {
"type": "button", type: 'button',
"actionType": "prev", actionType: 'prev',
"level": "info", level: 'info',
"visibleOn": "data.hasPrev", visibleOn: 'data.hasPrev',
"label": "上一个" label: '上一个'
}, },
{ {
"type": "button", type: 'button',
"actionType": "cancel", actionType: 'cancel',
"label": "关闭" label: '关闭'
}, },
{ {
"type": "submit", type: 'submit',
"actionType": "next", actionType: 'next',
"visibleOn": "data.hasNext", visibleOn: 'data.hasNext',
"label": "保存并下一个", label: '保存并下一个',
"level": "primary" level: 'primary'
}, },
{ {
"type": "submit", type: 'submit',
"visibleOn": "!data.hasNext", visibleOn: '!data.hasNext',
"label": "保存", label: '保存',
"level": "primary" level: 'primary'
}, },
{ {
"type": "button", type: 'button',
"actionType": "next", actionType: 'next',
"level": "info", level: 'info',
"visibleOn": "data.hasNext", visibleOn: 'data.hasNext',
"label": "下一个" label: '下一个'
} }
], ],
"body": { body: {
"type": "form", type: 'form',
"name": "sample-edit-form", name: 'sample-edit-form',
"api": "/api/sample/$id", api: '/api/sample/$id',
"controls": [ controls: [
{ {
"type": "text", type: 'text',
"name": "engine", name: 'engine',
"label": "Engine", label: 'Engine',
"required": true required: true
}, },
{ {
"type": "divider" type: 'divider'
}, },
{ {
"type": "text", type: 'text',
"name": "browser", name: 'browser',
"label": "Browser", label: 'Browser',
"required": true required: true
}, },
{ {
"type": "divider" type: 'divider'
}, },
{ {
"type": "text", type: 'text',
"name": "platform", name: 'platform',
"label": "Platform(s)", label: 'Platform(s)',
"required": true required: true
}, },
{ {
"type": "divider" type: 'divider'
}, },
{ {
"type": "text", type: 'text',
"name": "version", name: 'version',
"label": "Engine version" label: 'Engine version'
}, },
{ {
"type": "divider" type: 'divider'
}, },
{ {
"type": "text", type: 'text',
"name": "grade", name: 'grade',
"label": "CSS grade" label: 'CSS grade'
} }
] ]
} }
}
}
],
"toggled": true
} }
] }
} ],
} toggled: true
}
]
}
};

View File

@ -1,83 +1,78 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "Table 全键盘操作示例", title: 'Table 全键盘操作示例',
"remark": "bla bla bla", remark: 'bla bla bla',
"body": [ body: [
{
type: 'plain',
className: 'text-danger',
text:
'请通过上下左右键切换单元格,按 `Space` 键进入编辑模式,按 `Enter` 提交编辑,并最后点左上角的全部保存完成操作。'
},
{
type: 'crud',
className: 'm-t',
api: '/api/sample',
quickSaveApi: '/api/sample/bulkUpdate',
quickSaveItemApi: '/api/sample/$id',
columns: [
{ {
"type": "plain", name: 'id',
"className": "text-danger", label: 'ID',
"text": "请通过上下左右键切换单元格,按 `Space` 键进入编辑模式,按 `Enter` 提交编辑,并最后点左上角的全部保存完成操作。" width: 20,
sortable: true,
type: 'text',
toggled: true
}, },
{ {
"type": "crud", name: 'engine',
"className": "m-t", label: 'Rendering engine',
"api": "/api/sample", sortable: true,
"quickSaveApi": "/api/sample/bulkUpdate", quickEdit: {
"quickSaveItemApi": "/api/sample/$id", type: 'text',
"columns": [ required: true,
{ mode: 'inline'
"name": "id", },
"label": "ID", type: 'text',
"width": 20, toggled: true
"sortable": true, },
"type": "text", {
"toggled": true name: 'browser',
}, label: 'Browser',
{ sortable: true,
"name": "engine", quickEdit: {
"label": "Rendering engine", type: 'text',
"sortable": true, required: true
"quickEdit": { },
type: "text", type: 'text',
required: true, toggled: true
mode: 'inline' },
}, {
"type": "text", name: 'platform',
"toggled": true label: 'Platform(s)',
}, sortable: true,
{ quickEdit: true,
"name": "browser", type: 'text',
"label": "Browser", toggled: true
"sortable": true, },
"quickEdit": { {
type: "text", name: 'version',
required: true label: 'Engine version',
}, quickEdit: true,
"type": "text", type: 'text',
"toggled": true toggled: true
}, },
{ {
"name": "platform", name: 'grade',
"label": "Platform(s)", label: 'CSS grade',
"sortable": true, quickEdit: {
"quickEdit": true, type: 'select',
"type": "text", options: ['A', 'B', 'C', 'D', 'X']
"toggled": true },
}, type: 'text',
{ toggled: true
"name": "version",
"label": "Engine version",
"quickEdit": true,
"type": "text",
"toggled": true
},
{
"name": "grade",
"label": "CSS grade",
"quickEdit": {
"type": "select",
"options": [
"A",
"B",
"C",
"D",
"X"
]
},
"type": "text",
"toggled": true
}
]
} }
] ]
} }
]
};

View File

@ -1,214 +1,213 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "增删改查示例", title: '增删改查示例',
remark: "bla bla bla", remark: 'bla bla bla',
body: { body: {
type: "crud", type: 'crud',
api: "/api/sample", api: '/api/sample',
mode: "list", mode: 'list',
draggable: true, draggable: true,
saveOrderApi: { saveOrderApi: {
url: "/api/sample/saveOrder" url: '/api/sample/saveOrder'
},
orderField: 'weight',
filter: {
title: '条件搜索',
submitText: '',
controls: [
{
type: 'text',
name: 'keywords',
placeholder: '通过关键字搜索',
addOn: {
label: '搜索',
type: 'submit'
}
}, },
orderField: "weight", {
filter: { type: 'plain',
title: "条件搜索", text: '这只是个示例, 目前搜索对查询结果无效.'
submitText: "",
controls: [
{
type: "text",
name: "keywords",
placeholder: "通过关键字搜索",
addOn: {
label: "搜索",
type: "submit"
}
},
{
type: "plain",
text: "这只是个示例, 目前搜索对查询结果无效."
}
]
},
bulkActions: [
{
label: "批量删除",
actionType: "ajax",
api: "delete:/api/sample/${ids|raw}",
confirmText: "确定要批量删除?",
type: "button",
level: "danger"
},
{
label: "批量修改",
actionType: "dialog",
level: "info",
type: "button",
dialog: {
title: "批量编辑",
body: {
type: 'form',
api: "/api/sample/bulkUpdate2",
controls: [
{type: 'hidden', name: 'ids'},
{
type: "text",
name: "engine",
label: "Engine"
}
]
}
}
}
],
quickSaveApi: "/api/sample/bulkUpdate",
quickSaveItemApi: "/api/sample/$id",
listItem: {
actions: [
{
type: "button",
icon: "fa fa-eye",
actionType: "dialog",
dialog: {
title: "查看",
body: {
type: "form",
controls: [
{
type: "static",
name: "engine",
label: "Engine"
},
{
type: "divider"
},
{
type: "static",
name: "browser",
label: "Browser"
},
{
type: "divider"
},
{
type: "static",
name: "platform",
label: "Platform(s)"
},
{
type: "divider"
},
{
type: "static",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
},
{
type: "divider"
},
{
type: "html",
html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>"
}
]
}
}
},
{
type: "button",
icon: "fa fa-pencil",
actionType: "dialog",
dialog: {
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "text",
name: "grade",
label: "CSS grade"
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
body: [
{
name: "engine",
label: "Rendering engine",
sortable: true,
quickEdit: true
},
[
{
name: "browser",
label: "Browser"
},
{
name: "platform",
label: "Platform(s)"
}
],
{
name: "version",
label: "Engine version"
}
]
} }
]
},
bulkActions: [
{
label: '批量删除',
actionType: 'ajax',
api: 'delete:/api/sample/${ids|raw}',
confirmText: '确定要批量删除?',
type: 'button',
level: 'danger'
},
{
label: '批量修改',
actionType: 'dialog',
level: 'info',
type: 'button',
dialog: {
title: '批量编辑',
body: {
type: 'form',
api: '/api/sample/bulkUpdate2',
controls: [
{type: 'hidden', name: 'ids'},
{
type: 'text',
name: 'engine',
label: 'Engine'
}
]
}
}
}
],
quickSaveApi: '/api/sample/bulkUpdate',
quickSaveItemApi: '/api/sample/$id',
listItem: {
actions: [
{
type: 'button',
icon: 'fa fa-eye',
actionType: 'dialog',
dialog: {
title: '查看',
body: {
type: 'form',
controls: [
{
type: 'static',
name: 'engine',
label: 'Engine'
},
{
type: 'divider'
},
{
type: 'static',
name: 'browser',
label: 'Browser'
},
{
type: 'divider'
},
{
type: 'static',
name: 'platform',
label: 'Platform(s)'
},
{
type: 'divider'
},
{
type: 'static',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'static',
name: 'grade',
label: 'CSS grade'
},
{
type: 'divider'
},
{
type: 'html',
html:
'<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-pencil',
actionType: 'dialog',
dialog: {
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'text',
name: 'grade',
label: 'CSS grade'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
body: [
{
name: 'engine',
label: 'Rendering engine',
sortable: true,
quickEdit: true
},
[
{
name: 'browser',
label: 'Browser'
},
{
name: 'platform',
label: 'Platform(s)'
}
],
{
name: 'version',
label: 'Engine version'
}
]
} }
}
}; };

View File

@ -1,223 +1,219 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "增删改查示例", title: '增删改查示例',
remark: "bla bla bla", remark: 'bla bla bla',
body: { body: {
type: "crud", type: 'crud',
api: "/api/sample", api: '/api/sample',
mode: "list", mode: 'list',
draggable: true, draggable: true,
saveOrderApi: { saveOrderApi: {
url: "/api/sample/saveOrder" url: '/api/sample/saveOrder'
},
orderField: 'weight',
filter: {
title: '条件搜索',
submitText: '',
controls: [
{
type: 'text',
name: 'keywords',
placeholder: '通过关键字搜索',
addOn: {
label: '搜索',
type: 'submit'
}
}, },
orderField: "weight", {
filter: { type: 'plain',
title: "条件搜索", text: '这只是个示例, 目前搜索对查询结果无效.'
submitText: "",
controls: [
{
type: "text",
name: "keywords",
placeholder: "通过关键字搜索",
addOn: {
label: "搜索",
type: "submit"
}
},
{
type: "plain",
text: "这只是个示例, 目前搜索对查询结果无效."
}
]
},
bulkActions: [
{
label: "批量删除",
actionType: "ajax",
api: "delete:/api/sample/${ids|raw}",
confirmText: "确定要批量删除?",
type: "button",
level: "danger"
},
{
label: "批量修改",
actionType: "dialog",
level: "info",
type: "button",
dialog: {
title: "批量编辑",
body: {
type: 'form',
api: "/api/sample/bulkUpdate2",
controls: [
{type: 'hidden', name: 'ids'},
{
type: "text",
name: "engine",
label: "Engine"
}
]
}
}
}
],
quickSaveApi: "/api/sample/bulkUpdate",
quickSaveItemApi: "/api/sample/$id",
headerToolbar: [
"bulkActions"
],
footerToolbar: [
"load-more"
],
listItem: {
actions: [
{
type: "button",
icon: "fa fa-eye",
actionType: "dialog",
dialog: {
title: "查看",
body: {
type: "form",
controls: [
{
type: "static",
name: "engine",
label: "Engine"
},
{
type: "divider"
},
{
type: "static",
name: "browser",
label: "Browser"
},
{
type: "divider"
},
{
type: "static",
name: "platform",
label: "Platform(s)"
},
{
type: "divider"
},
{
type: "static",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
},
{
type: "divider"
},
{
type: "html",
html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>"
}
]
}
}
},
{
type: "button",
icon: "fa fa-pencil",
actionType: "dialog",
dialog: {
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "text",
name: "grade",
label: "CSS grade"
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
body: [
{
name: "engine",
label: "Rendering engine",
sortable: true,
quickEdit: true,
labelClassName: "w-sm pull-left text-muted"
},
[
{
name: "browser",
label: "Browser",
labelClassName: "w-sm pull-left text-muted"
},
{
name: "platform",
label: "Platform(s)",
labelClassName: "w-sm pull-left text-muted"
}
],
{
name: "version",
label: "Engine version",
labelClassName: "w-sm pull-left text-muted"
}
]
} }
]
},
bulkActions: [
{
label: '批量删除',
actionType: 'ajax',
api: 'delete:/api/sample/${ids|raw}',
confirmText: '确定要批量删除?',
type: 'button',
level: 'danger'
},
{
label: '批量修改',
actionType: 'dialog',
level: 'info',
type: 'button',
dialog: {
title: '批量编辑',
body: {
type: 'form',
api: '/api/sample/bulkUpdate2',
controls: [
{type: 'hidden', name: 'ids'},
{
type: 'text',
name: 'engine',
label: 'Engine'
}
]
}
}
}
],
quickSaveApi: '/api/sample/bulkUpdate',
quickSaveItemApi: '/api/sample/$id',
headerToolbar: ['bulkActions'],
footerToolbar: ['load-more'],
listItem: {
actions: [
{
type: 'button',
icon: 'fa fa-eye',
actionType: 'dialog',
dialog: {
title: '查看',
body: {
type: 'form',
controls: [
{
type: 'static',
name: 'engine',
label: 'Engine'
},
{
type: 'divider'
},
{
type: 'static',
name: 'browser',
label: 'Browser'
},
{
type: 'divider'
},
{
type: 'static',
name: 'platform',
label: 'Platform(s)'
},
{
type: 'divider'
},
{
type: 'static',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'static',
name: 'grade',
label: 'CSS grade'
},
{
type: 'divider'
},
{
type: 'html',
html:
'<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-pencil',
actionType: 'dialog',
dialog: {
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'text',
name: 'grade',
label: 'CSS grade'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
body: [
{
name: 'engine',
label: 'Rendering engine',
sortable: true,
quickEdit: true,
labelClassName: 'w-sm pull-left text-muted'
},
[
{
name: 'browser',
label: 'Browser',
labelClassName: 'w-sm pull-left text-muted'
},
{
name: 'platform',
label: 'Platform(s)',
labelClassName: 'w-sm pull-left text-muted'
}
],
{
name: 'version',
label: 'Engine version',
labelClassName: 'w-sm pull-left text-muted'
}
]
} }
}
}; };

View File

@ -1,202 +1,202 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "一次性加载,前端分页,前端排序", title: '一次性加载,前端分页,前端排序',
body: { body: {
type: "crud", type: 'crud',
loadDataOnce: true, loadDataOnce: true,
api: "/api/sample?waitSeconds=1", api: '/api/sample?waitSeconds=1',
filter: { filter: {
title: "条件搜索", title: '条件搜索',
submitText: "", submitText: '',
controls: [ controls: [
{ {
type: "text", type: 'text',
name: "keywords", name: 'keywords',
placeholder: "通过关键字搜索", placeholder: '通过关键字搜索',
addOn: { addOn: {
label: "搜索", label: '搜索',
type: "submit" type: 'submit'
} }
} }
] ]
}, },
columns: [ columns: [
{ {
name: "id", name: 'id',
label: "ID", label: 'ID',
width: 20, width: 20,
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true, toggled: true,
remark: 'Bla bla Bla' remark: 'Bla bla Bla'
}, },
{ {
name: "engine", name: 'engine',
label: "Rendering engine", label: 'Rendering engine',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "browser", name: 'browser',
label: "Browser", label: 'Browser',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: false toggled: false
}, },
{ {
name: "platform", name: 'platform',
label: "Platform(s)", label: 'Platform(s)',
sortable: true, sortable: true,
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "version", name: 'version',
label: "Engine version", label: 'Engine version',
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
name: "grade", name: 'grade',
label: "CSS grade", label: 'CSS grade',
type: "text", type: 'text',
toggled: true toggled: true
}, },
{ {
type: "operation", type: 'operation',
label: "操作", label: '操作',
width: 100, width: 100,
buttons: [ buttons: [
{ {
type: "button", type: 'button',
icon: "fa fa-eye", icon: 'fa fa-eye',
actionType: "dialog", actionType: 'dialog',
tooltip: "查看", tooltip: '查看',
dialog: { dialog: {
title: "查看", title: '查看',
body: { body: {
type: "form", type: 'form',
controls: [ controls: [
{ {
type: "static", type: 'static',
name: "engine", name: 'engine',
label: "Engine" label: 'Engine'
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "static", type: 'static',
name: "browser", name: 'browser',
label: "Browser" label: 'Browser'
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "static", type: 'static',
name: "platform", name: 'platform',
label: "Platform(s)" label: 'Platform(s)'
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "static", type: 'static',
name: "version", name: 'version',
label: "Engine version" label: 'Engine version'
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "static", type: 'static',
name: "grade", name: 'grade',
label: "CSS grade" label: 'CSS grade'
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "html", type: 'html',
html: html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>" '<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
} }
] ]
} }
}
},
{
type: "button",
icon: "fa fa-pencil",
tooltip: "编辑",
actionType: "drawer",
drawer: {
position: 'left',
size: 'lg',
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "select",
name: "grade",
label: "CSS grade",
options: ["A", "B", "C", "D", "X"],
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
tooltip: "删除",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
toggled: true
} }
] },
} {
type: 'button',
icon: 'fa fa-pencil',
tooltip: '编辑',
actionType: 'drawer',
drawer: {
position: 'left',
size: 'lg',
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'select',
name: 'grade',
label: 'CSS grade',
options: ['A', 'B', 'C', 'D', 'X']
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
tooltip: '删除',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
toggled: true
}
]
}
}; };

View File

@ -1,104 +1,105 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "支持自动合并单元格,从左到右,可配置从左侧起多少列内启动自动合并单元格,当前配置 3", title:
body: { '支持自动合并单元格,从左到右,可配置从左侧起多少列内启动自动合并单元格,当前配置 3',
type: "table", body: {
data: { type: 'table',
items: [ data: {
{ items: [
"engine": "Trident", {
"browser": "Internet Explorer 4.2", engine: 'Trident',
"platform": "Win 95+", browser: 'Internet Explorer 4.2',
"version": "4", platform: 'Win 95+',
"grade": "A" version: '4',
}, grade: 'A'
{
"engine": "Trident",
"browser": "Internet Explorer 4.2",
"platform": "Win 95+",
"version": "4",
"grade": "B"
},
{
"engine": "Trident",
"browser": "AOL browser (AOL desktop)",
"platform": "Win 95+",
"version": "4",
"grade": "C"
},
{
"engine": "Trident",
"browser": "AOL browser (AOL desktop)",
"platform": "Win 98",
"version": "3",
"grade": "A"
},
{
"engine": "Trident",
"browser": "AOL browser (AOL desktop)",
"platform": "Win 98",
"version": "4",
"grade": "A"
},
{
"engine": "Gecko",
"browser": "Firefox 1.0",
"platform": "Win 98+ / OSX.2+",
"version": "4",
"grade": "A"
},
{
"engine": "Gecko",
"browser": "Firefox 1.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "A"
},
{
"engine": "Gecko",
"browser": "Firefox 2.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "B"
},
{
"engine": "Gecko",
"browser": "Firefox 2.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "C"
},
{
"engine": "Gecko",
"browser": "Firefox 2.0",
"platform": "Win 98+ / OSX.2+",
"version": "5",
"grade": "D"
}
]
}, },
combineNum: 3, // {
columns: [ engine: 'Trident',
{ browser: 'Internet Explorer 4.2',
name: "engine", platform: 'Win 95+',
label: "Rendering engine" version: '4',
}, grade: 'B'
{ },
name: "browser", {
label: "Browser" engine: 'Trident',
}, browser: 'AOL browser (AOL desktop)',
{ platform: 'Win 95+',
name: "platform", version: '4',
label: "Platform(s)" grade: 'C'
}, },
{ {
name: "version", engine: 'Trident',
label: "Engine version" browser: 'AOL browser (AOL desktop)',
}, platform: 'Win 98',
{ version: '3',
name: "grade", grade: 'A'
label: "CSS grade", },
} {
] engine: 'Trident',
} browser: 'AOL browser (AOL desktop)',
platform: 'Win 98',
version: '4',
grade: 'A'
},
{
engine: 'Gecko',
browser: 'Firefox 1.0',
platform: 'Win 98+ / OSX.2+',
version: '4',
grade: 'A'
},
{
engine: 'Gecko',
browser: 'Firefox 1.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'A'
},
{
engine: 'Gecko',
browser: 'Firefox 2.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'B'
},
{
engine: 'Gecko',
browser: 'Firefox 2.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'C'
},
{
engine: 'Gecko',
browser: 'Firefox 2.0',
platform: 'Win 98+ / OSX.2+',
version: '5',
grade: 'D'
}
]
},
combineNum: 3, //
columns: [
{
name: 'engine',
label: 'Rendering engine'
},
{
name: 'browser',
label: 'Browser'
},
{
name: 'platform',
label: 'Platform(s)'
},
{
name: 'version',
label: 'Engine version'
},
{
name: 'grade',
label: 'CSS grade'
}
]
}
}; };

View File

@ -1,197 +1,197 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "支持多层嵌套,列数据中有 children 字段即可。建议不超过10层", title: '支持多层嵌套,列数据中有 children 字段即可。建议不超过10层',
body: { body: {
type: "crud", type: 'crud',
api: "/api/mock2/crud/table2", api: '/api/mock2/crud/table2',
saveOrderApi: '/api/mock2/form/saveData', saveOrderApi: '/api/mock2/form/saveData',
expandConfig: { expandConfig: {
expand: 'first', expand: 'first',
accordion: true accordion: true
},
draggable: true,
columns: [
{
name: 'id',
label: 'ID',
sortable: true,
type: 'text',
toggled: true,
width: 100
},
{
name: 'engine',
label: 'Rendering engine',
sortable: true,
searchable: true,
type: 'text',
toggled: true
},
{
name: 'browser',
label: 'Browser',
sortable: true,
type: 'text',
toggled: true
},
{
name: 'platform',
label: 'Platform(s)',
sortable: true,
type: 'text',
toggled: true
},
{
name: 'version',
label: 'Engine version',
quickEdit: true,
type: 'text',
toggled: true
},
{
name: 'grade',
label: 'CSS grade',
quickEdit: {
mode: 'inline',
type: 'select',
options: ['A', 'B', 'C', 'D', 'X'],
inputClassName: 'w-xs',
saveImmediately: true
}, },
draggable: true, type: 'text',
columns: [ toggled: true
{ },
name: "id", {
label: "ID", type: 'operation',
sortable: true, label: '操作',
type: "text", width: 100,
toggled: true, buttons: [
width: 100 {
}, type: 'button',
{ icon: 'fa fa-eye',
name: "engine", actionType: 'dialog',
label: "Rendering engine", dialog: {
sortable: true, title: '查看',
searchable: true, body: {
type: "text", type: 'form',
toggled: true controls: [
}, {
{ type: 'static',
name: "browser", name: 'engine',
label: "Browser", label: 'Engine'
sortable: true, },
type: "text", {
toggled: true type: 'divider'
}, },
{ {
name: "platform", type: 'static',
label: "Platform(s)", name: 'browser',
sortable: true, label: 'Browser'
type: "text", },
toggled: true {
}, type: 'divider'
{ },
name: "version", {
label: "Engine version", type: 'static',
quickEdit: true, name: 'platform',
type: "text", label: 'Platform(s)'
toggled: true },
}, {
{ type: 'divider'
name: "grade", },
label: "CSS grade", {
quickEdit: { type: 'static',
mode: "inline", name: 'version',
type: "select", label: 'Engine version'
options: ["A", "B", "C", "D", "X"], },
inputClassName: 'w-xs', {
saveImmediately: true type: 'divider'
}, },
type: "text", {
toggled: true type: 'static',
}, name: 'grade',
{ label: 'CSS grade'
type: "operation", },
label: "操作", {
width: 100, type: 'divider'
buttons: [ },
{ {
type: "button", type: 'html',
icon: "fa fa-eye", html:
actionType: "dialog", '<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
dialog: { }
title: "查看", ]
body: { }
type: "form",
controls: [
{
type: "static",
name: "engine",
label: "Engine"
},
{
type: "divider"
},
{
type: "static",
name: "browser",
label: "Browser"
},
{
type: "divider"
},
{
type: "static",
name: "platform",
label: "Platform(s)"
},
{
type: "divider"
},
{
type: "static",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
},
{
type: "divider"
},
{
type: "html",
html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>"
}
]
}
}
},
{
type: "button",
icon: "fa fa-pencil",
actionType: "drawer",
drawer: {
position: 'left',
size: 'lg',
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "select",
name: "grade",
label: "CSS grade",
options: ["A", "B", "C", "D", "X"],
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
toggled: true
} }
] },
} {
type: 'button',
icon: 'fa fa-pencil',
actionType: 'drawer',
drawer: {
position: 'left',
size: 'lg',
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'select',
name: 'grade',
label: 'CSS grade',
options: ['A', 'B', 'C', 'D', 'X']
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
toggled: true
}
]
}
}; };

View File

@ -1,357 +1,365 @@
export default { export default {
$schema: "http://amis.baidu.com/v2/schemas/page.json#", $schema: 'http://amis.baidu.com/v2/schemas/page.json#',
title: "增删改查示例", title: '增删改查示例',
remark: "bla bla bla", remark: 'bla bla bla',
toolbar: [ toolbar: [
{ {
type: "button", type: 'button',
actionType: "dialog", actionType: 'dialog',
label: "新增", label: '新增',
icon: 'fa fa-plus pull-left', icon: 'fa fa-plus pull-left',
primary: true, primary: true,
dialog: { dialog: {
title: "新增", title: '新增',
body: { body: {
type: "form", type: 'form',
name: "sample-edit-form", name: 'sample-edit-form',
api: "post:/api/sample", api: 'post:/api/sample',
controls: [ controls: [
{ {
type: "text", type: 'text',
name: "engine", name: 'engine',
label: "Engine", label: 'Engine',
required: true required: true
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "text", type: 'text',
name: "browser", name: 'browser',
label: "Browser", label: 'Browser',
required: true required: true
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "text", type: 'text',
name: "platform", name: 'platform',
label: "Platform(s)", label: 'Platform(s)',
required: true required: true
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "text", type: 'text',
name: "version", name: 'version',
label: "Engine version" label: 'Engine version'
}, },
{ {
type: "divider" type: 'divider'
}, },
{ {
type: "text", type: 'text',
name: "grade", name: 'grade',
label: "CSS grade" label: 'CSS grade'
}
]
}
} }
]
} }
], }
body: {
type: "crud",
draggable: true,
api: "/api/sample?waitSeconds=1",
keepItemSelectionOnPageChange: true,
labelTpl: '${id} ${engine}',
filter: {
title: "条件搜索",
submitText: "",
controls: [
{
type: "text",
name: "keywords",
placeholder: "通过关键字搜索",
addOn: {
label: "搜索",
type: "submit"
}
},
{
type: "plain",
text: "这里的表单项可以配置多个"
}
]
},
bulkActions: [
{
label: "批量删除",
actionType: "ajax",
api: "delete:/api/sample/${ids|raw}",
confirmText: "确定要批量删除?"
},
{
label: "批量修改",
actionType: "dialog",
dialog: {
title: "批量编辑",
name: "sample-bulk-edit",
body: {
type: "form",
api: "/api/sample/bulkUpdate2",
controls: [
{
type: 'hidden',
name: 'ids'
},
{
type: "text",
name: "engine",
label: "Engine"
}
]
}
}
}
],
quickSaveApi: "/api/sample/bulkUpdate",
quickSaveItemApi: "/api/sample/$id",
filterTogglable: true,
headerToolbar: ['filter-toggler', 'bulkActions', {
type: 'tpl',
tpl: '定制内容示例:当前有 ${count} 条数据。',
className: 'v-middle'
}, {
type: 'link',
href: 'https://www.baidu.com',
body: '百度一下',
htmlTarget: '_parent',
className: 'v-middle'
}, {
type: 'columns-toggler',
align: 'right'
}, {
type: 'drag-toggler',
align: 'right'
}, {
type: 'pagination',
align: 'right'
}],
footerToolbar: ['statistics', 'switch-per-page', 'pagination'],
columns: [
{
name: "id",
label: "ID",
width: 20,
sortable: true,
type: "text",
toggled: true,
remark: 'Bla bla Bla'
},
{
name: "engine",
label: "Rendering engine",
sortable: true,
searchable: true,
type: "text",
toggled: true
},
{
name: "browser",
label: "Browser",
sortable: true,
type: "text",
toggled: false
},
{
name: "platform",
label: "Platform(s)",
popOver: {
body: {
type: "tpl",
tpl: "偏了一点的popover"
},
offset: {
y: 100
}
},
sortable: true,
type: "text",
toggled: true
},
{
name: "version",
label: "Engine version",
quickEdit: true,
type: "text",
toggled: true,
filterable:{
options:[
{
label:'4',
value:'4'
},
{
label:'5',
value:'5'
},
{
label:'6',
value:'6'
},
]
}
},
{
name: "grade",
label: "CSS grade",
quickEdit: {
mode: "inline",
type: "select",
inputClassName: 'w-xs',
options: ["A", "B", "C", "D", "X"],
saveImmediately: true
},
type: "text",
toggled: true
},
{
type: "operation",
label: "操作",
width: 100,
buttons: [
{
type: "button",
icon: "fa fa-eye",
actionType: "dialog",
tooltip: "查看",
dialog: {
title: "查看",
body: {
type: "form",
controls: [
{
type: "static",
name: "engine",
label: "Engine"
},
{
type: "divider"
},
{
type: "static",
name: "browser",
label: "Browser"
},
{
type: "divider"
},
{
type: "static",
name: "platform",
label: "Platform(s)"
},
{
type: "divider"
},
{
type: "static",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
},
{
type: "divider"
},
{
type: "html",
html:
"<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>"
}
]
}
}
},
{
type: "button",
icon: "fa fa-pencil",
tooltip: "编辑",
actionType: "drawer",
drawer: {
position: 'left',
size: 'lg',
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "select",
name: "grade",
label: "CSS grade",
options: ["A", "B", "C", "D", "X"],
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
tooltip: "删除",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
toggled: true
}
]
} }
],
body: {
type: 'crud',
draggable: true,
api: '/api/sample?waitSeconds=1',
keepItemSelectionOnPageChange: true,
labelTpl: '${id} ${engine}',
filter: {
title: '条件搜索',
submitText: '',
controls: [
{
type: 'text',
name: 'keywords',
placeholder: '通过关键字搜索',
addOn: {
label: '搜索',
type: 'submit'
}
},
{
type: 'plain',
text: '这里的表单项可以配置多个'
}
]
},
bulkActions: [
{
label: '批量删除',
actionType: 'ajax',
api: 'delete:/api/sample/${ids|raw}',
confirmText: '确定要批量删除?'
},
{
label: '批量修改',
actionType: 'dialog',
dialog: {
title: '批量编辑',
name: 'sample-bulk-edit',
body: {
type: 'form',
api: '/api/sample/bulkUpdate2',
controls: [
{
type: 'hidden',
name: 'ids'
},
{
type: 'text',
name: 'engine',
label: 'Engine'
}
]
}
}
}
],
quickSaveApi: '/api/sample/bulkUpdate',
quickSaveItemApi: '/api/sample/$id',
filterTogglable: true,
headerToolbar: [
'filter-toggler',
'bulkActions',
{
type: 'tpl',
tpl: '定制内容示例:当前有 ${count} 条数据。',
className: 'v-middle'
},
{
type: 'link',
href: 'https://www.baidu.com',
body: '百度一下',
htmlTarget: '_parent',
className: 'v-middle'
},
{
type: 'columns-toggler',
align: 'right'
},
{
type: 'drag-toggler',
align: 'right'
},
{
type: 'pagination',
align: 'right'
}
],
footerToolbar: ['statistics', 'switch-per-page', 'pagination'],
columns: [
{
name: 'id',
label: 'ID',
width: 20,
sortable: true,
type: 'text',
toggled: true,
remark: 'Bla bla Bla'
},
{
name: 'engine',
label: 'Rendering engine',
sortable: true,
searchable: true,
type: 'text',
toggled: true
},
{
name: 'browser',
label: 'Browser',
sortable: true,
type: 'text',
toggled: false
},
{
name: 'platform',
label: 'Platform(s)',
popOver: {
body: {
type: 'tpl',
tpl: '偏了一点的popover'
},
offset: {
y: 100
}
},
sortable: true,
type: 'text',
toggled: true
},
{
name: 'version',
label: 'Engine version',
quickEdit: true,
type: 'text',
toggled: true,
filterable: {
options: [
{
label: '4',
value: '4'
},
{
label: '5',
value: '5'
},
{
label: '6',
value: '6'
}
]
}
},
{
name: 'grade',
label: 'CSS grade',
quickEdit: {
mode: 'inline',
type: 'select',
inputClassName: 'w-xs',
options: ['A', 'B', 'C', 'D', 'X'],
saveImmediately: true
},
type: 'text',
toggled: true
},
{
type: 'operation',
label: '操作',
width: 100,
buttons: [
{
type: 'button',
icon: 'fa fa-eye',
actionType: 'dialog',
tooltip: '查看',
dialog: {
title: '查看',
body: {
type: 'form',
controls: [
{
type: 'static',
name: 'engine',
label: 'Engine'
},
{
type: 'divider'
},
{
type: 'static',
name: 'browser',
label: 'Browser'
},
{
type: 'divider'
},
{
type: 'static',
name: 'platform',
label: 'Platform(s)'
},
{
type: 'divider'
},
{
type: 'static',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'static',
name: 'grade',
label: 'CSS grade'
},
{
type: 'divider'
},
{
type: 'html',
html:
'<p>添加其他 <span>Html 片段</span> 需要支持变量替换todo.</p>'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-pencil',
tooltip: '编辑',
actionType: 'drawer',
drawer: {
position: 'left',
size: 'lg',
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'select',
name: 'grade',
label: 'CSS grade',
options: ['A', 'B', 'C', 'D', 'X']
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
tooltip: '删除',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
toggled: true
}
]
}
}; };

View File

@ -1,92 +1,92 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "Test 信息:${page}", title: 'Test 信息:${page}',
body: { body: {
"type": "crud", type: 'crud',
"api": "/api/sample", api: '/api/sample',
"syncLocation": false, syncLocation: false,
"title": null, title: null,
"columns": [ columns: [
{ {
"name": "id", name: 'id',
"label": "ID", label: 'ID',
"width": 20 width: 20
}, },
{ {
"name": "engine", name: 'engine',
"label": "Rendering engine", label: 'Rendering engine',
"sortable": true sortable: true
}, },
{ {
"name": "grade", name: 'grade',
"type": "map", type: 'map',
"label": "Rendering engine", label: 'Rendering engine',
"map": { map: {
"A": "<span class='label label-info'>A</span>", A: "<span class='label label-info'>A</span>",
"B": "<span class='label label-success'>B</span>", B: "<span class='label label-success'>B</span>",
"C": "<span class='label label-primary'>C</span>", C: "<span class='label label-primary'>C</span>",
"X": "<span class='label label-danger'>X</span>", X: "<span class='label label-danger'>X</span>",
"*": "Unkown" '*': 'Unkown'
}
},
{
type: 'operation',
label: '操作',
width: 200,
buttons: [
{
type: 'button-group',
buttons: [
{
type: 'button',
label: '查看',
actionType: 'dialog',
dialog: {
disabled: true,
body: {
type: 'form',
controls: [
{
name: 'engine',
label: 'Rendering engine',
type: 'static'
}
]
}
} }
}, },
{
"type": "operation",
"label": "操作",
"width": 200,
"buttons": [
{
"type": "button-group",
"buttons": [
{
"type": "button",
"label": "查看",
"actionType": "dialog",
"dialog": {
"disabled": true,
"body": {
"type": "form",
"controls": [
{
"name": "engine",
"label": "Rendering engine",
"type": "static"
}
]
}
}
},
{ {
"type": "button", type: 'button',
"label": "编辑", label: '编辑',
"actionType": "dialog", actionType: 'dialog',
"dialog": { dialog: {
"body": { body: {
"api": "/api/sample/$id", api: '/api/sample/$id',
"type": "form", type: 'form',
"controls": [ controls: [
{ {
"name": "engine", name: 'engine',
"label": "Rendering engine", label: 'Rendering engine',
"type": "text" type: 'text'
} }
] ]
} }
} }
}, },
{ {
"type": "button", type: 'button',
"label": "删除", label: '删除',
"level": "danger", level: 'danger',
"actionType": "ajax", actionType: 'ajax',
"confirmText": "确定?", confirmText: '确定?',
"api": "delete:/api/sample/$id" api: 'delete:/api/sample/$id'
} }
] ]
} }
]
}
] ]
} }
]
}
}; };

View File

@ -1,83 +1,89 @@
export default { export default {
type: 'page', type: 'page',
title: '轮播图', title: '轮播图',
data: { data: {
carousel0: [ carousel0: [
'https://hiphotos.baidu.com/fex/%70%69%63/item/bd3eb13533fa828b13b24500f31f4134960a5a44.jpg', 'https://hiphotos.baidu.com/fex/%70%69%63/item/bd3eb13533fa828b13b24500f31f4134960a5a44.jpg',
'https://video-react.js.org/assets/poster.png', 'https://video-react.js.org/assets/poster.png',
'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg' 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg'
], ],
carousel1: [ carousel1: [
{ {
html: '<div style="width: 100%; height: 300px; background: #e3e3e3; text-align: center; line-height: 300px;">carousel data in form</div>' html:
}, '<div style="width: 100%; height: 300px; background: #e3e3e3; text-align: center; line-height: 300px;">carousel data in form</div>'
{ },
image: 'https://hiphotos.baidu.com/fex/%70%69%63/item/bd3eb13533fa828b13b24500f31f4134960a5a44.jpg' {
}, image:
{ 'https://hiphotos.baidu.com/fex/%70%69%63/item/bd3eb13533fa828b13b24500f31f4134960a5a44.jpg'
image: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg' },
} {
] image:
}, 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg'
body: [ }
]
},
body: [
{
type: 'grid',
columns: [
{ {
type: 'grid', type: 'panel',
columns: [ title: '直接页面配置',
{ body: {
type: 'panel', type: 'carousel',
title: '直接页面配置', controlsTheme: 'light',
body: { height: '300',
type: 'carousel', options: [
controlsTheme: 'light', {
height: '300', image: 'https://video-react.js.org/assets/poster.png'
options: [ },
{ {
image: 'https://video-react.js.org/assets/poster.png' html:
}, '<div style="width: 100%; height: 300px; background: #e3e3e3; text-align: center; line-height: 300px;">carousel data</div>'
{ },
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'
image: 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg' }
}
]
}
},
{
type: 'panel',
title: '使用itemSchema配置',
body: {
type: 'carousel',
name: 'carousel0',
controlsTheme: 'dark',
height: '300',
itemSchema: {
type: 'tpl',
tpl: '<div style="height: 100%; background-image: url(<%=data.item%>); background-position: center center; background-size: cover;"></div>'
}
}
}
] ]
}
}, },
{ {
type: 'grid', type: 'panel',
columns: [ title: '使用itemSchema配置',
{ body: {
type: 'form', type: 'carousel',
title: '表单内展示', name: 'carousel0',
sm: 6, controlsTheme: 'dark',
controls: [ height: '300',
{ itemSchema: {
type: 'carousel', type: 'tpl',
controlsTheme: 'dark', tpl:
name: 'carousel1', '<div style="height: 100%; background-image: url(<%=data.item%>); background-position: center center; background-size: cover;"></div>'
label: 'carousel', }
animation: 'slide', }
height: '300'
}
]
}
]
} }
] ]
} },
{
type: 'grid',
columns: [
{
type: 'form',
title: '表单内展示',
sm: 6,
controls: [
{
type: 'carousel',
controlsTheme: 'dark',
name: 'carousel1',
label: 'carousel',
animation: 'slide',
height: '300'
}
]
}
]
}
]
};

View File

@ -1,197 +1,160 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "图表示例", title: '图表示例',
"body": [ body: [
{
type: 'grid',
columns: [
{ {
"type": "grid", type: 'panel',
"columns": [ title: '本地配置示例 支持交互',
{ name: 'chart-local',
"type": "panel", body: [
"title": "本地配置示例 支持交互", {
"name": "chart-local", type: 'chart',
"body": [ config: {
{ title: {
"type": "chart", text: '极坐标双数值轴'
"config": {
"title": {
"text": "极坐标双数值轴"
},
"legend": {
"data": [
"line"
]
},
"polar": {
"center": [
"50%",
"54%"
]
},
"tooltip": {
"trigger": "axis",
"axisPointer": {
"type": "cross"
}
},
"angleAxis": {
"type": "value",
"startAngle": 0
},
"radiusAxis": {
"min": 0
},
"series": [
{
"coordinateSystem": "polar",
"name": "line",
"type": "line",
"showSymbol": false,
"data": [
[
0,
0
],
[
0.03487823687206265,
1
],
[
0.06958655048003272,
2
],
[
0.10395584540887964,
3
],
[
0.13781867790849958,
4
],
[
0.17101007166283433,
5
],
[
0.2033683215379001,
6
],
[
0.2347357813929454,
7
],
[
0.26495963211660245,
8
],
[
0.2938926261462365,
9
],
[
0.3213938048432697,
10
]
]
}
],
"animationDuration": 2000
},
clickAction: {
actionType: 'dialog',
dialog: {
title: '详情',
body: [
{
type: 'tpl',
tpl: '<span>当前选中值 ${value|json}<span>'
},
{
"type": "chart",
"api": "/api/mock2/chart/chart1"
}
]
}
}
}
]
}, },
{ legend: {
"type": "panel", data: ['line']
"title": "远程图表示例(返回值带function)", },
"name": "chart-remote", polar: {
"body": [ center: ['50%', '54%']
{ },
"type": "chart", tooltip: {
"api": "/api/mock2/chart/chart1" trigger: 'axis',
} axisPointer: {
] type: 'cross'
} }
] },
}, angleAxis: {
{ type: 'value',
"type": "panel", startAngle: 0
"title": "Form+chart组合", },
"body": [ radiusAxis: {
{ min: 0
"type": "form", },
"title": "过滤条件", series: [
"target": "chart1,chart2",
"submitOnInit":true,
"className": "m-b",
"wrapWithPanel": false,
"mode": "inline",
"controls": [
{
"type": "date",
"label": "开始日期",
"name": "starttime",
"value": "-8days",
"maxDate": "${endtime}"
},
{
"type": "date",
"label": "结束日期",
"name": "endtime",
"value": "-1days",
"minDate": "${starttime}"
},
{ {
"type": "text", coordinateSystem: 'polar',
"label": "条件", name: 'line',
"name": "name", type: 'line',
"addOn": { showSymbol: false,
"type": "submit", data: [
"label": "搜索", [0, 0],
"level": "primary" [0.03487823687206265, 1],
} [0.06958655048003272, 2],
[0.10395584540887964, 3],
[0.13781867790849958, 4],
[0.17101007166283433, 5],
[0.2033683215379001, 6],
[0.2347357813929454, 7],
[0.26495963211660245, 8],
[0.2938926261462365, 9],
[0.3213938048432697, 10]
]
} }
], ],
"actions": [] animationDuration: 2000
}, },
{ clickAction: {
type: 'divider' actionType: 'dialog',
}, dialog: {
{ title: '详情',
"type": "grid", body: [
"className": "m-t-lg", {
"columns": [ type: 'tpl',
{ tpl: '<span>当前选中值 ${value|json}<span>'
"type": "chart", },
"name": "chart1",
"initFetch": false, {
"api": "/api/mock2/chart/chart?name=$name&starttime=${starttime}&endtime=${endtime}" type: 'chart',
}, api: '/api/mock2/chart/chart1'
{ }
"type": "chart", ]
"name": "chart2", }
"initFetch": false,
"api": "/api/mock2/chart/chart2?name=$name"
}
]
} }
] }
} ]
] },
} {
type: 'panel',
title: '远程图表示例(返回值带function)',
name: 'chart-remote',
body: [
{
type: 'chart',
api: '/api/mock2/chart/chart1'
}
]
}
]
},
{
type: 'panel',
title: 'Form+chart组合',
body: [
{
type: 'form',
title: '过滤条件',
target: 'chart1,chart2',
submitOnInit: true,
className: 'm-b',
wrapWithPanel: false,
mode: 'inline',
controls: [
{
type: 'date',
label: '开始日期',
name: 'starttime',
value: '-8days',
maxDate: '${endtime}'
},
{
type: 'date',
label: '结束日期',
name: 'endtime',
value: '-1days',
minDate: '${starttime}'
},
{
type: 'text',
label: '条件',
name: 'name',
addOn: {
type: 'submit',
label: '搜索',
level: 'primary'
}
}
],
actions: []
},
{
type: 'divider'
},
{
type: 'grid',
className: 'm-t-lg',
columns: [
{
type: 'chart',
name: 'chart1',
initFetch: false,
api:
'/api/mock2/chart/chart?name=$name&starttime=${starttime}&endtime=${endtime}'
},
{
type: 'chart',
name: 'chart2',
initFetch: false,
api: '/api/mock2/chart/chart2?name=$name'
}
]
}
]
}
]
};

View File

@ -1,413 +1,413 @@
export default { export default {
type: 'page', type: 'page',
title: 'Drawer', title: 'Drawer',
body: [ body: [
{
type: 'button-toolbar',
className: 'block',
buttons: [
{ {
type: 'button-toolbar', type: 'button',
className: "block", label: '左侧弹出-极小框',
buttons: [ actionType: 'drawer',
{ drawer: {
type: 'button', position: 'left',
label: '左侧弹出-极小框', size: 'xs',
actionType: 'drawer', title: '提示',
drawer: { body: '这是个简单的弹框'
position: 'left', }
size: 'xs',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '左侧弹出-小框',
actionType: 'drawer',
drawer: {
position: 'left',
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '左侧弹出-中框',
actionType: 'drawer',
drawer: {
position: 'left',
size: 'md',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '左侧弹出-大框',
actionType: 'drawer',
drawer: {
position: 'left',
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '左侧弹出-超大',
actionType: 'drawer',
level: 'danger',
drawer: {
position: 'left',
size: 'xl',
title: '提示',
body: '这是个简单的弹框'
}
},
]
}, },
{ {
type: 'button-toolbar', type: 'button',
className: 'block m-t', label: '左侧弹出-小框',
buttons: [ actionType: 'drawer',
{ drawer: {
type: 'button', position: 'left',
label: '右侧弹出-极小框', size: 'sm',
level: 'success', title: '提示',
actionType: 'drawer', body: '这是个简单的弹框'
drawer: { }
position: 'right',
size: 'xs',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-小框',
level: 'success',
actionType: 'drawer',
drawer: {
position: 'right',
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-中框',
level: 'success',
actionType: 'drawer',
drawer: {
position: 'right',
size: 'md',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-大框',
level: 'success',
actionType: 'drawer',
drawer: {
position: 'right',
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-超大',
level: 'danger',
actionType: 'drawer',
drawer: {
size: 'xl',
position: 'right',
title: '提示',
body: '这是个简单的弹框'
}
}
]
}, },
{ {
type: 'button-toolbar', type: 'button',
className: 'block m-t', label: '左侧弹出-中框',
buttons: [ actionType: 'drawer',
{ drawer: {
type: 'button', position: 'left',
label: '顶部弹出-极小框', size: 'md',
actionType: 'drawer', title: '提示',
level: 'info', body: '这是个简单的弹框'
drawer: { }
position: 'top',
size: 'xs',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出-小框',
level: 'info',
actionType: 'drawer',
drawer: {
position: 'top',
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出-中框',
actionType: 'drawer',
level: 'info',
drawer: {
position: 'top',
size: 'md',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出-大框',
actionType: 'drawer',
level: 'info',
drawer: {
position: 'top',
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出 - 超大',
level: 'danger',
actionType: 'drawer',
drawer: {
position: 'top',
size: 'xl',
title: '提示',
body: '这是个简单的弹框'
}
}
]
}, },
{ {
type: 'button-toolbar', type: 'button',
className: 'block m-t', label: '左侧弹出-大框',
buttons: [ actionType: 'drawer',
{ drawer: {
type: 'button', position: 'left',
label: '底部弹出-极小框', size: 'lg',
actionType: 'drawer', title: '提示',
level: 'primary', body: '这是个简单的弹框'
drawer: { }
position: 'bottom',
size: 'xs',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-小框',
level: 'primary',
actionType: 'drawer',
drawer: {
position: 'bottom',
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-中框',
actionType: 'drawer',
level: 'primary',
drawer: {
position: 'bottom',
size: 'md',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-大框',
actionType: 'drawer',
level: 'primary',
drawer: {
position: 'bottom',
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-超大',
level: 'danger',
actionType: 'drawer',
drawer: {
position: 'bottom',
size: 'xl',
title: '提示',
body: '这是个简单的弹框'
}
}
]
}, },
{ {
type: 'button-toolbar', type: 'button',
className: 'block m-t', label: '左侧弹出-超大',
buttons: [ actionType: 'drawer',
{ level: 'danger',
type: 'button', drawer: {
label: '多级弹框', position: 'left',
actionType: 'drawer', size: 'xl',
level: 'danger', title: '提示',
drawer: { body: '这是个简单的弹框'
title: '提示', }
body: '这是个简单的弹框',
closeOnEsc: true,
actions: [
{
type: 'button',
actionType: 'confirm',
label: '确认',
primary: true
},
{
type: 'button',
actionType: 'drawer',
label: '再弹一个',
drawer: {
position: 'left',
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'drawer',
label: '来吧',
level: 'info',
drawer: {
position: 'right',
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'confirm',
label: '可以了',
primary: true
}
]
}
}
]
}
}
]
}
},
{
type: 'button',
label: '交叉测试',
actionType: 'drawer',
className: 'm-l-xs',
level: 'danger',
drawer: {
title: '提示',
closeOnEsc: true,
body: '这是个简单的弹框',
actions: [
{
type: 'button',
actionType: 'confirm',
label: '确认',
primary: true
},
{
type: 'button',
actionType: 'dialog',
closeOnEsc: true,
label: '再弹一个',
dialog: {
position: 'left',
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'drawer',
label: '来吧',
level: 'info',
drawer: {
position: 'right',
title: '弹框中的弹框',
body: '如果你想,可以无限弹下去',
closeOnEsc: true,
actions: [
{
type: 'button',
actionType: 'confirm',
label: '可以了',
primary: true
}
]
}
}
]
}
}
]
}
},
{
type: 'button',
label: '可拉拽调整大小',
actionType: 'drawer',
level: 'danger',
drawer: {
title: '提示',
closeOnEsc: true,
resizable: true,
body: '这是个简单的弹框',
}
},
]
} }
], ]
} },
{
type: 'button-toolbar',
className: 'block m-t',
buttons: [
{
type: 'button',
label: '右侧弹出-极小框',
level: 'success',
actionType: 'drawer',
drawer: {
position: 'right',
size: 'xs',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-小框',
level: 'success',
actionType: 'drawer',
drawer: {
position: 'right',
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-中框',
level: 'success',
actionType: 'drawer',
drawer: {
position: 'right',
size: 'md',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-大框',
level: 'success',
actionType: 'drawer',
drawer: {
position: 'right',
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '右侧弹出-超大',
level: 'danger',
actionType: 'drawer',
drawer: {
size: 'xl',
position: 'right',
title: '提示',
body: '这是个简单的弹框'
}
}
]
},
{
type: 'button-toolbar',
className: 'block m-t',
buttons: [
{
type: 'button',
label: '顶部弹出-极小框',
actionType: 'drawer',
level: 'info',
drawer: {
position: 'top',
size: 'xs',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出-小框',
level: 'info',
actionType: 'drawer',
drawer: {
position: 'top',
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出-中框',
actionType: 'drawer',
level: 'info',
drawer: {
position: 'top',
size: 'md',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出-大框',
actionType: 'drawer',
level: 'info',
drawer: {
position: 'top',
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '顶部弹出 - 超大',
level: 'danger',
actionType: 'drawer',
drawer: {
position: 'top',
size: 'xl',
title: '提示',
body: '这是个简单的弹框'
}
}
]
},
{
type: 'button-toolbar',
className: 'block m-t',
buttons: [
{
type: 'button',
label: '底部弹出-极小框',
actionType: 'drawer',
level: 'primary',
drawer: {
position: 'bottom',
size: 'xs',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-小框',
level: 'primary',
actionType: 'drawer',
drawer: {
position: 'bottom',
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-中框',
actionType: 'drawer',
level: 'primary',
drawer: {
position: 'bottom',
size: 'md',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-大框',
actionType: 'drawer',
level: 'primary',
drawer: {
position: 'bottom',
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '底部弹出-超大',
level: 'danger',
actionType: 'drawer',
drawer: {
position: 'bottom',
size: 'xl',
title: '提示',
body: '这是个简单的弹框'
}
}
]
},
{
type: 'button-toolbar',
className: 'block m-t',
buttons: [
{
type: 'button',
label: '多级弹框',
actionType: 'drawer',
level: 'danger',
drawer: {
title: '提示',
body: '这是个简单的弹框',
closeOnEsc: true,
actions: [
{
type: 'button',
actionType: 'confirm',
label: '确认',
primary: true
},
{
type: 'button',
actionType: 'drawer',
label: '再弹一个',
drawer: {
position: 'left',
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'drawer',
label: '来吧',
level: 'info',
drawer: {
position: 'right',
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'confirm',
label: '可以了',
primary: true
}
]
}
}
]
}
}
]
}
},
{
type: 'button',
label: '交叉测试',
actionType: 'drawer',
className: 'm-l-xs',
level: 'danger',
drawer: {
title: '提示',
closeOnEsc: true,
body: '这是个简单的弹框',
actions: [
{
type: 'button',
actionType: 'confirm',
label: '确认',
primary: true
},
{
type: 'button',
actionType: 'dialog',
closeOnEsc: true,
label: '再弹一个',
dialog: {
position: 'left',
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'drawer',
label: '来吧',
level: 'info',
drawer: {
position: 'right',
title: '弹框中的弹框',
body: '如果你想,可以无限弹下去',
closeOnEsc: true,
actions: [
{
type: 'button',
actionType: 'confirm',
label: '可以了',
primary: true
}
]
}
}
]
}
}
]
}
},
{
type: 'button',
label: '可拉拽调整大小',
actionType: 'drawer',
level: 'danger',
drawer: {
title: '提示',
closeOnEsc: true,
resizable: true,
body: '这是个简单的弹框'
}
}
]
}
]
};

View File

@ -1,266 +1,266 @@
export default { export default {
type: 'page', type: 'page',
title: 'Dialog', title: 'Dialog',
body: [ body: [
{
type: 'button-toolbar',
className: 'm-b',
buttons: [
{ {
type: 'button-toolbar', type: 'button',
className: 'm-b', label: '打开弹框',
buttons: [ actionType: 'dialog',
{ dialog: {
type: 'button', title: '提示',
label: '打开弹框', closeOnEsc: true,
actionType: 'dialog', body: '这是个简单的弹框'
dialog: { }
title: '提示',
closeOnEsc: true,
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '多级弹框',
actionType: 'dialog',
dialog: {
title: '提示',
closeOnEsc: true,
body: '这是个简单的弹框',
actions: [
{
type: 'button',
actionType: 'confirm',
label: '确认',
primary: true
},
{
type: 'button',
actionType: 'dialog',
label: '再弹一个',
dialog: {
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'dialog',
label: '来吧',
level: 'info',
dialog: {
title: '弹框中的弹框',
closeOnEsc: true,
body: '如果你想,可以无限弹下去',
actions: [
{
type: 'button',
actionType: 'confirm',
label: '不弹了',
primary: true
}
]
}
}
]
}
}
]
}
},
{
type: 'button',
label: '弹个表单',
actionType: 'dialog',
dialog: {
title: '在弹框中的表单',
closeOnEsc: true,
actions: [
{
label: '取消',
actionType: 'close',
type: 'button'
},
{
label: '确认',
actionType: 'confirm',
type: 'button',
level: 'primary'
},
{
label: '提交不关闭',
actionType: 'submit',
close: false,
type: 'button',
api: '/api/mock2/form/saveForm?waitSeconds=2',
level: 'primary'
},
{
label: '保存不关闭',
actionType: 'ajax',
type: 'button',
api: '/api/mock2/form/saveForm?waitSeconds=4',
level: 'info'
},
{
type: 'button',
label: 'Feedback',
close: true,
actionType: 'ajax',
api: '/api/mock2/form/initData?waitSeconds=2',
tooltip: '点击我后会发送一个请求,请求回来后,弹出一个框。',
feedback: {
title: '操作成功',
body: 'xxx 已操作成功'
}
}
],
body: {
type: "form",
api: "/api/mock2/form/saveForm?waitSeconds=2",
title: "常规模式",
mode: "normal",
controls: [
{
type: "email",
name: "email",
required: true,
placeholder: "请输入邮箱",
label: "邮箱"
},
{
type: "password",
name: "password",
label: "密码",
required: true,
placeholder: "请输入密码"
},
{
type: "checkbox",
name: "rememberMe",
label: "记住登录"
}
]
}
}
},
{
type: 'button',
label: '再弹个表单',
actionType: 'dialog',
dialog: {
title: '在弹框中的表单',
actions: [
{
label: '取消',
actionType: 'close',
type: 'button'
},
{
label: '确认',
actionType: 'confirm',
type: 'button',
level: 'primary',
disabledOn: '!data.rememberMe'
}
],
body: {
type: "form",
api: "/api/mock2/form/saveForm?waitSeconds=2",
title: "常规模式",
mode: "normal",
controls: [
{
type: "checkbox",
name: "rememberMe",
label: "勾上我才可以确认"
}
]
}
}
},
{
type: 'button',
label: 'Feedback',
actionType: 'ajax',
api: '/api/mock2/form/initData?waitSeconds=2',
tooltip: '点击我后会发送一个请求,请求回来后,弹出一个框。',
feedback: {
title: '操作成功',
closeOnEsc: true,
body: 'xxx 已操作成功'
}
},
{
type: 'button',
label: 'Feedback2',
actionType: 'ajax',
api: '/api/mock2/form/initData?waitSeconds=2',
tooltip: '可以根据条件弹出比如这个栗子看当前时间戳是否可以整除3',
feedback: {
visibleOn: '!(this.date % 3)',
title: '操作成功',
body: '当前时间戳: <code>${date}</code>'
}
},
]
}, },
{ {
type: "button-toolbar", type: 'button',
className: 'm-l-none', label: '多级弹框',
buttons: [ actionType: 'dialog',
{ dialog: {
type: 'button', title: '提示',
label: 'sm 弹框', closeOnEsc: true,
actionType: 'dialog', body: '这是个简单的弹框',
dialog: { actions: [
size: "sm", {
title: '提示', type: 'button',
body: '这是个简单的弹框' actionType: 'confirm',
} label: '确认',
}, primary: true
},
{ {
type: 'button', type: 'button',
label: '标准 弹框', actionType: 'dialog',
actionType: 'dialog', label: '再弹一个',
dialog: { dialog: {
title: '提示', title: '弹框中的弹框',
body: '这是个简单的弹框' closeOnEsc: true,
} body: '如果你想,可以无限弹下去',
}, actions: [
{
{ type: 'button',
type: 'button', actionType: 'dialog',
label: 'lg 弹框', label: '来吧',
actionType: 'dialog', level: 'info',
dialog: { dialog: {
size: "lg", title: '弹框中的弹框',
title: '提示', closeOnEsc: true,
body: '这是个简单的弹框' body: '如果你想,可以无限弹下去',
} actions: [
}, {
type: 'button',
{ actionType: 'confirm',
type: 'button', label: '不弹了',
label: 'xl 弹框', primary: true
actionType: 'dialog', }
dialog: { ]
size: "xl", }
title: '提示',
body: '这是个简单的弹框'
} }
]
} }
}
] ]
}
},
{
type: 'button',
label: '弹个表单',
actionType: 'dialog',
dialog: {
title: '在弹框中的表单',
closeOnEsc: true,
actions: [
{
label: '取消',
actionType: 'close',
type: 'button'
},
{
label: '确认',
actionType: 'confirm',
type: 'button',
level: 'primary'
},
{
label: '提交不关闭',
actionType: 'submit',
close: false,
type: 'button',
api: '/api/mock2/form/saveForm?waitSeconds=2',
level: 'primary'
},
{
label: '保存不关闭',
actionType: 'ajax',
type: 'button',
api: '/api/mock2/form/saveForm?waitSeconds=4',
level: 'info'
},
{
type: 'button',
label: 'Feedback',
close: true,
actionType: 'ajax',
api: '/api/mock2/form/initData?waitSeconds=2',
tooltip: '点击我后会发送一个请求,请求回来后,弹出一个框。',
feedback: {
title: '操作成功',
body: 'xxx 已操作成功'
}
}
],
body: {
type: 'form',
api: '/api/mock2/form/saveForm?waitSeconds=2',
title: '常规模式',
mode: 'normal',
controls: [
{
type: 'email',
name: 'email',
required: true,
placeholder: '请输入邮箱',
label: '邮箱'
},
{
type: 'password',
name: 'password',
label: '密码',
required: true,
placeholder: '请输入密码'
},
{
type: 'checkbox',
name: 'rememberMe',
label: '记住登录'
}
]
}
}
},
{
type: 'button',
label: '再弹个表单',
actionType: 'dialog',
dialog: {
title: '在弹框中的表单',
actions: [
{
label: '取消',
actionType: 'close',
type: 'button'
},
{
label: '确认',
actionType: 'confirm',
type: 'button',
level: 'primary',
disabledOn: '!data.rememberMe'
}
],
body: {
type: 'form',
api: '/api/mock2/form/saveForm?waitSeconds=2',
title: '常规模式',
mode: 'normal',
controls: [
{
type: 'checkbox',
name: 'rememberMe',
label: '勾上我才可以确认'
}
]
}
}
},
{
type: 'button',
label: 'Feedback',
actionType: 'ajax',
api: '/api/mock2/form/initData?waitSeconds=2',
tooltip: '点击我后会发送一个请求,请求回来后,弹出一个框。',
feedback: {
title: '操作成功',
closeOnEsc: true,
body: 'xxx 已操作成功'
}
},
{
type: 'button',
label: 'Feedback2',
actionType: 'ajax',
api: '/api/mock2/form/initData?waitSeconds=2',
tooltip: '可以根据条件弹出比如这个栗子看当前时间戳是否可以整除3',
feedback: {
visibleOn: '!(this.date % 3)',
title: '操作成功',
body: '当前时间戳: <code>${date}</code>'
}
} }
], ]
} },
{
type: 'button-toolbar',
className: 'm-l-none',
buttons: [
{
type: 'button',
label: 'sm 弹框',
actionType: 'dialog',
dialog: {
size: 'sm',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: '标准 弹框',
actionType: 'dialog',
dialog: {
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: 'lg 弹框',
actionType: 'dialog',
dialog: {
size: 'lg',
title: '提示',
body: '这是个简单的弹框'
}
},
{
type: 'button',
label: 'xl 弹框',
actionType: 'dialog',
dialog: {
size: 'xl',
title: '提示',
body: '这是个简单的弹框'
}
}
]
}
]
};

File diff suppressed because it is too large Load Diff

View File

@ -2,46 +2,46 @@ import React from 'react';
import makeSchemaRenderer from './SchemaRender'; import makeSchemaRenderer from './SchemaRender';
const FormComponent = makeSchemaRenderer({ const FormComponent = makeSchemaRenderer({
type: 'form', type: 'form',
mode: 'inline', mode: 'inline',
wrapWithPanel: false, wrapWithPanel: false,
className: 'pull-right m-t-sm m-r', className: 'pull-right m-t-sm m-r',
controls: [{ controls: [
"type": "input-group", {
"size": "sm", type: 'input-group',
"controls": [ size: 'sm',
{ controls: [
"type": "icon", {
"addOnclassName": "no-bg", type: 'icon',
"className": "text-sm", addOnclassName: 'no-bg',
"icon": "search", className: 'text-sm',
"vendor": "iconfont" icon: 'search',
}, vendor: 'iconfont'
{ },
"type": "text", {
"placeholder": "搜索文档", type: 'text',
"inputClassName": "b-l-none p-l-none", placeholder: '搜索文档',
"name": "docsearch" inputClassName: 'b-l-none p-l-none',
} name: 'docsearch'
] }
}] ]
}) }
]
});
export default class DocSearch extends React.Component { export default class DocSearch extends React.Component {
componentDidMount() { componentDidMount() {
const inputSelector = 'input[name="docsearch"]'; const inputSelector = 'input[name="docsearch"]';
docsearch({ docsearch({
appId: '3W0NHYOWPE', appId: '3W0NHYOWPE',
apiKey: '469f5cf3d54f9b86127970f913dc0725', apiKey: '469f5cf3d54f9b86127970f913dc0725',
indexName: 'gh_pages', indexName: 'gh_pages',
inputSelector, inputSelector,
debug: false, debug: false
}); });
} }
render() { render() {
return ( return <FormComponent showCode={false} theme={this.props.theme} />;
<FormComponent showCode={false} theme={this.props.theme} /> }
); }
}
}

View File

@ -3,49 +3,62 @@ import Editor from '../../src/editor/Editor';
import Switch from '../../src/components/Switch'; import Switch from '../../src/components/Switch';
import Button from '../../src/components/Button'; import Button from '../../src/components/Button';
import schema from './Form/Test'; import schema from './Form/Test';
import { Portal } from 'react-overlays'; import {Portal} from 'react-overlays';
export default class AMisSchemaEditor extends React.Component { export default class AMisSchemaEditor extends React.Component {
state = {
preview: localStorage.getItem('editting_preview') ? true : false,
schema: localStorage.getItem('editting_schema')
? JSON.parse(localStorage.getItem('editting_schema'))
: schema
};
state = { handleChange = value => {
preview: localStorage.getItem('editting_preview') ? true : false, localStorage.setItem('editting_schema', JSON.stringify(value));
schema: localStorage.getItem('editting_schema') ? JSON.parse(localStorage.getItem('editting_schema')) : schema
};
handleChange = (value) => { this.setState({
localStorage.setItem('editting_schema', JSON.stringify(value)); schema: value
});
};
handlePreviewChange = preview => {
localStorage.setItem('editting_preview', preview ? 'true' : '');
this.setState({ this.setState({
schema: value preview: !!preview
}); });
} };
handlePreviewChange = (preview) => { clearCache = () => {
localStorage.setItem('editting_preview', preview ? 'true' : ''); localStorage.removeItem('editting_schema');
this.setState({
schema: schema
});
};
this.setState({ render() {
preview: !!preview return (
}); <div className="h-full">
} <Portal container={() => document.querySelector('#headerBar')}>
clearCache = () => { <div className="inline m-l">
localStorage.removeItem('editting_schema'); 预览{' '}
this.setState({ <Switch
schema: schema value={this.state.preview}
}); onChange={this.handlePreviewChange}
} className="v-middle"
inline
/>
<Button size="sm" className="m-l" onClick={this.clearCache}>
清除缓存
</Button>
</div>
</Portal>
render() { <Editor
return ( preview={this.state.preview}
<div className="h-full"> value={this.state.schema}
<Portal container={() => document.querySelector('#headerBar')}> onChange={this.handleChange}
<div className="inline m-l" > className="fix-settings"
预览 <Switch value={this.state.preview} onChange={this.handlePreviewChange} className="v-middle" inline /> />
<Button size="sm" className="m-l" onClick={this.clearCache}>清除缓存</Button> </div>
</div> );
</Portal> }
}
<Editor preview={this.state.preview} value={this.state.schema} onChange={this.handleChange} className="fix-settings" />
</div>
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,95 +1,99 @@
import React from 'react'; import React from 'react';
import { import {FormItem, Renderer} from '../../../src/index';
FormItem,
Renderer
} from '../../../src/index';
@FormItem({ @FormItem({
type: 'custom' type: 'custom'
}) })
class MyFormItem extends React.Component { class MyFormItem extends React.Component {
render() { render() {
const { const {value, onChange} = this.props;
value,
onChange
} = this.props;
return ( return (
<div> <div>
<p>这个是个自定义组件通过注册渲染器的方式实现</p> <p>这个是个自定义组件通过注册渲染器的方式实现</p>
<p>当前值{value}</p> <p>当前值{value}</p>
<a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a> <a
</div> className="btn btn-default"
); onClick={() => onChange(Math.round(Math.random() * 10000))}
} >
随机修改
</a>
</div>
);
}
} }
@Renderer({ @Renderer({
test: /(^|\/)my\-renderer$/, test: /(^|\/)my\-renderer$/
}) })
class CustomRenderer extends React.Component { class CustomRenderer extends React.Component {
render() { render() {
const {tip} = this.props; const {tip} = this.props;
return ( return (
<div>{tip || '非 FormItem 类型的渲染器注册, 这种不能修改 form'}</div> <div>{tip || '非 FormItem 类型的渲染器注册, 这种不能修改 form'}</div>
); );
} }
} }
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "自定义组件示例", title: '自定义组件示例',
body: [ body: [
{
type: 'form',
mode: 'horizontal',
api: '/api/mock2/form/saveForm?waitSeconds=2',
actions: [
{ {
type: "form", type: 'submit',
mode: "horizontal", label: '提交',
api: "/api/mock2/form/saveForm?waitSeconds=2", primary: true
actions: [ }
{ ],
type: "submit", controls: [
label: "提交", {
primary: true name: 'a',
} children: ({value, onChange}) => (
], <div>
controls: [ <p>这个是个自定义组件最简单直接的方式不用注册直接使用</p>
{
name: 'a', <p>当前值{value}</p>
children: ({value, onChange}) => (
<div> <a
<p>这个是个自定义组件最简单直接的方式不用注册直接使用</p> className="btn btn-default"
onClick={() => onChange(Math.round(Math.random() * 10000))}
<p>当前值{value}</p> >
随机修改
<a className="btn btn-default" onClick={() => onChange(Math.round(Math.random() * 10000))}>随机修改</a> </a>
</div> </div>
) )
},
{
type: 'divider'
},
{
name: 'b',
type: 'custom',
label: '自定义FormItem'
},
{
type: 'divider'
},
{
type: 'my-renderer'
}
]
}, },
{ {
type: 'my-renderer', type: 'divider'
tip: '他能放 controls 里面,也能放外面。' },
{
name: 'b',
type: 'custom',
label: '自定义FormItem'
},
{
type: 'divider'
},
{
type: 'my-renderer'
} }
] ]
},
{
type: 'my-renderer',
tip: '他能放 controls 里面,也能放外面。'
}
]
}; };

View File

@ -1,273 +1,276 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
definitions: { definitions: {
options: { options: {
type: 'combo', type: 'combo',
multiple: true, multiple: true,
multiLine: true, multiLine: true,
controls: [ controls: [
{ {
type: 'group', type: 'group',
controls: [ controls: [
{ {
label: "名称", label: '名称',
name: "label", name: 'label',
type: "text", type: 'text',
required: true required: true
}, },
{
label: "值",
name: "value",
type: "text",
required: true
},
]
},
{ {
$ref: 'options', label: '值',
label: "子选项", name: 'value',
name: "children", type: 'text',
addButtonText: '新增子选项' required: true
} }
] ]
}, },
queryItem: { {
type: 'combo', $ref: 'options',
multiple: true, label: '子选项',
multiLine: true, name: 'children',
typeSwitchable: false, addButtonText: '新增子选项'
conditions: [
{
label: "条件",
test: "!data.hasOwnProperty('connect')",
scaffold: {},
controls: [
{
type: 'group',
className: 'm-b-none',
controls: [
{
name: 'key',
type: 'text',
placeholder: '字段名',
required: true
},
{
name: 'type',
type: 'select',
value: 0,
options: [
{
label: 'int64',
value: 0
},
{
label: 'double64',
value: 1
},
{
label: 'string',
value: 2
},
{
label: 'version',
value: 3
}
]
},
{
type: 'formula',
name: 'opt',
formula: '""',
condition: '${type}'
},
{
name: 'opt',
type: 'select',
placeholder: '请选择',
required: true,
options: [
{
label: '>',
value: '>',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: '<',
value: '<',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: '==',
value: '=='
},
{
label: '>=',
value: '>=',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: '<=',
value: '<=',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: 'in',
value: 'in',
},
{
label: 'not in',
value: 'not in',
},
{
label: '!=',
value: '!='
},
]
},
{
name: 'val',
type: 'text',
placeholder: '值',
required: true,
visibleOn: '~[">", "<", ">=", "<=", "==", "!="].indexOf(this.opt)'
},
{
name: 'val',
type: 'array',
required: true,
minLength: 1,
items: {
type: 'text',
placeholder: '值',
required: true,
},
visibleOn: '~["in", "not in"].indexOf(this.opt)'
}
]
}
]
},
{
label: "组合",
test: "data.hasOwnProperty('connect')",
scaffold: {
connect: "&",
exprs: [{}]
},
controls: [
{
type: "button-group",
name: 'connect',
value: '&',
clearable: false,
size: 'xs',
options: [
{
label: 'AND',
value: '&'
},
{
label: 'OR',
value: '|'
}
]
},
{
$ref: 'queryItem',
name: 'exprs',
minLength: 1,
value: [{}]
}
]
}
]
},
queryGroup: {
type: 'combo',
multiple: false,
multiLine: true,
controls: [
{
type: "button-group",
name: 'connect',
value: '&',
// label: "",
// mode: 'inline',
clearable: false,
size: 'sm',
options: [
{
label: 'AND',
value: '&'
},
{
label: 'OR',
value: '|'
}
]
},
{
$ref: 'queryItem',
name: 'exprs',
minLength: 1,
value: [{}]
}
]
} }
]
}, },
type: 'page',
title: '引用', queryItem: {
body: [ type: 'combo',
'<p>引用可以用来减少重复的结构定义,<code>最主要的是可以用来实现结构的递归定义</code>。</p>', multiple: true,
multiLine: true,
typeSwitchable: false,
conditions: [
{ {
type: 'form', label: '条件',
api: '/api/mock/saveForm', test: "!data.hasOwnProperty('connect')",
mode: 'horizontal', scaffold: {},
controls: [ controls: [
{
type: 'group',
className: 'm-b-none',
controls: [
{ {
$ref: 'options', name: 'key',
name: 'options', type: 'text',
value: [{ placeholder: '字段名',
label: '选项1', required: true
value: '1'
}],
minLength: 1,
label: '选项配置'
}
]
},
{
type: 'form',
api: '/api/mock/saveForm',
controls: [
{
$ref: 'queryGroup',
name: 'q',
value: {},
label: 'Query'
}, },
{ {
type: "static", name: 'type',
name: "q", type: 'select',
label: "当前值", value: 0,
tpl: "<pre>${q|json}</pre>" options: [
{
label: 'int64',
value: 0
},
{
label: 'double64',
value: 1
},
{
label: 'string',
value: 2
},
{
label: 'version',
value: 3
}
]
},
{
type: 'formula',
name: 'opt',
formula: '""',
condition: '${type}'
},
{
name: 'opt',
type: 'select',
placeholder: '请选择',
required: true,
options: [
{
label: '>',
value: '>',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: '<',
value: '<',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: '==',
value: '=='
},
{
label: '>=',
value: '>=',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: '<=',
value: '<=',
visibleOn: '~[0,1,3].indexOf(this.type)'
},
{
label: 'in',
value: 'in'
},
{
label: 'not in',
value: 'not in'
},
{
label: '!=',
value: '!='
}
]
},
{
name: 'val',
type: 'text',
placeholder: '值',
required: true,
visibleOn:
'~[">", "<", ">=", "<=", "==", "!="].indexOf(this.opt)'
},
{
name: 'val',
type: 'array',
required: true,
minLength: 1,
items: {
type: 'text',
placeholder: '值',
required: true
},
visibleOn: '~["in", "not in"].indexOf(this.opt)'
} }
] ]
}
]
}, },
]
{
label: '组合',
test: "data.hasOwnProperty('connect')",
scaffold: {
connect: '&',
exprs: [{}]
},
controls: [
{
type: 'button-group',
name: 'connect',
value: '&',
clearable: false,
size: 'xs',
options: [
{
label: 'AND',
value: '&'
},
{
label: 'OR',
value: '|'
}
]
},
{
$ref: 'queryItem',
name: 'exprs',
minLength: 1,
value: [{}]
}
]
}
]
},
queryGroup: {
type: 'combo',
multiple: false,
multiLine: true,
controls: [
{
type: 'button-group',
name: 'connect',
value: '&',
// label: "",
// mode: 'inline',
clearable: false,
size: 'sm',
options: [
{
label: 'AND',
value: '&'
},
{
label: 'OR',
value: '|'
}
]
},
{
$ref: 'queryItem',
name: 'exprs',
minLength: 1,
value: [{}]
}
]
}
},
type: 'page',
title: '引用',
body: [
'<p>引用可以用来减少重复的结构定义,<code>最主要的是可以用来实现结构的递归定义</code>。</p>',
{
type: 'form',
api: '/api/mock/saveForm',
mode: 'horizontal',
controls: [
{
$ref: 'options',
name: 'options',
value: [
{
label: '选项1',
value: '1'
}
],
minLength: 1,
label: '选项配置'
}
]
},
{
type: 'form',
api: '/api/mock/saveForm',
controls: [
{
$ref: 'queryGroup',
name: 'q',
value: {},
label: 'Query'
},
{
type: 'static',
name: 'q',
label: '当前值',
tpl: '<pre>${q|json}</pre>'
}
]
}
]
}; };

View File

@ -1,46 +1,47 @@
import React from 'react'; import React from 'react';
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "Editor", title: 'Editor',
body: [ body: [
{
type: 'form',
api: '/api/mock2/saveForm?waitSeconds=2',
title: '',
controls: [
{ {
type: "form", name: 'javascript',
api: "/api/mock2/saveForm?waitSeconds=2", type: 'editor',
title: "", label: 'Javascript',
controls: [ language: 'javascript',
{ value: 'console.log(1, 2, 3);'
name: "javascript", },
type: "editor",
label: "Javascript",
language: 'javascript',
value: "console.log(1, 2, 3);"
},
{ {
name: "html", name: 'html',
type: "editor", type: 'editor',
language: 'html', language: 'html',
label: "Html", label: 'Html',
value: "<html><head><title>Hello</title></head><body><p>world</p></body></html>" value:
}, '<html><head><title>Hello</title></head><body><p>world</p></body></html>'
},
{ {
name: "css", name: 'css',
type: "editor", type: 'editor',
language: 'css', language: 'css',
label: "CSS", label: 'CSS',
value: "body {color: red;}" value: 'body {color: red;}'
}, },
{ {
name: "json", name: 'json',
type: "editor", type: 'editor',
language: 'json', language: 'json',
label: "JSON", label: 'JSON',
value: `{"a": 1, "b": 2}` value: `{"a": 1, "b": 2}`
}
]
} }
] ]
}
]
}; };

View File

@ -1,148 +1,148 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "FieldSet 示例", title: 'FieldSet 示例',
body: [ body: [
{
type: 'form',
mode: 'horizontal',
api: '/api/mock2/saveForm?waitSeconds=2',
actions: [
{ {
type: "form", type: 'submit',
mode: "horizontal", label: '提交',
api: "/api/mock2/saveForm?waitSeconds=2", primary: true
actions: [ }
],
collapsable: true,
title: 'fieldSet 可以对表单元素做个分组',
controls: [
{
type: 'fieldSet',
title: '基本信息',
collapsable: true,
controls: [
{
type: 'group',
controls: [
{ {
type: "submit", type: 'email',
label: "提交", name: 'email',
primary: true placeholder: '请输入邮箱地址',
} label: '邮箱'
],
collapsable: true,
title: 'fieldSet 可以对表单元素做个分组',
controls: [
{
type: 'fieldSet',
title: '基本信息',
collapsable: true,
controls: [
{
type: 'group',
controls: [
{
type: "email",
name: "email",
placeholder: "请输入邮箱地址",
label: "邮箱"
},
{
type: "password",
name: "password",
label: false,
placeholder: "Password"
}
]
},
{
type: "divider"
},
{
type: 'group',
controls: [
{
type: "email",
name: "email",
placeholder: "请输入邮箱地址",
label: "邮箱"
},
{
type: "checkbox",
name: "rememberMe",
label: false,
option: "Remember me"
}
]
}
]
}, },
{ {
title: '其他信息', type: 'password',
type: 'fieldSet', name: 'password',
controls: [ label: false,
{ placeholder: 'Password'
type: "email",
name: "email",
placeholder: "请输入邮箱地址",
label: "邮箱"
},
{
type: "divider"
},
{
type: "checkbox",
name: "rememberMe",
option: "记住我"
}
]
} }
] ]
},
{
type: 'divider'
},
{
type: 'group',
controls: [
{
type: 'email',
name: 'email',
placeholder: '请输入邮箱地址',
label: '邮箱'
},
{
type: 'checkbox',
name: 'rememberMe',
label: false,
option: 'Remember me'
}
]
}
]
},
{
title: '其他信息',
type: 'fieldSet',
controls: [
{
type: 'email',
name: 'email',
placeholder: '请输入邮箱地址',
label: '邮箱'
},
{
type: 'divider'
},
{
type: 'checkbox',
name: 'rememberMe',
option: '记住我'
}
]
}
]
},
{
title: 'FieldSet 样式集',
type: 'form',
controls: [
{
title: '超级小',
type: 'fieldSet',
className: 'fieldset-xs',
controls: [
{
type: 'plain',
text: '文本 ...'
}
]
}, },
{ {
title: "FieldSet 样式集", title: '小尺寸',
type: "form", type: 'fieldSet',
controls: [ className: 'fieldset-sm',
{ controls: [
title: "超级小", {
type: 'fieldSet', type: 'plain',
className: "fieldset-xs", text: '文本 ...'
controls: [ }
{ ]
type: "plain", },
text: "文本 ..." {
} title: '正常尺寸',
] type: 'fieldSet',
}, className: 'fieldset',
{ controls: [
title: "小尺寸", {
type: 'fieldSet', type: 'plain',
className: "fieldset-sm", text: '文本 ...'
controls: [ }
{ ]
type: "plain", },
text: "文本 ..." {
} title: '中大尺寸',
] type: 'fieldSet',
}, className: 'fieldset-md',
{ controls: [
title: "正常尺寸", {
type: 'fieldSet', type: 'plain',
className: "fieldset", text: '文本 ...'
controls: [ }
{ ]
type: "plain", },
text: "文本 ..." {
} title: '超大尺寸',
] type: 'fieldSet',
}, className: 'fieldset-lg',
{ controls: [
title: "中大尺寸", {
type: 'fieldSet', type: 'plain',
className: "fieldset-md", text: '文本 ...'
controls: [ }
{ ]
type: "plain",
text: "文本 ..."
}
]
},
{
title: "超大尺寸",
type: 'fieldSet',
className: "fieldset-lg",
controls: [
{
type: "plain",
text: "文本 ..."
}
]
}
]
} }
] ]
}
]
}; };

View File

@ -1,101 +1,101 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "FieldSet In Tabs", title: 'FieldSet In Tabs',
remark: "", remark: '',
body: { body: {
type: "form", type: 'form',
collapsable: true, collapsable: true,
tabs: [ tabs: [
{ {
title: "Tab A", title: 'Tab A',
fieldSet: [ fieldSet: [
{ {
title: "Group A", title: 'Group A',
tabs: [ tabs: [
{ {
title: "SubTab A", title: 'SubTab A',
controls: [ controls: [
{ {
name: "a", name: 'a',
type: "text", type: 'text',
label: "Text" label: 'Text'
}, },
{ {
name: "a", name: 'a',
type: "text", type: 'text',
label: "Text" label: 'Text'
} }
]
},
{
title: "SubTab B",
controls: [
{
name: "a",
type: "text",
label: "Text"
},
{
name: "a",
type: "text",
label: "Text"
}
]
}
]
},
{
title: "Group B",
controls: [
{
name: "a",
type: "text",
label: "Text"
},
{
name: "a",
type: "text",
label: "Text"
}
]
}
] ]
}, },
{ {
title: "Tab B", title: 'SubTab B',
fieldSet: [ controls: [
{ {
title: "Group A", name: 'a',
controls: [ type: 'text',
{ label: 'Text'
name: "a", },
type: "text", {
label: "Text" name: 'a',
}, type: 'text',
{ label: 'Text'
name: "a", }
type: "text",
label: "Text"
}
]
},
{
title: "Group B",
controls: [
{
name: "a",
type: "text",
label: "Text"
},
{
name: "a",
type: "text",
label: "Text"
}
]
}
] ]
} }
]
},
{
title: 'Group B',
controls: [
{
name: 'a',
type: 'text',
label: 'Text'
},
{
name: 'a',
type: 'text',
label: 'Text'
}
]
}
] ]
} },
{
title: 'Tab B',
fieldSet: [
{
title: 'Group A',
controls: [
{
name: 'a',
type: 'text',
label: 'Text'
},
{
name: 'a',
type: 'text',
label: 'Text'
}
]
},
{
title: 'Group B',
controls: [
{
name: 'a',
type: 'text',
label: 'Text'
},
{
name: 'a',
type: 'text',
label: 'Text'
}
]
}
]
}
]
}
}; };

View File

@ -1,127 +1,127 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "公式示例", title: '公式示例',
"body": [ body: [
"<p>通过公式,可以动态的设置目标值。</p>", '<p>通过公式,可以动态的设置目标值。</p>',
{
type: 'form',
title: '自动应用',
api: '/api/mock2/form/saveForm',
controls: [
{ {
"type": "form", type: 'number',
title: "自动应用", name: 'a',
"api": "/api/mock2/form/saveForm", label: 'A'
"controls": [
{
"type": "number",
"name": "a",
"label": "A"
},
{
"type": "number",
"name": "b",
"label": "B"
},
{
"type": "number",
"name": "sum",
"label": "和",
"disabled": true,
description: '自动计算 A + B'
},
{
"type": "formula",
"name": "sum",
"value": 0,
"formula": "a + b"
}
]
}, },
{ {
"type": "form", type: 'number',
title: "手动应用", name: 'b',
"api": "/api/mock2/form/saveForm", label: 'B'
"controls": [ },
{
"type": "number",
"name": "a",
"label": "A"
},
{ {
"type": "number", type: 'number',
"name": "b", name: 'sum',
"label": "B" label: '和',
}, disabled: true,
description: '自动计算 A + B'
},
{ {
type: "group", type: 'formula',
controls: [ name: 'sum',
{ value: 0,
"type": "number", formula: 'a + b'
"name": "sum", }
"label": "和", ]
"disabled": true, },
"columnClassName": "col-sm-11",
},
{ {
"type": "button", type: 'form',
"label": "计算", title: '手动应用',
"columnClassName": "col-sm-1 v-bottom", api: '/api/mock2/form/saveForm',
"target": "theFormula" controls: [
} {
] type: 'number',
}, name: 'a',
label: 'A'
},
{ {
"type": "formula", type: 'number',
"name": "sum", name: 'b',
"id": "theFormula", label: 'B'
"value": 0, },
"formula": "a + b",
"initSet": false, {
"autoSet": false type: 'group',
} controls: [
] {
type: 'number',
name: 'sum',
label: '和',
disabled: true,
columnClassName: 'col-sm-11'
},
{
type: 'button',
label: '计算',
columnClassName: 'col-sm-1 v-bottom',
target: 'theFormula'
}
]
},
{
type: 'formula',
name: 'sum',
id: 'theFormula',
value: 0,
formula: 'a + b',
initSet: false,
autoSet: false
}
]
},
{
type: 'form',
title: '条件应用',
api: '/api/mock2/form/saveForm',
controls: [
{
type: 'radios',
name: 'radios',
inline: true,
label: 'radios',
options: [
{
label: 'a',
value: 'a'
},
{
label: 'b',
value: 'b'
}
],
description: 'radios 变化会自动清空 B'
}, },
{ {
"type": "form", type: 'text',
title: "条件应用", name: 'b',
"api": "/api/mock2/form/saveForm", label: 'B'
"controls": [
{
"type": "radios",
"name": "radios",
"inline": true,
"label": "radios",
"options": [
{
"label": 'a',
"value": 'a'
},
{
"label": 'b',
"value": 'b'
},
],
"description": 'radios 变化会自动清空 B'
},
{
"type": "text",
"name": "b",
"label": "B"
},
{
"type": "formula",
"name": "b",
"value": 'some string',
"formula": "''",
"condition": '${radios}',
"initSet": false,
}
]
}, },
]
} {
type: 'formula',
name: 'b',
value: 'some string',
formula: "''",
condition: '${radios}',
initSet: false
}
]
}
]
};

File diff suppressed because it is too large Load Diff

View File

@ -1,96 +1,92 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "其他类型演示", title: '其他类型演示',
body: [ body: [
{
type: 'form',
api: '/api/mock2/saveForm?waitSeconds=2',
title: 'Hint demo',
mode: 'horizontal',
horizontal: {
leftFixed: true
},
controls: [
{ {
type: "form", name: 'button',
api: "/api/mock2/saveForm?waitSeconds=2", type: 'button',
title: "Hint demo", label: 'ID',
mode: "horizontal", value: '',
horizontal: { size: 'xs',
leftFixed: true hint: '比如输入 a-xxxx-xxx'
},
{
type: 'input-group',
size: 'md',
label: 'Icon 组合',
controls: [
{
type: 'icon',
addOnclassName: 'no-bg',
className: 'text-sm',
icon: 'search',
vendor: 'iconfont'
}, },
controls: [ {
{ type: 'text',
name: "button", placeholder: '搜索作业ID/名称',
type: "button", inputClassName: 'b-l-none p-l-none',
label: "ID", name: 'jobName'
value: "", }
size: 'xs', ]
hint: '比如输入 a-xxxx-xxx' },
},
{ {
"type": "input-group", name: 'a',
"size": "md", type: 'text',
"label": "Icon 组合", label: 'ID',
"controls": [ value: '',
{ size: 'xs',
"type": "icon", hint: '比如输入 a-xxxx-xxx'
"addOnclassName": "no-bg", },
className: "text-sm",
"icon": "search",
"vendor": "iconfont"
},
{
"type": "text",
"placeholder": "搜索作业ID/名称",
"inputClassName": "b-l-none p-l-none",
"name": "jobName"
}
]
},
{ {
name: "a", name: 'b',
type: "text", type: 'text',
label: "ID", label: 'ID',
value: "", value: '',
size: 'xs', size: 'sm',
hint: '比如输入 a-xxxx-xxx' hint: '比如输入 a-xxxx-xxx'
}, },
{ {
name: "b", name: 'c',
type: "text", type: 'text',
label: "ID", label: 'ID',
value: "", value: '',
size: 'sm', size: 'md',
hint: '比如输入 a-xxxx-xxx' hint: '比如输入 a-xxxx-xxx'
}, },
{ {
name: "c", name: 'd',
type: "text", type: 'text',
label: "ID", label: 'ID',
value: "", value: '',
size: 'md', size: 'lg',
hint: '比如输入 a-xxxx-xxx' hint: '比如输入 a-xxxx-xxx'
}, },
{ {
name: "d", name: 'tag',
type: "text", type: 'tag',
label: "ID", label: 'Tag',
value: "", size: 'md',
size: 'lg', clearable: true,
hint: '比如输入 a-xxxx-xxx' placeholder: '多个标签以逗号分隔',
}, options: ['周小度', '杜小度']
{
name: "tag",
type: "tag",
label: "Tag",
size: 'md',
clearable: true,
placeholder: "多个标签以逗号分隔",
options: [
"周小度",
"杜小度"
]
}
]
} }
] ]
}
]
}; };

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,93 +1,93 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "显隐切换示例", title: '显隐切换示例',
body: [ body: [
{
name: 'hiddenOn',
type: 'form',
mode: 'horizontal',
api: '/api/mock2/saveForm?waitSeconds=2',
title: 'Hide On 和 disabledOn 示例',
controls: [
{ {
name: "hiddenOn", type: 'radios',
type: "form", name: 'type',
mode: "horizontal", label: '类型选择',
api: "/api/mock2/saveForm?waitSeconds=2", inline: true,
title: "Hide On 和 disabledOn 示例", value: '1',
controls: [ options: [
{ {
type: "radios", label: '类型 1',
name: "type", value: '1'
label: "类型选择", },
inline: true, {
value: "1", label: '类型 2',
options: [ value: '2'
{ },
label: "类型 1", {
value: "1" label: '类型 3',
}, value: '3'
{ }
label: "类型 2", ],
value: "2" description: '<span class="text-danger">请切换类型来看效果</span>'
}, },
{ {
label: "类型 3", type: 'text',
value: "3" label: '所有可见',
} name: 'text1'
], },
description: '<span class="text-danger">请切换类型来看效果</span>' {
}, type: 'text',
{ label: '类型2 可见',
type: "text", hiddenOn: 'data.type != 2',
label: "所有可见", name: 'text2'
name: "text1" },
}, {
{ type: 'text',
type: "text", label: '类型3 不可点',
label: "类型2 可见", disabledOn: 'data.type == 3',
hiddenOn: "data.type != 2", name: 'text3'
name: "text2" },
}, {
{ type: 'text',
type: "text", required: true,
label: "类型3 不可点", label: '必填字段',
disabledOn: "data.type == 3", name: 'test4'
name: "text3" },
}, {
{ type: 'button-toolbar',
type: "text", buttons: [
required: true, {
label: "必填字段", type: 'submit',
name: "test4" disabledOn: 'data.type == 1',
}, label: '类型1不可点'
{ },
type: "button-toolbar", {
buttons: [ type: 'reset',
{ label: '类型3出现且不可点',
type: "submit", visibleOn: 'data.type == 3',
disabledOn: "data.type == 1", disabledOn: 'data.type == 3'
label: "类型1不可点" },
}, {
{ type: 'button',
type: "reset", label: 'Baidu',
label: "类型3出现且不可点", href: 'http://www.baidu.com?a=1&b=$test4'
visibleOn: "data.type == 3", },
disabledOn: "data.type == 3", {
}, type: 'button',
{ actionType: 'ajax',
type: "button", label: 'No Submit',
label: "Baidu", action: '/api/mock2/saveForm?waitSeconds=5'
href: "http://www.baidu.com?a=1&b=$test4" },
}, {
{ type: 'submit',
type: "button", actionType: 'ajax',
actionType: "ajax", label: 'Submit',
label: "No Submit", action: '/api/mock2/saveForm?waitSeconds=5'
action: "/api/mock2/saveForm?waitSeconds=5" }
}, ]
{
type: "submit",
actionType: "ajax",
label: "Submit",
action: "/api/mock2/saveForm?waitSeconds=5"
}
]
}
]
} }
] ]
}
]
}; };

View File

@ -1,90 +1,91 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "动态拉取选项", title: '动态拉取选项',
name: "page-form-remote", name: 'page-form-remote',
body: [ body: [
{
type: 'form',
title: '动态表单元素示例',
name: 'demo-form',
api: '/api/mock2/form/saveForm?waitSeconds=2',
mode: 'horizontal',
actions: [
{ {
type: "form", type: 'submit',
title: "动态表单元素示例", label: '提交'
name: "demo-form",
api: "/api/mock2/form/saveForm?waitSeconds=2",
mode: "horizontal",
actions: [
{
type: "submit",
label: "提交"
}
],
controls: [
{
name: "select",
type: "select",
label: "动态选项",
source: "/api/mock2/form/getOptions?waitSeconds=1",
description: '通过接口一口气拉取选项',
clearable: true,
searchable: true
},
{
type: "divider"
},
{
name: "select2",
type: "select",
label: "选项自动补全",
autoComplete: "/api/mock2/options/autoComplete?term=$term",
placeholder: "请输入",
description: '通过接口自动补全'
},
{
type: "divider"
},
{
type: "text",
name: "text",
label: "文本提示",
source: "/api/mock2/form/getOptions?waitSeconds=1",
placeholder: '请选择'
},
{
type: "divider"
},
{
name: "text2",
type: "text",
label: "文本自动补全",
clearable: true,
autoComplete: "/api/mock2/options/autoComplete2?term=$term",
description: '通过接口自动补全'
},
{
name: "chained",
type: "chained-select",
label: "级联选项",
source:
"/api/mock2/options/chainedOptions?waitSeconds=1&parentId=$parentId&level=$level&maxLevel=4&waiSeconds=1",
desc: "无限级别, 只要 api 返回数据就能继续往下选择. 当没有下级时请返回 null.",
value: "a,b"
},
{
type: "divider"
},
{
name: "tree",
type: "tree",
label: "动态树",
source: "/api/mock2/options/tree?waitSeconds=1"
},
{
type: "divider"
},
{
name: "matrix",
type: "matrix",
label: "动态矩阵开关",
source: "/api/mock2/options/matrix?waitSeconds=1"
}
]
} }
] ],
controls: [
{
name: 'select',
type: 'select',
label: '动态选项',
source: '/api/mock2/form/getOptions?waitSeconds=1',
description: '通过接口一口气拉取选项',
clearable: true,
searchable: true
},
{
type: 'divider'
},
{
name: 'select2',
type: 'select',
label: '选项自动补全',
autoComplete: '/api/mock2/options/autoComplete?term=$term',
placeholder: '请输入',
description: '通过接口自动补全'
},
{
type: 'divider'
},
{
type: 'text',
name: 'text',
label: '文本提示',
source: '/api/mock2/form/getOptions?waitSeconds=1',
placeholder: '请选择'
},
{
type: 'divider'
},
{
name: 'text2',
type: 'text',
label: '文本自动补全',
clearable: true,
autoComplete: '/api/mock2/options/autoComplete2?term=$term',
description: '通过接口自动补全'
},
{
name: 'chained',
type: 'chained-select',
label: '级联选项',
source:
'/api/mock2/options/chainedOptions?waitSeconds=1&parentId=$parentId&level=$level&maxLevel=4&waiSeconds=1',
desc:
'无限级别, 只要 api 返回数据就能继续往下选择. 当没有下级时请返回 null.',
value: 'a,b'
},
{
type: 'divider'
},
{
name: 'tree',
type: 'tree',
label: '动态树',
source: '/api/mock2/options/tree?waitSeconds=1'
},
{
type: 'divider'
},
{
name: 'matrix',
type: 'matrix',
label: '动态矩阵开关',
source: '/api/mock2/options/matrix?waitSeconds=1'
}
]
}
]
}; };

View File

@ -1,21 +1,21 @@
import React from 'react'; import React from 'react';
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "富文本编辑器", title: '富文本编辑器',
body: [ body: [
{
type: 'form',
api: '/api/mock2/saveForm?waitSeconds=2',
title: 'Form elements',
controls: [
{ {
type: "form", name: 'html',
api: "/api/mock2/saveForm?waitSeconds=2", type: 'rich-text',
title: "Form elements", label: '富文本',
controls: [ value: '<p>Just do <code>IT</code></p>'
{
name: "html",
type: "rich-text",
label: "富文本",
value: "<p>Just do <code>IT</code></p>"
}
]
} }
] ]
}
]
}; };

View File

@ -3,154 +3,157 @@ import TitleBar from '../../../src/components/TitleBar';
import {render} from '../../../src/index'; import {render} from '../../../src/index';
const Schema = { const Schema = {
"title": "Person", title: 'Person',
"type": "object", type: 'object',
"properties": { properties: {
"firstName": { firstName: {
"title": "First Name", title: 'First Name',
"type": "string" type: 'string'
},
"lastName": {
"type": "string"
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0
},
"tag": {
"type": "array",
"description": "Tags",
"default": ["IT"],
"items": {
"type": "text"
}
},
"clients": {
"type": "array",
"description": "Tags",
"items": {
"type": "object",
"properties": {
"firstName": {
"title": "First Name",
"type": "string"
},
"lastName": {
"type": "string"
}
}
}
}
}, },
"required": ["firstName", "lastName"] lastName: {
type: 'string'
},
age: {
description: 'Age in years',
type: 'integer',
minimum: 0
},
tag: {
type: 'array',
description: 'Tags',
default: ['IT'],
items: {
type: 'text'
}
},
clients: {
type: 'array',
description: 'Tags',
items: {
type: 'object',
properties: {
firstName: {
title: 'First Name',
type: 'string'
},
lastName: {
type: 'string'
}
}
}
}
},
required: ['firstName', 'lastName']
}; };
function property2control(property, key, schema) { function property2control(property, key, schema) {
const requiredList= schema.required || []; const requiredList = schema.required || [];
const rest = {}; const rest = {};
const validations = {}; const validations = {};
let type = 'text'; let type = 'text';
if (property.type === 'integer') {
type = 'number';
typeof property.minimum === 'number' && (rest.min = property.minimum);
// property.max
} else if (property.type === 'array') {
type = 'combo';
const items = property.items;
if (property.type === 'integer') { if (items.type === 'object') {
type = 'number'; rest.controls = makeControls(items.properties, items);
rest.multiLine = true;
typeof property.minimum === 'number' && (rest.min = property.minimum); } else {
// property.max type = 'array';
} else if (property.type === 'array') { rest.inline = true;
type = 'combo'; rest.items = property2control(items, 'item', property);
const items = property.items;
if (items.type === 'object') {
rest.controls = makeControls(items.properties, items);
rest.multiLine = true;
} else {
type = 'array';
rest.inline = true;
rest.items = property2control(items, 'item', property);
}
} }
}
if (typeof property.minimum === 'number') { if (typeof property.minimum === 'number') {
validations.minimum = property.minimum; validations.minimum = property.minimum;
} }
return { return {
name: key, name: key,
type, type,
required: !!~requiredList.indexOf(key), required: !!~requiredList.indexOf(key),
label: property.title || property.description, label: property.title || property.description,
desc: property.title && property.description, desc: property.title && property.description,
value: property.default, value: property.default,
validations, validations,
...rest ...rest
}; };
} }
function makeControls(properties, schema) { function makeControls(properties, schema) {
const keys = Object.keys(properties); const keys = Object.keys(properties);
return keys.map(key => property2control(properties[key], key, schema)); return keys.map(key => property2control(properties[key], key, schema));
} }
function JSONSchme2AMisSchema(schema) { function JSONSchme2AMisSchema(schema) {
if (schema.type !== 'object') { if (schema.type !== 'object') {
throw new Error('JSONSchme2AMisSchema 只支持 object 转换'); throw new Error('JSONSchme2AMisSchema 只支持 object 转换');
} }
return { return {
title: schema.title, title: schema.title,
type: 'form', type: 'form',
mode: "horizontal", mode: 'horizontal',
controls: makeControls(schema.properties, schema) controls: makeControls(schema.properties, schema)
} };
} }
const amisFormSchema = JSONSchme2AMisSchema(Schema); const amisFormSchema = JSONSchme2AMisSchema(Schema);
export default class JSONSchemaForm extends React.Component { export default class JSONSchemaForm extends React.Component {
state = { state = {
data: {} data: {}
}; };
renderForm() { renderForm() {
return render({ return render({
type: 'page', type: 'page',
title: '', title: '',
body: { body: {
...amisFormSchema, ...amisFormSchema,
onChange: values => this.setState({ onChange: values =>
data: { this.setState({
...values data: {
} ...values
})
} }
}); })
} }
});
}
render() { render() {
return ( return (
<div> <div>
<TitleBar title="JSON Schema Form" /> <TitleBar title="JSON Schema Form" />
<div className="wrapper"> <div className="wrapper">
<div> <div>
<h3>Schema</h3> <h3>Schema</h3>
<pre><code>{JSON.stringify(Schema, null, 2)}</code></pre> <pre>
</div> <code>{JSON.stringify(Schema, null, 2)}</code>
</pre>
</div>
<div> <div>
<h3>Form</h3> <h3>Form</h3>
{this.renderForm()} {this.renderForm()}
</div> </div>
<div> <div>
<h3>Data</h3> <h3>Data</h3>
<pre><code>{JSON.stringify(this.state.data, null, 2)}</code></pre> <pre>
</div> <code>{JSON.stringify(this.state.data, null, 2)}</code>
</div> </pre>
</div> </div>
); </div>
} </div>
);
}
} }

View File

@ -1,130 +1,132 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "所有 Form 元素列举", title: '所有 Form 元素列举',
data: { data: {
id: 1, id: 1,
image: "https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg" image:
}, 'https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3893101144,2877209892&fm=23&gp=0.jpg'
body: [ },
body: [
{
type: 'form',
api: '/api/mock2/saveForm?waitSeconds=2',
title: '表单项静态展示',
mode: 'horizontal',
controls: [
{ {
type: "form", type: 'static',
api: "/api/mock2/saveForm?waitSeconds=2", label: '文本',
title: "表单项静态展示", value: '文本'
mode: "horizontal", },
controls: [
{
type: "static",
label: "文本",
value: "文本"
},
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static-tpl", type: 'static-tpl',
label: "模板", label: '模板',
tpl: "自己拼接 HTML 取变量 \\${id}: ${id}" tpl: '自己拼接 HTML 取变量 \\${id}: ${id}'
}, },
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static-date", type: 'static-date',
label: "日期", label: '日期',
value: Math.round(Date.now()/1000) value: Math.round(Date.now() / 1000)
}, },
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static-datetime", type: 'static-datetime',
label: "日期时间", label: '日期时间',
value: Math.round(Date.now()/1000) value: Math.round(Date.now() / 1000)
}, },
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static-mapping", type: 'static-mapping',
label: "映射", label: '映射',
value: Math.floor(Math.random() * 5), value: Math.floor(Math.random() * 5),
map: { map: {
'*': "<span class='label label-default'>-</span>", '*': "<span class='label label-default'>-</span>",
'0': "<span class='label label-info'>一</span>", '0': "<span class='label label-info'>一</span>",
'1': "<span class='label label-success'>二</span>", '1': "<span class='label label-success'>二</span>",
'2': "<span class='label label-danger'>三</span>", '2': "<span class='label label-danger'>三</span>",
'3': "<span class='label label-warning'>四</span>", '3': "<span class='label label-warning'>四</span>",
'4': "<span class='label label-primary'>五</span>", '4': "<span class='label label-primary'>五</span>"
} }
}, },
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static-progress", type: 'static-progress',
label: "进度", label: '进度',
value: 66.66 value: 66.66
}, },
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static-image", type: 'static-image',
label: "图片", label: '图片',
name: "image", name: 'image',
popOver: { popOver: {
title: "查看大图", title: '查看大图',
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>' body:
} '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
}, }
},
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: 'static-json', type: 'static-json',
label: 'JSON', label: 'JSON',
value: {a: 1, b: 2, c: {d: 3}} value: {a: 1, b: 2, c: {d: 3}}
}, },
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static", type: 'static',
label: "可复制", label: '可复制',
value: "文本", value: '文本',
copyable: { copyable: {
content: "内容,支持变量 ${id}" content: '内容,支持变量 ${id}'
} }
}, },
{ {
type: 'divider' type: 'divider'
}, },
{ {
type: "static", type: 'static',
name: "text", name: 'text',
label: "可快速编辑", label: '可快速编辑',
value: "文本", value: '文本',
quickEdit: true quickEdit: true
},
]
} }
] ]
}
]
}; };

View File

@ -1,60 +1,60 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "SubForm 示例", title: 'SubForm 示例',
body: [ body: [
{
type: 'form',
api: '/api/mock2/saveForm?waitSeconds=2',
title: 'Form elements',
mode: 'horizontal',
// debug: true,
controls: [
{ {
type: "form", type: 'form',
api: "/api/mock2/saveForm?waitSeconds=2", label: '子表单单条',
title: "Form elements", name: 'subForm1',
mode: "horizontal", btnLabel: '点击设置',
// debug: true, form: {
title: '子表单',
controls: [ controls: [
{ {
type: "form", name: 'a',
label: "子表单单条", type: 'text',
name: "subForm1", label: 'Foo'
btnLabel: "点击设置", },
form: { {
title: "子表单", name: 'b',
controls: [ type: 'switch',
{ label: 'Boo'
name: "a", }
type: "text",
label: "Foo"
},
{
name: "b",
type: "switch",
label: "Boo"
}
]
}
},
{
type: "form",
label: "子表单多条",
name: "subForm2",
labelField: 'a',
btnLabel: "点击设置",
multiple: true,
form: {
title: "子表单",
controls: [
{
name: "a",
type: "text",
label: "Foo"
},
{
name: "b",
type: "switch",
label: "Boo"
}
]
}
},
] ]
}
},
{
type: 'form',
label: '子表单多条',
name: 'subForm2',
labelField: 'a',
btnLabel: '点击设置',
multiple: true,
form: {
title: '子表单',
controls: [
{
name: 'a',
type: 'text',
label: 'Foo'
},
{
name: 'b',
type: 'switch',
label: 'Boo'
}
]
}
} }
] ]
}
]
}; };

View File

@ -1,146 +1,146 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "表格编辑", title: '表格编辑',
body: { body: {
type: "form", type: 'form',
mode: "horizontal", mode: 'horizontal',
api: "/api/mock2/form/saveForm?waitSeconds=2", api: '/api/mock2/form/saveForm?waitSeconds=2',
actions: [ actions: [
{ {
type: "submit", type: 'submit',
label: "提交", label: '提交',
primary: true primary: true
} }
],
controls: [
{
type: 'combo',
name: 'colors',
label: 'Combo',
multiple: true,
draggable: true,
multiLine: true,
value: [
{
color: 'green',
name: '颜色'
}
], ],
controls: [ controls: [
{ {
type: 'combo', type: 'color',
name: 'colors', name: 'color'
label: 'Combo', },
multiple: true, {
draggable: true, type: 'text',
multiLine: true, name: 'name',
value: [ placeholder: '说明文字'
{ }
color: 'green',
name: '颜色'
}
],
controls: [
{
type: 'color',
name: 'color'
},
{
type: 'text',
name: 'name',
placeholder: '说明文字'
}
]
},
{
type: "static",
label: "当前值",
tpl: "<pre>${colors|json}</pre>"
},
{
type: 'table',
name: 'colors',
label: 'Table',
draggable: true,
columns: [
{
label: 'Color',
name: 'color',
quickEdit: {
type: 'color',
saveImmediately: true
}
},
{
label: '说明文字',
name: 'name',
quickEdit: {
type: 'text',
mode: 'inline',
saveImmediately: true
}
}
]
},
{
type: 'button',
label: 'Table2新增一行',
target: 'table2',
actionType: 'add'
},
{
"type": "table",
"name": "table2",
"label": "Table2",
"editable": true,
"addable": true,
"removable": true,
"draggable": true,
"columns": [
{
"name": "a",
"label": "A"
},
{
"name": "b",
"label": "B",
"quickEdit": {
"type": "select",
"options": [
{
"label": "A",
"value": "a"
},
{
"label": "B",
"value": "b"
}
]
}
}
]
},
{
"type": "table",
"name": "table3",
"label": "Table3(指定第2列只有update时能编辑)",
"editable": true,
"addable": true,
"removable": true,
"draggable": true,
"columns": [
{
"name": "a",
"label": "A",
"quickEdit": true
},
{
"name": "b",
"label": "B",
"quickEdit": false,
"quickEditOnUpdate": {
"type": "select",
"options": [
{
"label": "A",
"value": "a"
},
{
"label": "B",
"value": "b"
}
]
},
}
]
}
] ]
} },
{
type: 'static',
label: '当前值',
tpl: '<pre>${colors|json}</pre>'
},
{
type: 'table',
name: 'colors',
label: 'Table',
draggable: true,
columns: [
{
label: 'Color',
name: 'color',
quickEdit: {
type: 'color',
saveImmediately: true
}
},
{
label: '说明文字',
name: 'name',
quickEdit: {
type: 'text',
mode: 'inline',
saveImmediately: true
}
}
]
},
{
type: 'button',
label: 'Table2新增一行',
target: 'table2',
actionType: 'add'
},
{
type: 'table',
name: 'table2',
label: 'Table2',
editable: true,
addable: true,
removable: true,
draggable: true,
columns: [
{
name: 'a',
label: 'A'
},
{
name: 'b',
label: 'B',
quickEdit: {
type: 'select',
options: [
{
label: 'A',
value: 'a'
},
{
label: 'B',
value: 'b'
}
]
}
}
]
},
{
type: 'table',
name: 'table3',
label: 'Table3(指定第2列只有update时能编辑)',
editable: true,
addable: true,
removable: true,
draggable: true,
columns: [
{
name: 'a',
label: 'A',
quickEdit: true
},
{
name: 'b',
label: 'B',
quickEdit: false,
quickEditOnUpdate: {
type: 'select',
options: [
{
label: 'A',
value: 'a'
},
{
label: 'B',
value: 'b'
}
]
}
}
]
}
]
}
}; };

View File

@ -1,169 +1,171 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "Tabs 示例", title: 'Tabs 示例',
body: [ body: [
{
type: 'form',
mode: 'horizontal',
api: '/api/mock2/form/saveForm?waitSeconds=2',
title: '',
actions: [
{ {
type: "form", type: 'button',
mode: "horizontal", actionType: 'dialog',
api: "/api/mock2/form/saveForm?waitSeconds=2", label: '弹框中的 Tabs',
title: "", level: 'info',
actions: [ dialog: {
title: '',
// size: "md",
body: {
type: 'form',
mode: 'horizontal',
horizontal: {
leftFixed: 'xs'
},
api: '/api/mock2/form/saveForm?waitSeconds=2',
actions: [
{ {
type: "button", type: 'submit',
actionType: "dialog", label: '提交',
label: "弹框中的 Tabs", primary: true
level: "info",
dialog: {
title: "",
// size: "md",
body: {
type: "form",
mode: "horizontal",
horizontal: {
leftFixed: 'xs'
},
api: "/api/mock2/form/saveForm?waitSeconds=2",
actions: [
{
type: "submit",
label: "提交",
primary: true
}
],
controls: [{
type: 'tabs',
tabs: [
{
title: "基本信息",
controls: [
[
{
type: "email",
name: "email1",
placeholder: "请输入邮箱地址",
label: "邮箱"
},
{
type: "password",
name: "password",
placeholder: "密码",
label: false
}
],
{
type: "divider"
},
[
{
type: "email",
name: "email2",
placeholder: "请输入邮箱地址",
label: "邮箱"
},
{
type: "checkbox",
name: "rememberMe",
label: false,
option: "记住我"
}
]
]
},
{
title: "其他信息",
controls: [
{
type: "email",
name: "email3",
placeholder: "请输入邮箱地址",
label: "邮箱"
},
{
type: "divider"
},
{
type: "checkbox",
name: "rememberMe2",
option: "记住我"
}
]
}
]
}]
}
}
},
{
type: "submit",
label: "提交",
primary: true
} }
], ],
controls: [ controls: [
{ {
type: 'tabs', type: 'tabs',
tabs: [
tabs: [ {
title: '基本信息',
controls: [
[
{
type: 'email',
name: 'email1',
placeholder: '请输入邮箱地址',
label: '邮箱'
},
{
type: 'password',
name: 'password',
placeholder: '密码',
label: false
}
],
{ {
title: "基本信息", type: 'divider'
hash: 'tab1', },
controls: [ [
[ {
{ type: 'email',
type: "email", name: 'email2',
name: "email", placeholder: '请输入邮箱地址',
placeholder: "请输入邮箱地址", label: '邮箱'
label: "邮箱" },
}, {
{ type: 'checkbox',
type: "password", name: 'rememberMe',
name: "password", label: false,
placeholder: "密码", option: '记住我'
label: false }
} ]
], ]
{ },
type: "divider" {
}, title: '其他信息',
[ controls: [
{ {
type: "email", type: 'email',
name: "email2", name: 'email3',
placeholder: "请输入邮箱地址", placeholder: '请输入邮箱地址',
label: "邮箱" label: '邮箱'
},
{
type: "checkbox",
name: "rememberMe",
label: false,
option: "记住我"
}
]
]
}, },
{ {
title: "其他信息", type: 'divider'
hash: 'tab2', },
controls: [ {
{ type: 'checkbox',
type: "email", name: 'rememberMe2',
name: "email3", option: '记住我'
placeholder: "请输入邮箱地址",
label: "邮箱"
},
{
type: "divider"
},
{
type: "checkbox",
name: "rememberMe4",
label: "记住我"
}
]
} }
] ]
}
]
} }
] ]
}
}
},
{
type: 'submit',
label: '提交',
primary: true
} }
] ],
controls: [
{
type: 'tabs',
tabs: [
{
title: '基本信息',
hash: 'tab1',
controls: [
[
{
type: 'email',
name: 'email',
placeholder: '请输入邮箱地址',
label: '邮箱'
},
{
type: 'password',
name: 'password',
placeholder: '密码',
label: false
}
],
{
type: 'divider'
},
[
{
type: 'email',
name: 'email2',
placeholder: '请输入邮箱地址',
label: '邮箱'
},
{
type: 'checkbox',
name: 'rememberMe',
label: false,
option: '记住我'
}
]
]
},
{
title: '其他信息',
hash: 'tab2',
controls: [
{
type: 'email',
name: 'email3',
placeholder: '请输入邮箱地址',
label: '邮箱'
},
{
type: 'divider'
},
{
type: 'checkbox',
name: 'rememberMe4',
label: '记住我'
}
]
}
]
}
]
}
]
}; };

View File

@ -1,126 +1,132 @@
export default { export default {
"type": "page", type: 'page',
"body": { body: {
"type": "form", type: 'form',
"title": "详情", title: '详情',
"name": "scene_detail", name: 'scene_detail',
"mode": "horizontal", mode: 'horizontal',
"submitText": "", submitText: '',
"submitOnChange": false, submitOnChange: false,
"actions": [{ actions: [
"type": "button", {
"label": "修改", type: 'button',
"actionType": "drawer", label: '修改',
"drawer": { actionType: 'drawer',
"type": "form", drawer: {
"position": "left", type: 'form',
"title": "修改内容", position: 'left',
"controls": [{ title: '修改内容',
"type": "text", controls: [
"label": "标题", {
"name": "name", type: 'text',
"required": true label: '标题',
}, { name: 'name',
"label": "描述", required: true
"type": "text", },
"name": "typeDesc", {
"required": true label: '描述',
}, { type: 'text',
"label": "内容", name: 'typeDesc',
"type": "textarea", required: true
"name": "contents", },
"required": true {
}] label: '内容',
type: 'textarea',
name: 'contents',
required: true
} }
}], ]
"controls": [ }
{ }
type: "tree", ],
name: "tree", controls: [
label: "树", {
options: [ type: 'tree',
{ name: 'tree',
label: "Folder A", label: '树',
value: 1, options: [
children: [ {
{ label: 'Folder A',
label: "file A", value: 1,
value: 2 children: [
}, {
{ label: 'file A',
label: "file B", value: 2
value: 3 },
} {
] label: 'file B',
}, value: 3
{ }
label: "file C", ]
value: 4 },
}, {
{ label: 'file C',
label: "file D", value: 4
value: 5 },
} {
] label: 'file D',
}, value: 5
{ }
type: "divider"
},
{
type: "tree",
name: "trees",
label: "树多选",
multiple: true,
options: [
{
label: "Folder A",
value: 1,
children: [
{
label: "file A",
value: 2
},
{
label: "file B",
value: 3
}
]
},
{
label: "file C",
value: 4
},
{
label: "file D",
value: 5
}
]
},
{
type: "divider"
},
{
name: "select",
type: "tree-select",
label: "动态选项",
source: "/api/mock2/form/getTreeOptions?waitSeconds=1",
description: '通过接口一口气拉取选项',
clearable: true,
searchable: true
},
{
type: "divider"
},
{
name: "select2",
type: "tree-select",
label: "选项自动补全",
autoComplete: "/api/mock2/tree/autoComplete?term=$term",
placeholder: "请输入",
description: '通过接口自动补全',
multiple: true
},
] ]
} },
} {
type: 'divider'
},
{
type: 'tree',
name: 'trees',
label: '树多选',
multiple: true,
options: [
{
label: 'Folder A',
value: 1,
children: [
{
label: 'file A',
value: 2
},
{
label: 'file B',
value: 3
}
]
},
{
label: 'file C',
value: 4
},
{
label: 'file D',
value: 5
}
]
},
{
type: 'divider'
},
{
name: 'select',
type: 'tree-select',
label: '动态选项',
source: '/api/mock2/form/getTreeOptions?waitSeconds=1',
description: '通过接口一口气拉取选项',
clearable: true,
searchable: true
},
{
type: 'divider'
},
{
name: 'select2',
type: 'tree-select',
label: '选项自动补全',
autoComplete: '/api/mock2/tree/autoComplete?term=$term',
placeholder: '请输入',
description: '通过接口自动补全',
multiple: true
}
]
}
};

View File

@ -1,112 +1,112 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "表单验证示例", title: '表单验证示例',
toolbar: "<a target='_blank' href='/docs/renderers/Form/FormItem'>文档</a>", toolbar: "<a target='_blank' href='/docs/renderers/Form/FormItem'>文档</a>",
body: [ body: [
{
type: 'form',
autoFocus: false,
messages: {
validateFailed: '请仔细检查表单规则,部分表单项没通过验证'
},
title: '表单',
actions: [
{ {
type: "form", type: 'submit',
autoFocus: false, label: '提交'
messages: {
'validateFailed': '请仔细检查表单规则,部分表单项没通过验证'
},
title: "表单",
actions: [
{
type: "submit",
label: "提交"
}
],
api: "/api/mock2/form/saveFormFailed?waitSeconds=2",
mode: "horizontal",
controls: [
{
type: "text",
name: "test",
label: "必填",
required: true
},
{
type: "divider"
},
{
name: "test1",
type: "email",
label: "Email"
},
{
type: "divider"
},
{
name: "url",
type: "url",
label: "Url"
},
{
type: "divider"
},
{
name: "num",
type: "text",
label: "数字",
validations: "isNumeric"
},
{
type: "divider"
},
{
name: "alpha",
type: "text",
label: "字母或数字",
validations: "isAlphanumeric"
},
{
type: "divider"
},
{
name: "int",
type: "text",
label: "整形",
validations: "isInt"
},
{
type: "divider"
},
{
name: "minLength",
type: "text",
label: "长度限制",
validations: "minLength:2,maxLength:10"
},
{
type: "divider"
},
{
name: "min",
type: "text",
label: "数值限制",
validations: "maximum:10,minimum:2"
},
{
type: "divider"
},
{
name: "reg",
type: "text",
label: "正则",
validations: "matchRegexp:/^abc/",
validationErrors: {
matchRegexp: "请输入abc开头的好么?"
}
},
{
type: "divider"
},
{
name: "test2",
type: "text",
label: "服务端验证"
}
]
} }
] ],
api: '/api/mock2/form/saveFormFailed?waitSeconds=2',
mode: 'horizontal',
controls: [
{
type: 'text',
name: 'test',
label: '必填',
required: true
},
{
type: 'divider'
},
{
name: 'test1',
type: 'email',
label: 'Email'
},
{
type: 'divider'
},
{
name: 'url',
type: 'url',
label: 'Url'
},
{
type: 'divider'
},
{
name: 'num',
type: 'text',
label: '数字',
validations: 'isNumeric'
},
{
type: 'divider'
},
{
name: 'alpha',
type: 'text',
label: '字母或数字',
validations: 'isAlphanumeric'
},
{
type: 'divider'
},
{
name: 'int',
type: 'text',
label: '整形',
validations: 'isInt'
},
{
type: 'divider'
},
{
name: 'minLength',
type: 'text',
label: '长度限制',
validations: 'minLength:2,maxLength:10'
},
{
type: 'divider'
},
{
name: 'min',
type: 'text',
label: '数值限制',
validations: 'maximum:10,minimum:2'
},
{
type: 'divider'
},
{
name: 'reg',
type: 'text',
label: '正则',
validations: 'matchRegexp:/^abc/',
validationErrors: {
matchRegexp: '请输入abc开头的好么?'
}
},
{
type: 'divider'
},
{
name: 'test2',
type: 'text',
label: '服务端验证'
}
]
}
]
}; };

File diff suppressed because it is too large Load Diff

View File

@ -1,137 +1,137 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "HBox & Grid", title: 'HBox & Grid',
"type": "page", type: 'page',
"body": [ body: [
{
type: 'plain',
tpl: 'Grid 请参考 bootstrap 的 grid 布局',
inline: false,
className: 'h3 m-b-xs'
},
{
type: 'grid',
columns: [
{ {
"type": "plain", type: 'tpl',
"tpl": "Grid 请参考 bootstrap 的 grid 布局", tpl: 'sm-2',
"inline": false, sm: 2,
"className": "h3 m-b-xs" className: 'bg-info',
inline: false
}, },
{ {
"type": "grid", type: 'tpl',
"columns": [ tpl: 'sm-4',
{ sm: 4,
"type": "tpl", className: 'bg-success',
"tpl": "sm-2", inline: false
"sm": 2,
"className": "bg-info",
"inline": false
},
{
"type": "tpl",
"tpl": "sm-4",
"sm": 4,
"className": "bg-success",
"inline": false
},
{
"type": "tpl",
"tpl": "sm-6",
"sm": 6,
"className": "bg-primary",
"inline": false
}
]
}, },
{ {
"type": "plain", type: 'tpl',
"tpl": "Hbox", tpl: 'sm-6',
"inline": false, sm: 6,
"className": "h3 m-t m-b-xs" className: 'bg-primary',
inline: false
}
]
},
{
type: 'plain',
tpl: 'Hbox',
inline: false,
className: 'h3 m-t m-b-xs'
},
{
type: 'hbox',
columns: [
{
type: 'tpl',
tpl: '平均分配',
className: 'bg-info',
inline: false
}, },
{ {
"type": "hbox", type: 'tpl',
"columns": [ tpl: '平均分配',
{ className: 'bg-success',
"type": "tpl", inline: false
"tpl": "平均分配",
"className": "bg-info",
"inline": false
},
{
"type": "tpl",
"tpl": "平均分配",
"className": "bg-success",
"inline": false
},
{
"type": "tpl",
"tpl": "平均分配",
"className": "bg-primary",
"inline": false
}
]
}, },
{ {
"type": "plain", type: 'tpl',
"tpl": "Hbox 部分定宽", tpl: '平均分配',
"inline": false, className: 'bg-primary',
"className": "h3 m-t m-b-xs" inline: false
}
]
},
{
type: 'plain',
tpl: 'Hbox 部分定宽',
inline: false,
className: 'h3 m-t m-b-xs'
},
{
type: 'hbox',
columns: [
{
type: 'tpl',
tpl: 'w-xs',
className: 'bg-info',
inline: false,
columnClassName: 'w-xs'
}, },
{ {
"type": "hbox", type: 'tpl',
"columns": [ tpl: 'w-sm',
{ className: 'bg-info lter',
"type": "tpl", inline: false,
"tpl": "w-xs", columnClassName: 'w-sm'
"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
}
]
}, },
{ {
"type": "plain", type: 'tpl',
"tpl": "示例", tpl: 'w',
"inline": false, className: 'bg-info dk',
"className": "h3 m-t m-b-xs" inline: false,
columnClassName: 'w'
}, },
{ {
"type": "grid", type: 'tpl',
"columns": [ tpl: '平均分配',
{ className: 'bg-success',
"type": "panel", inline: false
"title": "面板1",
"className": "Panel--danger",
"body": "内容",
"sm": 4
},
{
"type": "panel",
"title": "面板2",
"className": "Panel--primary",
"body": "内容",
"sm": 8
}
]
}, },
] {
} type: 'tpl',
tpl: '平均分配',
className: 'bg-primary',
inline: false
}
]
},
{
type: 'plain',
tpl: '示例',
inline: false,
className: 'h3 m-t m-b-xs'
},
{
type: 'grid',
columns: [
{
type: 'panel',
title: '面板1',
className: 'Panel--danger',
body: '内容',
sm: 4
},
{
type: 'panel',
title: '面板2',
className: 'Panel--primary',
body: '内容',
sm: 8
}
]
}
]
};

View File

@ -1,31 +1,31 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "IFrame 可以用来嵌入其他网站", title: 'IFrame 可以用来嵌入其他网站',
"body": [ body: [
{
type: 'form',
mode: 'inline',
target: 'window',
title: '',
controls: [
{ {
type: 'form', type: 'text',
mode: 'inline', name: 'keywords',
target: 'window', addOn: {
title: '', type: 'submit',
controls: [ label: '搜索',
{ level: 'info',
type: 'text', icon: 'fa fa-search pull-left'
name: 'keywords', }
addOn: {
type: 'submit',
label: '搜索',
level: 'info',
icon: 'fa fa-search pull-left'
}
}
]
},
{
type: 'iframe',
className: 'b-a',
src: "https://www.baidu.com/s?wd=${keywords|url_encode}",
height: 500
} }
] ]
} },
{
type: 'iframe',
className: 'b-a',
src: 'https://www.baidu.com/s?wd=${keywords|url_encode}',
height: 500
}
]
};

View File

@ -1,174 +1,173 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
title: "表单与列表之间的联动", title: '表单与列表之间的联动',
body: [ body: [
{
title: '',
type: 'form',
mode: 'inline',
target: 'list',
wrapWithPanel: false,
className: 'm-b',
controls: [
{ {
title: "", type: 'text',
type: 'form', name: 'keywords',
mode: 'inline', placeholder: '通过关键字搜索',
target: 'list', clearable: true,
wrapWithPanel: false, addOn: {
className: 'm-b', type: 'submit',
controls: [ icon: 'fa fa-search',
{ level: 'primary'
type: "text", }
name: "keywords", }
placeholder: "通过关键字搜索", ]
clearable: true, },
addOn: { {
type: 'submit', type: 'crud',
icon: 'fa fa-search', name: 'list',
level: 'primary' api: '/api/sample',
} mode: 'list',
}, listItem: {
actions: [
] {
}, type: 'button',
{ icon: 'fa fa-eye',
type: "crud", actionType: 'dialog',
name: 'list', dialog: {
api: "/api/sample", title: '查看',
mode: "list", body: {
listItem: { type: 'form',
actions: [ controls: [
{ {
type: "button", type: 'static',
icon: "fa fa-eye", name: 'engine',
actionType: "dialog", label: 'Engine'
dialog: { },
title: "查看", {
body: { type: 'divider'
type: "form", },
controls: [ {
{ type: 'static',
type: "static", name: 'browser',
name: "engine", label: 'Browser'
label: "Engine" },
}, {
{ type: 'divider'
type: "divider" },
}, {
{ type: 'static',
type: "static", name: 'platform',
name: "browser", label: 'Platform(s)'
label: "Browser" },
}, {
{ type: 'divider'
type: "divider" },
}, {
{ type: 'static',
type: "static", name: 'version',
name: "platform", label: 'Engine version'
label: "Platform(s)" },
}, {
{ type: 'divider'
type: "divider" },
}, {
{ type: 'static',
type: "static", name: 'grade',
name: "version", label: 'CSS grade'
label: "Engine version" }
},
{
type: "divider"
},
{
type: "static",
name: "grade",
label: "CSS grade"
}
]
}
}
},
{
type: "button",
icon: "fa fa-pencil",
actionType: "dialog",
dialog: {
title: "编辑",
body: {
type: "form",
name: "sample-edit-form",
api: "/api/sample/$id",
controls: [
{
type: "text",
name: "engine",
label: "Engine",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "browser",
label: "Browser",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "platform",
label: "Platform(s)",
required: true
},
{
type: "divider"
},
{
type: "text",
name: "version",
label: "Engine version"
},
{
type: "divider"
},
{
type: "text",
name: "grade",
label: "CSS grade"
}
]
}
}
},
{
type: "button",
icon: "fa fa-times text-danger",
actionType: "ajax",
confirmText: "您确认要删除?",
api: "delete:/api/sample/$id"
}
],
body: [
{
name: "engine",
label: "Rendering engine",
labelClassName: "w-sm"
},
[
{
name: "browser",
label: "Browser",
labelClassName: "w-sm"
},
{
name: "platform",
label: "Platform(s)",
labelClassName: "w-sm"
}
],
{
name: "version",
label: "Engine version",
labelClassName: "w-sm"
}
] ]
}
} }
}] },
}; {
type: 'button',
icon: 'fa fa-pencil',
actionType: 'dialog',
dialog: {
title: '编辑',
body: {
type: 'form',
name: 'sample-edit-form',
api: '/api/sample/$id',
controls: [
{
type: 'text',
name: 'engine',
label: 'Engine',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'browser',
label: 'Browser',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'platform',
label: 'Platform(s)',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'version',
label: 'Engine version'
},
{
type: 'divider'
},
{
type: 'text',
name: 'grade',
label: 'CSS grade'
}
]
}
}
},
{
type: 'button',
icon: 'fa fa-times text-danger',
actionType: 'ajax',
confirmText: '您确认要删除?',
api: 'delete:/api/sample/$id'
}
],
body: [
{
name: 'engine',
label: 'Rendering engine',
labelClassName: 'w-sm'
},
[
{
name: 'browser',
label: 'Browser',
labelClassName: 'w-sm'
},
{
name: 'platform',
label: 'Platform(s)',
labelClassName: 'w-sm'
}
],
{
name: 'version',
label: 'Engine version',
labelClassName: 'w-sm'
}
]
}
}
]
};

View File

@ -1,67 +1,67 @@
export default { export default {
type: 'page', type: 'page',
title: '表单与表单之间的联动', title: '表单与表单之间的联动',
aside: { aside: {
type: 'form', type: 'form',
target: 'detailForm', target: 'detailForm',
className: 'wrapper-sm', // className: 'wrapper-sm', //
wrapWithPanel: false, // panel wrapWithPanel: false, // panel
controls: [ controls: [
{ {
type: 'text', type: 'text',
placeholder: '关键字', placeholder: '关键字',
name: 'keywords', name: 'keywords',
addOn: { addOn: {
type: 'submit', type: 'submit',
label: '搜索', label: '搜索',
primary: true primary: true
} }
}, },
'<span class="text-danger">请在此输入内容后点击搜索</sapn>' '<span class="text-danger">请在此输入内容后点击搜索</sapn>'
] ]
}, },
body: { body: {
name: 'detailForm', name: 'detailForm',
type: 'form', type: 'form',
mode: 'horizontal', mode: 'horizontal',
title: '', title: '',
initApi: '/api/mock2/form/initData?keywords=${keywords}', initApi: '/api/mock2/form/initData?keywords=${keywords}',
actions: [], actions: [],
controls: [ controls: [
'Form 模型除了用来提交数据外,还比较适合用来做详情数据的展示', 'Form 模型除了用来提交数据外,还比较适合用来做详情数据的展示',
{ {
type: 'divider' type: 'divider'
}, },
{ {
label: '名称', label: '名称',
type: 'static', type: 'static',
labelClassName: 'text-muted', labelClassName: 'text-muted',
name: 'name' name: 'name'
}, },
{ {
label: '作者', label: '作者',
type: 'static', type: 'static',
labelClassName: 'text-muted', labelClassName: 'text-muted',
name: 'author' name: 'author'
}, },
{ {
label: '输入信息', label: '输入信息',
type: 'static', type: 'static',
labelClassName: 'text-muted', labelClassName: 'text-muted',
name: 'info' name: 'info'
}, },
{ {
label: '请求时间', label: '请求时间',
type: 'static-datetime', type: 'static-datetime',
labelClassName: 'text-muted', labelClassName: 'text-muted',
format: 'YYYY-MM-DD HH:mm:ss', format: 'YYYY-MM-DD HH:mm:ss',
name: 'date' name: 'date'
} }
] ]
} }
} };

View File

@ -1,306 +1,305 @@
export default { export default {
type: 'page', type: 'page',
title: '表单初始数据自动重新拉取', title: '表单初始数据自动重新拉取',
body: [ body: [
{
type: 'form',
mode: 'horizontal',
title: '监听表单内部的修改',
initApi: '/api/mock2/form/initData?tpl=${tpl}',
actions: [],
controls: [
'<span class="text-danger">当 <code>initApi</code> 中有变量,且变量的值发生了变化了,则该表单就会重新初始数据。</span>',
{ {
type: 'form', type: 'divider'
mode: 'horizontal',
title: '监听表单内部的修改',
initApi: '/api/mock2/form/initData?tpl=${tpl}',
actions: [],
controls: [
'<span class="text-danger">当 <code>initApi</code> 中有变量,且变量的值发生了变化了,则该表单就会重新初始数据。</span>',
{
type: 'divider'
},
{
label: '数据模板',
type: 'select',
labelClassName: 'text-muted',
name: 'tpl',
value: 'tpl1',
inline: true,
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
],
description: '<span class="text-danger">请修改这里看效果</span>'
},
{
label: '名称',
type: 'static',
labelClassName: 'text-muted',
name: 'name'
},
{
label: '作者',
type: 'static',
labelClassName: 'text-muted',
name: 'author'
},
{
label: '请求时间',
type: 'static-datetime',
labelClassName: 'text-muted',
format: 'YYYY-MM-DD HH:mm:ss',
name: 'date'
}
]
},
{
type: 'grid',
columns: [
{
type: 'form',
mode: 'horizontal',
title: '自动填充',
actions: [],
controls: [
{
label: '数据模板',
type: 'select',
labelClassName: 'text-muted',
name: 'tpl',
value: 'tpl1',
inline: true,
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
],
description: '<span class="text-danger">请修改这里看效果</span>'
},
'<div class="text-danger m-b">如果 <code>initApi</code> 已经暂用,用 <code>service</code>一样可以拉取值填充,同样以下 api 值发生变化时会自动填充。</div>',
{
type: 'service',
api: '/api/mock2/form/initData?tpl=${tpl}',
body: {
controls: [
{
label: '名称',
type: 'text',
labelClassName: 'text-muted',
name: 'name'
},
{
label: '作者',
type: 'text',
labelClassName: 'text-muted',
name: 'author'
},
{
label: '请求时间',
type: 'datetime',
labelClassName: 'text-muted',
inputFormat: 'YYYY-MM-DD HH:mm:ss',
name: 'date'
}
]
}
}
]
},
{
type: 'form',
mode: 'horizontal',
title: '手动填充',
actions: [],
controls: [
{
type: 'group',
label: '数据模板',
labelClassName: 'text-muted',
controls: [
{
type: 'select',
name: 'tpl',
value: 'tpl1',
mode: 'inline',
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
]
},
{
mode: 'inline',
type: 'button',
label: '获取',
level: 'dark',
actionType: 'reload',
target: 'theService'
}
]
},
'<div class="text-danger m-b">如果不想自动填充,自动填充,则把参数放在 data 里面,就不会监控变化自动拉取了,同时把 <code>servcie</code> 的初始拉取关掉,然后来个刷新目标组件的按钮。</div>',
{
type: 'service',
name: 'theService',
api: {
method: 'get',
url: '/api/mock2/form/initData',
data: {
tpl: '${tpl}'
}
},
body: {
controls: [
{
label: '名称',
type: 'text',
labelClassName: 'text-muted',
name: 'name'
},
{
label: '作者',
type: 'text',
labelClassName: 'text-muted',
name: 'author'
},
{
label: '请求时间',
type: 'datetime',
labelClassName: 'text-muted',
inputFormat: 'YYYY-MM-DD HH:mm:ss',
name: 'date'
}
]
}
}
]
}
]
}, },
{ {
type: 'divider' label: '数据模板',
type: 'select',
labelClassName: 'text-muted',
name: 'tpl',
value: 'tpl1',
inline: true,
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
],
description: '<span class="text-danger">请修改这里看效果</span>'
}, },
{ {
type: 'form', label: '名称',
title: '条件表单', type: 'static',
target: 'detailForm', labelClassName: 'text-muted',
submitOnInit: true, name: 'name'
mode: 'inline',
controls: [
{
label: '数据模板',
type: 'select',
labelClassName: 'text-muted',
name: 'tpl',
value: 'tpl1',
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
]
},
{
type: 'submit',
label: '提交',
primary: true
}
]
}, },
{ {
name: 'detailForm', label: '作者',
type: 'form', type: 'static',
mode: 'horizontal', labelClassName: 'text-muted',
title: '响应表单', name: 'author'
initApi: '/api/mock2/form/initData?tpl=${tpl}', },
initFetchOn: 'data.tpl',
actions: [], {
controls: [ label: '请求时间',
'<span class="text-danger">当 <code>initApi</code> 中有变量,且变量的值发生了变化了,则该表单就会重新初始数据。</span>', type: 'static-datetime',
{ labelClassName: 'text-muted',
type: 'divider' format: 'YYYY-MM-DD HH:mm:ss',
}, name: 'date'
{
label: '名称',
type: 'static',
labelClassName: 'text-muted',
name: 'name'
},
{
label: '作者',
type: 'static',
labelClassName: 'text-muted',
name: 'author'
},
{
label: '请求时间',
type: 'static-datetime',
labelClassName: 'text-muted',
format: 'YYYY-MM-DD HH:mm:ss',
name: 'date'
}
]
} }
] ]
} },
{
type: 'grid',
columns: [
{
type: 'form',
mode: 'horizontal',
title: '自动填充',
actions: [],
controls: [
{
label: '数据模板',
type: 'select',
labelClassName: 'text-muted',
name: 'tpl',
value: 'tpl1',
inline: true,
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
],
description: '<span class="text-danger">请修改这里看效果</span>'
},
'<div class="text-danger m-b">如果 <code>initApi</code> 已经暂用,用 <code>service</code>一样可以拉取值填充,同样以下 api 值发生变化时会自动填充。</div>',
{
type: 'service',
api: '/api/mock2/form/initData?tpl=${tpl}',
body: {
controls: [
{
label: '名称',
type: 'text',
labelClassName: 'text-muted',
name: 'name'
},
{
label: '作者',
type: 'text',
labelClassName: 'text-muted',
name: 'author'
},
{
label: '请求时间',
type: 'datetime',
labelClassName: 'text-muted',
inputFormat: 'YYYY-MM-DD HH:mm:ss',
name: 'date'
}
]
}
}
]
},
{
type: 'form',
mode: 'horizontal',
title: '手动填充',
actions: [],
controls: [
{
type: 'group',
label: '数据模板',
labelClassName: 'text-muted',
controls: [
{
type: 'select',
name: 'tpl',
value: 'tpl1',
mode: 'inline',
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
]
},
{
mode: 'inline',
type: 'button',
label: '获取',
level: 'dark',
actionType: 'reload',
target: 'theService'
}
]
},
'<div class="text-danger m-b">如果不想自动填充,自动填充,则把参数放在 data 里面,就不会监控变化自动拉取了,同时把 <code>servcie</code> 的初始拉取关掉,然后来个刷新目标组件的按钮。</div>',
{
type: 'service',
name: 'theService',
api: {
method: 'get',
url: '/api/mock2/form/initData',
data: {
tpl: '${tpl}'
}
},
body: {
controls: [
{
label: '名称',
type: 'text',
labelClassName: 'text-muted',
name: 'name'
},
{
label: '作者',
type: 'text',
labelClassName: 'text-muted',
name: 'author'
},
{
label: '请求时间',
type: 'datetime',
labelClassName: 'text-muted',
inputFormat: 'YYYY-MM-DD HH:mm:ss',
name: 'date'
}
]
}
}
]
}
]
},
{
type: 'divider'
},
{
type: 'form',
title: '条件表单',
target: 'detailForm',
submitOnInit: true,
mode: 'inline',
controls: [
{
label: '数据模板',
type: 'select',
labelClassName: 'text-muted',
name: 'tpl',
value: 'tpl1',
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
]
},
{
type: 'submit',
label: '提交',
primary: true
}
]
},
{
name: 'detailForm',
type: 'form',
mode: 'horizontal',
title: '响应表单',
initApi: '/api/mock2/form/initData?tpl=${tpl}',
initFetchOn: 'data.tpl',
actions: [],
controls: [
'<span class="text-danger">当 <code>initApi</code> 中有变量,且变量的值发生了变化了,则该表单就会重新初始数据。</span>',
{
type: 'divider'
},
{
label: '名称',
type: 'static',
labelClassName: 'text-muted',
name: 'name'
},
{
label: '作者',
type: 'static',
labelClassName: 'text-muted',
name: 'author'
},
{
label: '请求时间',
type: 'static-datetime',
labelClassName: 'text-muted',
format: 'YYYY-MM-DD HH:mm:ss',
name: 'date'
}
]
}
]
};

View File

@ -1,60 +1,60 @@
export default { export default {
type: 'page', type: 'page',
title: '表单选线之间的远程联动', title: '表单选线之间的远程联动',
body: { body: {
type: 'form', type: 'form',
mode: 'horizontal', mode: 'horizontal',
title: '', title: '',
actions: [], actions: [],
controls: [ controls: [
'<p class="text-danger">表单选项可以设置 source 通过 API 远程拉取,同时如果 source 中有变量的话,变量值发生变化就会重新拉取,达到联动效果。</p>', '<p class="text-danger">表单选项可以设置 source 通过 API 远程拉取,同时如果 source 中有变量的话,变量值发生变化就会重新拉取,达到联动效果。</p>',
{ {
type: 'divider' type: 'divider'
}, },
{ {
label: '选项1', label: '选项1',
type: 'select', type: 'select',
labelClassName: 'text-muted', labelClassName: 'text-muted',
name: 'a', name: 'a',
inline: true, inline: true,
options: [ options: [
{ {
label: '选项1', label: '选项1',
value: 1 value: 1
}, },
{ {
label: '选项2', label: '选项2',
value: 2 value: 2
}, },
{ {
label: '选项3', label: '选项3',
value: 3 value: 3
} }
]
},
{
label: '选项2',
type: 'select',
labelClassName: 'text-muted',
name: 'b',
inline: true,
source: '/api/mock2/options/level2?a=${a}',
initFetchOn: 'data.a'
},
{
label: '选项3',
type: 'select',
labelClassName: 'text-muted',
name: 'c',
inline: true,
visibleOn: 'data.b',
source: '/api/mock2/options/level3?b=${b}'
},
] ]
} },
}
{
label: '选项2',
type: 'select',
labelClassName: 'text-muted',
name: 'b',
inline: true,
source: '/api/mock2/options/level2?a=${a}',
initFetchOn: 'data.a'
},
{
label: '选项3',
type: 'select',
labelClassName: 'text-muted',
name: 'c',
inline: true,
visibleOn: 'data.b',
source: '/api/mock2/options/level3?b=${b}'
}
]
}
};

View File

@ -1,68 +1,68 @@
export default { export default {
type: 'page', type: 'page',
title: '表单选线的联动', title: '表单选线的联动',
body: { body: {
type: 'form', type: 'form',
mode: 'horizontal', mode: 'horizontal',
title: '', title: '',
actions: [], actions: [],
controls: [ controls: [
'<p class="text-danger">表单选项内也能联动,通过配置 visibleOn、hiddenOn或者disabledOn</p>', '<p class="text-danger">表单选项内也能联动,通过配置 visibleOn、hiddenOn或者disabledOn</p>',
{ {
type: 'divider' type: 'divider'
}, },
{ {
label: '选项1', label: '选项1',
type: 'list', type: 'list',
multiple: false, multiple: false,
labelClassName: 'text-muted', labelClassName: 'text-muted',
name: 'a', name: 'a',
inline: true, inline: true,
options: [ options: [
{ {
label: '选项1', label: '选项1',
value: 1 value: 1
}, },
{ {
label: '选项2', label: '选项2',
value: 2 value: 2
}, },
{ {
label: '选项3', label: '选项3',
value: 3 value: 3
} }
]
},
{
label: '选项2',
type: 'radios',
labelClassName: 'text-muted',
name: 'b',
inline: true,
options: [
{
label: '选项1',
value: 1,
disabledOn: 'data.a == 1'
},
{
label: '选项2',
value: 2,
hiddenOn: 'data.a == 2'
},
{
label: '选项3',
value: 3,
visibleOn: 'data.a == 3'
}
]
}
] ]
} },
}
{
label: '选项2',
type: 'radios',
labelClassName: 'text-muted',
name: 'b',
inline: true,
options: [
{
label: '选项1',
value: 1,
disabledOn: 'data.a == 1'
},
{
label: '选项2',
value: 2,
hiddenOn: 'data.a == 2'
},
{
label: '选项3',
value: 3,
visibleOn: 'data.a == 3'
}
]
}
]
}
};

View File

@ -1,49 +1,49 @@
export default { export default {
$schema: "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
type: 'page', type: 'page',
title: "地址栏变化自动更新", title: '地址栏变化自动更新',
initApi: '/api/mock2/form/initData?id=${id}', initApi: '/api/mock2/form/initData?id=${id}',
aside: { aside: {
type: 'wrapper', type: 'wrapper',
size: 'xs', size: 'xs',
className: '', className: '',
body: { body: {
type: 'nav', type: 'nav',
stacked: true, stacked: true,
links: [ links: [
{ {
label: '页面1', label: '页面1',
to: '?id=1' to: '?id=1'
}, },
{ {
label: '页面2', label: '页面2',
children: [ children: [
{ {
label: '页面2-1', label: '页面2-1',
to: '?id=2-1', to: '?id=2-1'
}, },
{ {
label: '页面2-2', label: '页面2-2',
to: '?id=2-2', to: '?id=2-2'
}, },
{ {
label: '页面2-3disabled', label: '页面2-3disabled',
disabled: true, disabled: true,
to: '?id=2-3', to: '?id=2-3'
}, }
] ]
}, },
{ {
label: '页面3', label: '页面3',
to: '?id=3' to: '?id=3'
}
]
} }
}, ]
body: [ }
'<p><span class="text-danger">注意 page 渲染器的 `initApi` 中有变量跟地址栏中变量关联,只要值发生了变化,就会重新拉取一次 initApi。</sapn></p>', },
"<p>这些数据是通过 initApi 拉取到的数据。 `\\$infoId`: <span class=\"text-danger\">${infoId|default:空}</span></p>" body: [
] '<p><span class="text-danger">注意 page 渲染器的 `initApi` 中有变量跟地址栏中变量关联,只要值发生了变化,就会重新拉取一次 initApi。</sapn></p>',
'<p>这些数据是通过 initApi 拉取到的数据。 `\\$infoId`: <span class="text-danger">${infoId|default:空}</span></p>'
]
}; };

View File

@ -11,180 +11,220 @@ import NestedLinks from '../../src/components/AsideNav';
import {Portal} from 'react-overlays'; import {Portal} from 'react-overlays';
class CodePreview extends React.Component { class CodePreview extends React.Component {
state = { state = {
PlayGround: null PlayGround: null
}; };
componentDidMount() { componentDidMount() {
require(['./Play'], (component) => this.setState({ require(['./Play'], component =>
PlayGround: component.default this.setState({
})) PlayGround: component.default
} }));
}
render() { render() {
const { const {
container, container,
height, height,
setAsideFolded, setAsideFolded,
setHeaderVisible, setHeaderVisible,
...rest ...rest
} = this.props; } = this.props;
const PlayGround = this.state.PlayGround; const PlayGround = this.state.PlayGround;
// .markdown-body Overlay // .markdown-body Overlay
return ( return (
<div> <div>
<span style={{display: 'block', height: height}} ref="span"></span> <span style={{display: 'block', height: height}} ref="span" />
{PlayGround ? <Overlay {PlayGround ? (
container={container} <Overlay
target={() => this.refs.span} container={container}
placement="bottom" target={() => this.refs.span}
show placement="bottom"
> show
<PopOver offset={{x: 0, y: -height}} style={{height}} className="doc-shcema-preview-popover"> >
<div className="doc-schema-preview"> <PopOver
<PlayGround {...rest} vertical /> offset={{x: 0, y: -height}}
</div> style={{height}}
</PopOver> className="doc-shcema-preview-popover"
</Overlay> : null } >
</div> <div className="doc-schema-preview">
); <PlayGround {...rest} vertical />
} </div>
</PopOver>
</Overlay>
) : null}
</div>
);
}
} }
function isActive(link, location) { function isActive(link, location) {
return !!(link.fullPath && link.fullPath === location.hash); return !!(link.fullPath && link.fullPath === location.hash);
} }
export default function(doc) { export default function(doc) {
return class extends React.Component { return class extends React.Component {
static displayName = 'MarkdownRenderer'; static displayName = 'MarkdownRenderer';
ref = null; ref = null;
doms = []; doms = [];
constructor(props) { constructor(props) {
super(props); super(props);
this.divRef = this.divRef.bind(this); this.divRef = this.divRef.bind(this);
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
}
componentDidMount() {
this.renderSchema();
if (location.hash && location.hash.length > 1) {
//
if (window.history && 'scrollRestoration' in window.history) {
window.history.scrollRestoration = 'manual';
}
const dom = document.querySelector(`[name="${location.hash.substring(1)}"]`);
dom && dom.scrollIntoView();
}
}
componentDidUpdate() {
this.renderSchema();
}
componentWillUnmount() {
this.doms.forEach(dom => ReactDOM.unmountComponentAtNode(dom));
}
handleClick(e) {
const href = e.target.getAttribute('href');
if (href && href[0] !== '#' && !/^http/.test(href)) {
e.preventDefault();
this.props.push(href);
}
}
divRef(ref) {
this.ref = ref;
if (ref) {
ref.innerHTML = doc.html;
}
}
renderSchema() {
const scripts = document.querySelectorAll('script[type="text/schema"]');
if (!scripts && !scripts.length) {
return;
}
for (let i = 0, len = scripts.length; i < len; i++) {
let script = scripts[i];
let props = {};
[].slice.apply(script.attributes).forEach(item => {
props[item.name] = item.value
});
let dom = document.createElement('div');
let height = props.height ? parseInt(props.height, 10) : 200;
dom.setAttribute("class", "doc-play-ground")
dom.setAttribute("style", `height: ${height}px;`);
script.parentNode.replaceChild(dom, script);
this.doms.push(dom);
ReactDOM.unstable_renderSubtreeIntoContainer(this, (
<LazyComponent
{...this.props}
container={() => ReactDOM.findDOMNode(this)}
height={height}
component={CodePreview}
code={script.innerText}
scope={props.scope}
unMountOnHidden
placeholder="加载中,请稍后。。。"
/>
), dom);
}
}
render() {
const {location} = this.props;
return (
<div className="pos-rlt text-left">
{doc.title ? (<TitleBar title={doc.title} />) : null}
<div className="markdown-body" ref={this.divRef}>Doc</div>
{doc.toc && doc.toc.children && doc.toc.children.length > 1 ? (
<Portal
container={() => document.querySelector('#asideInner')}
>
<NestedLinks
navigations={[doc.toc]}
renderLink={({link, active, toggleExpand, depth, classnames: cx}) => {
let children = [];
if (link.children) {
children.push(
<span
key="expand-toggle"
className={cx(`AsideNav-itemArrow`)}
></span>
);
}
link.badge && children.push(
<b key="badge" className={cx('AsideNav-itemBadge', link.badgeClassName || 'bg-info')}>{link.badge}</b>
);
depth === 1 && children.push(
<i key="icon" className={cx("AsideNav-itemIcon fa fa-flag")} />
);
children.push(
<span key="label" className={cx("AsideNav-itemLabel")}>{link.label}</span>
);
return link.fragment ? (<a href={`#${link.fragment}`}>{children}</a>) : (<a onClick={link.children ? () => toggleExpand(link) : null}>{children}</a>);
}}
isActive={link => isActive(link, location)}
/>
</Portal>
) : null}
</div>
);
}
} }
componentDidMount() {
this.renderSchema();
if (location.hash && location.hash.length > 1) {
//
if (window.history && 'scrollRestoration' in window.history) {
window.history.scrollRestoration = 'manual';
}
const dom = document.querySelector(
`[name="${location.hash.substring(1)}"]`
);
dom && dom.scrollIntoView();
}
}
componentDidUpdate() {
this.renderSchema();
}
componentWillUnmount() {
this.doms.forEach(dom => ReactDOM.unmountComponentAtNode(dom));
}
handleClick(e) {
const href = e.target.getAttribute('href');
if (href && href[0] !== '#' && !/^http/.test(href)) {
e.preventDefault();
this.props.push(href);
}
}
divRef(ref) {
this.ref = ref;
if (ref) {
ref.innerHTML = doc.html;
}
}
renderSchema() {
const scripts = document.querySelectorAll('script[type="text/schema"]');
if (!scripts && !scripts.length) {
return;
}
for (let i = 0, len = scripts.length; i < len; i++) {
let script = scripts[i];
let props = {};
[].slice.apply(script.attributes).forEach(item => {
props[item.name] = item.value;
});
let dom = document.createElement('div');
let height = props.height ? parseInt(props.height, 10) : 200;
dom.setAttribute('class', 'doc-play-ground');
dom.setAttribute('style', `height: ${height}px;`);
script.parentNode.replaceChild(dom, script);
this.doms.push(dom);
ReactDOM.unstable_renderSubtreeIntoContainer(
this,
<LazyComponent
{...this.props}
container={() => ReactDOM.findDOMNode(this)}
height={height}
component={CodePreview}
code={script.innerText}
scope={props.scope}
unMountOnHidden
placeholder="加载中,请稍后。。。"
/>,
dom
);
}
}
render() {
const {location} = this.props;
return (
<div className="pos-rlt text-left">
{doc.title ? <TitleBar title={doc.title} /> : null}
<div className="markdown-body" ref={this.divRef}>
Doc
</div>
{doc.toc && doc.toc.children && doc.toc.children.length > 1 ? (
<Portal container={() => document.querySelector('#asideInner')}>
<NestedLinks
navigations={[doc.toc]}
renderLink={({
link,
active,
toggleExpand,
depth,
classnames: cx
}) => {
let children = [];
if (link.children) {
children.push(
<span
key="expand-toggle"
className={cx(`AsideNav-itemArrow`)}
/>
);
}
link.badge &&
children.push(
<b
key="badge"
className={cx(
'AsideNav-itemBadge',
link.badgeClassName || 'bg-info'
)}
>
{link.badge}
</b>
);
depth === 1 &&
children.push(
<i
key="icon"
className={cx('AsideNav-itemIcon fa fa-flag')}
/>
);
children.push(
<span key="label" className={cx('AsideNav-itemLabel')}>
{link.label}
</span>
);
return link.fragment ? (
<a href={`#${link.fragment}`}>{children}</a>
) : (
<a
onClick={link.children ? () => toggleExpand(link) : null}
>
{children}
</a>
);
}}
isActive={link => isActive(link, location)}
/>
</Portal>
) : null}
</div>
);
}
};
} }

View File

@ -1,27 +1,27 @@
export default { export default {
type: 'page', type: 'page',
title: '标题', title: '标题',
remark: '提示 Tip', remark: '提示 Tip',
body: [ body: [
` `
<p>\`initApi\` 拉取失败时,页面内容区会显示对应的错误信息。</p> <p>\`initApi\` 拉取失败时,页面内容区会显示对应的错误信息。</p>
<p>其他提示示例</p> <p>其他提示示例</p>
`, `,
{ {
type: 'alert', type: 'alert',
level: 'success', level: 'success',
body: `温馨提示:对页面功能的提示说明,绿色为正向类的消息提示` body: `温馨提示:对页面功能的提示说明,绿色为正向类的消息提示`
}, },
{ {
type: 'alert', type: 'alert',
level: 'warning', level: 'warning',
body: `您的私有网络已达到配额,如需更多私有网络,可以通过<a>工单</a>申请` body: `您的私有网络已达到配额,如需更多私有网络,可以通过<a>工单</a>申请`
} }
], ],
aside: '边栏', aside: '边栏',
toolbar: '工具栏', toolbar: '工具栏',
initApi: '/api/mock2/page/initDataError' initApi: '/api/mock2/page/initDataError'
} };

View File

@ -1,23 +1,23 @@
export default { export default {
type: 'page', type: 'page',
title: '表单页面', title: '表单页面',
body: { body: {
type: 'form', type: 'form',
mode: 'horizontal', mode: 'horizontal',
title: '', title: '',
api: '/api/mock2/form/saveForm', api: '/api/mock2/form/saveForm',
controls: [ controls: [
{ {
label: 'Name', label: 'Name',
type: 'text', type: 'text',
name: 'name' name: 'name'
}, },
{ {
label: 'Email', label: 'Email',
type: 'email', type: 'email',
name: 'email' name: 'email'
} }
] ]
} }
} };

View File

@ -1,9 +1,9 @@
export default { export default {
type: 'page', type: 'page',
title: '标题', title: '标题',
remark: '提示 Tip', remark: '提示 Tip',
body: "内容部分. 可以使用 \\${var} 获取变量。如: `\\$date`: ${date}", body: '内容部分. 可以使用 \\${var} 获取变量。如: `\\$date`: ${date}',
aside: '边栏部分', aside: '边栏部分',
toolbar: '工具栏', toolbar: '工具栏',
initApi: '/api/mock2/page/initData' initApi: '/api/mock2/page/initData'
} };

View File

@ -1,7 +1,5 @@
import React from 'react'; import React from 'react';
import { import {toast} from '../../src/components/Toast';
toast
} from '../../src/components/Toast';
import {render} from '../../src/index'; import {render} from '../../src/index';
import axios from 'axios'; import axios from 'axios';
import Frame from 'react-frame-component'; import Frame from 'react-frame-component';
@ -18,14 +16,14 @@ const DEFAULT_CONTENT = `{
}`; }`;
const scopes = { const scopes = {
'none': ``, none: ``,
'body': `{ body: `{
"type": "page", "type": "page",
"body": SCHEMA_PLACEHOLDER "body": SCHEMA_PLACEHOLDER
}`, }`,
'form': `{ form: `{
"type": "page", "type": "page",
"body": { "body": {
"title": "", "title": "",
@ -39,7 +37,7 @@ const scopes = {
} }
}`, }`,
'form-item': `{ 'form-item': `{
"type": "page", "type": "page",
"body": { "body": {
"title": "", "title": "",
@ -53,229 +51,247 @@ const scopes = {
"actions": [] "actions": []
} }
}` }`
}; };
export default class PlayGround extends React.Component { export default class PlayGround extends React.Component {
state = null;
startX = 0;
oldContents = '';
frameTemplate;
state = null; static defaultProps = {
startX = 0; useIFrame: false,
oldContents = ''; vertical: false
frameTemplate; };
static defaultProps = { constructor(props) {
useIFrame: false, super(props);
vertical: false
const schema = this.buildSchema(props.code || DEFAULT_CONTENT, props);
this.state = {
asideWidth: props.asideWidth || Math.max(300, window.innerWidth * 0.3),
schema: schema,
schemaCode: JSON.stringify(schema, null, 2)
}; };
constructor(props) { this.handleMouseDown = this.handleMouseDown.bind(this);
super(props); this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
const schema = this.buildSchema(props.code || DEFAULT_CONTENT, props); this.removeWindowEvents = this.removeWindowEvents.bind(this);
this.state = { this.handleChange = this.handleChange.bind(this);
asideWidth: props.asideWidth || Math.max(300, window.innerWidth * 0.3), this.schemaProps = {
schema: schema, style: {
schemaCode: JSON.stringify(schema, null, 2) height: '100%'
}
};
this.env = {
updateLocation: () => {},
fetcher: config => {
config = {
dataType: 'json',
...config
}; };
this.handleMouseDown = this.handleMouseDown.bind(this); if (config.dataType === 'json' && config.data) {
this.handleMouseMove = this.handleMouseMove.bind(this); config.data = JSON.stringify(config.data);
this.handleMouseUp = this.handleMouseUp.bind(this); config.headers = config.headers || {};
this.removeWindowEvents = this.removeWindowEvents.bind(this); config.headers['Content-Type'] = 'application/json';
this.handleChange = this.handleChange.bind(this);
this.schemaProps = {
style: {
height: '100%'
}
};
this.env = {
updateLocation: () => {
},
fetcher: config => {
config = {
dataType: 'json',
...config
};
if (config.dataType === 'json' && config.data) {
config.data = JSON.stringify(config.data)
config.headers = config.headers || {};
config.headers['Content-Type'] = 'application/json';
}
return axios[config.method](config.url, config.data, config);
},
notify: (type, msg) => toast[type] ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息') : console.warn('[Notify]', type, msg)
} }
const links = [].slice.call(document.head.querySelectorAll('link,style')).map(item => item.outerHTML); return axios[config.method](config.url, config.data, config);
this.frameTemplate = `<!DOCTYPE html><html><head>${links.join('')}</head><body><div></div></body></html>`; },
notify: (type, msg) =>
toast[type]
? toast[type](msg, type === 'error' ? '系统错误' : '系统消息')
: console.warn('[Notify]', type, msg)
};
const links = [].slice
.call(document.head.querySelectorAll('link,style'))
.map(item => item.outerHTML);
this.frameTemplate = `<!DOCTYPE html><html><head>${links.join(
''
)}</head><body><div></div></body></html>`;
}
componentWillReceiveProps(nextprops) {
const props = this.props;
if (props.code !== nextprops.code) {
const schema = this.buildSchema(
nextprops.code || DEFAULT_CONTENT,
nextprops
);
this.setState({
schema: schema,
schemaCode: JSON.stringify(schema, null, 2)
});
} }
}
componentWillReceiveProps(nextprops) { componentDidMount() {
const props = this.props; this.props.setAsideFolded && this.props.setAsideFolded(true);
}
if (props.code !== nextprops.code) { componentWillUnmount() {
const schema = this.buildSchema(nextprops.code || DEFAULT_CONTENT, nextprops); this.props.setAsideFolded && this.props.setAsideFolded(false);
this.setState({ }
schema: schema,
schemaCode: JSON.stringify(schema, null, 2)
});
}
}
componentDidMount() { buildSchema(schemaContent, props = this.props) {
this.props.setAsideFolded && this.props.setAsideFolded(true); const query = props.location.query;
}
componentWillUnmount() { try {
this.props.setAsideFolded && this.props.setAsideFolded(false); const scope = query.scope || props.scope;
}
buildSchema(schemaContent, props = this.props) { if (scope && scopes[scope]) {
const query = props.location.query; schemaContent = scopes[scope].replace(
'SCHEMA_PLACEHOLDER',
try { schemaContent
const scope = query.scope || props.scope;
if (scope && scopes[scope]) {
schemaContent = scopes[scope].replace('SCHEMA_PLACEHOLDER', schemaContent);
}
schemaContent = stripJsonComments(schemaContent).replace(/('|")raw:/g, '$1'); //
return JSON.parse(schemaContent);
} catch (e) {
console.error(this.formatMessage(e.message, schemaContent));
}
return {};
}
formatMessage(message, input) {
if (/position\s?(\d+)$/.test(message)) {
const lines = input.substring(0, parseInt(RegExp.$1, 10)).split(/\n|\r\n|\r/);
message = `Json 语法错误,请检测。出错位置:${lines.length},列:${lines[lines.length -1].length}`;
}
return message;
}
renderPreview() {
const schema = this.state.schema;
if (!this.props.useIFrame) {
return render(schema, this.schemaProps, this.env);
}
return (
<Frame
width="100%"
height="100%"
frameBorder={0}
initialContent={this.frameTemplate}
>
{render(schema, this.schemaProps, this.env)}
</Frame>
); );
}
schemaContent = stripJsonComments(schemaContent).replace(
/('|")raw:/g,
'$1'
); //
return JSON.parse(schemaContent);
} catch (e) {
console.error(this.formatMessage(e.message, schemaContent));
} }
handleChange(value) { return {};
this.setState({ }
schemaCode: value
});
try { formatMessage(message, input) {
const schema = JSON.parse(value); if (/position\s?(\d+)$/.test(message)) {
const lines = input
this.setState({ .substring(0, parseInt(RegExp.$1, 10))
schema .split(/\n|\r\n|\r/);
}); message = `Json 语法错误,请检测。出错位置:${lines.length},列:${
} catch (e) { lines[lines.length - 1].length
//ignore }`;
}
} }
handleMouseDown(e) { return message;
this.startX = e.clientX; }
this.startWidth = this.state.asideWidth;
// this.startPosition.y = e.clientY; renderPreview() {
const schema = this.state.schema;
window.addEventListener('mouseup', this.handleMouseUp); if (!this.props.useIFrame) {
window.addEventListener('mousemove', this.handleMouseMove); return render(schema, this.schemaProps, this.env);
return false;
} }
handleMouseMove(e) { return (
const diff = this.startX - e.clientX; <Frame
e.preventDefault(); width="100%"
height="100%"
frameBorder={0}
initialContent={this.frameTemplate}
>
{render(schema, this.schemaProps, this.env)}
</Frame>
);
}
this.setState({ handleChange(value) {
asideWidth: Math.min(800, Math.max(200, this.startWidth + diff)) this.setState({
}); schemaCode: value
});
try {
const schema = JSON.parse(value);
this.setState({
schema
});
} catch (e) {
//ignore
} }
}
handleMouseUp() { handleMouseDown(e) {
this.removeWindowEvents(); this.startX = e.clientX;
} this.startWidth = this.state.asideWidth;
removeWindowEvents() { // this.startPosition.y = e.clientY;
window.removeEventListener('mouseup', this.handleMouseUp);
window.removeEventListener('mousemove', this.handleMouseMove);
}
renderEditor() { window.addEventListener('mouseup', this.handleMouseUp);
return ( window.addEventListener('mousemove', this.handleMouseMove);
<CodeEditor return false;
value={this.state.schemaCode} }
onChange={this.handleChange}
language="json"
/>
);
}
render() { handleMouseMove(e) {
const { const diff = this.startX - e.clientX;
vertical e.preventDefault();
} = this.props;
if (vertical) {
return (
<div className="vbox">
<div className="row-row">
<div className="cell pos-rlt">
<div className="scroll-y h-full pos-abt w-full">
{this.renderPreview()}
</div>
</div>
</div>
<div className="row-row" style={{height: 200}}>
<div className="cell">
{this.renderEditor()}
</div>
</div>
</div>
);
}
return ( this.setState({
<div style={{ asideWidth: Math.min(800, Math.max(200, this.startWidth + diff))
position: "absolute", });
top: 50, }
bottom: 0
}}> handleMouseUp() {
<div className="hbox"> this.removeWindowEvents();
<div className="col pos-rlt"> }
<div className="scroll-y h-full pos-abt w-full">
{this.renderPreview()} removeWindowEvents() {
</div> window.removeEventListener('mouseup', this.handleMouseUp);
</div> window.removeEventListener('mousemove', this.handleMouseMove);
<div className="col bg-light lter b-l bg-auto pos-rlt" style={{width: this.state.asideWidth}}> }
<div className="resizer" onMouseDown={this.handleMouseDown}></div>
{this.renderEditor()} renderEditor() {
</div> return (
</div> <CodeEditor
value={this.state.schemaCode}
onChange={this.handleChange}
language="json"
/>
);
}
render() {
const {vertical} = this.props;
if (vertical) {
return (
<div className="vbox">
<div className="row-row">
<div className="cell pos-rlt">
<div className="scroll-y h-full pos-abt w-full">
{this.renderPreview()}
</div>
</div> </div>
); </div>
<div className="row-row" style={{height: 200}}>
<div className="cell">{this.renderEditor()}</div>
</div>
</div>
);
} }
return (
<div
style={{
position: 'absolute',
top: 50,
bottom: 0
}}
>
<div className="hbox">
<div className="col pos-rlt">
<div className="scroll-y h-full pos-abt w-full">
{this.renderPreview()}
</div>
</div>
<div
className="col bg-light lter b-l bg-auto pos-rlt"
style={{width: this.state.asideWidth}}
>
<div className="resizer" onMouseDown={this.handleMouseDown} />
{this.renderEditor()}
</div>
</div>
</div>
);
}
} }

View File

@ -3,187 +3,207 @@ import {render} from '../../src/index';
import axios from 'axios'; import axios from 'axios';
import {toast} from '../../src/components/Toast'; import {toast} from '../../src/components/Toast';
import {alert, confirm} from '../../src/components/Alert'; import {alert, confirm} from '../../src/components/Alert';
import Button from '../../src/components/Button' import Button from '../../src/components/Button';
import LazyComponent from '../../src/components/LazyComponent' import LazyComponent from '../../src/components/LazyComponent';
import {default as DrawerContainer} from '../../src/components/Drawer' import {default as DrawerContainer} from '../../src/components/Drawer';
import { Portal } from 'react-overlays'; import {Portal} from 'react-overlays';
import {withRouter} from 'react-router'; import {withRouter} from 'react-router';
function loadEditor() { function loadEditor() {
return new Promise((resolve) => require(['../../src/components/Editor'], (component) => resolve(component.default))); return new Promise(resolve =>
require(['../../src/components/Editor'], component =>
resolve(component.default))
);
} }
export default function(schema) { export default function(schema) {
if (!schema['$schema']) { if (!schema['$schema']) {
schema = { schema = {
'$schema': 'https://houtai.baidu.com/v2/schemas/page.json', $schema: 'https://houtai.baidu.com/v2/schemas/page.json',
...schema ...schema
}; };
} }
return withRouter(
return withRouter(class extends React.Component { class extends React.Component {
static displayName = 'SchemaRenderer'; static displayName = 'SchemaRenderer';
state = {open: false}; state = {open: false};
toggleCode = () => this.setState({ toggleCode = () =>
open: !this.state.open this.setState({
open: !this.state.open
}); });
close = () => this.setState({ close = () =>
open: false this.setState({
open: false
}); });
constructor(props) { constructor(props) {
super(props); super(props);
const {router} = props; const {router} = props;
const normalizeLink = (to) => { const normalizeLink = to => {
to = to || ''; to = to || '';
const location = router.getCurrentLocation(); const location = router.getCurrentLocation();
if (to && to[0] === '#') { if (to && to[0] === '#') {
to = location.pathname + location.search + to; to = location.pathname + location.search + to;
} else if (to && to[0] === '?') { } else if (to && to[0] === '?') {
to = location.pathname + to; to = location.pathname + to;
} }
const idx = to.indexOf('?'); const idx = to.indexOf('?');
const idx2 = to.indexOf('#'); const idx2 = to.indexOf('#');
let pathname = ~idx ? to.substring(0, idx) : ~idx2 ? to.substring(0, idx2) : to; let pathname = ~idx
let search = ~idx ? to.substring(idx, ~idx2 ? idx2 : undefined) : ''; ? to.substring(0, idx)
let hash = ~idx2 ? to.substring(idx2) : ''; : ~idx2
? to.substring(0, idx2)
if (!pathname) { : to;
pathname = location.pathname; let search = ~idx ? to.substring(idx, ~idx2 ? idx2 : undefined) : '';
} else if (pathname[0] != '/' && !/^https?:\/\//.test(pathname)) { let hash = ~idx2 ? to.substring(idx2) : '';
let relativeBase = location.pathname;
const paths = relativeBase.split('/'); if (!pathname) {
paths.pop(); pathname = location.pathname;
let m; } else if (pathname[0] != '/' && !/^https?:\/\//.test(pathname)) {
while ((m = /^\.\.?\//.exec(pathname))) { let relativeBase = location.pathname;
if (m[0] === '../') { const paths = relativeBase.split('/');
paths.pop(); paths.pop();
} let m;
pathname = pathname.substring(m[0].length); while ((m = /^\.\.?\//.exec(pathname))) {
} if (m[0] === '../') {
pathname = paths.concat(pathname).join('/'); paths.pop();
} }
pathname = pathname.substring(m[0].length);
return pathname + search + hash;
} }
this.env = { pathname = paths.concat(pathname).join('/');
updateLocation: (location, replace) => { }
router[replace ? 'replace' : 'push'](normalizeLink(location));
},
isCurrentUrl: (to) => {
const link = normalizeLink(to);
return router.isActive(link);
},
jumpTo: (to) => {
to = normalizeLink(to);
if (/^https?:\/\//.test(to)) {
window.location.replace(to);
} else {
router.push(to);
}
},
fetcher: ({
url,
method,
data,
config
}) => {
if (data && data instanceof FormData) {
// config.headers = config.headers || {};
// config.headers['Content-Type'] = 'multipart/form-data';
} else if (data
&& typeof data !== 'string'
&& !(data instanceof Blob)
&& !(data instanceof ArrayBuffer)
) {
data = JSON.stringify(data);
config = config || {};
config.headers = config.headers || {};
config.headers['Content-Type'] = 'application/json';
}
if (method !== 'post' && method !== 'put' && method !== 'patch') { return pathname + search + hash;
if (data) { };
if (method === 'delete') { this.env = {
config.data = data; updateLocation: (location, replace) => {
} else { router[replace ? 'replace' : 'push'](normalizeLink(location));
config.params = data; },
} isCurrentUrl: to => {
} const link = normalizeLink(to);
return router.isActive(link);
},
jumpTo: to => {
to = normalizeLink(to);
return axios[method](url, config); if (/^https?:\/\//.test(to)) {
} window.location.replace(to);
} else {
router.push(to);
}
},
fetcher: ({url, method, data, config}) => {
if (data && data instanceof FormData) {
// config.headers = config.headers || {};
// config.headers['Content-Type'] = 'multipart/form-data';
} else if (
data &&
typeof data !== 'string' &&
!(data instanceof Blob) &&
!(data instanceof ArrayBuffer)
) {
data = JSON.stringify(data);
config = config || {};
config.headers = config.headers || {};
config.headers['Content-Type'] = 'application/json';
}
return axios[method](url, data, config); if (method !== 'post' && method !== 'put' && method !== 'patch') {
}, if (data) {
isCancel: value => axios.isCancel(value), if (method === 'delete') {
notify: (type, msg) => toast[type] ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息') : console.warn('[Notify]', type, msg), config.data = data;
alert, } else {
confirm, config.params = data;
copy: (content) => console.log('Copy', content) }
}; }
this.handleEditorMount = this.handleEditorMount.bind(this); return axios[method](url, config);
} }
handleEditorMount(editor, monaco) { return axios[method](url, data, config);
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({ },
enableSchemaRequest: true, isCancel: value => axios.isCancel(value),
validate: true notify: (type, msg) =>
}); toast[type]
} ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息')
: console.warn('[Notify]', type, msg),
alert,
confirm,
copy: content => console.log('Copy', content)
};
renderCode() { this.handleEditorMount = this.handleEditorMount.bind(this);
return ( }
<LazyComponent
getComponent={loadEditor}
editorDidMount={this.handleEditorMount}
language="json"
value={schema}
placeholder="加载中,请稍后。。。"
disabled
/>
);
}
renderSchema() { handleEditorMount(editor, monaco) {
const { monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
router, enableSchemaRequest: true,
location, validate: true
theme });
} = this.props; }
return render(schema, { renderCode() {
location, return (
theme <LazyComponent
}, this.env); getComponent={loadEditor}
} editorDidMount={this.handleEditorMount}
language="json"
value={schema}
placeholder="加载中,请稍后。。。"
disabled
/>
);
}
render() { renderSchema() {
const ns = this.props.classPrefix; const {router, location, theme} = this.props;
const showCode = this.props.showCode;
return ( return render(
<div className="schema-wrapper"> schema,
{showCode !== false ? ( {
<DrawerContainer location,
classPrefix={ns} theme
size="lg" },
onHide={this.close} this.env
show={this.state.open} );
position="left" }
>
{this.state.open ? this.renderCode() : null} render() {
</DrawerContainer> const ns = this.props.classPrefix;
) : null } const showCode = this.props.showCode;
{this.renderSchema()} return (
{showCode !== false ? ( <div className="schema-wrapper">
<Portal container={() => document.querySelector('.navbar-nav')}> {showCode !== false ? (
<Button classPrefix={ns} onClick={this.toggleCode} active={this.state.open} iconOnly tooltip="查看源码" level="link" placement="bottom" className="view-code"><i className="fa fa-code" /></Button> <DrawerContainer
</Portal> classPrefix={ns}
) : null} size="lg"
</div> onHide={this.close}
); show={this.state.open}
} position="left"
}); >
{this.state.open ? this.renderCode() : null}
</DrawerContainer>
) : null}
{this.renderSchema()}
{showCode !== false ? (
<Portal container={() => document.querySelector('.navbar-nav')}>
<Button
classPrefix={ns}
onClick={this.toggleCode}
active={this.state.open}
iconOnly
tooltip="查看源码"
level="link"
placement="bottom"
className="view-code"
>
<i className="fa fa-code" />
</Button>
</Portal>
) : null}
</div>
);
}
}
);
} }

View File

@ -2,89 +2,93 @@ import React from 'react';
import TitleBar from '../../../src/components/TitleBar'; import TitleBar from '../../../src/components/TitleBar';
import {render} from '../../../src/index'; import {render} from '../../../src/index';
export default class SdkTest extends React.Component { export default class SdkTest extends React.Component {
state = { state = {
data: { data: {
name: 'Amis Renderer', name: 'Amis Renderer',
id: 1, id: 1,
email: 'xxx@xxx.com' email: 'xxx@xxx.com'
}
};
renderForm() {
return render({
title: '',
type: 'form',
controls: [
{
type: 'text',
name: 'name',
label: 'Name'
},
{
type: 'text',
name: 'id',
label: 'Id'
},
{
type: 'email',
name: 'email',
label: 'Email'
},
{
type: 'static',
label: '最后更新时间',
name: 'lastModified'
}
]
}, {
data: this.state.data,
onFailed: (reason, errors) => {
console.log('Submit Failed', errors, '\n', reason);
},
onSubmit: (values) => {
console.log('Submit', values);
},
onChange: (values, diff) => {
this.setState({
data: {
...values,
lastModified: new Date()
}
});
console.log('Diff', diff);
},
});
} }
};
handleClick = () => { renderForm() {
this.setState({ return render(
{
title: '',
type: 'form',
controls: [
{
type: 'text',
name: 'name',
label: 'Name'
},
{
type: 'text',
name: 'id',
label: 'Id'
},
{
type: 'email',
name: 'email',
label: 'Email'
},
{
type: 'static',
label: '最后更新时间',
name: 'lastModified'
}
]
},
{
data: this.state.data,
onFailed: (reason, errors) => {
console.log('Submit Failed', errors, '\n', reason);
},
onSubmit: values => {
console.log('Submit', values);
},
onChange: (values, diff) => {
this.setState({
data: { data: {
name: 'Amis Renderer', ...values,
id: Math.round(Math.random() * 1000), lastModified: new Date()
email: 'xxx@xxx.com'
} }
}) });
};
render() { console.log('Diff', diff);
return ( }
<div> }
<TitleBar title="API 调用 集成在你的 React 应用中" /> );
<div className="wrapper"> }
{this.renderForm()}
<button onClick={this.handleClick}>随机修改</button> handleClick = () => {
this.setState({
data: {
name: 'Amis Renderer',
id: Math.round(Math.random() * 1000),
email: 'xxx@xxx.com'
}
});
};
<h3>当前值</h3> render() {
<pre><code>{JSON.stringify(this.state.data, null, 2)}</code></pre> return (
</div> <div>
</div> <TitleBar title="API 调用 集成在你的 React 应用中" />
); <div className="wrapper">
} {this.renderForm()}
<button onClick={this.handleClick}>随机修改</button>
<h3>当前值</h3>
<pre>
<code>{JSON.stringify(this.state.data, null, 2)}</code>
</pre>
</div>
</div>
);
}
} }

View File

@ -1,118 +1,118 @@
export default { export default {
type: 'page', type: 'page',
title: '动态加载数据', title: '动态加载数据',
body: [ body: [
'<span class="text-danger">除了用 Page、CRUD、Form 或者 Wizard 能拉取数据外,还可以通过 Service 专门拉取数据,然后丢给其他类型的渲染器渲染。</span>', '<span class="text-danger">除了用 Page、CRUD、Form 或者 Wizard 能拉取数据外,还可以通过 Service 专门拉取数据,然后丢给其他类型的渲染器渲染。</span>',
{
type: 'form',
title: '条件输入',
className: 'm-t',
wrapWithPanel: false,
target: 'service1',
mode: 'inline',
controls: [
{
type: 'text',
name: 'keywords',
placeholder: '关键字',
addOn: {
type: 'button',
icon: 'fa fa-search',
actionType: 'submit',
level: 'primary'
}
}
]
},
{
name: 'service1',
type: 'service',
className: 'm-t',
api: '/api/mock2/service/data?keywords=${keywords}',
body: [
'当前关键字是 ${keywords},当前时间是: ${date|date:YYYY-MM-DD HH\\:mm}',
{ {
type: 'form', type: 'table',
title: '条件输入', className: 'm-t',
className: 'm-t', source: '${table1}',
wrapWithPanel: false, columns: [
target: 'service1', {
mode: 'inline', name: 'id',
controls: [ label: 'ID',
{ type: 'text'
type: 'text', },
name: 'keywords', {
placeholder: '关键字', name: 'text',
addOn: { label: '文本',
type: 'button', type: 'text'
icon: 'fa fa-search', },
actionType: 'submit', {
level: 'primary' type: 'image',
} label: '图片',
} name: 'image',
] popOver: {
title: '查看大图',
body:
'<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
}
},
{
name: 'date',
type: 'date',
label: '日期'
}
]
}, },
{ {
name: 'service1', type: 'table',
type: 'service', source: '${table2}',
className: 'm-t', columns: [
api: '/api/mock2/service/data?keywords=${keywords}', {
body: [ name: 'progress',
'当前关键字是 ${keywords},当前时间是: ${date|date:YYYY-MM-DD HH\\:mm}', label: '进度',
type: 'progress'
},
{
name: 'boolean',
label: '状态',
type: 'status'
},
{
name: 'boolean',
label: '开关',
type: 'switch'
// readOnly: false //
},
{
name: 'type',
label: '映射',
type: 'mapping',
map: {
'*': '其他:${type}',
'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>"
}
},
{
{ name: 'list',
type: 'table', type: 'list',
className: 'm-t', label: 'List',
source: '${table1}', placeholder: '-',
columns: [ listItem: {
{ title: '${title}',
name: "id", subTitle: '${description}'
label: "ID", }
type: "text" }
}, ]
{
name: "text",
label: "文本",
type: "text"
},
{
type: 'image',
label: '图片',
name: 'image',
popOver: {
title: '查看大图',
body: '<div class="w-xxl"><img class="w-full" src="${image}"/></div>'
}
},
{
name: 'date',
type: 'date',
label: '日期'
}
]
},
{
type: 'table',
source: '${table2}',
columns: [
{
name: "progress",
label: "进度",
type: "progress"
},
{
name: "boolean",
label: "状态",
type: "status"
},
{
name: "boolean",
label: "开关",
type: "switch",
// readOnly: false //
},
{
name: "type",
label: "映射",
type: "mapping",
map: {
"*": "其他:${type}",
"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>"
}
},
{
name: 'list',
type: 'list',
label: 'List',
placeholder: '-',
listItem: {
title: '${title}',
subTitle: '${description}'
}
}
]
}
]
} }
] ]
} }
]
};

View File

@ -1,68 +1,68 @@
export default { export default {
type: 'page', type: 'page',
title: '动态加载表单中的部分', title: '动态加载表单中的部分',
body: [ body: [
'<span class="text-danger">同样通过 <code>service</code>的<code>schemaApi</code> 来加载部分内容,当然也可以全部由它来加载</span>', '<span class="text-danger">同样通过 <code>service</code>的<code>schemaApi</code> 来加载部分内容,当然也可以全部由它来加载</span>',
{
type: 'form',
panelClassName: 'Panel--info m-t',
target: 'service1',
mode: 'horizontal',
api: '/api/mock2/form/saveForm?waitSeconds=1',
fieldSet: [
{
title: '基本信息',
controls: [
{
type: 'text',
label: '字段一',
name: 'filed1'
},
{
type: 'text',
label: '字段二',
name: 'filed2'
}
]
},
{ {
type: 'form', title: '其他信息',
panelClassName: 'Panel--info m-t', controls: [
target: 'service1', {
mode: 'horizontal', name: 'tpl',
api: '/api/mock2/form/saveForm?waitSeconds=1', type: 'select',
fieldSet: [ label: '模板',
inline: true,
required: true,
value: 'tpl1',
options: [
{ {
title: '基本信息', label: '模板1',
controls: [ value: 'tpl1'
{
type: 'text',
label: '字段一',
name: 'filed1',
},
{
type: 'text',
label: '字段二',
name: 'filed2'
}
]
}, },
{ {
title: '其他信息', label: '模板2',
controls: [ value: 'tpl2'
{ },
name: 'tpl', {
type: 'select', label: '模板3',
label: '模板', value: 'tpl3'
inline: true,
required: true,
value: 'tpl1',
options: [
{
label: '模板1',
value: 'tpl1'
},
{
label: '模板2',
value: 'tpl2'
},
{
label: '模板3',
value: 'tpl3'
}
]
},
{
type: 'service',
className: 'm-t',
initFetchSchemaOn: 'data.tpl',
schemaApi: '/api/mock2/service/form?tpl=$tpl',
}
]
} }
] ]
},
{
type: 'service',
className: 'm-t',
initFetchSchemaOn: 'data.tpl',
schemaApi: '/api/mock2/service/form?tpl=$tpl'
}
]
} }
] ]
} }
]
};

View File

@ -1,50 +1,50 @@
export default { export default {
type: 'page', type: 'page',
title: '动态加载页面', title: '动态加载页面',
body: [ body: [
'<span class="text-danger">可以通过 <code>service</code>的<code>schemaApi</code> 动态控制内容。</span>', '<span class="text-danger">可以通过 <code>service</code>的<code>schemaApi</code> 动态控制内容。</span>',
{
type: 'form',
title: '条件输入',
panelClassName: 'panel-info m-t',
target: 'service1',
mode: 'inline',
submitOnInit: true,
controls: [
{ {
type: 'form', label: '加载页面类型',
title: '条件输入', required: true,
panelClassName: 'panel-info m-t', type: 'button-group',
target: 'service1', submitOnChange: true,
mode: 'inline', value: 'crud',
submitOnInit: true, name: 'type',
controls: [ options: [
{ {
label: '加载页面类型', label: 'Crud',
required: true, value: 'crud'
type: 'button-group', },
submitOnChange: true,
value: 'crud',
name: 'type',
options: [
{
label: 'Crud',
value: 'crud'
},
{ {
label: 'Form', label: 'Form',
value: 'form' value: 'form'
}, },
{ {
label: 'Tabs', label: 'Tabs',
value: 'tabs' value: 'tabs'
} }
] ]
}
]
},
{
name: 'service1',
type: 'service',
className: 'm-t',
initFetchSchema: false,
schemaApi: '/api/mock2/service/schema?type=$type',
} }
] ]
} },
{
name: 'service1',
type: 'service',
className: 'm-t',
initFetchSchema: false,
schemaApi: '/api/mock2/service/schema?type=$type'
}
]
};

View File

@ -1,47 +1,48 @@
export default { export default {
type: 'page', type: 'page',
title: '表单中选项卡分组', title: '表单中选项卡分组',
subTitle: '', subTitle: '',
body: [ body: [
'<p>多个 controls 可以通过 tabs 来分组展示,表单将作为一个整体提交。</p>', '<p>多个 controls 可以通过 tabs 来分组展示,表单将作为一个整体提交。</p>',
{
type: 'form',
title: '',
tabs: [
{ {
type: 'form', title: '选项卡1',
title: '', hash: 'tab1',
tabs: [ controls: [
{ {
title: '选项卡1', type: 'text',
hash: 'tab1', label: '文本1',
controls: [ name: 'a'
{
type: 'text',
label: '文本1',
name: 'a'
}
]
},
{
title: '选项卡2',
hash: 'tab2',
controls: [
{
type: 'text',
label: '文本2',
name: 'b'
}
]
},
{
title: '选项卡3',
hash: 'tab3',
controls: [
{
type: 'text',
label: '文本3',
name: 'c'
}
]
} }
] ]
}] },
} {
title: '选项卡2',
hash: 'tab2',
controls: [
{
type: 'text',
label: '文本2',
name: 'b'
}
]
},
{
title: '选项卡3',
hash: 'tab3',
controls: [
{
type: 'text',
label: '文本3',
name: 'c'
}
]
}
]
}
]
};

View File

@ -1,165 +1,163 @@
export default { export default {
type: 'page', type: 'page',
title: '选项卡示例', title: '选项卡示例',
subTitle: '所有选项卡都在当前页面中包括默认、line、card以及radio模式', subTitle: '所有选项卡都在当前页面中包括默认、line、card以及radio模式',
body: [ body: [
{
type: 'tabs',
tabs: [
{ {
type: 'tabs', title: '选项卡1',
tabs: [ hash: 'tab1',
{ body: '选项卡内容1'
title: '选项卡1', },
hash: 'tab1',
body: '选项卡内容1'
},
{ {
title: '选项卡2', title: '选项卡2',
hash: 'tab2', hash: 'tab2',
body: { body: {
type: 'form', type: 'form',
panelClassName: 'panel-primary', panelClassName: 'panel-primary',
controls: [ controls: [
{ {
type: 'text', type: 'text',
name: 'a', name: 'a',
label: '文本' label: '文本'
} }
]
}
},
{
title: '选项卡3',
body: {
type: "crud",
api: "/api/sample",
filter: {
title: "条件搜索",
submitText: "",
controls: [
{
type: "text",
name: "keywords",
placeholder: "通过关键字搜索",
clearable: true,
addOn: {
label: "搜索",
type: "submit"
}
},
{
type: "plain",
text: "这里的表单项可以配置多个"
}
]
},
columns: [
{
name: "id",
label: "ID",
width: 20
},
{
name: "engine",
label: "Rendering engine"
},
{
name: "browser",
label: "Browser"
},
{
name: "platform",
label: "Platform(s)"
},
{
name: "version",
label: "Engine version"
},
{
name: "grade",
label: "CSS grade"
},
{
type: "operation",
label: "操作",
width: 100,
buttons: [
]
}
]
}
}
] ]
}
}, },
{
type: 'divider'
},
{
type: 'tabs',
mode: 'line',
tabs: [
{
title: '选项卡1',
body: '选项卡内容1'
},
{
title: '选项卡3',
body: {
type: 'crud',
api: '/api/sample',
filter: {
title: '条件搜索',
submitText: '',
controls: [
{ {
title: '选项卡2', type: 'text',
body: '选项卡内容2' name: 'keywords',
placeholder: '通过关键字搜索',
clearable: true,
addOn: {
label: '搜索',
type: 'submit'
}
}, },
{ {
title: '选项卡3', type: 'plain',
body: '选项卡内容3' text: '这里的表单项可以配置多个'
} }
]
},
columns: [
{
name: 'id',
label: 'ID',
width: 20
},
{
name: 'engine',
label: 'Rendering engine'
},
{
name: 'browser',
label: 'Browser'
},
{
name: 'platform',
label: 'Platform(s)'
},
{
name: 'version',
label: 'Engine version'
},
{
name: 'grade',
label: 'CSS grade'
},
{
type: 'operation',
label: '操作',
width: 100,
buttons: []
}
] ]
}, }
}
]
},
{
type: 'divider'
},
{
type: 'tabs',
mode: 'line',
tabs: [
{ {
type: 'divider' title: '选项卡1',
body: '选项卡内容1'
}, },
{ {
type: 'tabs', title: '选项卡2',
mode: 'card', body: '选项卡内容2'
tabs: [
{
title: '选项卡1',
body: '选项卡内容1'
},
{
title: '选项卡2',
body: '选项卡内容2'
},
{
title: '选项卡3',
body: '选项卡内容3'
}
]
}, },
{ {
type: 'divider' title: '选项卡3',
}, body: '选项卡内容3'
}
]
},
{
type: 'divider'
},
{
type: 'tabs',
mode: 'card',
tabs: [
{ {
type: 'tabs', title: '选项卡1',
mode: 'radio', body: '选项卡内容1'
tabs: [
{
title: '选项卡1',
body: '选项卡内容1'
},
{
title: '选项卡2',
body: '选项卡内容2'
},
{
title: '选项卡3',
body: '选项卡内容3'
}
]
}, },
]
} {
title: '选项卡2',
body: '选项卡内容2'
},
{
title: '选项卡3',
body: '选项卡内容3'
}
]
},
{
type: 'divider'
},
{
type: 'tabs',
mode: 'radio',
tabs: [
{
title: '选项卡1',
body: '选项卡内容1'
},
{
title: '选项卡2',
body: '选项卡内容2'
},
{
title: '选项卡3',
body: '选项卡内容3'
}
]
}
]
};

View File

@ -1,35 +1,35 @@
export default { export default {
type: 'page', type: 'page',
title: '选项卡1页面', title: '选项卡1页面',
body: [ body: [
'<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。这样可以让 url 更加友好,而不是只能用 hash。</p>', '<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。这样可以让 url 更加友好,而不是只能用 hash。</p>',
{
type: 'nav',
links: [
{ {
type: 'nav', label: '选项卡1',
links: [ icon: 'fa fa-cloud',
{ to: './tab1'
label: '选项卡1',
icon: 'fa fa-cloud',
to: './tab1'
},
{
label: '选项卡2',
to: './tab2'
},
{
label: '选项卡3',
icon: 'fa fa-youtube',
to: './tab3'
}
]
}, },
{ {
type: 'wrapper', label: '选项卡2',
className: 'wrapper bg-white b-l b-b b-r', to: './tab2'
body: '选项卡1的内容' },
{
label: '选项卡3',
icon: 'fa fa-youtube',
to: './tab3'
} }
] ]
} },
{
type: 'wrapper',
className: 'wrapper bg-white b-l b-b b-r',
body: '选项卡1的内容'
}
]
};

View File

@ -1,35 +1,35 @@
export default { export default {
type: 'page', type: 'page',
title: '选项卡2页面', title: '选项卡2页面',
body: [ body: [
'<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。</p>', '<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。</p>',
{
type: 'nav',
links: [
{ {
type: 'nav', label: '选项卡1',
links: [ icon: 'fa fa-cloud',
{ to: './tab1'
label: '选项卡1',
icon: 'fa fa-cloud',
to: './tab1'
},
{
label: '选项卡2',
to: './tab2'
},
{
label: '选项卡3',
icon: 'fa fa-youtube',
to: './tab3'
}
]
}, },
{ {
type: 'wrapper', label: '选项卡2',
className: 'wrapper bg-white b-l b-b b-r', to: './tab2'
body: '选项卡2的内容' },
{
label: '选项卡3',
icon: 'fa fa-youtube',
to: './tab3'
} }
] ]
} },
{
type: 'wrapper',
className: 'wrapper bg-white b-l b-b b-r',
body: '选项卡2的内容'
}
]
};

View File

@ -1,121 +1,83 @@
export default { export default {
type: 'page', type: 'page',
title: '选项卡3页面', title: '选项卡3页面',
body: [ body: [
'<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。</p>', '<p>也可以多个页面,利用导航<code>nav</code>渲染期模拟 tabs 的效果。</p>',
{
type: 'nav',
links: [
{ {
type: 'nav', label: '选项卡1',
links: [ icon: 'fa fa-cloud',
{ to: './tab1'
label: '选项卡1',
icon: 'fa fa-cloud',
to: './tab1'
},
{
label: '选项卡2',
to: './tab2'
},
{
label: '选项卡3',
icon: 'fa fa-youtube',
to: './tab3'
}
]
}, },
{ {
type: 'wrapper', label: '选项卡2',
className: 'wrapper bg-white b-l b-b b-r', to: './tab2'
body: { },
"type": "chart",
"config": { {
"title": { label: '选项卡3',
"text": "极坐标双数值轴" icon: 'fa fa-youtube',
}, to: './tab3'
"legend": {
"data": [
"line"
]
},
"polar": {
"center": [
"50%",
"54%"
]
},
"tooltip": {
"trigger": "axis",
"axisPointer": {
"type": "cross"
}
},
"angleAxis": {
"type": "value",
"startAngle": 0
},
"radiusAxis": {
"min": 0
},
"series": [
{
"coordinateSystem": "polar",
"name": "line",
"type": "line",
"showSymbol": false,
"data": [
[
0,
0
],
[
0.03487823687206265,
1
],
[
0.06958655048003272,
2
],
[
0.10395584540887964,
3
],
[
0.13781867790849958,
4
],
[
0.17101007166283433,
5
],
[
0.2033683215379001,
6
],
[
0.2347357813929454,
7
],
[
0.26495963211660245,
8
],
[
0.2938926261462365,
9
],
[
0.3213938048432697,
10
]
]
}
],
"animationDuration": 2000
}
}
} }
] ]
} },
{
type: 'wrapper',
className: 'wrapper bg-white b-l b-b b-r',
body: {
type: 'chart',
config: {
title: {
text: '极坐标双数值轴'
},
legend: {
data: ['line']
},
polar: {
center: ['50%', '54%']
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'cross'
}
},
angleAxis: {
type: 'value',
startAngle: 0
},
radiusAxis: {
min: 0
},
series: [
{
coordinateSystem: 'polar',
name: 'line',
type: 'line',
showSymbol: false,
data: [
[0, 0],
[0.03487823687206265, 1],
[0.06958655048003272, 2],
[0.10395584540887964, 3],
[0.13781867790849958, 4],
[0.17101007166283433, 5],
[0.2033683215379001, 6],
[0.2347357813929454, 7],
[0.26495963211660245, 8],
[0.2938926261462365, 9],
[0.3213938048432697, 10]
]
}
],
animationDuration: 2000
}
}
}
]
};

View File

@ -1,36 +1,37 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "异步任务", title: '异步任务',
"body": [ body: [
'<p class="text-danger"></p>', '<p class="text-danger"></p>',
{
type: 'tasks',
name: 'tasks',
items: [
{ {
"type": "tasks", label: 'hive 任务',
"name": "tasks", key: 'hive',
"items": [ status: 4,
{ remark:
"label": "hive 任务", '查看详情<a target="_blank" href="http://www.baidu.com">日志</a>。'
"key": "hive",
"status": 4,
"remark": "查看详情<a target=\"_blank\" href=\"http://www.baidu.com\">日志</a>。"
},
{
"label": "小流量",
"key": "partial",
"status": 4
},
{
"label": "全量",
"key": "full",
"status": 4
}
]
}, },
{ {
"type": "tasks", label: '小流量',
"name": "tasks", key: 'partial',
"className": "b-a bg-white table-responsive m-t", status: 4
"checkApi": "/api/mock2/task" },
{
label: '全量',
key: 'full',
status: 4
} }
] ]
} },
{
type: 'tasks',
name: 'tasks',
className: 'b-a bg-white table-responsive m-t',
checkApi: '/api/mock2/task'
}
]
};

View File

@ -1,46 +1,77 @@
import React from 'react'; import React from 'react';
import Button from '../../src/components/Button'; import Button from '../../src/components/Button';
export default class TestComponent extends React.Component { export default class TestComponent extends React.Component {
render() { render() {
return ( return (
<div className="wrapper"> <div className="wrapper">
<div className="m-b"> <div className="m-b">
<Button className="m-r-xs" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="primary" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="primary" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="secondary" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="secondary" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="success" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="success" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="info" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="info" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="warning" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="warning" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="danger" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="danger" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="light" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="light" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" level="dark" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" level="dark" classPrefix="cxd-">
</div> 按钮
</Button>
</div>
<div className="m-b"> <div className="m-b">
<Button className="m-r-xs" size="xs" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" size="sm" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" size="md" classPrefix="cxd-">
按钮
</Button>
<Button className="m-r-xs" size="lg" classPrefix="cxd-">
按钮
</Button>
</div>
<Button className="m-r-xs" size="xs" classPrefix="cxd-">按钮</Button> <div className="m-b">
<Button className="m-r-xs" size="sm" classPrefix="cxd-">按钮</Button> <Button className="m-r-xs" classPrefix="cxd-">
<Button className="m-r-xs" size="md" classPrefix="cxd-">按钮</Button> <i className="fa fa-cloud" />
<Button className="m-r-xs" size="lg" classPrefix="cxd-">按钮</Button> <span>按钮</span>
</div> </Button>
<Button className="m-r-xs" classPrefix="cxd-">
<div className="m-b"> <span>按钮</span>
<i className="fa fa-cloud" />
<Button className="m-r-xs" classPrefix="cxd-"><i className="fa fa-cloud"/><span>按钮</span></Button> </Button>
<Button className="m-r-xs" classPrefix="cxd-"><span>按钮</span><i className="fa fa-cloud"/></Button> <Button className="m-r-xs" classPrefix="cxd-" iconOnly>
<Button className="m-r-xs" classPrefix="cxd-" iconOnly><i className="fa fa-cloud"/></Button> <i className="fa fa-cloud" />
</div> </Button>
</div> </div>
) </div>
} );
} }
}

View File

@ -1,14 +1,14 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "视频播放器", title: '视频播放器',
"body": [ body: [
'<p class="text-danger">另外还支持直播流, flv 和 hls 格式</p>', '<p class="text-danger">另外还支持直播流, flv 和 hls 格式</p>',
{ {
"type": "video", type: 'video',
"autoPlay": false, autoPlay: false,
"rates": [1.0, 1.5, 2.0], rates: [1.0, 1.5, 2.0],
"src": "https://media.w3.org/2010/05/sintel/trailer_hd.mp4", src: 'https://media.w3.org/2010/05/sintel/trailer_hd.mp4',
"poster": "https://video-react.js.org/assets/poster.png" poster: 'https://video-react.js.org/assets/poster.png'
} }
] ]
} };

View File

@ -1,148 +1,142 @@
export default { export default {
"$schema": "https://houtai.baidu.com/v2/schemas/page.json#", $schema: 'https://houtai.baidu.com/v2/schemas/page.json#',
"title": "表单向导", title: '表单向导',
"body": [ body: [
{
type: 'wizard',
api: '/api/mock2/form/saveForm?waitSeconds=2',
initApi: '/api/mock2/form/initData?waitSeconds=2',
steps: [
{ {
"type": "wizard", title: '第一步',
"api": "/api/mock2/form/saveForm?waitSeconds=2", controls: [
"initApi": "/api/mock2/form/initData?waitSeconds=2", {
"steps": [ name: 'website',
{ label: '网址',
"title": "第一步", type: 'url',
"controls": [ required: true
{ },
"name": "website", {
"label": "网址", name: 'name',
"type": "url", label: '名称',
"required": true type: 'text',
}, required: true
{ }
"name": "name", ]
"label": "名称",
"type": "text",
"required": true
}
]
},
{
"title": "Step 2",
"controls": [
{
"name": "email2",
"label": "邮箱",
"type": "email",
"required": true
}
]
},
{
"title": "Step 3",
"controls": [
"这是最后一步了"
]
}
]
}, },
{ {
"type": "wizard", title: 'Step 2',
"api": "/api/mock2/form/saveForm?waitSeconds=2", controls: [
"mode": "vertical", {
"steps": [ name: 'email2',
{ label: '邮箱',
"title": "第一步", type: 'email',
"controls": [ required: true
{ }
"name": "website", ]
"label": "网址",
"type": "url",
"required": true
},
{
"name": "email",
"label": "邮箱",
"type": "email",
"required": true
}
]
},
{
"title": "Step 2",
"controls": [
{
"name": "email2",
"label": "邮箱",
"type": "email",
"required": true
}
]
},
{
"title": "Step 3",
"controls": [
"这是最后一步了"
]
}
]
}, },
{ {
"type": "wizard", title: 'Step 3',
"steps": [ controls: ['这是最后一步了']
{
"title": "第一步",
"controls": [
{
"name": "website",
"label": "网址",
"type": "url",
"required": true
},
{
"name": "email",
"label": "邮箱",
"type": "email",
"required": true
}
],
"api": "/api/mock2/form/saveForm?waitSeconds=2"
},
{
"title": "第二步",
"controls": [
{
"name": "test1",
"type": "email",
"label": "Email",
"value": "test@test.com"
},
{
"type": "divider"
},
{
"type": "text",
"name": "test2",
"label": "必填示例",
"required": true
},
{
"type": "divider"
},
{
"type": "text",
"name": "test3",
"placeholder": "可选"
}
],
"initApi": "/api/mock2/form/initForm",
"api": "/api/mock2/form/saveForm?waitSeconds=2"
},
{
"title": "确定",
"controls": [
"最后一步了,确认要提交吗?"
],
"api": "/api/mock2/form/saveForm?waitSeconds=2"
}
]
} }
] ]
} },
{
type: 'wizard',
api: '/api/mock2/form/saveForm?waitSeconds=2',
mode: 'vertical',
steps: [
{
title: '第一步',
controls: [
{
name: 'website',
label: '网址',
type: 'url',
required: true
},
{
name: 'email',
label: '邮箱',
type: 'email',
required: true
}
]
},
{
title: 'Step 2',
controls: [
{
name: 'email2',
label: '邮箱',
type: 'email',
required: true
}
]
},
{
title: 'Step 3',
controls: ['这是最后一步了']
}
]
},
{
type: 'wizard',
steps: [
{
title: '第一步',
controls: [
{
name: 'website',
label: '网址',
type: 'url',
required: true
},
{
name: 'email',
label: '邮箱',
type: 'email',
required: true
}
],
api: '/api/mock2/form/saveForm?waitSeconds=2'
},
{
title: '第二步',
controls: [
{
name: 'test1',
type: 'email',
label: 'Email',
value: 'test@test.com'
},
{
type: 'divider'
},
{
type: 'text',
name: 'test2',
label: '必填示例',
required: true
},
{
type: 'divider'
},
{
type: 'text',
name: 'test3',
placeholder: '可选'
}
],
initApi: '/api/mock2/form/initForm',
api: '/api/mock2/form/saveForm?waitSeconds=2'
},
{
title: '确定',
controls: ['最后一步了,确认要提交吗?'],
api: '/api/mock2/form/saveForm?waitSeconds=2'
}
]
}
]
};

View File

@ -1,208 +1,229 @@
import './polyfills/index'; import './polyfills/index';
import React from 'react'; import React from 'react';
import { render as renderReact } from 'react-dom'; import {render as renderReact} from 'react-dom';
import axios from 'axios'; import axios from 'axios';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
import qs from 'qs'; import qs from 'qs';
import { import {
toast, toast,
alert, alert,
confirm, confirm,
ToastComponent, ToastComponent,
AlertComponent, AlertComponent,
render as renderAmis render as renderAmis
} from '../src/index'; } from '../src/index';
export function embed(container: string | HTMLElement, schema: any, data: any, env: any) { export function embed(
if (typeof container === 'string') { container: string | HTMLElement,
container = document.querySelector(container) as HTMLElement; schema: any,
} data: any,
if (!container) { env: any
console.error('选择器不对,页面上没有此元素'); ) {
return; if (typeof container === 'string') {
} else if (container.tagName === 'BODY') { container = document.querySelector(container) as HTMLElement;
let div = document.createElement('div'); }
container.appendChild(div); if (!container) {
container = div; console.error('选择器不对,页面上没有此元素');
} return;
container.classList.add('amis-scope'); } else if (container.tagName === 'BODY') {
let scoped:any; let div = document.createElement('div');
const normalizeLink = (to:string) => { container.appendChild(div);
to = to || ''; container = div;
const location = window.location; }
container.classList.add('amis-scope');
let scoped: any;
const normalizeLink = (to: string) => {
to = to || '';
const location = window.location;
if (to && to[0] === '#') { if (to && to[0] === '#') {
to = location.pathname + location.search + to; to = location.pathname + location.search + to;
} else if (to && to[0] === '?') { } else if (to && to[0] === '?') {
to = location.pathname + to; to = location.pathname + to;
}
const idx = to.indexOf('?');
const idx2 = to.indexOf('#');
let pathname = ~idx ? to.substring(0, idx) : ~idx2 ? to.substring(0, idx2) : to;
let search = ~idx ? to.substring(idx, ~idx2 ? idx2 : undefined) : '';
let hash = ~idx2 ? to.substring(idx2) : '';
if (!pathname) {
pathname = location.pathname;
} else if (pathname[0] != '/' && !/^https?\:\/\//.test(pathname)) {
let relativeBase = location.pathname;
const paths = relativeBase.split('/');
paths.pop();
let m;
while ((m = /^\.\.?\//.exec(pathname))) {
if (m[0] === '../') {
paths.pop();
}
pathname = pathname.substring(m[0].length);
}
pathname = paths.concat(pathname).join('/');
}
return pathname + search + hash;
} }
const responseAdpater = (api:any) => (value:any) => { const idx = to.indexOf('?');
let response = value.data; const idx2 = to.indexOf('#');
if (env && env.responseAdpater) { let pathname = ~idx
const url = api.url; ? to.substring(0, idx)
const idx = api.url.indexOf('?'); : ~idx2
const query = ~idx ? qs.parse(api.url.substring(idx)) : {}; ? to.substring(0, idx2)
const request = { : to;
...api, let search = ~idx ? to.substring(idx, ~idx2 ? idx2 : undefined) : '';
query: query, let hash = ~idx2 ? to.substring(idx2) : '';
body: api.data
};
response = env.responseAdpater(api, response, query, request);
} else {
if (response.hasOwnProperty('errno')) {
response.status = response.errno;
response.msg = response.errmsg;
} else if (response.hasOwnProperty('no')) {
response.status = response.no;
response.msg = response.error;
}
}
const result = { if (!pathname) {
...value, pathname = location.pathname;
data: response } else if (pathname[0] != '/' && !/^https?\:\/\//.test(pathname)) {
let relativeBase = location.pathname;
const paths = relativeBase.split('/');
paths.pop();
let m;
while ((m = /^\.\.?\//.exec(pathname))) {
if (m[0] === '../') {
paths.pop();
} }
return result; pathname = pathname.substring(m[0].length);
}
pathname = paths.concat(pathname).join('/');
}
return pathname + search + hash;
};
const responseAdpater = (api: any) => (value: any) => {
let response = value.data;
if (env && env.responseAdpater) {
const url = api.url;
const idx = api.url.indexOf('?');
const query = ~idx ? qs.parse(api.url.substring(idx)) : {};
const request = {
...api,
query: query,
body: api.data
};
response = env.responseAdpater(api, response, query, request);
} else {
if (response.hasOwnProperty('errno')) {
response.status = response.errno;
response.msg = response.errmsg;
} else if (response.hasOwnProperty('no')) {
response.status = response.no;
response.msg = response.error;
}
}
const result = {
...value,
data: response
}; };
return result;
};
renderReact(( renderReact(
<div className="amis-routes-wrapper"> <div className="amis-routes-wrapper">
<ToastComponent position={env && env.toastPosition || 'top-right'} closeButton={false} timeOut={5000} extendedTimeOut={3000}/> <ToastComponent
<AlertComponent container={container} /> position={(env && env.toastPosition) || 'top-right'}
closeButton={false}
timeOut={5000}
extendedTimeOut={3000}
/>
<AlertComponent container={container} />
{renderAmis(schema, { {renderAmis(
...data, schema,
scopeRef: (ref:any) => scoped = ref {
}, { ...data,
getModalContainer: () => document.querySelector('.amis-scope'), scopeRef: (ref: any) => (scoped = ref)
notify: (type: string, msg: string) => toast[type] ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息') : console.warn('[Notify]', type, msg), },
alert, {
confirm, getModalContainer: () => document.querySelector('.amis-scope'),
updateLocation: (to:any, replace:boolean) => { notify: (type: string, msg: string) =>
if (to === 'goBack') { toast[type]
return window.history.back(); ? toast[type](msg, type === 'error' ? '系统错误' : '系统消息')
} : console.warn('[Notify]', type, msg),
alert,
confirm,
updateLocation: (to: any, replace: boolean) => {
if (to === 'goBack') {
return window.history.back();
}
replace || (location.href = normalizeLink(to)); replace || (location.href = normalizeLink(to));
}, },
isCurrentUrl: (to:string) => { isCurrentUrl: (to: string) => {
const link = normalizeLink(to); const link = normalizeLink(to);
const location = window.location; const location = window.location;
let pathname = link; let pathname = link;
let search = ''; let search = '';
const idx = link.indexOf('?'); const idx = link.indexOf('?');
if (~idx) { if (~idx) {
pathname = link.substring(0, idx); pathname = link.substring(0, idx);
search = link.substring(idx); search = link.substring(idx);
} }
if (search) { if (search) {
if (pathname !== location.pathname || !location.search) { if (pathname !== location.pathname || !location.search) {
return false; return false;
} }
const query = qs.parse(search.substring(1)); const query = qs.parse(search.substring(1));
const currentQuery = qs.parse(location.search.substring(1)); const currentQuery = qs.parse(location.search.substring(1));
return Object.keys(query).every(key => query[key] === currentQuery[key]); return Object.keys(query).every(
} else if (pathname === location.pathname) { key => query[key] === currentQuery[key]
return true; );
} } else if (pathname === location.pathname) {
return true;
}
return false; return false;
}, },
jumpTo: (to:string, action?:any) => { jumpTo: (to: string, action?: any) => {
if (to === 'goBack') { if (to === 'goBack') {
return window.history.back(); return window.history.back();
} }
to = normalizeLink(to); to = normalizeLink(to);
if (action && action.actionType === 'url') { if (action && action.actionType === 'url') {
action.blank === false ? (window.location.href = to) : window.open(to); action.blank === false
return; ? (window.location.href = to)
} : window.open(to);
return;
}
if (/^https?:\/\//.test(to)) { if (/^https?:\/\//.test(to)) {
window.location.replace(to); window.location.replace(to);
} else { } else {
location.href = to; location.href = to;
} }
}, },
fetcher: (api: any) => { fetcher: (api: any) => {
let { let {url, method, data, responseType, config, headers} = api;
url, config = config || {};
method, config.withCredentials = true;
data, responseType && (config.responseType = responseType);
responseType,
config, if (config.cancelExecutor) {
headers config.cancelToken = new (axios as any).CancelToken(
} = api; config.cancelExecutor
config = config || {}; );
config.withCredentials = true; }
responseType && (config.responseType = responseType);
config.headers = headers || {};
if (config.cancelExecutor) { config.method = method;
config.cancelToken = new (axios as any).CancelToken(config.cancelExecutor);
} if (method === 'get' && data) {
config.params = data;
config.headers = headers || {}; } else if (data && data instanceof FormData) {
config.method = method; // config.headers['Content-Type'] = 'multipart/form-data';
} else if (
if (method === 'get' && data) { data &&
config.params = data; typeof data !== 'string' &&
} else if (data && data instanceof FormData) { !(data instanceof Blob) &&
// config.headers['Content-Type'] = 'multipart/form-data'; !(data instanceof ArrayBuffer)
} else if (data ) {
&& typeof data !== 'string' data = JSON.stringify(data);
&& !(data instanceof Blob) config.headers['Content-Type'] = 'application/json';
&& !(data instanceof ArrayBuffer) }
) {
data = JSON.stringify(data); data && (config.data = data);
config.headers['Content-Type'] = 'application/json'; return axios(url, config).then(responseAdpater(api));
} },
isCancel: (value: any) => (axios as any).isCancel(value),
data && (config.data = data); copy: (contents: string, options: any = {}) => {
return axios(url, config) const ret = copy(contents, options);
.then(responseAdpater(api)); ret && options.shutup !== true && toast.info('内容已拷贝到剪切板');
}, return ret;
isCancel: (value: any) => (axios as any).isCancel(value), },
copy: (contents: string, options: any = {}) => { richTextToken: '',
const ret = copy(contents, options); ...env
ret && options.shutup !== true && toast.info('内容已拷贝到剪切板'); }
return ret; )}
}, </div>,
richTextToken: '', container
...env );
})} return scoped;
</div>
), container);
return scoped;
} }

View File

@ -3,12 +3,9 @@
* @author liaoxuezhi@cloud.com * @author liaoxuezhi@cloud.com
*/ */
import React from 'react'; import React from 'react';
import { render } from 'react-dom'; import {render} from 'react-dom';
import App from './components/App'; import App from './components/App';
export function bootstrap(mountTo, initalState) { export function bootstrap(mountTo, initalState) {
render( render(<App />, mountTo);
<App />,
mountTo
);
} }

View File

@ -1,37 +1,36 @@
const __moduleId = (str: string) => ''; const __moduleId = (str: string) => '';
const mapping: { const mapping: {
[propName: string]: any; [propName: string]: any;
} = { } = {
'jquery': __moduleId('jquery'), jquery: __moduleId('jquery'),
'react': __moduleId('react'), react: __moduleId('react'),
'react-dom': __moduleId('react-dom'), 'react-dom': __moduleId('react-dom'),
'react-addons-update': __moduleId('react-addons-update'), 'react-addons-update': __moduleId('react-addons-update'),
'immutability-helper': __moduleId('react-addons-update'), 'immutability-helper': __moduleId('react-addons-update'),
'react-cropper': __moduleId('react-cropper'), 'react-cropper': __moduleId('react-cropper'),
'react-dropzone': __moduleId('react-dropzone'), 'react-dropzone': __moduleId('react-dropzone'),
'classnames': __moduleId('classnames'), classnames: __moduleId('classnames'),
'axios': __moduleId('axios'), axios: __moduleId('axios'),
'moment': __moduleId('moment'), moment: __moduleId('moment'),
'mobx': __moduleId('mobx'), mobx: __moduleId('mobx'),
'mobx-state-tree': __moduleId('mobx-state-tree'), 'mobx-state-tree': __moduleId('mobx-state-tree'),
'react-transition-group': __moduleId('react-transition-group'), 'react-transition-group': __moduleId('react-transition-group'),
'echarts': __moduleId('echarts'), echarts: __moduleId('echarts'),
'zrender': __moduleId('zrender'), zrender: __moduleId('zrender'),
'sortablejs': __moduleId('sortablejs'), sortablejs: __moduleId('sortablejs'),
'amis': __moduleId('../src'), amis: __moduleId('../src'),
'amis/embed': __moduleId('./embed.tsx'), 'amis/embed': __moduleId('./embed.tsx'),
'prop-types': __moduleId('prop-types'), 'prop-types': __moduleId('prop-types'),
'async': __moduleId('async'), async: __moduleId('async'),
'qs': __moduleId('qs') qs: __moduleId('qs')
}; };
function amisRequire(...args: Array<any>) { function amisRequire(...args: Array<any>) {
let id = args.shift(); let id = args.shift();
id = Array.isArray(id) ? id.map(id => mapping[id] || id) : mapping[id] || id; id = Array.isArray(id) ? id.map(id => mapping[id] || id) : mapping[id] || id;
args.unshift(id); args.unshift(id);
return require.apply(this, args); return require.apply(this, args);
}; }
(window as any).amisRequire = amisRequire; (window as any).amisRequire = amisRequire;

View File

@ -1,46 +1,46 @@
// https://tc39.github.io/ecma262/#sec-array.prototype.find // https://tc39.github.io/ecma262/#sec-array.prototype.find
if (!Array.prototype.find) { if (!Array.prototype.find) {
Object.defineProperty(Array.prototype, 'find', { Object.defineProperty(Array.prototype, 'find', {
value: function(predicate) { value: function(predicate) {
// 1. Let O be ? ToObject(this value). // 1. Let O be ? ToObject(this value).
if (this == null) { if (this == null) {
throw new TypeError('"this" is null or not defined'); throw new TypeError('"this" is null or not defined');
}
var o = Object(this);
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0;
// 3. If IsCallable(predicate) is false, throw a TypeError exception.
if (typeof predicate !== 'function') {
throw new TypeError('predicate must be a function');
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
} }
// e. Increase k by 1.
var o = Object(this); k++;
}
// 2. Let len be ? ToLength(? Get(O, "length")).
var len = o.length >>> 0; // 7. Return undefined.
return undefined;
// 3. If IsCallable(predicate) is false, throw a TypeError exception. },
if (typeof predicate !== 'function') { configurable: true,
throw new TypeError('predicate must be a function'); writable: true
} });
}
// 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
var thisArg = arguments[1];
// 5. Let k be 0.
var k = 0;
// 6. Repeat, while k < len
while (k < len) {
// a. Let Pk be ! ToString(k).
// b. Let kValue be ? Get(O, Pk).
// c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
// d. If testResult is true, return kValue.
var kValue = o[k];
if (predicate.call(thisArg, kValue, k, o)) {
return kValue;
}
// e. Increase k by 1.
k++;
}
// 7. Return undefined.
return undefined;
},
configurable: true,
writable: true
});
}

View File

@ -1,77 +1,88 @@
if (!Array.from) { if (!Array.from) {
Array.from = (function () { Array.from = (function() {
var toStr = Object.prototype.toString; var toStr = Object.prototype.toString;
var isCallable = function (fn) { var isCallable = function(fn) {
return typeof fn === 'function' || toStr.call(fn) === '[object Function]'; return typeof fn === 'function' || toStr.call(fn) === '[object Function]';
}; };
var toInteger = function (value) { var toInteger = function(value) {
var number = Number(value); var number = Number(value);
if (isNaN(number)) { return 0; } if (isNaN(number)) {
if (number === 0 || !isFinite(number)) { return number; } return 0;
return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number)); }
}; if (number === 0 || !isFinite(number)) {
var maxSafeInteger = Math.pow(2, 53) - 1; return number;
var toLength = function (value) { }
var len = toInteger(value); return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
return Math.min(Math.max(len, 0), maxSafeInteger); };
}; var maxSafeInteger = Math.pow(2, 53) - 1;
var toLength = function(value) {
// The length property of the from method is 1. var len = toInteger(value);
return function from(arrayLike/*, mapFn, thisArg */) { return Math.min(Math.max(len, 0), maxSafeInteger);
// 1. Let C be the this value. };
var C = this;
// The length property of the from method is 1.
// 2. Let items be ToObject(arrayLike). return function from(arrayLike /*, mapFn, thisArg */) {
var items = Object(arrayLike); // 1. Let C be the this value.
var C = this;
// 3. ReturnIfAbrupt(items).
if (arrayLike == null) { // 2. Let items be ToObject(arrayLike).
throw new TypeError("Array.from requires an array-like object - not null or undefined"); var items = Object(arrayLike);
// 3. ReturnIfAbrupt(items).
if (arrayLike == null) {
throw new TypeError(
'Array.from requires an array-like object - not null or undefined'
);
}
// 4. If mapfn is undefined, then let mapping be false.
var mapFn = arguments.length > 1 ? arguments[1] : void undefined;
var T;
if (typeof mapFn !== 'undefined') {
// 5. else
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
if (!isCallable(mapFn)) {
throw new TypeError(
'Array.from: when provided, the second argument must be a function'
);
} }
// 4. If mapfn is undefined, then let mapping be false. // 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
var mapFn = arguments.length > 1 ? arguments[1] : void undefined; if (arguments.length > 2) {
var T; T = arguments[2];
if (typeof mapFn !== 'undefined') {
// 5. else
// 5. a If IsCallable(mapfn) is false, throw a TypeError exception.
if (!isCallable(mapFn)) {
throw new TypeError('Array.from: when provided, the second argument must be a function');
}
// 5. b. If thisArg was supplied, let T be thisArg; else let T be undefined.
if (arguments.length > 2) {
T = arguments[2];
}
} }
}
// 10. Let lenValue be Get(items, "length").
// 11. Let len be ToLength(lenValue). // 10. Let lenValue be Get(items, "length").
var len = toLength(items.length); // 11. Let len be ToLength(lenValue).
var len = toLength(items.length);
// 13. If IsConstructor(C) is true, then
// 13. a. Let A be the result of calling the [[Construct]] internal method // 13. If IsConstructor(C) is true, then
// of C with an argument list containing the single item len. // 13. a. Let A be the result of calling the [[Construct]] internal method
// 14. a. Else, Let A be ArrayCreate(len). // of C with an argument list containing the single item len.
var A = isCallable(C) ? Object(new C(len)) : new Array(len); // 14. a. Else, Let A be ArrayCreate(len).
var A = isCallable(C) ? Object(new C(len)) : new Array(len);
// 16. Let k be 0.
var k = 0; // 16. Let k be 0.
// 17. Repeat, while k < len… (also steps a - h) var k = 0;
var kValue; // 17. Repeat, while k < len… (also steps a - h)
while (k < len) { var kValue;
kValue = items[k]; while (k < len) {
if (mapFn) { kValue = items[k];
A[k] = typeof T === 'undefined' ? mapFn(kValue, k) : mapFn.call(T, kValue, k); if (mapFn) {
} else { A[k] =
A[k] = kValue; typeof T === 'undefined'
} ? mapFn(kValue, k)
k += 1; : mapFn.call(T, kValue, k);
} else {
A[k] = kValue;
} }
// 18. Let putStatus be Put(A, "length", len, true). k += 1;
A.length = len; }
// 20. Return A. // 18. Let putStatus be Put(A, "length", len, true).
return A; A.length = len;
}; // 20. Return A.
}()); return A;
} };
})();
}

View File

@ -1,29 +1,32 @@
if (typeof Object.assign != 'function') { if (typeof Object.assign != 'function') {
// Must be writable: true, enumerable: false, configurable: true // Must be writable: true, enumerable: false, configurable: true
Object.defineProperty(Object, "assign", { Object.defineProperty(Object, 'assign', {
value: function assign(target, varArgs) { // .length of function is 2 value: function assign(target, varArgs) {
'use strict'; // .length of function is 2
if (target == null) { // TypeError if undefined or null 'use strict';
throw new TypeError('Cannot convert undefined or null to object'); if (target == null) {
// TypeError if undefined or null
throw new TypeError('Cannot convert undefined or null to object');
}
var to = Object(target);
for (var index = 1; index < arguments.length; index++) {
var nextSource = arguments[index];
if (nextSource != null) {
// Skip over if undefined or null
for (var nextKey in nextSource) {
// Avoid bugs when hasOwnProperty is shadowed
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
} }
}
var to = Object(target); }
}
for (var index = 1; index < arguments.length; index++) { return to;
var nextSource = arguments[index]; },
writable: true,
if (nextSource != null) { // Skip over if undefined or null configurable: true
for (var nextKey in nextSource) { });
// Avoid bugs when hasOwnProperty is shadowed }
if (Object.prototype.hasOwnProperty.call(nextSource, nextKey)) {
to[nextKey] = nextSource[nextKey];
}
}
}
}
return to;
},
writable: true,
configurable: true
});
}

View File

@ -3,23 +3,24 @@
* @author mdn * @author mdn
*/ */
if (!Element.prototype.matches) { if (!Element.prototype.matches) {
Element.prototype.matches = Element.prototype.msMatchesSelector Element.prototype.matches =
|| Element.prototype.webkitMatchesSelector; Element.prototype.msMatchesSelector ||
Element.prototype.webkitMatchesSelector;
} }
if (!Element.prototype.closest) { if (!Element.prototype.closest) {
Element.prototype.closest = function (s) { Element.prototype.closest = function(s) {
var el = this; var el = this;
if (!document.documentElement.contains(el)) { if (!document.documentElement.contains(el)) {
return null; return null;
} }
do { do {
if (el.matches(s)) { if (el.matches(s)) {
return el; return el;
} }
el = el.parentElement; el = el.parentElement;
} while (el !== null); } while (el !== null);
return null; return null;
}; };
} }

View File

@ -4,4 +4,4 @@ import './Array.find';
import './cloest'; import './cloest';
import 'promise/polyfill'; import 'promise/polyfill';
import 'es6-symbol/implement'; import 'es6-symbol/implement';

View File

@ -1,6 +1,6 @@
{ {
"name": "amis", "name": "amis",
"version": "1.0.4", "version": "1.0.4-beta.3",
"description": "一种MIS页面生成工具", "description": "一种MIS页面生成工具",
"main": "lib/index.js", "main": "lib/index.js",
"scripts": { "scripts": {
@ -10,7 +10,7 @@
"stop": "fis3 server stop", "stop": "fis3 server stop",
"dev": "fis3 release -cwd ./public", "dev": "fis3 release -cwd ./public",
"publish2npm": "sh publish.sh && npm publish", "publish2npm": "sh publish.sh && npm publish",
"prettier": "prettier --write 'src/**/*.{tsx,ts}'" "prettier": "prettier --write '{src,examples}/**/*.{tsx,ts,jsx}'"
}, },
"repository": { "repository": {
"type": "git", "type": "git",

View File

@ -14,202 +14,218 @@ import {noop, autobind, qsstringify} from './utils/helper';
import {RendererData, Action} from './types'; import {RendererData, Action} from './types';
export interface ScopedComponentType extends React.Component<RendererProps> { export interface ScopedComponentType extends React.Component<RendererProps> {
focus?: () =>void; focus?: () => void;
doAction?: (action: Action, data: RendererData, throwErrors?: boolean) => void; doAction?: (
receive?: (values: RendererData, subPath?: string) => void; action: Action,
reload?: (subPath?: string, query?: RendererData | null, ctx?: RendererData) => void; data: RendererData,
throwErrors?: boolean
) => void;
receive?: (values: RendererData, subPath?: string) => void;
reload?: (
subPath?: string,
query?: RendererData | null,
ctx?: RendererData
) => void;
} }
export interface IScopedContext { export interface IScopedContext {
parent?: AlisIScopedContext; parent?: AlisIScopedContext;
registerComponent: (component: ScopedComponentType) => void; registerComponent: (component: ScopedComponentType) => void;
unRegisterComponent: (component: ScopedComponentType) => void; unRegisterComponent: (component: ScopedComponentType) => void;
getComponentByName: (name: string) => ScopedComponentType | void; getComponentByName: (name: string) => ScopedComponentType | void;
getComponents: () => Array<ScopedComponentType>; getComponents: () => Array<ScopedComponentType>;
reload: (target: string, ctx: RendererData) => void; reload: (target: string, ctx: RendererData) => void;
send: (target: string, ctx: RendererData) => void; send: (target: string, ctx: RendererData) => void;
} }
type AlisIScopedContext = IScopedContext; type AlisIScopedContext = IScopedContext;
export const ScopedContext = React.createContext(createScopedTools('')); export const ScopedContext = React.createContext(createScopedTools(''));
function createScopedTools(path?: string, parent?: AlisIScopedContext, env?: RendererEnv): IScopedContext { function createScopedTools(
const components: Array<ScopedComponentType> = []; path?: string,
parent?: AlisIScopedContext,
env?: RendererEnv
): IScopedContext {
const components: Array<ScopedComponentType> = [];
return { return {
parent, parent,
registerComponent(component: ScopedComponentType) { registerComponent(component: ScopedComponentType) {
// 不要把自己注册在自己的 Scoped 上,自己的 Scoped 是给孩子们注册的。 // 不要把自己注册在自己的 Scoped 上,自己的 Scoped 是给孩子们注册的。
if (component.props.$path === path && parent) { if (component.props.$path === path && parent) {
return parent.registerComponent(component); return parent.registerComponent(component);
} }
if (!~components.indexOf(component)) { if (!~components.indexOf(component)) {
components.push(component); components.push(component);
} }
}, },
unRegisterComponent(component: ScopedComponentType) { unRegisterComponent(component: ScopedComponentType) {
// 自己本身实际上注册在父级 Scoped 上。 // 自己本身实际上注册在父级 Scoped 上。
if (component.props.$path === path && parent) { if (component.props.$path === path && parent) {
return parent.unRegisterComponent(component); return parent.unRegisterComponent(component);
} }
const idx = components.indexOf(component); const idx = components.indexOf(component);
if (~idx) { if (~idx) {
components.splice(idx, 1); components.splice(idx, 1);
} }
}, },
getComponentByName(name: string) { getComponentByName(name: string) {
if (~name.indexOf('.')) { if (~name.indexOf('.')) {
const paths = name.split('.'); const paths = name.split('.');
const len = paths.length; const len = paths.length;
return paths.reduce((scope, name, idx) => { return paths.reduce((scope, name, idx) => {
if (scope && scope.getComponentByName) { if (scope && scope.getComponentByName) {
const result = scope.getComponentByName(name); const result = scope.getComponentByName(name);
return result && idx < len - 1 ? result.context : result; return result && idx < len - 1 ? result.context : result;
} }
return null; return null;
}, this); }, this);
} }
const resolved = find( const resolved = find(
components, components,
component => component.props.name === name || component.props.id === name component =>
); component.props.name === name || component.props.id === name
return resolved || (parent && parent.getComponentByName(name)); );
}, return resolved || (parent && parent.getComponentByName(name));
},
getComponents() { getComponents() {
return components.concat(); return components.concat();
}, },
reload(target: string, ctx: any) { reload(target: string, ctx: any) {
const scoped = this; const scoped = this;
if (target === 'window') { if (target === 'window') {
return location.reload(); return location.reload();
} }
let targets = typeof target === 'string' ? target.split(/\s*,\s*/) : target; let targets =
targets.forEach(name => { typeof target === 'string' ? target.split(/\s*,\s*/) : target;
const idx2 = name.indexOf('?'); targets.forEach(name => {
let query = null; const idx2 = name.indexOf('?');
let query = null;
if (~idx2) { if (~idx2) {
query = dataMapping(qs.parse(name.substring(idx2 + 1)), ctx); query = dataMapping(qs.parse(name.substring(idx2 + 1)), ctx);
name = name.substring(0, idx2); name = name.substring(0, idx2);
}
const idx = name.indexOf('.');
let subPath = '';
if (~idx) {
subPath = name.substring(1 + idx);
name = name.substring(0, idx);
}
const component = scoped.getComponentByName(name);
component && component.reload && component.reload(subPath, query, ctx);
});
},
send(receive: string, values: object) {
const scoped = this;
let receives = typeof receive === 'string' ? receive.split(/\s*,\s*/) : receive;
// todo 没找到做提示!
receives.forEach(name => {
const idx = name.indexOf('.');
let subPath = '';
if (~idx) {
subPath = name.substring(1 + idx);
name = name.substring(0, idx);
}
const component = scoped.getComponentByName(name);
if (component && component.receive) {
component.receive(values, subPath);
} else if (name === 'window' && env && env.updateLocation) {
const query = {
...(location.search ? qs.parse(location.search.substring(1)) : {}),
...values
};
const link = location.pathname + '?' + qsstringify(query);
env.updateLocation(link);
}
});
} }
};
const idx = name.indexOf('.');
let subPath = '';
if (~idx) {
subPath = name.substring(1 + idx);
name = name.substring(0, idx);
}
const component = scoped.getComponentByName(name);
component && component.reload && component.reload(subPath, query, ctx);
});
},
send(receive: string, values: object) {
const scoped = this;
let receives =
typeof receive === 'string' ? receive.split(/\s*,\s*/) : receive;
// todo 没找到做提示!
receives.forEach(name => {
const idx = name.indexOf('.');
let subPath = '';
if (~idx) {
subPath = name.substring(1 + idx);
name = name.substring(0, idx);
}
const component = scoped.getComponentByName(name);
if (component && component.receive) {
component.receive(values, subPath);
} else if (name === 'window' && env && env.updateLocation) {
const query = {
...(location.search ? qs.parse(location.search.substring(1)) : {}),
...values
};
const link = location.pathname + '?' + qsstringify(query);
env.updateLocation(link);
}
});
}
};
} }
export function HocScoped< export function HocScoped<
T extends { T extends {
$path?: string; $path?: string;
env: RendererEnv; env: RendererEnv;
} }
>( >(
ComposedComponent: React.ComponentType<T> ComposedComponent: React.ComponentType<T>
): React.ComponentType< ): React.ComponentType<
T & { T & {
scopeRef?: (ref: any) => void; scopeRef?: (ref: any) => void;
} }
> & { > & {
ComposedComponent: React.ComponentType<T>; ComposedComponent: React.ComponentType<T>;
} { } {
class ScopedComponent extends React.Component< class ScopedComponent extends React.Component<
T & { T & {
scopeRef?: (ref: any) => void; scopeRef?: (ref: any) => void;
} }
> { > {
static displayName = `Scoped(${ComposedComponent.displayName || ComposedComponent.name})`; static displayName = `Scoped(${ComposedComponent.displayName ||
static contextType = ScopedContext; ComposedComponent.name})`;
static ComposedComponent = ComposedComponent; static contextType = ScopedContext;
ref: any; static ComposedComponent = ComposedComponent;
ref: any;
getWrappedInstance() { getWrappedInstance() {
return this.ref; return this.ref;
}
@autobind
childRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.ref = ref;
}
scoped = createScopedTools(this.props.$path, this.context, this.props.env);
componentWillMount() {
const scopeRef = this.props.scopeRef;
scopeRef && scopeRef(this.scoped);
}
componentWillUnmount() {
const scopeRef = this.props.scopeRef;
scopeRef && scopeRef(null);
}
render() {
const {scopeRef, ...rest} = this.props;
return (
<ScopedContext.Provider value={this.scoped}>
<ComposedComponent {...rest as any /* todo */} ref={this.childRef} />
</ScopedContext.Provider>
);
}
} }
hoistNonReactStatic(ScopedComponent, ComposedComponent); @autobind
return ScopedComponent; childRef(ref: any) {
while (ref && ref.getWrappedInstance) {
ref = ref.getWrappedInstance();
}
this.ref = ref;
}
scoped = createScopedTools(this.props.$path, this.context, this.props.env);
componentWillMount() {
const scopeRef = this.props.scopeRef;
scopeRef && scopeRef(this.scoped);
}
componentWillUnmount() {
const scopeRef = this.props.scopeRef;
scopeRef && scopeRef(null);
}
render() {
const {scopeRef, ...rest} = this.props;
return (
<ScopedContext.Provider value={this.scoped}>
<ComposedComponent {...rest as any /* todo */} ref={this.childRef} />
</ScopedContext.Provider>
);
}
}
hoistNonReactStatic(ScopedComponent, ComposedComponent);
return ScopedComponent;
} }
export default HocScoped; export default HocScoped;

View File

@ -16,289 +16,304 @@ import {ServiceRenderer} from './renderers/Form/Service';
// 兼容老的用法,老用法 label 用在 checkbox 的右侧内容,新用法用 option 来代替。 // 兼容老的用法,老用法 label 用在 checkbox 的右侧内容,新用法用 option 来代替。
addSchemaFilter(function CheckboxPropsFilter(schema: Schema, renderer) { addSchemaFilter(function CheckboxPropsFilter(schema: Schema, renderer) {
if (renderer.component !== CheckboxControlRenderer) { if (renderer.component !== CheckboxControlRenderer) {
return schema;
}
if (schema.label && typeof schema.option === 'undefined') {
schema = {
...schema
};
schema.option = schema.label;
delete schema.label;
}
return schema; return schema;
}
if (schema.label && typeof schema.option === 'undefined') {
schema = {
...schema
};
schema.option = schema.label;
delete schema.label;
}
return schema;
}); });
function convertFieldSetTabs2Controls(schema: any) { function convertFieldSetTabs2Controls(schema: any) {
const toUpdate: any = {}; const toUpdate: any = {};
let flag = false; let flag = false;
toUpdate.controls = Array.isArray(schema.controls) ? schema.controls.concat() : []; toUpdate.controls = Array.isArray(schema.controls)
toUpdate.controls = toUpdate.controls.map((control: any) => { ? schema.controls.concat()
if (Array.isArray(control)) { : [];
let converted = convertFieldSetTabs2Controls({ toUpdate.controls = toUpdate.controls.map((control: any) => {
type: 'group', if (Array.isArray(control)) {
controls: control let converted = convertFieldSetTabs2Controls({
}); type: 'group',
controls: control
});
if (converted !== control) { if (converted !== control) {
flag = true; flag = true;
} }
return converted; return converted;
} }
return control; return control;
});
schema.fieldSet &&
(Array.isArray(schema.fieldSet)
? schema.fieldSet
: [schema.fieldSet]
).forEach((fieldSet: any) => {
flag = true;
toUpdate.controls.push({
...convertFieldSetTabs2Controls(fieldSet),
type: 'fieldSet',
collapsable: schema.collapsable
});
}); });
schema.fieldSet && schema.tabs &&
(Array.isArray(schema.fieldSet) ? schema.fieldSet : [schema.fieldSet]).forEach((fieldSet: any) => { (flag = true) &&
flag = true; toUpdate.controls.push({
toUpdate.controls.push({ type: 'tabs',
...convertFieldSetTabs2Controls(fieldSet), tabs: schema.tabs.map((tab: any) => convertFieldSetTabs2Controls(tab))
type: 'fieldSet', });
collapsable: schema.collapsable
});
});
schema.tabs && if (flag) {
(flag = true) && schema = {
toUpdate.controls.push({ ...schema,
type: 'tabs', ...toUpdate
tabs: schema.tabs.map((tab: any) => convertFieldSetTabs2Controls(tab)) };
}); delete schema.fieldSet;
delete schema.tabs;
if (flag) { }
schema = { return schema;
...schema,
...toUpdate
};
delete schema.fieldSet;
delete schema.tabs;
}
return schema;
} }
// Form 中,把 fieldSet 和 tabs 转成 {type: 'fieldSet', controls: []} // Form 中,把 fieldSet 和 tabs 转成 {type: 'fieldSet', controls: []}
// 同时把数组用法转成 {type: 'group', controls: []} // 同时把数组用法转成 {type: 'group', controls: []}
addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) { addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) {
if (renderer.component !== FormRenderer) { if (renderer.component !== FormRenderer) {
return schema; return schema;
} }
if (schema.fieldSet || schema.tabs) { if (schema.fieldSet || schema.tabs) {
// console.warn('Form 下面直接用 fieldSet 或者 tabs 将不支持,请改成在 controls 数组中添加。'); // console.warn('Form 下面直接用 fieldSet 或者 tabs 将不支持,请改成在 controls 数组中添加。');
schema = convertFieldSetTabs2Controls(schema); schema = convertFieldSetTabs2Controls(schema);
} else if (Array.isArray(schema.controls)) { } else if (Array.isArray(schema.controls)) {
let flag = false; let flag = false;
let converted = schema.controls.map((control: any) => { let converted = schema.controls.map((control: any) => {
if (Array.isArray(control)) { if (Array.isArray(control)) {
let converted = convertFieldSetTabs2Controls({ let converted = convertFieldSetTabs2Controls({
type: 'group', type: 'group',
controls: control controls: control
});
if (converted !== control) {
flag = true;
}
return converted;
}
return control;
}); });
if (flag) { if (converted !== control) {
schema = { flag = true;
...schema,
controls: converted
};
} }
} return converted;
}
return control;
});
return schema; if (flag) {
schema = {
...schema,
controls: converted
};
}
}
return schema;
}); });
// FieldSet 中把 controls 里面的数组用法转成 {type: 'group', controls: []} // FieldSet 中把 controls 里面的数组用法转成 {type: 'group', controls: []}
addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) { addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) {
if (renderer.component !== FieldSetRenderer) { if (renderer.component !== FieldSetRenderer) {
return schema; return schema;
} }
if (Array.isArray(schema.controls)) { if (Array.isArray(schema.controls)) {
let flag = false; let flag = false;
let converted = schema.controls.map((control: any) => { let converted = schema.controls.map((control: any) => {
if (Array.isArray(control)) { if (Array.isArray(control)) {
let converted = convertFieldSetTabs2Controls({ let converted = convertFieldSetTabs2Controls({
type: 'group', type: 'group',
controls: control controls: control
});
if (converted !== control) {
flag = true;
}
return converted;
}
return control;
}); });
if (flag) { if (converted !== control) {
schema = { flag = true;
...schema,
controls: converted
};
} }
} return converted;
}
return control;
});
return schema; if (flag) {
schema = {
...schema,
controls: converted
};
}
}
return schema;
}); });
// Form 里面的 Tabs 中把 controls 里面的数组用法转成 {type: 'group', controls: []} // Form 里面的 Tabs 中把 controls 里面的数组用法转成 {type: 'group', controls: []}
addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) { addSchemaFilter(function FormPropsFilter(schema: Schema, renderer) {
if (renderer.component !== TabsRenderer) { if (renderer.component !== TabsRenderer) {
return schema;
}
if (Array.isArray(schema.tabs)) {
let flag = false;
let converted = schema.tabs.map((tab: any) => {
let flag2 = false;
let converted = (tab.controls || []).map((control: any) => {
if (Array.isArray(control)) {
let converted = convertFieldSetTabs2Controls({
type: 'group',
controls: control
});
if (converted !== control) {
flag2 = true;
}
return converted;
}
return control;
});
if (flag2) {
flag = true;
tab = {
...tab,
controls: converted
};
}
return tab;
});
if (flag) {
schema = {
...schema,
tabs: converted
};
}
}
return schema; return schema;
}
if (Array.isArray(schema.tabs)) {
let flag = false;
let converted = schema.tabs.map((tab: any) => {
let flag2 = false;
let converted = (tab.controls || []).map((control: any) => {
if (Array.isArray(control)) {
let converted = convertFieldSetTabs2Controls({
type: 'group',
controls: control
});
if (converted !== control) {
flag2 = true;
}
return converted;
}
return control;
});
if (flag2) {
flag = true;
tab = {
...tab,
controls: converted
};
}
return tab;
});
if (flag) {
schema = {
...schema,
tabs: converted
};
}
}
return schema;
}); });
function convertArray2Hbox(arr: Array<any>): any { function convertArray2Hbox(arr: Array<any>): any {
let flag = false; let flag = false;
let converted = arr.map((item: any) => { let converted = arr.map((item: any) => {
if (Array.isArray(item)) { if (Array.isArray(item)) {
flag = true; flag = true;
return convertArray2Hbox(item); return convertArray2Hbox(item);
}
return item;
});
if (!flag) {
converted = arr;
} }
return { return item;
type: 'hbox', });
columns: converted if (!flag) {
}; converted = arr;
}
return {
type: 'hbox',
columns: converted
};
} }
// CRUD/List 和 CRUD/Card 的 body 中的数组用法转成 hbox // CRUD/List 和 CRUD/Card 的 body 中的数组用法转成 hbox
addSchemaFilter(function(schema: Schema, renderer) { addSchemaFilter(function(schema: Schema, renderer) {
if (renderer.component !== CardRenderer && renderer.component !== ListItemRenderer) { if (
return schema; renderer.component !== CardRenderer &&
} renderer.component !== ListItemRenderer
) {
if (Array.isArray(schema.body)) {
let flag = false;
let converted = schema.body.map((item: any) => {
if (Array.isArray(item)) {
flag = true;
return convertArray2Hbox(item);
}
return item;
});
if (flag) {
schema = {
...schema,
body: converted
};
}
}
return schema; return schema;
}
if (Array.isArray(schema.body)) {
let flag = false;
let converted = schema.body.map((item: any) => {
if (Array.isArray(item)) {
flag = true;
return convertArray2Hbox(item);
}
return item;
});
if (flag) {
schema = {
...schema,
body: converted
};
}
}
return schema;
}); });
// button group 的 btnClassName 和 btnActiveClassName 改成 btnLevel 和 btnActiveLevel 了 // button group 的 btnClassName 和 btnActiveClassName 改成 btnLevel 和 btnActiveLevel 了
addSchemaFilter(function(scheam: Schema, renderer) { addSchemaFilter(function(scheam: Schema, renderer) {
if (renderer.component !== ButtonGroupControlRenderer) { if (renderer.component !== ButtonGroupControlRenderer) {
return scheam;
}
if (scheam.btnClassName || scheam.btnActiveClassName) {
scheam = {
...scheam,
btnLevel: getLevelFromClassName(scheam.btnClassName),
btnActiveLevel: getLevelFromClassName(scheam.btnActiveClassName)
};
delete scheam.btnClassName;
delete scheam.btnActiveClassName;
}
return scheam; return scheam;
}
if (scheam.btnClassName || scheam.btnActiveClassName) {
scheam = {
...scheam,
btnLevel: getLevelFromClassName(scheam.btnClassName),
btnActiveLevel: getLevelFromClassName(scheam.btnActiveClassName)
};
delete scheam.btnClassName;
delete scheam.btnActiveClassName;
}
return scheam;
}); });
// FieldSet className 定制样式方式改成 size 来配置 // FieldSet className 定制样式方式改成 size 来配置
addSchemaFilter(function(scheam: Schema, renderer) { addSchemaFilter(function(scheam: Schema, renderer) {
if (renderer.component !== FieldSetRenderer) { if (renderer.component !== FieldSetRenderer) {
return scheam;
}
if (scheam.className && !scheam.size && /\bfieldset(?:\-(xs|sm|md|lg))?\b/.test(scheam.className)) {
scheam = {
...scheam,
size: RegExp.$1 || 'base',
className: scheam.className.replace(/\bfieldset(?:\-(xs|sm|md|lg))?\b/, '')
};
delete scheam.btnClassName;
delete scheam.btnActiveClassName;
}
return scheam; return scheam;
}
if (
scheam.className &&
!scheam.size &&
/\bfieldset(?:\-(xs|sm|md|lg))?\b/.test(scheam.className)
) {
scheam = {
...scheam,
size: RegExp.$1 || 'base',
className: scheam.className.replace(
/\bfieldset(?:\-(xs|sm|md|lg))?\b/,
''
)
};
delete scheam.btnClassName;
delete scheam.btnActiveClassName;
}
return scheam;
}); });
// FieldSet className 定制样式方式改成 size 来配置 // FieldSet className 定制样式方式改成 size 来配置
addSchemaFilter(function(scheam: Schema, renderer) { addSchemaFilter(function(scheam: Schema, renderer) {
if (renderer.component !== ServiceRenderer) { if (renderer.component !== ServiceRenderer) {
return scheam;
}
if (scheam.body && scheam.body.controls) {
scheam = {
...scheam,
controls: scheam.body.controls
};
delete scheam.body;
}
return scheam; return scheam;
}
if (scheam.body && scheam.body.controls) {
scheam = {
...scheam,
controls: scheam.body.controls
};
delete scheam.body;
}
return scheam;
}); });

View File

@ -7,39 +7,43 @@ import React from 'react';
import {themeable, ClassNamesFn} from '../theme'; import {themeable, ClassNamesFn} from '../theme';
interface NotFoundProps { interface NotFoundProps {
code?: string | number; code?: string | number;
description?: string; description?: string;
links?: React.ReactNode; links?: React.ReactNode;
footerText?: React.ReactNode; footerText?: React.ReactNode;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
} }
export class NotFound extends React.Component<NotFoundProps, any> { export class NotFound extends React.Component<NotFoundProps, any> {
render() { render() {
const {links, footerText, description, children, code} = this.props; const {links, footerText, description, children, code} = this.props;
return ( return (
<div className="container w-xxl w-auto-xs"> <div className="container w-xxl w-auto-xs">
<div className="text-center m-b-lg"> <div className="text-center m-b-lg">
<h1 className="text-shadow text-white">{code || '404'}</h1> <h1 className="text-shadow text-white">{code || '404'}</h1>
{description ? <div className="text-danger">{description}</div> : null} {description ? (
</div> <div className="text-danger">{description}</div>
) : null}
</div>
{children} {children}
{links ? <div className="list-group bg-info auto m-b-sm m-b-lg">{links}</div> : null} {links ? (
<div className="list-group bg-info auto m-b-sm m-b-lg">{links}</div>
) : null}
{footerText ? ( {footerText ? (
<div className="text-center"> <div className="text-center">
<p> <p>
<small className="text-muted">{footerText}</small> <small className="text-muted">{footerText}</small>
</p> </p>
</div> </div>
) : null} ) : null}
</div> </div>
); );
} }
} }
export default themeable(NotFound); export default themeable(NotFound);

View File

@ -10,166 +10,180 @@ import Button from './Button';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
export interface AlertProps { export interface AlertProps {
container?: any; container?: any;
confirmText?: string; confirmText?: string;
cancelText?: string; cancelText?: string;
title?: string; title?: string;
confirmBtnLevel?: string; confirmBtnLevel?: string;
alertBtnLevel?: string; alertBtnLevel?: string;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
theme?: string; theme?: string;
} }
export interface AlertState { export interface AlertState {
show: boolean; show: boolean;
title?: string; title?: string;
content: string; content: string;
confirm: boolean; confirm: boolean;
} }
export class Alert extends React.Component<AlertProps, AlertState> { export class Alert extends React.Component<AlertProps, AlertState> {
static instance: any = null; static instance: any = null;
static getInstance() { static getInstance() {
if (!Alert.instance) { if (!Alert.instance) {
console.warn('Alert 组件应该没有被渲染,所以隐性的渲染到 body 了'); console.warn('Alert 组件应该没有被渲染,所以隐性的渲染到 body 了');
const container = document.body; const container = document.body;
const div = document.createElement('div'); const div = document.createElement('div');
container.appendChild(div); container.appendChild(div);
render(<ThemedAlert />, div); render(<ThemedAlert />, div);
}
return Alert.instance;
} }
_resolve: (value: any) => void; return Alert.instance;
_modal: any; }
_body: any;
state: AlertState = {
show: false,
title: '',
content: '',
confirm: false
};
constructor(props: AlertProps) {
super(props);
this.close = this.close.bind(this); _resolve: (value: any) => void;
this.handleConfirm = this.handleConfirm.bind(this); _modal: any;
this.handleCancel = this.handleCancel.bind(this); _body: any;
this.modalRef = this.modalRef.bind(this); state: AlertState = {
this.bodyRef = this.bodyRef.bind(this); show: false,
title: '',
content: '',
confirm: false
};
constructor(props: AlertProps) {
super(props);
this.close = this.close.bind(this);
this.handleConfirm = this.handleConfirm.bind(this);
this.handleCancel = this.handleCancel.bind(this);
this.modalRef = this.modalRef.bind(this);
this.bodyRef = this.bodyRef.bind(this);
}
static defaultProps = {
confirmText: '确认',
cancelText: '取消',
title: '系统消息',
alertBtnLevel: 'primary',
confirmBtnLevel: 'danger'
};
componentWillMount() {
Alert.instance = this;
}
componentDidMount() {
this._body && (this._body.innerHTML = this.state.content);
}
componentDidUpdate(prevProps: AlertProps, prevState: AlertState) {
if (prevState.content !== this.state.content) {
this._body && (this._body.innerHTML = this.state.content);
} }
}
static defaultProps = { componentWillUnmount() {
confirmText: '确认', Alert.instance = null;
cancelText: '取消', }
title: '系统消息',
alertBtnLevel: 'primary',
confirmBtnLevel: 'danger'
};
componentWillMount() { handleConfirm() {
Alert.instance = this; this.close(true);
} }
componentDidMount() { handleCancel() {
this._body && (this._body.innerHTML = this.state.content); this.close(false);
} }
componentDidUpdate(prevProps: AlertProps, prevState: AlertState) { close(confirmed: boolean) {
if (prevState.content !== this.state.content) { const isConfirm = this.state.confirm;
this._body && (this._body.innerHTML = this.state.content);
}
}
componentWillUnmount() { this.setState(
Alert.instance = null; {
} show: false
},
isConfirm ? () => this._resolve(confirmed) /*this._reject()*/ : undefined
);
}
handleConfirm() { alert(content: string, title?: string) {
this.close(true); this.setState({
} title,
content,
show: true,
confirm: false
});
}
handleCancel() { confirm(content: string, title?: string) {
this.close(false); this.setState({
} title,
content,
show: true,
confirm: true
});
close(confirmed: boolean) { return new Promise(resolve => {
const isConfirm = this.state.confirm; this._resolve = resolve;
});
}
this.setState( modalRef(ref: any) {
{ this._modal = ref;
show: false }
},
isConfirm ? () => this._resolve(confirmed) /*this._reject()*/ : undefined
);
}
alert(content: string, title?: string) { bodyRef(ref: any) {
this.setState({ this._body = ref;
title, this._body && (this._body.innerHTML = this.state.content);
content, }
show: true,
confirm: false
});
}
confirm(content: string, title?: string) { render() {
this.setState({ const {
title, container,
content, cancelText,
show: true, confirmText,
confirm: true title,
}); confirmBtnLevel,
alertBtnLevel,
return new Promise(resolve => { classnames: cx,
this._resolve = resolve; classPrefix
}); } = this.props;
} return (
<Modal
modalRef(ref: any) { show={this.state.show}
this._modal = ref; onHide={this.handleCancel}
} container={container}
ref={this.modalRef}
bodyRef(ref: any) { >
this._body = ref; <div className={cx('Modal-header')}>
this._body && (this._body.innerHTML = this.state.content); <div className={cx('Modal-title')}>{this.state.title || title}</div>
} </div>
<div className={cx('Modal-body')}>
render() { <div ref={this.bodyRef} />
const { </div>
container, <div className={cx('Modal-footer')}>
cancelText, {this.state.confirm ? (
confirmText, <Button onClick={this.handleCancel}>{cancelText}</Button>
title, ) : null}
confirmBtnLevel, <Button
alertBtnLevel, level={this.state.confirm ? confirmBtnLevel : alertBtnLevel}
classnames: cx, onClick={this.handleConfirm}
classPrefix >
} = this.props; {confirmText}
return ( </Button>
<Modal show={this.state.show} onHide={this.handleCancel} container={container} ref={this.modalRef}> </div>
<div className={cx('Modal-header')}> </Modal>
<div className={cx('Modal-title')}>{this.state.title || title}</div> );
</div> }
<div className={cx('Modal-body')}>
<div ref={this.bodyRef} />
</div>
<div className={cx('Modal-footer')}>
{this.state.confirm ? <Button onClick={this.handleCancel}>{cancelText}</Button> : null}
<Button level={this.state.confirm ? confirmBtnLevel : alertBtnLevel} onClick={this.handleConfirm}>
{confirmText}
</Button>
</div>
</Modal>
);
}
} }
export const alert: (content: string, title?: string) => void = (content, title) => export const alert: (content: string, title?: string) => void = (
Alert.getInstance().alert(content, title); content,
export const confirm: (content: string, title?: string) => Promise<any> = (content, title) => title
Alert.getInstance().confirm(content, title); ) => Alert.getInstance().alert(content, title);
export const confirm: (content: string, title?: string) => Promise<any> = (
content,
title
) => Alert.getInstance().confirm(content, title);
export const ThemedAlert = themeable(Alert); export const ThemedAlert = themeable(Alert);
export default ThemedAlert; export default ThemedAlert;

View File

@ -7,58 +7,76 @@ import React from 'react';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
export interface AlertProps { export interface AlertProps {
level: 'danger' | 'info' | 'success' | 'warning'; level: 'danger' | 'info' | 'success' | 'warning';
className: string; className: string;
showCloseButton: boolean; showCloseButton: boolean;
onClose?: () => void; onClose?: () => void;
classnames: ClassNamesFn; classnames: ClassNamesFn;
classPrefix: string; classPrefix: string;
} }
export interface AlertState { export interface AlertState {
show: boolean; show: boolean;
} }
export class Alert extends React.Component<AlertProps, AlertState> { export class Alert extends React.Component<AlertProps, AlertState> {
static defaultProps: Pick<AlertProps, 'level' | 'className' | 'showCloseButton'> = { static defaultProps: Pick<
level: 'info', AlertProps,
className: '', 'level' | 'className' | 'showCloseButton'
showCloseButton: false > = {
level: 'info',
className: '',
showCloseButton: false
};
static propsList: Array<string> = [
'level',
'className',
'showCloseButton',
'onClose'
];
constructor(props: AlertProps) {
super(props);
this.handleClick = this.handleClick.bind(this);
this.state = {
show: true
}; };
static propsList: Array<string> = ['level', 'className', 'showCloseButton', 'onClose']; }
constructor(props: AlertProps) { handleClick() {
super(props); this.setState(
{
show: false
},
this.props.onClose
);
}
this.handleClick = this.handleClick.bind(this); render() {
this.state = { const {
show: true classnames: cx,
}; className,
} level,
children,
showCloseButton
} = this.props;
handleClick() { return this.state.show ? (
this.setState( <div className={cx('Alert', level ? `Alert--${level}` : '', className)}>
{ {showCloseButton ? (
show: false <button
}, className={cx('Alert-close')}
this.props.onClose onClick={this.handleClick}
); type="button"
} >
<span>×</span>
render() { </button>
const {classnames: cx, className, level, children, showCloseButton} = this.props; ) : null}
{children}
return this.state.show ? ( </div>
<div className={cx('Alert', level ? `Alert--${level}` : '', className)}> ) : null;
{showCloseButton ? ( }
<button className={cx('Alert-close')} onClick={this.handleClick} type="button">
<span>×</span>
</button>
) : null}
{children}
</div>
) : null;
}
} }
export default themeable(Alert); export default themeable(Alert);

View File

@ -11,218 +11,254 @@ import {ClassNamesFn, themeable} from '../theme';
export type LinkItem = LinkItemProps; export type LinkItem = LinkItemProps;
interface LinkItemProps { interface LinkItemProps {
id?: number; id?: number;
label: string; label: string;
hidden?: boolean; hidden?: boolean;
open?: boolean; open?: boolean;
active?: boolean; active?: boolean;
className?: string; className?: string;
children?: Array<LinkItem>; children?: Array<LinkItem>;
path?: string; path?: string;
icon?: string; icon?: string;
component?: React.ReactType; component?: React.ReactType;
} }
interface Navigation { interface Navigation {
label: string; label: string;
children: Array<LinkItem>; children: Array<LinkItem>;
prefix?: JSX.Element; prefix?: JSX.Element;
affix?: JSX.Element; affix?: JSX.Element;
className?: string; className?: string;
[propName: string]: any; [propName: string]: any;
} }
interface AsideNavProps { interface AsideNavProps {
id?: string; id?: string;
className?: string; className?: string;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
renderLink: Function; renderLink: Function;
isActive: Function; isActive: Function;
isOpen: (link: LinkItemProps) => boolean; isOpen: (link: LinkItemProps) => boolean;
navigations: Array<Navigation>; navigations: Array<Navigation>;
renderSubLinks: (link: LinkItemProps, renderLink: Function, depth: number, props: AsideNavProps) => React.ReactNode; renderSubLinks: (
link: LinkItemProps,
renderLink: Function,
depth: number,
props: AsideNavProps
) => React.ReactNode;
} }
interface AsideNavState { interface AsideNavState {
navigations: Array<Navigation>; navigations: Array<Navigation>;
} }
export class AsideNav extends React.Component<AsideNavProps, AsideNavState> { export class AsideNav extends React.Component<AsideNavProps, AsideNavState> {
static defaultProps = { static defaultProps = {
renderLink: (item: LinkItemProps) => <a>{item.label}</a>, renderLink: (item: LinkItemProps) => <a>{item.label}</a>,
renderSubLinks: (link: LinkItemProps, renderLink: Function, depth: number, {classnames: cx}: AsideNavProps) => renderSubLinks: (
link.children && link.children.length ? ( link: LinkItemProps,
<ul className={cx('AsideNav-subList')}> renderLink: Function,
{link.label ? ( depth: number,
<li key="subHeader" className={cx('AsideNav-subHeader')}> {classnames: cx}: AsideNavProps
<a>{link.label}</a> ) =>
</li> link.children && link.children.length ? (
) : null} <ul className={cx('AsideNav-subList')}>
{link.children.map((link, key) => renderLink(link, key, {}, depth + 1))} {link.label ? (
</ul> <li key="subHeader" className={cx('AsideNav-subHeader')}>
) : link.label && depth === 1 ? ( <a>{link.label}</a>
<div className={cx('AsideNav-tooltip')}>{link.label}</div> </li>
) : null, ) : null}
isActive: (link: LinkItem) => link.open, {link.children.map((link, key) =>
isOpen: (item: LinkItemProps) => (item.children ? item.children.some(item => item.open) : false) renderLink(link, key, {}, depth + 1)
)}
</ul>
) : link.label && depth === 1 ? (
<div className={cx('AsideNav-tooltip')}>{link.label}</div>
) : null,
isActive: (link: LinkItem) => link.open,
isOpen: (item: LinkItemProps) =>
item.children ? item.children.some(item => item.open) : false
};
constructor(props: AsideNavProps) {
super(props);
const isOpen = props.isOpen;
let id = 1;
this.state = {
navigations: mapTree(
props.navigations,
(item: Navigation) => {
const isActive =
typeof item.active === 'undefined'
? (props.isActive as Function)(item)
: item.active;
return {
...item,
id: id++,
active: isActive,
open: isActive || isOpen(item as LinkItemProps)
};
},
1,
true
)
}; };
constructor(props: AsideNavProps) { this.renderLink = this.renderLink.bind(this);
super(props); this.toggleExpand = this.toggleExpand.bind(this);
}
const isOpen = props.isOpen; componentWillReceiveProps(nextProps: AsideNavProps) {
let id = 1; const props = this.props;
this.state = { const isOpen = props.isOpen;
navigations: mapTree(
props.navigations,
(item: Navigation) => {
const isActive =
typeof item.active === 'undefined' ? (props.isActive as Function)(item) : item.active;
return { if (
...item, props.navigations !== nextProps.navigations ||
id: id++, props.isActive !== nextProps.isActive
active: isActive, ) {
open: isActive || isOpen(item as LinkItemProps) let id = 1;
}; this.setState({
}, navigations: mapTree(
1, nextProps.navigations,
true (item: Navigation) => {
) const isActive =
}; typeof item.active === 'undefined'
? (nextProps.isActive as Function)(item)
: item.active;
this.renderLink = this.renderLink.bind(this); return {
this.toggleExpand = this.toggleExpand.bind(this); ...item,
id: id++,
active: isActive,
open: isActive || isOpen(item as LinkItemProps)
};
},
1,
true
)
});
}
}
toggleExpand(link: LinkItemProps, e?: React.MouseEvent<HTMLElement>) {
if (e) {
e.stopPropagation();
e.preventDefault();
} }
componentWillReceiveProps(nextProps: AsideNavProps) { this.setState({
const props = this.props; navigations: mapTree(
const isOpen = props.isOpen; this.state.navigations,
(item: Navigation) => ({
...item,
open: link.id === item.id ? !item.open : item.open
}),
1,
true
)
});
}
if (props.navigations !== nextProps.navigations || props.isActive !== nextProps.isActive) { renderLink(
let id = 1; link: LinkItemProps,
this.setState({ key: any,
navigations: mapTree( props: Partial<AsideNavProps> = {},
nextProps.navigations, depth = 1
(item: Navigation) => { ): React.ReactNode {
const isActive = const {
typeof item.active === 'undefined' ? (nextProps.isActive as Function)(item) : item.active; renderLink,
isActive,
renderSubLinks,
classnames: cx,
...others
} = this.props;
return { const dom = (renderLink as Function)({
...item, link,
id: id++, active: link.active,
active: isActive, open: link.open,
open: isActive || isOpen(item as LinkItemProps) toggleExpand: this.toggleExpand,
}; depth,
}, classnames: cx,
1, ...others
true });
)
}); if (!dom) {
} return;
} }
toggleExpand(link: LinkItemProps, e?: React.MouseEvent<HTMLElement>) { return (
if (e) { <li
e.stopPropagation(); {...props}
e.preventDefault(); key={key}
} className={cx(`AsideNav-item`, link.className, {
[`is-open`]: link.open,
[`is-active`]: link.active
})}
>
{dom}
{renderSubLinks(link, this.renderLink, depth, this.props)}
</li>
);
}
this.setState({ render() {
navigations: mapTree( const navigations = this.state.navigations;
this.state.navigations, let links: Array<React.ReactNode> = [];
(item: Navigation) => ({ const {className, classnames: cx} = this.props;
...item,
open: link.id === item.id ? !item.open : item.open
}),
1,
true
)
});
}
renderLink(link: LinkItemProps, key: any, props: Partial<AsideNavProps> = {}, depth = 1): React.ReactNode { navigations.forEach((navigation, index) => {
const {renderLink, isActive, renderSubLinks, classnames: cx, ...others} = this.props; if (navigation.prefix) {
const prefix: JSX.Element =
const dom = (renderLink as Function)({ typeof navigation.prefix === 'function'
link, ? (navigation.prefix as any)(this.props)
active: link.active, : navigation.prefix;
open: link.open, links.push(
toggleExpand: this.toggleExpand, React.cloneElement(prefix, {
depth, ...prefix.props,
classnames: cx, key: `${index}-prefix`
...others })
});
if (!dom) {
return;
}
return (
<li
{...props}
key={key}
className={cx(`AsideNav-item`, link.className, {
[`is-open`]: link.open,
[`is-active`]: link.active
})}
>
{dom}
{renderSubLinks(link, this.renderLink, depth, this.props)}
</li>
); );
} }
render() { navigation.label &&
const navigations = this.state.navigations; links.push(
let links: Array<React.ReactNode> = []; <li
const {className, classnames: cx} = this.props; key={`${index}-label`}
className={cx(`AsideNav-label`, navigation.className)}
navigations.forEach((navigation, index) => { >
if (navigation.prefix) { <span>{navigation.label}</span>
const prefix: JSX.Element = </li>
typeof navigation.prefix === 'function'
? (navigation.prefix as any)(this.props)
: navigation.prefix;
links.push(
React.cloneElement(prefix, {
...prefix.props,
key: `${index}-prefix`
})
);
}
navigation.label &&
links.push(
<li key={`${index}-label`} className={cx(`AsideNav-label`, navigation.className)}>
<span>{navigation.label}</span>
</li>
);
navigation.children.forEach((item, key) => {
const link = this.renderLink(item, `${index}-${key}`);
link && links.push(link);
});
if (navigation.affix) {
const affix: JSX.Element =
typeof navigation.affix === 'function' ? (navigation.affix as any)(this.props) : navigation.affix;
links.push(
React.cloneElement(affix, {
...affix.props,
key: `${index}-affix`
})
);
}
});
return (
<nav className={cx(`AsideNav`, className)}>
<ul className={cx(`AsideNav-list`)}>{links}</ul>
</nav>
); );
}
navigation.children.forEach((item, key) => {
const link = this.renderLink(item, `${index}-${key}`);
link && links.push(link);
});
if (navigation.affix) {
const affix: JSX.Element =
typeof navigation.affix === 'function'
? (navigation.affix as any)(this.props)
: navigation.affix;
links.push(
React.cloneElement(affix, {
...affix.props,
key: `${index}-affix`
})
);
}
});
return (
<nav className={cx(`AsideNav`, className)}>
<ul className={cx(`AsideNav-list`)}>{links}</ul>
</nav>
);
}
} }
export default themeable(AsideNav); export default themeable(AsideNav);

View File

@ -9,116 +9,126 @@ import {pickEventsProps} from '../utils/helper';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
interface ButtonProps interface ButtonProps
extends React.DetailedHTMLProps<React.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> { extends React.DetailedHTMLProps<
id?: string; React.ButtonHTMLAttributes<HTMLButtonElement>,
className?: string; HTMLButtonElement
href?: string; > {
size?: 'xs' | 'sm' | 'md' | 'lg'; id?: string;
type: 'button' | 'reset' | 'submit'; className?: string;
level: string; // 'link' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger' | 'light' | 'dark' | 'default'; href?: string;
tooltip?: string | TooltipObject; size?: 'xs' | 'sm' | 'md' | 'lg';
placement: 'top' | 'right' | 'bottom' | 'left'; type: 'button' | 'reset' | 'submit';
tooltipContainer?: any; level: string; // 'link' | 'primary' | 'secondary' | 'info' | 'success' | 'warning' | 'danger' | 'light' | 'dark' | 'default';
tooltipTrigger: Trigger | Array<Trigger>; tooltip?: string | TooltipObject;
tooltipRootClose: boolean; placement: 'top' | 'right' | 'bottom' | 'left';
disabled?: boolean; tooltipContainer?: any;
active?: boolean; tooltipTrigger: Trigger | Array<Trigger>;
block?: boolean; tooltipRootClose: boolean;
iconOnly?: boolean; disabled?: boolean;
disabledTip?: string | TooltipObject; active?: boolean;
classPrefix: string; block?: boolean;
classnames: ClassNamesFn; iconOnly?: boolean;
componentClass: React.ReactType; disabledTip?: string | TooltipObject;
classPrefix: string;
classnames: ClassNamesFn;
componentClass: React.ReactType;
} }
export class Button extends React.Component<ButtonProps> { export class Button extends React.Component<ButtonProps> {
static defaultProps: Pick< static defaultProps: Pick<
ButtonProps, ButtonProps,
'componentClass' | 'level' | 'type' | 'placement' | 'tooltipTrigger' | 'tooltipRootClose' | 'componentClass'
> = { | 'level'
componentClass: 'button', | 'type'
level: 'default', | 'placement'
type: 'button', | 'tooltipTrigger'
placement: 'top', | 'tooltipRootClose'
tooltipTrigger: ['hover', 'focus'], > = {
tooltipRootClose: false componentClass: 'button',
}; level: 'default',
type: 'button',
placement: 'top',
tooltipTrigger: ['hover', 'focus'],
tooltipRootClose: false
};
renderButton() { renderButton() {
let { let {
level, level,
size, size,
disabled, disabled,
className, className,
componentClass: Comp, componentClass: Comp,
classnames: cx, classnames: cx,
children, children,
disabledTip, disabledTip,
block, block,
type, type,
active, active,
iconOnly, iconOnly,
href, href,
...rest ...rest
} = this.props; } = this.props;
if (href) { if (href) {
Comp = 'a'; Comp = 'a';
}
return (
<Comp
type={Comp === 'a' ? undefined : type}
{...pickEventsProps(rest)}
href={href}
className={cx(
`Button`,
{
[`Button--${level}`]: level,
[`Button--${size}`]: size,
[`Button--block`]: block,
[`Button--iconOnly`]: iconOnly,
'is-disabled': disabled,
'is-active': active
},
className
)}
disabled={disabled}
>
{children}
</Comp>
);
} }
render() { return (
const { <Comp
tooltip, type={Comp === 'a' ? undefined : type}
placement, {...pickEventsProps(rest)}
tooltipContainer, href={href}
tooltipTrigger, className={cx(
tooltipRootClose, `Button`,
disabled, {
disabledTip, [`Button--${level}`]: level,
classPrefix, [`Button--${size}`]: size,
classnames: cx [`Button--block`]: block,
} = this.props; [`Button--iconOnly`]: iconOnly,
'is-disabled': disabled,
'is-active': active
},
className
)}
disabled={disabled}
>
{children}
</Comp>
);
}
return ( render() {
<TooltipWrapper const {
placement={placement} tooltip,
tooltip={disabled ? disabledTip : tooltip} placement,
container={tooltipContainer} tooltipContainer,
trigger={tooltipTrigger} tooltipTrigger,
rootClose={tooltipRootClose} tooltipRootClose,
> disabled,
{disabled && disabledTip ? ( disabledTip,
<div className={cx('Button--disabled-wrap')}>{this.renderButton()}</div> classPrefix,
) : ( classnames: cx
this.renderButton() } = this.props;
)}
</TooltipWrapper> return (
); <TooltipWrapper
} placement={placement}
tooltip={disabled ? disabledTip : tooltip}
container={tooltipContainer}
trigger={tooltipTrigger}
rootClose={tooltipRootClose}
>
{disabled && disabledTip ? (
<div className={cx('Button--disabled-wrap')}>
{this.renderButton()}
</div>
) : (
this.renderButton()
)}
</TooltipWrapper>
);
}
} }
export default themeable(Button); export default themeable(Button);

View File

@ -7,111 +7,115 @@ import React from 'react';
import cx from 'classnames'; import cx from 'classnames';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
import {autobind} from '../utils/helper'; import {autobind} from '../utils/helper';
import { filter } from '../utils/tpl'; import {filter} from '../utils/tpl';
const sizeMap = { const sizeMap = {
sm: 'i-checks-sm', sm: 'i-checks-sm',
lg: 'i-checks-lg', lg: 'i-checks-lg',
small: 'i-checks-sm', small: 'i-checks-sm',
large: 'i-checks-lg' large: 'i-checks-lg'
}; };
interface CheckboxProps { interface CheckboxProps {
id?: string; id?: string;
key?: string | number; key?: string | number;
style?: React.CSSProperties; style?: React.CSSProperties;
type?: string; type?: string;
size?: 'sm' | 'lg' | 'small' | 'large'; size?: 'sm' | 'lg' | 'small' | 'large';
label?: string; label?: string;
labelClassName?: string; labelClassName?: string;
className?: string; className?: string;
onChange?: (value: any) => void; onChange?: (value: any) => void;
value?: any; value?: any;
containerClass?: string; containerClass?: string;
inline?: boolean; inline?: boolean;
trueValue?: boolean; trueValue?: boolean;
falseValue?: boolean; falseValue?: boolean;
disabled?: boolean; disabled?: boolean;
readOnly?: boolean; readOnly?: boolean;
checked?: boolean; checked?: boolean;
name?: string; name?: string;
description?: string; description?: string;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
partial?: boolean; partial?: boolean;
data?: any; data?: any;
} }
export class Checkbox extends React.Component<CheckboxProps, any> { export class Checkbox extends React.Component<CheckboxProps, any> {
static defaultProps = { static defaultProps = {
trueValue: true, trueValue: true,
falseValue: false, falseValue: false,
type: 'checkbox' type: 'checkbox'
}; };
@autobind @autobind
handleCheck(e: React.ChangeEvent<any>) { handleCheck(e: React.ChangeEvent<any>) {
const {trueValue, falseValue, onChange} = this.props; const {trueValue, falseValue, onChange} = this.props;
if (!onChange) { if (!onChange) {
return; return;
}
onChange(e.currentTarget.checked ? trueValue : falseValue);
} }
render() { onChange(e.currentTarget.checked ? trueValue : falseValue);
let { }
size,
className,
classnames: cx,
value,
label,
partial,
trueValue,
children,
disabled,
description,
readOnly,
checked,
type,
name,
data,
labelClassName
} = this.props;
className = (className ? className : '') + (size && sizeMap[size] ? ` ${sizeMap[size]}` : ''); render() {
let {
size,
className,
classnames: cx,
value,
label,
partial,
trueValue,
children,
disabled,
description,
readOnly,
checked,
type,
name,
data,
labelClassName
} = this.props;
return ( className =
<label (className ? className : '') +
className={cx( (size && sizeMap[size] ? ` ${sizeMap[size]}` : '');
`Checkbox Checkbox--${type}`,
{ return (
'Checkbox--full': !partial <label
}, className={cx(
className `Checkbox Checkbox--${type}`,
)} {
> 'Checkbox--full': !partial
<input },
type={type} className
checked={ )}
typeof checked !== 'undefined' >
? checked <input
: typeof value === 'undefined' type={type}
? value checked={
: value == trueValue typeof checked !== 'undefined'
} ? checked
onChange={this.handleCheck} : typeof value === 'undefined'
disabled={disabled} ? value
readOnly={readOnly} : value == trueValue
name={name} }
/> onChange={this.handleCheck}
<i /> disabled={disabled}
<span className={cx(labelClassName)}>{children || label}</span> readOnly={readOnly}
{description ? (<div className={cx("Checkbox-desc")}>{filter(description, data)}</div>) : null} name={name}
</label> />
); <i />
} <span className={cx(labelClassName)}>{children || label}</span>
{description ? (
<div className={cx('Checkbox-desc')}>{filter(description, data)}</div>
) : null}
</label>
);
}
} }
export default themeable(Checkbox); export default themeable(Checkbox);

View File

@ -15,77 +15,98 @@ import {ClassNamesFn, themeable} from '../theme';
// import isPlainObject = require('lodash/isPlainObject'); // import isPlainObject = require('lodash/isPlainObject');
export interface Option { export interface Option {
label?: string; label?: string;
value?: any; value?: any;
disabled?: boolean; disabled?: boolean;
children?: Options; children?: Options;
description?: string; description?: string;
[propName: string]: any; [propName: string]: any;
} }
export interface Options extends Array<Option> {} export interface Options extends Array<Option> {}
export interface OptionProps { export interface OptionProps {
multi?: boolean; multi?: boolean;
multiple?: boolean; multiple?: boolean;
valueField?: string; valueField?: string;
options?: Options; options?: Options;
joinValues: boolean; joinValues: boolean;
extractValue: boolean; extractValue: boolean;
delimiter: string; delimiter: string;
clearable: boolean; clearable: boolean;
placeholder?: string; placeholder?: string;
} }
export type OptionValue = string | number | null | undefined | Option; export type OptionValue = string | number | null | undefined | Option;
export function value2array(value: OptionValue | Array<OptionValue>, props: Partial<OptionProps>): Array<Option> { export function value2array(
if (props.multi || props.multiple) { value: OptionValue | Array<OptionValue>,
if (typeof value === 'string') { props: Partial<OptionProps>
value = value.split(props.delimiter || ','); ): Array<Option> {
} if (props.multi || props.multiple) {
if (typeof value === 'string') {
if (!Array.isArray(value)) { value = value.split(props.delimiter || ',');
if (value === null || value === undefined) {
return [];
}
value = [value];
}
return (value as Array<OptionValue>)
.map((value: OptionValue) =>
expandValue(
!props.joinValues && value && value.hasOwnProperty(props.valueField || 'value')
? (value as any)[props.valueField || 'value']
: value,
props
)
)
.filter((item: Option) => item) as Array<Option>;
} }
let expandedValue = expandValue(value as OptionValue, props); if (!Array.isArray(value)) {
return expandedValue ? [expandedValue] : []; if (value === null || value === undefined) {
return [];
}
value = [value];
}
return (value as Array<OptionValue>)
.map((value: OptionValue) =>
expandValue(
!props.joinValues &&
value &&
value.hasOwnProperty(props.valueField || 'value')
? (value as any)[props.valueField || 'value']
: value,
props
)
)
.filter((item: Option) => item) as Array<Option>;
}
let expandedValue = expandValue(value as OptionValue, props);
return expandedValue ? [expandedValue] : [];
} }
export function expandValue(value: OptionValue, props: Partial<OptionProps>): Option | null { export function expandValue(
const valueType = typeof value; value: OptionValue,
props: Partial<OptionProps>
): Option | null {
const valueType = typeof value;
if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean' && valueType !== 'object') { if (
return null; valueType !== 'string' &&
} valueType !== 'number' &&
valueType !== 'boolean' &&
valueType !== 'object'
) {
return null;
}
let {options, valueField} = props; let {options, valueField} = props;
if (!options) { if (!options) {
return null; return null;
} }
if (valueType === 'object' && value && value.hasOwnProperty(props.valueField || 'value')) { if (
value = (value as Option)[valueField || 'value'] || ''; valueType === 'object' &&
} value &&
value.hasOwnProperty(props.valueField || 'value')
) {
value = (value as Option)[valueField || 'value'] || '';
}
return find(flattenTree(options), item => isObject(value) ? item[valueField || 'value'] === value : String(item[valueField || 'value']) === String(value)) as Option; return find(flattenTree(options), item =>
isObject(value)
? item[valueField || 'value'] === value
: String(item[valueField || 'value']) === String(value)
) as Option;
} }
/** /**
@ -100,130 +121,143 @@ export function expandValue(value: OptionValue, props: Partial<OptionProps>): Op
* ] * ]
*/ */
interface CheckboxesProps extends OptionProps { interface CheckboxesProps extends OptionProps {
id?: string; id?: string;
key?: string; key?: string;
className?: string; className?: string;
type: string; type: string;
placeholder?: string; placeholder?: string;
disabled?: boolean; disabled?: boolean;
value?: string; value?: string;
onChange?: Function; onChange?: Function;
inline?: boolean; inline?: boolean;
columnsCount?: number; columnsCount?: number;
checked?: boolean; checked?: boolean;
labelClassName?: string; labelClassName?: string;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
} }
export class Checkboxes extends React.PureComponent<CheckboxesProps, any> { export class Checkboxes extends React.PureComponent<CheckboxesProps, any> {
static defaultProps = { static defaultProps = {
joinValues: true, joinValues: true,
extractValue: false, extractValue: false,
inline: false, inline: false,
delimiter: ',', delimiter: ',',
columnsCount: 1 // 一行显示一个 columnsCount: 1 // 一行显示一个
}; };
toggleOption(option: Option) { toggleOption(option: Option) {
const {value, onChange, joinValues, extractValue, delimiter, valueField, options} = this.props; const {
value,
onChange,
joinValues,
extractValue,
delimiter,
valueField,
options
} = this.props;
let valueArray = value2array(value, { let valueArray = value2array(value, {
multiple: true, multiple: true,
valueField, valueField,
delimiter, delimiter,
options options
}); });
let idx = valueArray.indexOf(option); let idx = valueArray.indexOf(option);
if (!~idx) { if (!~idx) {
option = option =
value2array(option[valueField || 'value'], { value2array(option[valueField || 'value'], {
multiple: true, multiple: true,
valueField, valueField,
delimiter, delimiter,
options options
})[0] || option; })[0] || option;
idx = valueArray.indexOf(option); idx = valueArray.indexOf(option);
}
if (~idx) {
valueArray.splice(idx, 1);
} else {
valueArray.push(option);
}
let newValue: string | Array<Option> = valueArray;
if (joinValues) {
newValue = newValue.map(item => item[valueField || 'value']).join(delimiter);
} else if (extractValue) {
newValue = newValue.map(item => item[valueField || 'value']);
}
onChange && onChange(newValue);
} }
render() { if (~idx) {
const { valueArray.splice(idx, 1);
value, } else {
valueField, valueArray.push(option);
delimiter,
options,
className,
placeholder,
columnsCount,
disabled,
inline,
labelClassName
} = this.props;
let valueArray = value2array(value, {
multiple: true,
valueField,
delimiter,
options
});
let body: Array<React.ReactNode> = [];
if (options) {
body = options.map((option, key) => (
<Checkbox
key={key}
onChange={() => this.toggleOption(option)}
checked={!!~valueArray.indexOf(option)}
disabled={disabled || option.disabled}
inline={inline}
labelClassName={labelClassName}
>
{option.label}
</Checkbox>
));
}
if (!inline && (columnsCount as number) > 1) {
let cellClassName = `col-sm-${(12 / (columnsCount as number))
.toFixed(1)
.replace(/\.0$/, '')
.replace(/\./, '-')}`;
body = chunk(body, columnsCount).map((group, groupIndex) => (
<div className="row" key={groupIndex}>
{group.map((item, index) => (
<div key={index} className={cellClassName}>
{item}
</div>
))}
</div>
));
}
return <div className={className}>{body && body.length ? body : placeholder}</div>;
} }
let newValue: string | Array<Option> = valueArray;
if (joinValues) {
newValue = newValue
.map(item => item[valueField || 'value'])
.join(delimiter);
} else if (extractValue) {
newValue = newValue.map(item => item[valueField || 'value']);
}
onChange && onChange(newValue);
}
render() {
const {
value,
valueField,
delimiter,
options,
className,
placeholder,
columnsCount,
disabled,
inline,
labelClassName
} = this.props;
let valueArray = value2array(value, {
multiple: true,
valueField,
delimiter,
options
});
let body: Array<React.ReactNode> = [];
if (options) {
body = options.map((option, key) => (
<Checkbox
key={key}
onChange={() => this.toggleOption(option)}
checked={!!~valueArray.indexOf(option)}
disabled={disabled || option.disabled}
inline={inline}
labelClassName={labelClassName}
>
{option.label}
</Checkbox>
));
}
if (!inline && (columnsCount as number) > 1) {
let cellClassName = `col-sm-${(12 / (columnsCount as number))
.toFixed(1)
.replace(/\.0$/, '')
.replace(/\./, '-')}`;
body = chunk(body, columnsCount).map((group, groupIndex) => (
<div className="row" key={groupIndex}>
{group.map((item, index) => (
<div key={index} className={cellClassName}>
{item}
</div>
))}
</div>
));
}
return (
<div className={className}>
{body && body.length ? body : placeholder}
</div>
);
}
} }
export default themeable( export default themeable(
uncontrollable(Checkboxes, { uncontrollable(Checkboxes, {
value: 'onChange' value: 'onChange'
}) })
); );

View File

@ -7,98 +7,114 @@
import React from 'react'; import React from 'react';
import css = require('dom-helpers/style'); import css = require('dom-helpers/style');
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
import Transition, {EXITED, ENTERING, EXITING} from 'react-transition-group/Transition'; import Transition, {
EXITED,
ENTERING,
EXITING
} from 'react-transition-group/Transition';
import {autobind} from '../utils/helper'; import {autobind} from '../utils/helper';
const collapseStyles: { const collapseStyles: {
[propName: string]: string; [propName: string]: string;
} = { } = {
[EXITED]: 'out', [EXITED]: 'out',
[EXITING]: 'out', [EXITING]: 'out',
[ENTERING]: 'in' [ENTERING]: 'in'
}; };
export interface CollapseProps { export interface CollapseProps {
show?: boolean; show?: boolean;
mountOnEnter?: boolean; mountOnEnter?: boolean;
unmountOnExit?: boolean; unmountOnExit?: boolean;
className?: string; className?: string;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
} }
export class Collapse extends React.Component<CollapseProps, any> { export class Collapse extends React.Component<CollapseProps, any> {
static defaultProps: Pick<CollapseProps, 'show' | 'mountOnEnter' | 'unmountOnExit'> = { static defaultProps: Pick<
show: false, CollapseProps,
mountOnEnter: false, 'show' | 'mountOnEnter' | 'unmountOnExit'
unmountOnExit: false > = {
}; show: false,
mountOnEnter: false,
unmountOnExit: false
};
contentDom: any; contentDom: any;
contentRef = (ref: any) => (this.contentDom = ref); contentRef = (ref: any) => (this.contentDom = ref);
@autobind @autobind
handleEnter(elem: HTMLElement) { handleEnter(elem: HTMLElement) {
elem.style['height'] = null; elem.style['height'] = null;
} }
@autobind @autobind
handleEntering(elem: HTMLElement) { handleEntering(elem: HTMLElement) {
elem.style['height'] = `${elem['scrollHeight']}px`; elem.style['height'] = `${elem['scrollHeight']}px`;
} }
@autobind @autobind
handleEntered(elem: HTMLElement) { handleEntered(elem: HTMLElement) {
elem.style['height'] = null; elem.style['height'] = null;
} }
@autobind @autobind
handleExit(elem: HTMLElement) { handleExit(elem: HTMLElement) {
let offsetHeight = elem['offsetHeight']; let offsetHeight = elem['offsetHeight'];
const height = offsetHeight + parseInt(css(elem, 'marginTop'), 10) + parseInt(css(elem, 'marginBottom'), 10); const height =
elem.style['height'] = `${height}px`; offsetHeight +
parseInt(css(elem, 'marginTop'), 10) +
parseInt(css(elem, 'marginBottom'), 10);
elem.style['height'] = `${height}px`;
// trigger browser reflow // trigger browser reflow
elem.offsetHeight; elem.offsetHeight;
} }
@autobind @autobind
handleExiting(elem: HTMLElement) { handleExiting(elem: HTMLElement) {
elem.style['height'] = null; elem.style['height'] = null;
} }
render() { render() {
const {show, children, classnames: cx, mountOnEnter, unmountOnExit} = this.props; const {
show,
children,
classnames: cx,
mountOnEnter,
unmountOnExit
} = this.props;
return ( return (
<Transition <Transition
mountOnEnter={mountOnEnter} mountOnEnter={mountOnEnter}
unmountOnExit={unmountOnExit} unmountOnExit={unmountOnExit}
in={show} in={show}
timeout={300} timeout={300}
onEnter={this.handleEnter} onEnter={this.handleEnter}
onEntering={this.handleEntering} onEntering={this.handleEntering}
onEntered={this.handleEntered} onEntered={this.handleEntered}
onExit={this.handleExit} onExit={this.handleExit}
onExiting={this.handleExiting} onExiting={this.handleExiting}
> >
{(status: string) => { {(status: string) => {
if (status === ENTERING) { if (status === ENTERING) {
this.contentDom.offsetWidth; this.contentDom.offsetWidth;
} }
return React.cloneElement(children as any, { return React.cloneElement(children as any, {
...(children as React.ReactElement).props, ...(children as React.ReactElement).props,
ref: this.contentRef, ref: this.contentRef,
className: cx( className: cx(
'Collapse-content', 'Collapse-content',
(children as React.ReactElement).props.className, (children as React.ReactElement).props.className,
collapseStyles[status] collapseStyles[status]
) )
}); });
}} }}
</Transition> </Transition>
); );
} }
} }
export default themeable(Collapse); export default themeable(Collapse);

View File

@ -15,242 +15,256 @@ import PopOver from './PopOver';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
export interface ColorProps { export interface ColorProps {
placeholder?: string; placeholder?: string;
format: string; format: string;
// closeOnSelect:boolean; // closeOnSelect:boolean;
clearable: boolean; clearable: boolean;
className?: string; className?: string;
disabled?: boolean; disabled?: boolean;
popOverContainer?: any; popOverContainer?: any;
placement?: string; placement?: string;
value: any; value: any;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
onChange: (value: any) => void; onChange: (value: any) => void;
presetColors?: string[]; presetColors?: string[];
} }
export interface ColorControlState { export interface ColorControlState {
isOpened: boolean; isOpened: boolean;
isFocused: boolean; isFocused: boolean;
inputValue: string; inputValue: string;
} }
export class ColorControl extends React.PureComponent<ColorProps, ColorControlState> { export class ColorControl extends React.PureComponent<
static defaultProps = { ColorProps,
format: 'hex', ColorControlState
clearable: true, > {
placeholder: '请选择颜色' static defaultProps = {
// closeOnSelect: true format: 'hex',
}; clearable: true,
state = { placeholder: '请选择颜色'
isOpened: false, // closeOnSelect: true
isFocused: false, };
inputValue: this.props.value || '' state = {
}; isOpened: false,
popover: any; isFocused: false,
closeTimer: number; inputValue: this.props.value || ''
preview: React.RefObject<HTMLElement>; };
input: React.RefObject<HTMLInputElement>; popover: any;
constructor(props: ColorProps) { closeTimer: number;
super(props); preview: React.RefObject<HTMLElement>;
input: React.RefObject<HTMLInputElement>;
constructor(props: ColorProps) {
super(props);
this.open = this.open.bind(this); this.open = this.open.bind(this);
this.close = this.close.bind(this); this.close = this.close.bind(this);
this.focus = this.focus.bind(this); this.focus = this.focus.bind(this);
this.blur = this.blur.bind(this); this.blur = this.blur.bind(this);
this.handleChange = this.handleChange.bind(this); this.handleChange = this.handleChange.bind(this);
this.handleFocus = this.handleFocus.bind(this); this.handleFocus = this.handleFocus.bind(this);
this.handleBlur = this.handleBlur.bind(this); this.handleBlur = this.handleBlur.bind(this);
this.clearValue = this.clearValue.bind(this); this.clearValue = this.clearValue.bind(this);
this.handleInputChange = this.handleInputChange.bind(this); this.handleInputChange = this.handleInputChange.bind(this);
this.handleClick = this.handleClick.bind(this); this.handleClick = this.handleClick.bind(this);
this.preview = React.createRef(); this.preview = React.createRef();
this.input = React.createRef(); this.input = React.createRef();
}
componentWillReceiveProps(nextProps: ColorProps) {
const props = this.props;
if (props.value !== nextProps.value) {
this.setState({
inputValue: nextProps.value || ''
});
} }
}
componentWillReceiveProps(nextProps: ColorProps) { handleFocus() {
const props = this.props; this.setState({
isFocused: true
});
}
if (props.value !== nextProps.value) { handleBlur() {
this.setState({ this.setState({
inputValue: nextProps.value || '' isFocused: false,
}); inputValue: this.props.value
});
}
focus() {
this.input.current && this.input.current.focus();
}
blur() {
this.input.current && this.input.current.blur();
}
open(fn?: () => void) {
if (this.props.disabled) {
return;
}
this.setState(
{
isOpened: true
},
fn
);
}
close() {
this.setState({
isOpened: false
});
}
clearValue() {
const onChange = this.props.onChange;
onChange('');
}
handleClick() {
this.state.isOpened ? this.close() : this.open(this.focus);
}
handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
const onChange = this.props.onChange;
this.setState(
{
inputValue: e.currentTarget.value
},
() => {
const dom: HTMLElement = this.preview.current as HTMLElement;
// 通过读取dom上到值确认当前输入值是否有效。
if (dom && dom.style.backgroundColor === this.state.inputValue) {
onChange(this.state.inputValue);
} }
}
);
}
handleChange(color: ColorResult) {
const {
onChange,
format
// closeOnSelect
} = this.props;
if (format === 'rgba') {
onChange(
`rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.rgb.a})`
);
} else if (format === 'rgb') {
onChange(`rgb(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b})`);
} else if (format === 'hsl') {
onChange(
`hsl(${Math.round(color.hsl.h)}, ${Math.round(
color.hsl.s * 100
)}%, ${Math.round(color.hsl.l * 100)}%)`
);
} else {
onChange(color.hex);
} }
handleFocus() { // closeOnSelect && this.close();
this.setState({ }
isFocused: true
});
}
handleBlur() { render() {
this.setState({ const {
isFocused: false, classPrefix: ns,
inputValue: this.props.value className,
}); value,
} placeholder,
disabled,
popOverContainer,
format,
clearable,
placement,
classnames: cx,
presetColors
} = this.props;
focus() { const isOpened = this.state.isOpened;
this.input.current && this.input.current.focus(); const isFocused = this.state.isFocused;
}
blur() { return (
this.input.current && this.input.current.blur(); <div
} className={cx(
`ColorPicker`,
{
'is-disabled': disabled,
'is-focused': isFocused
},
className
)}
>
<input
size={10}
ref={this.input}
type="text"
autoComplete="off"
className={cx('ColorPicker-input')}
value={this.state.inputValue || ''}
placeholder={placeholder}
disabled={disabled}
onChange={this.handleInputChange}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
onClick={this.handleClick}
/>
open(fn?: () => void) { {clearable && !disabled && value ? (
if (this.props.disabled) { <a onClick={this.clearValue} className={cx('ColorPicker-clear')}>
return; <Icon icon="close" className="icon" />
} </a>
this.setState( ) : null}
{
isOpened: true
},
fn
);
}
close() { <span onClick={this.handleClick} className={cx('ColorPicker-preview')}>
this.setState({ <i
isOpened: false ref={this.preview}
}); className={`${ns}ColorPicker-previewIcon`}
} style={{background: this.state.inputValue || '#ccc'}}
/>
</span>
clearValue() { {isOpened ? (
const onChange = this.props.onChange; <Overlay
onChange(''); placement={
} placement || 'left-bottom-left-top right-bottom-right-top'
handleClick() {
this.state.isOpened ? this.close() : this.open(this.focus);
}
handleInputChange(e: React.ChangeEvent<HTMLInputElement>) {
const onChange = this.props.onChange;
this.setState(
{
inputValue: e.currentTarget.value
},
() => {
const dom: HTMLElement = this.preview.current as HTMLElement;
// 通过读取dom上到值确认当前输入值是否有效。
if (dom && dom.style.backgroundColor === this.state.inputValue) {
onChange(this.state.inputValue);
}
} }
); target={() => findDOMNode(this)}
} onHide={this.close}
container={popOverContainer || (() => findDOMNode(this))}
handleChange(color: ColorResult) { rootClose={false}
const { show
onChange, >
format <PopOver
// closeOnSelect classPrefix={ns}
} = this.props; className={cx('ColorPicker-popover')}
onHide={this.close}
if (format === 'rgba') { overlay
onChange(`rgba(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b}, ${color.rgb.a})`);
} else if (format === 'rgb') {
onChange(`rgb(${color.rgb.r}, ${color.rgb.g}, ${color.rgb.b})`);
} else if (format === 'hsl') {
onChange(
`hsl(${Math.round(color.hsl.h)}, ${Math.round(color.hsl.s * 100)}%, ${Math.round(color.hsl.l * 100)}%)`
);
} else {
onChange(color.hex);
}
// closeOnSelect && this.close();
}
render() {
const {
classPrefix: ns,
className,
value,
placeholder,
disabled,
popOverContainer,
format,
clearable,
placement,
classnames: cx,
presetColors
} = this.props;
const isOpened = this.state.isOpened;
const isFocused = this.state.isFocused;
return (
<div
className={cx(
`ColorPicker`,
{
'is-disabled': disabled,
'is-focused': isFocused
},
className
)}
> >
<input <SketchPicker
size={10} disableAlpha={!!~['rgb', 'hex'].indexOf(format as string)}
ref={this.input} color={value}
type="text" presetColors={presetColors}
autoComplete="off" onChangeComplete={this.handleChange}
className={cx('ColorPicker-input')} />
value={this.state.inputValue || ''} </PopOver>
placeholder={placeholder} </Overlay>
disabled={disabled} ) : null}
onChange={this.handleInputChange} </div>
onFocus={this.handleFocus} );
onBlur={this.handleBlur} }
onClick={this.handleClick}
/>
{clearable && !disabled && value ? (
<a onClick={this.clearValue} className={cx('ColorPicker-clear')}>
<Icon icon="close" className="icon" />
</a>
) : null}
<span onClick={this.handleClick} className={cx('ColorPicker-preview')}>
<i
ref={this.preview}
className={`${ns}ColorPicker-previewIcon`}
style={{background: this.state.inputValue || '#ccc'}}
/>
</span>
{isOpened ? (
<Overlay
placement={placement || 'left-bottom-left-top right-bottom-right-top'}
target={() => findDOMNode(this)}
onHide={this.close}
container={popOverContainer || (() => findDOMNode(this))}
rootClose={false}
show
>
<PopOver classPrefix={ns} className={cx('ColorPicker-popover')} onHide={this.close} overlay>
<SketchPicker
disableAlpha={!!~['rgb', 'hex'].indexOf(format as string)}
color={value}
presetColors={presetColors}
onChangeComplete={this.handleChange}
/>
</PopOver>
</Overlay>
) : null}
</div>
);
}
} }
export default themeable( export default themeable(
uncontrollable(ColorControl, { uncontrollable(ColorControl, {
value: 'onChange' value: 'onChange'
}) })
); );

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,11 @@
*/ */
import React from 'react'; import React from 'react';
import Transition, {ENTERED, ENTERING, EXITING} from 'react-transition-group/Transition'; import Transition, {
ENTERED,
ENTERING,
EXITING
} from 'react-transition-group/Transition';
import {Portal} from 'react-overlays'; import {Portal} from 'react-overlays';
import {Icon} from './icons'; import {Icon} from './icons';
import cx from 'classnames'; import cx from 'classnames';
@ -16,151 +20,169 @@ import {noop, autobind} from '../utils/helper';
type DrawerPosition = 'top' | 'right' | 'bottom' | 'left'; type DrawerPosition = 'top' | 'right' | 'bottom' | 'left';
export interface DrawerProps { export interface DrawerProps {
className?: string; className?: string;
size: any; size: any;
overlay: boolean; overlay: boolean;
onHide: () => void; onHide: () => void;
closeOnEsc?: boolean; closeOnEsc?: boolean;
container: any; container: any;
show?: boolean; show?: boolean;
position: DrawerPosition; position: DrawerPosition;
disabled?: boolean; disabled?: boolean;
closeOnOutside?: boolean; closeOnOutside?: boolean;
classPrefix: string; classPrefix: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
onExited?: () => void; onExited?: () => void;
onEntered?: () => void; onEntered?: () => void;
disableOnClickOutside: () => void; disableOnClickOutside: () => void;
enableOnClickOutside: () => void; enableOnClickOutside: () => void;
} }
export interface DrawerState {} export interface DrawerState {}
const fadeStyles: { const fadeStyles: {
[propName: string]: string; [propName: string]: string;
} = { } = {
[ENTERING]: 'in', [ENTERING]: 'in',
[ENTERED]: 'in' [ENTERED]: 'in'
}; };
export class Drawer extends React.Component<DrawerProps, DrawerState> { export class Drawer extends React.Component<DrawerProps, DrawerState> {
static defaultProps: Pick< static defaultProps: Pick<
DrawerProps, DrawerProps,
'container' | 'position' | 'size' | 'overlay' | 'disableOnClickOutside' | 'enableOnClickOutside' | 'container'
> = { | 'position'
container: document.body, | 'size'
position: 'left', | 'overlay'
size: 'md', | 'disableOnClickOutside'
overlay: true, | 'enableOnClickOutside'
disableOnClickOutside: noop, > = {
enableOnClickOutside: noop container: document.body,
}; position: 'left',
size: 'md',
overlay: true,
disableOnClickOutside: noop,
enableOnClickOutside: noop
};
contentDom: any; contentDom: any;
componentDidMount() { componentDidMount() {
if (this.props.show) { if (this.props.show) {
this.handleEntered(); this.handleEntered();
}
} }
}
componentWillUnmount() { componentWillUnmount() {
if (this.props.show) { if (this.props.show) {
this.handleExited(); this.handleExited();
}
} }
}
contentRef = (ref: any) => (this.contentDom = ref); contentRef = (ref: any) => (this.contentDom = ref);
handleEntered = () => { handleEntered = () => {
const onEntered = this.props.onEntered; const onEntered = this.props.onEntered;
document.body.classList.add(`is-modalOpened`); document.body.classList.add(`is-modalOpened`);
onEntered && onEntered(); onEntered && onEntered();
}; };
handleExited = () => { handleExited = () => {
const onExited = this.props.onExited; const onExited = this.props.onExited;
document.activeElement && (document.activeElement as HTMLElement).blur(); document.activeElement && (document.activeElement as HTMLElement).blur();
onExited && onExited(); onExited && onExited();
setTimeout(() => { setTimeout(() => {
document.querySelector('.amis-dialog-widget') || document.body.classList.remove(`is-modalOpened`); document.querySelector('.amis-dialog-widget') ||
}, 200); document.body.classList.remove(`is-modalOpened`);
}; }, 200);
};
modalRef = (ref: any) => { modalRef = (ref: any) => {
if (ref) { if (ref) {
addModal(this); addModal(this);
(ref as HTMLElement).classList.add(`${this.props.classPrefix}Modal--${current()}th`); (ref as HTMLElement).classList.add(
} else { `${this.props.classPrefix}Modal--${current()}th`
removeModal(); );
} } else {
}; removeModal();
@autobind
handleWidgetClick(e: React.MouseEvent) {
const {classPrefix: ns, closeOnOutside, onHide} = this.props;
if ((e.target as HTMLElement).closest(`.${ns}Drawer-content`)) {
return;
}
closeOnOutside && onHide && onHide();
} }
};
render() { @autobind
const { handleWidgetClick(e: React.MouseEvent) {
classPrefix: ns, const {classPrefix: ns, closeOnOutside, onHide} = this.props;
className, if ((e.target as HTMLElement).closest(`.${ns}Drawer-content`)) {
children, return;
container, }
show, closeOnOutside && onHide && onHide();
position, }
size,
onHide,
disabled,
overlay
} = this.props;
return ( render() {
<Portal container={container}> const {
<Transition classPrefix: ns,
mountOnEnter className,
unmountOnExit children,
in={show} container,
timeout={500} show,
onExited={this.handleExited} position,
onEntered={this.handleEntered} size,
onHide,
disabled,
overlay
} = this.props;
return (
<Portal container={container}>
<Transition
mountOnEnter
unmountOnExit
in={show}
timeout={500}
onExited={this.handleExited}
onEntered={this.handleEntered}
>
{(status: string) => {
if (status === ENTERING) {
// force reflow
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短上次的样式还没应用进去所以这里强制reflow一把。
// 否则看不到动画。
this.contentDom.offsetWidth;
}
return (
<div
ref={this.modalRef}
role="dialog"
className={cx(
`amis-dialog-widget ${ns}Drawer`,
{
[`${ns}Drawer--${position}`]: position,
[`${ns}Drawer--${size}`]: size,
[`${ns}Drawer--noOverlay`]: !overlay
},
className
)}
onClick={this.handleWidgetClick} // 其实不需要插件,直接写逻辑吧
>
{overlay ? (
<div
className={cx(`${ns}Drawer-overlay`, fadeStyles[status])}
/>
) : null}
<div
ref={this.contentRef}
className={cx(`${ns}Drawer-content`, fadeStyles[status])}
> >
{(status: string) => { <a
if (status === ENTERING) { onClick={disabled ? undefined : onHide}
// force reflow className={`${ns}Drawer-close`}
// 由于从 mount 进来到加上 in 这个 class 估计是时间太短上次的样式还没应用进去所以这里强制reflow一把。 >
// 否则看不到动画。 <Icon icon="close" className="icon" />
this.contentDom.offsetWidth; </a>
} {children}
</div>
return ( </div>
<div );
ref={this.modalRef} }}
role="dialog" </Transition>
className={cx( </Portal>
`amis-dialog-widget ${ns}Drawer`, );
{ }
[`${ns}Drawer--${position}`]: position,
[`${ns}Drawer--${size}`]: size,
[`${ns}Drawer--noOverlay`]: !overlay
},
className
)}
onClick={this.handleWidgetClick} // 其实不需要插件,直接写逻辑吧
>
{overlay ? <div className={cx(`${ns}Drawer-overlay`, fadeStyles[status])} /> : null}
<div ref={this.contentRef} className={cx(`${ns}Drawer-content`, fadeStyles[status])}>
<a onClick={disabled ? undefined : onHide} className={`${ns}Drawer-close`}>
<Icon icon="close" className="icon" />
</a>
{children}
</div>
</div>
);
}}
</Transition>
</Portal>
);
}
} }
export default themeable(Drawer); export default themeable(Drawer);

View File

@ -9,379 +9,500 @@ import cx from 'classnames';
import {ClassNamesFn, themeable} from '../theme'; import {ClassNamesFn, themeable} from '../theme';
function noJsExt(raw: string) { function noJsExt(raw: string) {
return raw.replace(/\.js$/, ''); return raw.replace(/\.js$/, '');
} }
const defaultConfig = { const defaultConfig = {
url: 'vs/loader.js', url: 'vs/loader.js',
'vs/nls': { 'vs/nls': {
availableLanguages: { availableLanguages: {
'*': 'zh-cn' '*': 'zh-cn'
} }
}, },
paths: {} paths: {}
}; };
try { try {
// fis 编译的话,能正确赋值上,如果不是,那请通过外部参数传递。 // fis 编译的话,能正确赋值上,如果不是,那请通过外部参数传递。
defaultConfig.url = __uri('monaco-editor/min/vs/loader.js'); defaultConfig.url = __uri('monaco-editor/min/vs/loader.js');
defaultConfig.paths = { defaultConfig.paths = {
vs: noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.js')).replace(/\/vs\/.*$/, ''), vs: noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.js')).replace(
'vs/base/worker/workerMain': noJsExt(__uri('monaco-editor/min/vs/base/worker/workerMain.js')), /\/vs\/.*$/,
''
),
'vs/base/worker/workerMain': noJsExt(
__uri('monaco-editor/min/vs/base/worker/workerMain.js')
),
'vs/basic-languages/apex/apex': noJsExt(__uri('monaco-editor/min/vs/basic-languages/apex/apex')), 'vs/basic-languages/apex/apex': noJsExt(
'vs/basic-languages/azcli/azcli': noJsExt(__uri('monaco-editor/min/vs/basic-languages/azcli/azcli')), __uri('monaco-editor/min/vs/basic-languages/apex/apex')
'vs/basic-languages/clojure/clojure': noJsExt(__uri('monaco-editor/min/vs/basic-languages/clojure/clojure')), ),
'vs/basic-languages/bat/bat': noJsExt(__uri('monaco-editor/min/vs/basic-languages/bat/bat')), 'vs/basic-languages/azcli/azcli': noJsExt(
'vs/basic-languages/coffee/coffee': noJsExt(__uri('monaco-editor/min/vs/basic-languages/coffee/coffee')), __uri('monaco-editor/min/vs/basic-languages/azcli/azcli')
'vs/basic-languages/cpp/cpp': noJsExt(__uri('monaco-editor/min/vs/basic-languages/cpp/cpp')), ),
'vs/basic-languages/csharp/csharp': noJsExt(__uri('monaco-editor/min/vs/basic-languages/csharp/csharp')), 'vs/basic-languages/clojure/clojure': noJsExt(
'vs/basic-languages/css/css': noJsExt(__uri('monaco-editor/min/vs/basic-languages/css/css')), __uri('monaco-editor/min/vs/basic-languages/clojure/clojure')
'vs/basic-languages/dockerfile/dockerfile': noJsExt( ),
__uri('monaco-editor/min/vs/basic-languages/dockerfile/dockerfile') 'vs/basic-languages/bat/bat': noJsExt(
), __uri('monaco-editor/min/vs/basic-languages/bat/bat')
'vs/basic-languages/fsharp/fsharp': noJsExt(__uri('monaco-editor/min/vs/basic-languages/fsharp/fsharp')), ),
'vs/basic-languages/go/go': noJsExt(__uri('monaco-editor/min/vs/basic-languages/go/go')), 'vs/basic-languages/coffee/coffee': noJsExt(
'vs/basic-languages/handlebars/handlebars': noJsExt( __uri('monaco-editor/min/vs/basic-languages/coffee/coffee')
__uri('monaco-editor/min/vs/basic-languages/handlebars/handlebars') ),
), 'vs/basic-languages/cpp/cpp': noJsExt(
'vs/basic-languages/html/html': noJsExt(__uri('monaco-editor/min/vs/basic-languages/html/html')), __uri('monaco-editor/min/vs/basic-languages/cpp/cpp')
'vs/basic-languages/ini/ini': noJsExt(__uri('monaco-editor/min/vs/basic-languages/ini/ini')), ),
'vs/basic-languages/java/java': noJsExt(__uri('monaco-editor/min/vs/basic-languages/java/java')), 'vs/basic-languages/csharp/csharp': noJsExt(
'vs/basic-languages/javascript/javascript': noJsExt( __uri('monaco-editor/min/vs/basic-languages/csharp/csharp')
__uri('monaco-editor/min/vs/basic-languages/javascript/javascript') ),
), 'vs/basic-languages/css/css': noJsExt(
'vs/basic-languages/less/less': noJsExt(__uri('monaco-editor/min/vs/basic-languages/less/less')), __uri('monaco-editor/min/vs/basic-languages/css/css')
'vs/basic-languages/lua/lua': noJsExt(__uri('monaco-editor/min/vs/basic-languages/lua/lua')), ),
'vs/basic-languages/markdown/markdown': noJsExt( 'vs/basic-languages/dockerfile/dockerfile': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/markdown/markdown') __uri('monaco-editor/min/vs/basic-languages/dockerfile/dockerfile')
), ),
'vs/basic-languages/msdax/msdax': noJsExt(__uri('monaco-editor/min/vs/basic-languages/msdax/msdax')), 'vs/basic-languages/fsharp/fsharp': noJsExt(
'vs/basic-languages/objective-c/objective-c': noJsExt( __uri('monaco-editor/min/vs/basic-languages/fsharp/fsharp')
__uri('monaco-editor/min/vs/basic-languages/objective-c/objective-c') ),
), 'vs/basic-languages/go/go': noJsExt(
'vs/basic-languages/php/php': noJsExt(__uri('monaco-editor/min/vs/basic-languages/php/php')), __uri('monaco-editor/min/vs/basic-languages/go/go')
'vs/basic-languages/postiats/postiats': noJsExt( ),
__uri('monaco-editor/min/vs/basic-languages/postiats/postiats') 'vs/basic-languages/handlebars/handlebars': noJsExt(
), __uri('monaco-editor/min/vs/basic-languages/handlebars/handlebars')
'vs/basic-languages/powershell/powershell': noJsExt( ),
__uri('monaco-editor/min/vs/basic-languages/powershell/powershell') 'vs/basic-languages/html/html': noJsExt(
), __uri('monaco-editor/min/vs/basic-languages/html/html')
'vs/basic-languages/pug/pug': noJsExt(__uri('monaco-editor/min/vs/basic-languages/pug/pug')), ),
'vs/basic-languages/python/python': noJsExt(__uri('monaco-editor/min/vs/basic-languages/python/python')), 'vs/basic-languages/ini/ini': noJsExt(
'vs/basic-languages/r/r': noJsExt(__uri('monaco-editor/min/vs/basic-languages/r/r')), __uri('monaco-editor/min/vs/basic-languages/ini/ini')
'vs/basic-languages/razor/razor': noJsExt(__uri('monaco-editor/min/vs/basic-languages/razor/razor')), ),
'vs/basic-languages/redis/redis': noJsExt(__uri('monaco-editor/min/vs/basic-languages/redis/redis')), 'vs/basic-languages/java/java': noJsExt(
'vs/basic-languages/redshift/redshift': noJsExt( __uri('monaco-editor/min/vs/basic-languages/java/java')
__uri('monaco-editor/min/vs/basic-languages/redshift/redshift') ),
), 'vs/basic-languages/javascript/javascript': noJsExt(
'vs/basic-languages/ruby/ruby': noJsExt(__uri('monaco-editor/min/vs/basic-languages/ruby/ruby')), __uri('monaco-editor/min/vs/basic-languages/javascript/javascript')
'vs/basic-languages/rust/rust': noJsExt(__uri('monaco-editor/min/vs/basic-languages/rust/rust')), ),
'vs/basic-languages/sb/sb': noJsExt(__uri('monaco-editor/min/vs/basic-languages/sb/sb')), 'vs/basic-languages/less/less': noJsExt(
'vs/basic-languages/scheme/scheme': noJsExt(__uri('monaco-editor/min/vs/basic-languages/scheme/scheme')), __uri('monaco-editor/min/vs/basic-languages/less/less')
'vs/basic-languages/scss/scss': noJsExt(__uri('monaco-editor/min/vs/basic-languages/scss/scss')), ),
'vs/basic-languages/shell/shell': noJsExt(__uri('monaco-editor/min/vs/basic-languages/shell/shell')), 'vs/basic-languages/lua/lua': noJsExt(
'vs/basic-languages/solidity/solidity': noJsExt( __uri('monaco-editor/min/vs/basic-languages/lua/lua')
__uri('monaco-editor/min/vs/basic-languages/solidity/solidity') ),
), 'vs/basic-languages/markdown/markdown': noJsExt(
'vs/basic-languages/sql/sql': noJsExt(__uri('monaco-editor/min/vs/basic-languages/sql/sql')), __uri('monaco-editor/min/vs/basic-languages/markdown/markdown')
'vs/basic-languages/st/st': noJsExt(__uri('monaco-editor/min/vs/basic-languages/st/st')), ),
'vs/basic-languages/swift/swift': noJsExt(__uri('monaco-editor/min/vs/basic-languages/swift/swift')), 'vs/basic-languages/msdax/msdax': noJsExt(
'vs/basic-languages/typescript/typescript': noJsExt( __uri('monaco-editor/min/vs/basic-languages/msdax/msdax')
__uri('monaco-editor/min/vs/basic-languages/typescript/typescript') ),
), 'vs/basic-languages/objective-c/objective-c': noJsExt(
'vs/basic-languages/vb/vb': noJsExt(__uri('monaco-editor/min/vs/basic-languages/vb/vb')), __uri('monaco-editor/min/vs/basic-languages/objective-c/objective-c')
'vs/basic-languages/xml/xml': noJsExt(__uri('monaco-editor/min/vs/basic-languages/xml/xml')), ),
'vs/basic-languages/yaml/yaml': noJsExt(__uri('monaco-editor/min/vs/basic-languages/yaml/yaml')), 'vs/basic-languages/php/php': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/php/php')
),
'vs/basic-languages/postiats/postiats': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/postiats/postiats')
),
'vs/basic-languages/powershell/powershell': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/powershell/powershell')
),
'vs/basic-languages/pug/pug': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/pug/pug')
),
'vs/basic-languages/python/python': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/python/python')
),
'vs/basic-languages/r/r': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/r/r')
),
'vs/basic-languages/razor/razor': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/razor/razor')
),
'vs/basic-languages/redis/redis': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/redis/redis')
),
'vs/basic-languages/redshift/redshift': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/redshift/redshift')
),
'vs/basic-languages/ruby/ruby': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/ruby/ruby')
),
'vs/basic-languages/rust/rust': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/rust/rust')
),
'vs/basic-languages/sb/sb': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/sb/sb')
),
'vs/basic-languages/scheme/scheme': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/scheme/scheme')
),
'vs/basic-languages/scss/scss': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/scss/scss')
),
'vs/basic-languages/shell/shell': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/shell/shell')
),
'vs/basic-languages/solidity/solidity': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/solidity/solidity')
),
'vs/basic-languages/sql/sql': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/sql/sql')
),
'vs/basic-languages/st/st': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/st/st')
),
'vs/basic-languages/swift/swift': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/swift/swift')
),
'vs/basic-languages/typescript/typescript': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/typescript/typescript')
),
'vs/basic-languages/vb/vb': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/vb/vb')
),
'vs/basic-languages/xml/xml': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/xml/xml')
),
'vs/basic-languages/yaml/yaml': noJsExt(
__uri('monaco-editor/min/vs/basic-languages/yaml/yaml')
),
'vs/editor/editor.main': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.js')), 'vs/editor/editor.main': noJsExt(
'vs/editor/editor.main.css': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.css')), __uri('monaco-editor/min/vs/editor/editor.main.js')
'vs/editor/editor.main.nls': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.nls.js')), ),
'vs/editor/editor.main.nls.zh-cn': noJsExt(__uri('monaco-editor/min/vs/editor/editor.main.nls.zh-cn.js')), 'vs/editor/editor.main.css': noJsExt(
__uri('monaco-editor/min/vs/editor/editor.main.css')
),
'vs/editor/editor.main.nls': noJsExt(
__uri('monaco-editor/min/vs/editor/editor.main.nls.js')
),
'vs/editor/editor.main.nls.zh-cn': noJsExt(
__uri('monaco-editor/min/vs/editor/editor.main.nls.zh-cn.js')
),
// 'vs/editor/contrib/suggest/media/String_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_16x.svg')), // 'vs/editor/contrib/suggest/media/String_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_16x.svg')),
// 'vs/editor/contrib/suggest/media/String_inverse_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_inverse_16x.svg')), // 'vs/editor/contrib/suggest/media/String_inverse_16x.svg': noJsExt(__uri('monaco-editor/min/vs/editor/contrib/suggest/media/String_inverse_16x.svg')),
// 'vs/editor/standalone/browser/quickOpen/symbol-sprite.svg': noJsExt(__uri('monaco-editor/min/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg')), // 'vs/editor/standalone/browser/quickOpen/symbol-sprite.svg': noJsExt(__uri('monaco-editor/min/vs/editor/standalone/browser/quickOpen/symbol-sprite.svg')),
'vs/language/typescript/tsMode': noJsExt(__uri('monaco-editor/min/vs/language/typescript/tsMode.js')), 'vs/language/typescript/tsMode': noJsExt(
// 'vs/language/typescript/lib/typescriptServices': noJsExt(__uri('monaco-editor/min/vs/language/typescript/lib/typescriptServices.js')), __uri('monaco-editor/min/vs/language/typescript/tsMode.js')
'vs/language/typescript/tsWorker': noJsExt(__uri('monaco-editor/min/vs/language/typescript/tsWorker.js')), ),
// 'vs/language/typescript/lib/typescriptServices': noJsExt(__uri('monaco-editor/min/vs/language/typescript/lib/typescriptServices.js')),
'vs/language/typescript/tsWorker': noJsExt(
__uri('monaco-editor/min/vs/language/typescript/tsWorker.js')
),
'vs/language/json/jsonMode': noJsExt(__uri('monaco-editor/min/vs/language/json/jsonMode.js')), 'vs/language/json/jsonMode': noJsExt(
'vs/language/json/jsonWorker': noJsExt(__uri('monaco-editor/min/vs/language/json/jsonWorker.js')), __uri('monaco-editor/min/vs/language/json/jsonMode.js')
),
'vs/language/json/jsonWorker': noJsExt(
__uri('monaco-editor/min/vs/language/json/jsonWorker.js')
),
'vs/language/html/htmlMode': noJsExt(__uri('monaco-editor/min/vs/language/html/htmlMode.js')), 'vs/language/html/htmlMode': noJsExt(
'vs/language/html/htmlWorker': noJsExt(__uri('monaco-editor/min/vs/language/html/htmlWorker.js')), __uri('monaco-editor/min/vs/language/html/htmlMode.js')
),
'vs/language/html/htmlWorker': noJsExt(
__uri('monaco-editor/min/vs/language/html/htmlWorker.js')
),
'vs/language/css/cssMode': noJsExt(__uri('monaco-editor/min/vs/language/css/cssMode.js')), 'vs/language/css/cssMode': noJsExt(
'vs/language/css/cssWorker': noJsExt(__uri('monaco-editor/min/vs/language/css/cssWorker.js')) __uri('monaco-editor/min/vs/language/css/cssMode.js')
}; ),
'vs/language/css/cssWorker': noJsExt(
__uri('monaco-editor/min/vs/language/css/cssWorker.js')
)
};
// cdn 支持 // cdn 支持
/^(https?:)?\/\//.test(defaultConfig.paths.vs) && /^(https?:)?\/\//.test(defaultConfig.paths.vs) &&
((window as any).MonacoEnvironment = { ((window as any).MonacoEnvironment = {
getWorkerUrl: function() { getWorkerUrl: function() {
return `data:text/javascript;charset=utf-8,${encodeURIComponent(` return `data:text/javascript;charset=utf-8,${encodeURIComponent(`
self.MonacoEnvironment = { self.MonacoEnvironment = {
baseUrl: '${defaultConfig.paths.vs}', baseUrl: '${defaultConfig.paths.vs}',
paths: ${JSON.stringify(defaultConfig.paths)} paths: ${JSON.stringify(defaultConfig.paths)}
}; };
importScripts('${__uri('monaco-editor/min/vs/base/worker/workerMain.js')}');`)}`; importScripts('${__uri(
} 'monaco-editor/min/vs/base/worker/workerMain.js'
}); )}');`)}`;
}
});
} catch (e) {} } catch (e) {}
export function monacoFactory(containerElement, monaco, options) { export function monacoFactory(containerElement, monaco, options) {
return monaco.editor.create(containerElement, { return monaco.editor.create(containerElement, {
autoIndent: true, autoIndent: true,
formatOnType: true, formatOnType: true,
formatOnPaste: true, formatOnPaste: true,
selectOnLineNumbers: true, selectOnLineNumbers: true,
scrollBeyondLastLine: false, scrollBeyondLastLine: false,
folding: true, folding: true,
minimap: { minimap: {
enabled: false enabled: false
}, },
...options ...options
}); });
} }
export interface EditorProps { export interface EditorProps {
value?: string; value?: string;
defaultValue?: string; defaultValue?: string;
width?: number | string; width?: number | string;
height?: number | string; height?: number | string;
onChange?: (value: string, event: any) => void; onChange?: (value: string, event: any) => void;
language?: string; language?: string;
editorTheme?: string; editorTheme?: string;
options: { options: {
[propName: string]: any; [propName: string]: any;
}; };
classPrefix: string; classPrefix: string;
className?: string; className?: string;
classnames: ClassNamesFn; classnames: ClassNamesFn;
context?: any; context?: any;
style?: any; style?: any;
onFocus?: () => void; onFocus?: () => void;
onBlur?: () => void; onBlur?: () => void;
editorDidMount?: (editor: any, monaco: any) => void; editorDidMount?: (editor: any, monaco: any) => void;
editorWillMount?: (monaco: any) => void; editorWillMount?: (monaco: any) => void;
editorWillUnmount?: (editor: any, monaco: any) => void; editorWillUnmount?: (editor: any, monaco: any) => void;
editorFactory?: (conatainer: HTMLElement, monaco: any, options: any) => any; editorFactory?: (conatainer: HTMLElement, monaco: any, options: any) => any;
requireConfig: { requireConfig: {
url: string; url: string;
paths?: any; paths?: any;
[propName: string]: any; [propName: string]: any;
}; };
} }
export class Editor extends React.Component<EditorProps, any> { export class Editor extends React.Component<EditorProps, any> {
static defaultProps = { static defaultProps = {
requireConfig: defaultConfig, requireConfig: defaultConfig,
language: 'javascript', language: 'javascript',
editorTheme: 'vs', editorTheme: 'vs',
width: '100%', width: '100%',
height: '100%', height: '100%',
options: {} options: {}
}; };
editor: any; editor: any;
container: any; container: any;
currentValue: any; currentValue: any;
preventTriggerChangeEvent: boolean; preventTriggerChangeEvent: boolean;
disposes: Array<{dispose: () => void}> = []; disposes: Array<{dispose: () => void}> = [];
constructor(props: EditorProps) { constructor(props: EditorProps) {
super(props); super(props);
this.wrapperRef = this.wrapperRef.bind(this); this.wrapperRef = this.wrapperRef.bind(this);
this.currentValue = props.value; this.currentValue = props.value;
}
componentWillReceiveProps(nextProps: EditorProps) {
if (
this.props.options.readOnly !== nextProps.options.readOnly &&
this.editor
) {
this.editor.updateOptions && this.editor.updateOptions(nextProps.options);
} }
}
componentWillReceiveProps(nextProps: EditorProps) { componentDidUpdate() {
if (this.props.options.readOnly !== nextProps.options.readOnly && this.editor) { if (this.props.value !== this.currentValue && this.editor) {
this.editor.updateOptions && this.editor.updateOptions(nextProps.options); let value = String(this.props.value);
}
if (this.props.language === 'json') {
try {
value = JSON.stringify(JSON.parse(value), null, 4);
} catch (e) {}
}
this.preventTriggerChangeEvent = true;
this.editor.setValue && this.editor.setValue(value);
this.preventTriggerChangeEvent = false;
} }
}
componentDidUpdate() { componentWillUnmount() {
if (this.props.value !== this.currentValue && this.editor) { if (this.editor) {
let value = String(this.props.value); const context = this.props.context || window;
const monaco = context.monaco || (window as any).monaco;
if (this.props.language === 'json') { const editorWillUnmount = this.props.editorWillUnmount;
try { editorWillUnmount && editorWillUnmount(this.editor, monaco);
value = JSON.stringify(JSON.parse(value), null, 4);
} catch (e) {}
}
this.preventTriggerChangeEvent = true;
this.editor.setValue && this.editor.setValue(value);
this.preventTriggerChangeEvent = false;
}
} }
this.disposes.forEach(({dispose}) => dispose());
this.disposes = [];
}
componentWillUnmount() { wrapperRef(ref: any) {
if (this.editor) { this.container = ref;
const context = this.props.context || window; if (ref) {
const monaco = context.monaco || (window as any).monaco; this.loadMonaco();
const editorWillUnmount = this.props.editorWillUnmount; } else {
editorWillUnmount && editorWillUnmount(this.editor, monaco); try {
}
this.disposes.forEach(({dispose}) => dispose()); this.disposes.forEach(({dispose}) => dispose());
this.disposes = []; this.disposes = [];
} if (this.editor) {
this.editor.getModel().dispose();
wrapperRef(ref: any) { this.editor.dispose();
this.container = ref;
if (ref) {
this.loadMonaco();
} else {
try {
this.disposes.forEach(({dispose}) => dispose());
this.disposes = [];
if (this.editor) {
this.editor.getModel().dispose();
this.editor.dispose();
}
this.editor = null;
} catch (e) {
// ignore
}
} }
this.editor = null;
} catch (e) {
// ignore
}
} }
}
loadMonaco() { loadMonaco() {
const {requireConfig} = this.props; const {requireConfig} = this.props;
const loaderUrl = requireConfig.url || 'vs/loader.js'; const loaderUrl = requireConfig.url || 'vs/loader.js';
const context = const context =
(window as any).monacaAmd || (window as any).monacaAmd ||
((window as any).monacaAmd = { ((window as any).monacaAmd = {
document: window.document document: window.document
}); });
const onGotAmdLoader = () => { const onGotAmdLoader = () => {
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) { if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
// Do not use webpack // Do not use webpack
if (requireConfig.paths && requireConfig.paths.vs) { if (requireConfig.paths && requireConfig.paths.vs) {
context.require.config(requireConfig); context.require.config(requireConfig);
}
}
// Load monaco
context['require'](['vs/editor/editor.main', 'vs/editor/editor.main.nls.zh-cn'], () => {
this.initMonaco();
});
// Call the delayed callbacks when AMD loader has been loaded
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = false;
let loaderCallbacks = context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__;
if (loaderCallbacks && loaderCallbacks.length) {
let currentCallback = loaderCallbacks.shift();
while (currentCallback) {
currentCallback.fn.call(currentCallback.context);
currentCallback = loaderCallbacks.shift();
}
}
}
};
// Load AMD loader if necessary
if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
// We need to avoid loading multiple loader.js when there are multiple editors loading concurrently
// delay to call callbacks except the first one
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ = context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ || [];
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__.push({
context: this,
fn: onGotAmdLoader
});
} else {
if (typeof context.require === 'undefined') {
var loaderScript = context.document.createElement('script');
loaderScript.type = 'text/javascript';
loaderScript.src = loaderUrl;
loaderScript.addEventListener('load', onGotAmdLoader);
context.document.body.appendChild(loaderScript);
context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = true;
} else {
onGotAmdLoader();
}
} }
} }
initMonaco() { // Load monaco
let value = this.props.value !== null ? this.props.value : this.props.defaultValue; context['require'](
const {language, editorTheme, options, editorFactory} = this.props; ['vs/editor/editor.main', 'vs/editor/editor.main.nls.zh-cn'],
const containerElement = this.container; () => {
if (!containerElement) { this.initMonaco();
return;
} }
const context = this.props.context || window; );
const monaco = context.monaco || (window as any).monaco;
if (typeof monaco !== 'undefined') {
// Before initializing monaco editor
this.editorWillMount(monaco);
if (this.props.language === 'json') { // Call the delayed callbacks when AMD loader has been loaded
try { if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
value = JSON.stringify(typeof value === 'string' ? JSON.parse(value) : value, null, 4); context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = false;
} catch (e) { let loaderCallbacks = context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__;
// ignore if (loaderCallbacks && loaderCallbacks.length) {
} let currentCallback = loaderCallbacks.shift();
} while (currentCallback) {
currentCallback.fn.call(currentCallback.context);
const factory = editorFactory || monacoFactory; currentCallback = loaderCallbacks.shift();
this.editor = factory(containerElement, monaco, { }
...options,
automaticLayout: true,
value,
language,
editorTheme,
theme: editorTheme
});
// json 默认开启验证。
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
enableSchemaRequest: true,
validate: true
});
// After initializing monaco editor
this.editorDidMount(this.editor, monaco);
} }
} }
};
editorWillMount(monaco: any) { // Load AMD loader if necessary
const {editorWillMount} = this.props; if (context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__) {
editorWillMount && editorWillMount(monaco); // We need to avoid loading multiple loader.js when there are multiple editors loading concurrently
// delay to call callbacks except the first one
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ =
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__ || [];
context.__REACT_MONACO_EDITOR_LOADER_CALLBACKS__.push({
context: this,
fn: onGotAmdLoader
});
} else {
if (typeof context.require === 'undefined') {
var loaderScript = context.document.createElement('script');
loaderScript.type = 'text/javascript';
loaderScript.src = loaderUrl;
loaderScript.addEventListener('load', onGotAmdLoader);
context.document.body.appendChild(loaderScript);
context.__REACT_MONACO_EDITOR_LOADER_ISPENDING__ = true;
} else {
onGotAmdLoader();
}
} }
editorDidMount(editor: any, monaco: any) { }
const {editorDidMount, onChange, onFocus, onBlur} = this.props;
editorDidMount && editorDidMount(editor, monaco);
editor.onDidChangeModelContent &&
this.disposes.push(
editor.onDidChangeModelContent((event: any) => {
const value = editor.getValue();
// Always refer to the latest value
this.currentValue = value;
// Only invoking when user input changed initMonaco() {
if (!this.preventTriggerChangeEvent && onChange) { let value =
onChange(value, event); this.props.value !== null ? this.props.value : this.props.defaultValue;
} const {language, editorTheme, options, editorFactory} = this.props;
}) const containerElement = this.container;
); if (!containerElement) {
onFocus && editor.onDidFocusEditorWidget && this.disposes.push(editor.onDidFocusEditorWidget(onFocus)); return;
onBlur && editor.onDidBlurEditorWidget && this.disposes.push(editor.onDidBlurEditorWidget(onBlur));
} }
const context = this.props.context || window;
const monaco = context.monaco || (window as any).monaco;
if (typeof monaco !== 'undefined') {
// Before initializing monaco editor
this.editorWillMount(monaco);
render() { if (this.props.language === 'json') {
const {className, classPrefix: ns, width, height} = this.props; try {
let style = this.props.style || {}; value = JSON.stringify(
style.width = width; typeof value === 'string' ? JSON.parse(value) : value,
style.height = height; null,
4
);
} catch (e) {
// ignore
}
}
return <div className={cx(`${ns}MonacoEditor`, className)} style={style} ref={this.wrapperRef} />; const factory = editorFactory || monacoFactory;
this.editor = factory(containerElement, monaco, {
...options,
automaticLayout: true,
value,
language,
editorTheme,
theme: editorTheme
});
// json 默认开启验证。
monaco.languages.json.jsonDefaults.setDiagnosticsOptions({
enableSchemaRequest: true,
validate: true
});
// After initializing monaco editor
this.editorDidMount(this.editor, monaco);
} }
}
editorWillMount(monaco: any) {
const {editorWillMount} = this.props;
editorWillMount && editorWillMount(monaco);
}
editorDidMount(editor: any, monaco: any) {
const {editorDidMount, onChange, onFocus, onBlur} = this.props;
editorDidMount && editorDidMount(editor, monaco);
editor.onDidChangeModelContent &&
this.disposes.push(
editor.onDidChangeModelContent((event: any) => {
const value = editor.getValue();
// Always refer to the latest value
this.currentValue = value;
// Only invoking when user input changed
if (!this.preventTriggerChangeEvent && onChange) {
onChange(value, event);
}
})
);
onFocus &&
editor.onDidFocusEditorWidget &&
this.disposes.push(editor.onDidFocusEditorWidget(onFocus));
onBlur &&
editor.onDidBlurEditorWidget &&
this.disposes.push(editor.onDidBlurEditorWidget(onBlur));
}
render() {
const {className, classPrefix: ns, width, height} = this.props;
let style = this.props.style || {};
style.width = width;
style.height = height;
return (
<div
className={cx(`${ns}MonacoEditor`, className)}
style={style}
ref={this.wrapperRef}
/>
);
}
} }
export default themeable(Editor); export default themeable(Editor);

Some files were not shown because too many files have changed in this diff Show More