diff --git a/.fusion b/.fusion
index 2789b01949..355849d605 100644
--- a/.fusion
+++ b/.fusion
@@ -95,6 +95,7 @@
"range": "lib/range/scss/variable.scss",
"rating": "lib/rating/scss/variable.scss",
"search": "lib/search/scss/variable.scss",
+ "shell": "lib/shell/scss/variable.scss",
"slider": "lib/slider/scss/variable.scss",
"split-button": "lib/split-button/scss/variable.scss",
"step": "lib/step/scss/variable.scss",
diff --git a/docs/shell/adaptor/index.jsx b/docs/shell/adaptor/index.jsx
new file mode 100644
index 0000000000..fbcd00f4df
--- /dev/null
+++ b/docs/shell/adaptor/index.jsx
@@ -0,0 +1,205 @@
+import React from 'react';
+import { Types } from '@alifd/adaptor-helper';
+import { Shell, Icon } from '@alifd/next';
+
+export default {
+ name: 'Shell',
+ shape: ['normal'],
+ editor: (shape) => {
+ return {
+ props: [{
+ name: 'level',
+ type: Types.enum,
+ default: 'light',
+ options: {
+ normal: ['light', 'dark', 'brand'],
+ }[shape],
+ },{
+ name: 'device',
+ label: 'Device',
+ type: Types.enum,
+ options: ['desktop', 'tablet', 'phone'],
+ default: 'desktop',
+ },{
+ name: 'branding',
+ label: 'Branding',
+ type: Types.bool,
+ default: true,
+ },{
+ name: 'actions',
+ label: 'Actions',
+ type: Types.bool,
+ default: true,
+ },{
+ name: 'navigation',
+ label: 'Navigation',
+ type: Types.enum,
+ options: ['ver', 'hoz', false],
+ default: 'ver',
+ },{
+ name: 'localNav',
+ label: 'LocalNav',
+ type: Types.bool,
+ default: true,
+ },{
+ name: 'appbar',
+ label: 'Appbar',
+ type: Types.bool,
+ default: true,
+ },{
+ name: 'footer',
+ label: 'Footer',
+ type: Types.bool,
+ default: true,
+ },{
+ name: 'tooldock',
+ label: 'Tooldock',
+ type: Types.bool,
+ default: true,
+ },{
+ name: 'ancillary',
+ label: 'Ancillary',
+ type: Types.bool,
+ default: true,
+ }]
+ };
+ },
+ adaptor: ({ level, device, branding, actions, localNav, appbar, footer, tooldock, ancillary, navigation, ...others }) => {
+ let logoStyle = {},
+ shellStyle = {};
+
+ switch(level) {
+ case 'light':
+ logoStyle = {width: 32, height: 32, background: '#000', opacity: '0.04'};
+ break;
+ case 'dark':
+ logoStyle = {width: 32, height: 32, background: '#FFF', opacity: '0.2'};
+ break;
+ case 'brand':
+ logoStyle = {width: 32, height: 32, background: '#000', opacity: '0.04'};
+ break;
+ default:
+ break;
+ }
+
+ switch(device) {
+ case 'phone':
+ shellStyle = {height: 500, width: 480, border: '1px solid #eee'};
+ break;
+ case 'tablet':
+ shellStyle = {height: 500, width: 768, border: '1px solid #eee'};
+ break;
+ case 'desktop':
+ shellStyle = {height: 500, width: 1000, border: '1px solid #eee'};
+ break;
+ default:
+ break;
+ }
+
+ return (
+
+ {
+ branding
+ ?
+
+ App Name
+
+ : null
+ }
+
+ {
+ !navigation
+ ?
+
+ Nav Item 1
+ Nav Item 2
+ Nav Item 3
+ Nav Item 4
+ Nav Item 5
+ Nav Item 6
+ Nav Item 7
+
+
+ : null
+ }
+ {
+ actions
+ ?
+
+
+
+ Name
+
+ : null
+ }
+ {
+ localNav
+ ?
+
+
+ Local Nav1
+
+
+ Local Nav2
+
+
+ Local Nav3
+
+ Local Nav4
+ Local Nav5
+ Local Nav6
+ Local Nav7
+ Local Nav8
+ Local Nav4
+ Local Nav5
+ Local Nav6
+ Local Nav7
+ Local Nav8
+
+
+ : null
+ }
+ {
+ appbar
+ ?
+
+
+ : null
+ }
+
+
+
+
+ {
+ ancillary
+ ?
+
+ : null
+ }
+ {
+ tooldock
+ ?
+
+
+
+
+
+
+
+
+
+
+ : null
+ }
+ {
+ footer
+ ?
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+ : null
+ }
+
+ );
+ }
+};
diff --git a/docs/shell/demo/basic.md b/docs/shell/demo/basic.md
new file mode 100644
index 0000000000..35caea4158
--- /dev/null
+++ b/docs/shell/demo/basic.md
@@ -0,0 +1,76 @@
+# 基本
+
+- order: 0
+
+基本的Shell
+
+:::lang=en-us
+# Type
+
+- order: 0
+
+Basic usage of shell
+
+:::
+
+---
+
+````jsx
+import { Search, Icon, Nav, Shell } from '@alifd/next';
+
+const { SubNav, Item, Group, Divider } = Nav;
+
+class App extends React.Component {
+ render() {
+ return (
+
+
+
+
+ App Name
+
+
+
+
+
+
+
+ MyName
+
+
+
+
+
+
+
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+
+
+ );
+ }
+}
+
+ReactDOM.render((
+
+), mountNode);
+````
+````css
+.avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ vertical-align: middle;
+}
+.rectangular {
+ width: 32px;
+ height: 32px;
+ background: rgba(0, 0, 0, 0.04);
+}
+
+.iframe-hack {
+ width: 100%;
+ height: 500px;
+}
+````
diff --git a/docs/shell/demo/complicated.md b/docs/shell/demo/complicated.md
new file mode 100644
index 0000000000..fbd0724842
--- /dev/null
+++ b/docs/shell/demo/complicated.md
@@ -0,0 +1,154 @@
+# 复合类型
+
+- order: 3
+
+全集
+
+:::lang=en-us
+# Type
+
+- order: 3
+
+With all components.
+
+:::
+
+---
+
+````jsx
+import { Search, Icon, Nav, Shell, Radio } from '@alifd/next';
+
+const { SubNav, Item, Group, Divider } = Nav;
+
+class App extends React.Component {
+ state = {
+ device: 'desktop'
+ }
+ onChange = device => {
+ this.setState({
+ device
+ });
+ }
+
+ btnClick = () => {
+ this.setState({
+ navcollapse: !this.state.navcollapse
+ });
+ }
+
+ onCollapseChange = (visible, e) => {
+ console.log('onCollapseChange:',visible, e);
+
+ this.setState({
+ navcollapse: visible
+ });
+ }
+
+ render() {
+ return (
+
+ phone
+ tablet
+ desktop
+
+
+
+
+ App Name
+
+
+
+
+
+
+ MyName
+
+
+
+
+ Nav Item 1
+ Nav Item 2
+ Nav Item 3
+ Nav Item 4
+ Nav Item 5
+ Nav Item 6
+ Nav Item 7
+
+
+ { this.state.navcollapse ? : }
+
+
+
+
+
+
+ - Local Nav1
+
+
+ - Local Nav2
+
+
+ - Local Nav3
+
+ - Local Nav4
+ - Local Nav5
+ - Local Nav6
+ - Local Nav7
+ - Local Nav8
+ - Local Nav4
+ - Local Nav5
+ - Local Nav6
+ - Local Nav7
+ - Local Nav8
+
+
+
+
+
+
+
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
+ }
+}
+
+ReactDOM.render((
+
+), mountNode);
+````
+````css
+.avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ vertical-align: middle;
+}
+.rectangular {
+ width: 32px;
+ height: 32px;
+ background: rgba(0, 0, 0, 0.04);
+}
+
+.iframe-hack {
+ width: 100%;
+ height: 500px;
+}
+````
diff --git a/docs/shell/demo/header-global-local.md b/docs/shell/demo/header-global-local.md
new file mode 100644
index 0000000000..c0e62099f3
--- /dev/null
+++ b/docs/shell/demo/header-global-local.md
@@ -0,0 +1,123 @@
+# 头-双侧边栏
+
+- order: 2
+
+头部加双侧边栏
+
+:::lang=en-us
+# Type
+
+- order: 2
+
+Header with double asider
+
+:::
+
+---
+
+````jsx
+import { Menu, Search, Nav, Shell, Radio } from '@alifd/next';
+
+const { SubNav, Item, Group, Divider } = Nav;
+
+class App extends React.Component {
+ state = {
+ device: 'desktop'
+ }
+ onChange = device => {
+ this.setState({
+ device
+ });
+ }
+ render() {
+ return (
+
+
+ phone
+ tablet
+ desktop
+
+
+
+
+ App Name
+
+
+
+
+
+
+ MyName
+
+
+
+
+ Nav Item 1
+ Nav Item 2
+ Nav Item 3
+ Nav Item 4
+ Nav Item 5
+ Nav Item 6
+ Nav Item 7
+
+
+
+
+
+
+ - Local Nav1
+
+
+ - Local Nav2
+
+
+ - Local Nav3
+
+ - Local Nav4
+ - Local Nav5
+ - Local Nav6
+ - Local Nav7
+ - Local Nav8
+ - Local Nav4
+ - Local Nav5
+ - Local Nav6
+ - Local Nav7
+ - Local Nav8
+
+
+
+
+
+
+
+
+ );
+ }
+}
+
+ReactDOM.render((
+
+), mountNode);
+````
+````css
+.root {
+ height: 500px;
+ overflow: auto;
+}
+
+.avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ vertical-align: middle;
+}
+.rectangular {
+ width: 32px;
+ height: 32px;
+ background: rgba(0, 0, 0, 0.04);
+}
+.iframe-hack {
+ width: 100%;
+ height: 500px;
+}
+````
diff --git a/docs/shell/demo/header-global.md b/docs/shell/demo/header-global.md
new file mode 100644
index 0000000000..1a28c766a5
--- /dev/null
+++ b/docs/shell/demo/header-global.md
@@ -0,0 +1,93 @@
+# 头-侧边栏
+
+- order: 1
+
+头部加侧边栏,最通用的布局
+
+:::lang=en-us
+# Type
+
+- order: 1
+
+Header with asider.
+
+:::
+
+---
+
+````jsx
+import { Menu, Search, Nav, Shell, Radio } from '@alifd/next';
+
+const { SubNav, Item, Group, Divider } = Nav;
+
+class App extends React.Component {
+ state = {
+ device: 'desktop'
+ }
+ onChange = device => {
+ this.setState({
+ device
+ });
+ }
+ render() {
+ return (
+
+ phone
+ tablet
+ desktop
+
+
+
+
+ App Name
+
+
+
+
+
+
+ MyName
+
+
+
+
+ Nav Item 1
+ Nav Item 2
+ Nav Item 3
+ Nav Item 4
+ Nav Item 5
+ Nav Item 6
+ Nav Item 7
+
+
+
+
+
+
+
+
);
+ }
+}
+
+ReactDOM.render((
+
+), mountNode);
+````
+````css
+
+.avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ vertical-align: middle;
+}
+.rectangular {
+ width: 32px;
+ height: 32px;
+ background: rgba(0, 0, 0, 0.04);
+}
+.iframe-hack {
+ width: 100%;
+ height: 500px;
+}
+````
diff --git a/docs/shell/index.en-us.md b/docs/shell/index.en-us.md
new file mode 100644
index 0000000000..59dba278a7
--- /dev/null
+++ b/docs/shell/index.en-us.md
@@ -0,0 +1,73 @@
+# Shell
+
+- category: Components
+- family: General
+- chinese: 框架
+- type: 布局
+
+---
+
+Support IE10+
+
+## Guide
+
+Shell is the infrastructure framework of the whole application. It embodies the structure of the application and the basic capabilities of the application, so that users can complete all their operations under the same framework.
+
+### 何时使用
+
+- Shell should be configured according to the actual business requirements.
+- The same application uses a unified Shell framework to avoid confusion.
+
+````jsx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+````
+
+` ` uses css-grid, others are `display: flex`
+
+## API
+
+### Shell
+| Param | Description | Type | Default Value |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| device | Preset screen width, tt determines whether `Navigation` `LocalNavigation` `Ancillary`take space or not **option**: 'phone', 'tablet', 'desktop' | Enum | desktop |
+
+### Shell.Navigation
+It will tell his children whether it's collapse or not by `isCollapse` via Context.
+
+| Param | Description | Type | Default Value |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| collapse | collapse or not | Boolean | false |
+| direction | header or asider **option**: 'hoz', 'ver' | Enum | hoz |
+
+
+### Shell.LocalNavigation
+| Param | Description | Type | Default Value |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| collapse | collapse or not | Boolean | false |
+
+### Shell.ToolDock
+| Param | Description | Type | Default Value |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| collapse | collapse or not | Boolean | false |
+
+### Shell.Ancillary
+| Param | Description | Type | Default Value |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| collapse | collapse or not | Boolean | false |
+
diff --git a/docs/shell/index.md b/docs/shell/index.md
new file mode 100644
index 0000000000..ef98ceff21
--- /dev/null
+++ b/docs/shell/index.md
@@ -0,0 +1,79 @@
+# Shell
+
+- category: Components
+- family: General
+- chinese: 框架
+- type: 布局
+
+---
+
+仅支持IE10+
+
+## Guide
+
+Shell 是整个应用的基础结构框架。它体现应用的结构形式和承载应用的基本能力,让用户可以在同一套框架下完成自己所有的操作。
+
+### 何时使用
+
+- Shell 应该根据业务实际诉求的复杂度进行配置;
+- 同一个应用统一使用一套 Shell 框架,避免出现混乱问题;
+
+````jsx
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+````
+
+其中 ` ` 采用Grid布局, 其他均为 Flex布局
+
+## API
+
+### Shell
+| 参数 | 说明 | 类型 | 默认值 |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| device | 预设屏幕宽度,会影响`Navigation` `LocalNavigation` `Ancillary`等是否占据空间 **可选值**: 'phone', 'tablet', 'desktop' | Enum | desktop |
+| type | 样式类型,分浅色主题、深色主题、主题色主题,用户可自定义配置 **可选值**: 'light', 'dark', 'brand' | Enum | light |
+
+### Shell.Navigation
+向子组件透传 isCollapse 的Context,表示当前是否处于折叠状态
+
+| 参数 | 说明 | 类型 | 默认值 |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| direction | 方向 **可选值**: 'hoz', 'ver' | Enum | hoz |
+| collapse | 是否折叠(折叠成只有icon状态) | Boolean | false |
+| onCollapseChange | 默认按钮触发的展开收起状态 | Function | () => {} |
+
+
+### Shell.LocalNavigation
+| 参数 | 说明 | 类型 | 默认值 |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| collapse | 是否折叠(完全收起) | Boolean | false |
+| onCollapseChange | 默认按钮触发的展开收起状态 | Function | () => {} |
+
+### Shell.ToolDock
+| 参数 | 说明 | 类型 | 默认值 |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| collapse | 是否折叠(完全收起) | Boolean | false |
+| onCollapseChange | 默认按钮触发的展开收起状态 | Function | () => {} |
+
+### Shell.Ancillary
+| 参数 | 说明 | 类型 | 默认值 |
+| -------------------- | ------------ | ----------------- | ------------------ |
+| collapse | 是否折叠(完全收起) | Boolean | false |
+| onCollapseChange | 默认按钮触发的展开收起状态 | Function | () => {} |
+
+
diff --git a/docs/shell/theme/index.jsx b/docs/shell/theme/index.jsx
new file mode 100644
index 0000000000..b2769ced94
--- /dev/null
+++ b/docs/shell/theme/index.jsx
@@ -0,0 +1,364 @@
+import { Demo, DemoGroup, DemoHead, initDemo } from '../../../src/demo-helper';
+import Shell from '../../../src/shell';
+import Nav from '../../../src/nav';
+import Search from '../../../src/search';
+import Icon from '../../../src/icon';
+import ConfigProvider from '../../../src/config-provider';
+import zhCN from '../../../src/locale/zh-cn';
+import enUS from '../../../src/locale/en-us';
+import '../../../src/demo-helper/style.js';
+import '../../../src/shell/style.js';
+import '../../../src/search/style.js';
+import '../../../src/nav/style.js';
+
+/* eslint-disable */
+const i18nMap = {
+ 'zh-cn': {
+ button: '按钮',
+ light: 'Shell模版1 - light',
+ dark: 'Shell模版2 - dark',
+ brand: 'Shell模版3 - brand',
+ },
+ 'en-us': {
+ button: 'Button',
+ light: 'Template 1 - light',
+ dark: 'Template 2 - dark',
+ brand: 'Template 3 - brand',
+ }
+};
+class RenderShell extends React.Component {
+ render() {
+ const { type, i18n, demoFunction } = this.props;
+ const device = demoFunction.device.value;
+ const globalDir = demoFunction.navigation.value;
+ // let globalNavType = demoFunction.navigationType.value,
+ // localNavType = demoFunction.localNavType.value,
+ let globalHozNavType = 'normal',
+ localNavType = 'normal',
+ logoStyle = {},
+ shellStyle = {};
+
+ switch(type) {
+ case 'light':
+ logoStyle = {width: 32, height: 32, background: '#000', opacity: '0.04'};
+ globalHozNavType = 'normal';
+ break;
+ case 'dark':
+ logoStyle = {width: 32, height: 32, background: '#FFF', opacity: '0.2'};
+ globalHozNavType = globalDir === 'hoz' ? 'primary' : 'normal';
+ break;
+ case 'brand':
+ logoStyle = {width: 32, height: 32, background: '#000', opacity: '0.04'};
+ globalHozNavType = globalDir === 'hoz' ? 'secondary' : 'normal';
+ break;
+ default:
+ break;
+ }
+
+ switch(device) {
+ case 'phone':
+ shellStyle = {height: 500, width: 480, border: '1px solid #eee'};
+ break;
+ case 'tablet':
+ shellStyle = {height: 500, width: 768, border: '1px solid #eee'};
+ break;
+ case 'desktop':
+ shellStyle = {height: 500, width: 1000, border: '1px solid #eee'};
+ break;
+ default:
+ break;
+ }
+ return (
+
+
+ {
+ demoFunction.branding.value === 'true'
+ ?
+
+ App Name
+
+ : null
+ }
+
+ {
+ demoFunction.navigation.value !== 'false'
+ ?
+
+ Nav Item 1
+ Nav Item 2
+ Nav Item 3
+ Nav Item 4
+ Nav Item 5
+ Nav Item 6
+ Nav Item 7
+
+
+ : null
+ }
+ {
+ demoFunction.actions.value === 'true'
+ ?
+
+
+
+ Name
+
+ : null
+ }
+ {
+ demoFunction.localNav.value === 'true'
+ ?
+
+
+ Local Nav1
+
+
+ Local Nav2
+
+
+ Local Nav3
+
+ Local Nav4
+ Local Nav5
+ Local Nav6
+ Local Nav7
+ Local Nav8
+ Local Nav4
+ Local Nav5
+ Local Nav6
+ Local Nav7
+ Local Nav8
+
+
+ : null
+ }
+ {
+ demoFunction.appbar.value === 'true'
+ ?
+
+
+ : null
+ }
+
+
+
+
+ {
+ demoFunction.ancillary.value === 'true'
+ ?
+
+ : null
+ }
+ {
+ demoFunction.tooldock.value === 'true'
+ ?
+
+
+
+
+
+
+
+
+
+
+ : null
+ }
+ {
+ demoFunction.footer.value === 'true'
+ ?
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+ : null
+ }
+
+
+ );
+ }
+}
+
+const renderShell = (type, i18n, demoFunction) => {
+ return ;
+}
+
+class FunctionDemo extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ demoFunction: {
+ 'device': {
+ label: 'Device',
+ value: 'desktop',
+ enum: [{
+ label: 'desktop',
+ value: 'desktop'
+ }, {
+ label: 'tablet',
+ value: 'tablet'
+ }, {
+ label: 'phone',
+ value: 'phone'
+ }]
+ },
+ 'branding': {
+ label: 'Branding',
+ value: 'true',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ 'actions': {
+ label: 'Actions',
+ value: 'true',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ 'navigation': {
+ label: 'Applicaitoin Nav',
+ value: 'ver',
+ enum: [{
+ label: '侧栏',
+ value: 'ver'
+ }, {
+ label: '顶部',
+ value: 'hoz'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ // 'navigationType': {
+ // label: 'Applicaitoin Nav Type',
+ // value: 'normal',
+ // enum: [{
+ // label: 'normal',
+ // value: 'normal'
+ // }, {
+ // label: 'primary',
+ // value: 'primary'
+ // }, {
+ // label: 'secondary',
+ // value: 'secondary'
+ // }, {
+ // label: 'line',
+ // value: 'line'
+ // }]
+ // },
+ 'localNav': {
+ label: 'Local Nav',
+ value: 'false',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ // 'localNavType': {
+ // label: 'Local Nav Type',
+ // value: 'normal',
+ // enum: [{
+ // label: 'normal',
+ // value: 'normal'
+ // }, {
+ // label: 'primary',
+ // value: 'primary'
+ // }, {
+ // label: 'secondary',
+ // value: 'secondary'
+ // }, {
+ // label: 'line',
+ // value: 'line'
+ // }]
+ // },
+ 'appbar': {
+ label: 'Appbar',
+ value: 'false',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ 'footer': {
+ label: 'Footer',
+ value: 'false',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ 'ancillary': {
+ label: 'Ancillary',
+ value: 'false',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ 'tooldock': {
+ label: 'Tooldock',
+ value: 'false',
+ enum: [{
+ label: '有',
+ value: 'true'
+ }, {
+ label: '无',
+ value: 'false'
+ }]
+ },
+ }
+ }
+ }
+
+ onFunctionChange = (ret) => {
+ this.setState({
+ demoFunction: ret,
+ });
+ }
+
+ render() {
+ const { title, locale, types, shellRender } = this.props;
+ const { demoFunction } = this.state;
+
+ return (
+ {
+ types.map(type => shellRender(type, locale, demoFunction))
+ }
+ )
+ }
+}
+
+
+function render(i18n, lang) {
+ return ReactDOM.render(
+
+
, document.getElementById('container'));
+}
+
+window.renderDemo = function (lang = 'en-us') {
+ render(i18nMap[lang], lang);
+};
+
+renderDemo();
+
+initDemo('shell');
diff --git a/docs/typography/theme/index.jsx b/docs/typography/theme/index.jsx
index 8475976ac8..9bf8e5387c 100644
--- a/docs/typography/theme/index.jsx
+++ b/docs/typography/theme/index.jsx
@@ -77,4 +77,4 @@ window.renderDemo = function (lang) {
window.renderDemo('en-us');
-initDemo('paragraph');
+initDemo('typography');
diff --git a/index-noreset.scss b/index-noreset.scss
index bd571476f0..d382dbd866 100644
--- a/index-noreset.scss
+++ b/index-noreset.scss
@@ -49,3 +49,6 @@
@import "lib/tree-select/index.scss";
@import "lib/upload/index.scss";
@import "lib/virtual-list/index.scss";
+@import "lib/shell/index.scss";
+@import "lib/notification/index.scss";
+@import "lib/typography/index.scss";
diff --git a/scripts/config.js b/scripts/config.js
index 18e6133ab3..11b50b9984 100644
--- a/scripts/config.js
+++ b/scripts/config.js
@@ -71,5 +71,8 @@ module.exports = {
'upload',
'validate',
'virtual-list',
+ 'shell',
+ 'notification',
+ 'typography',
],
};
diff --git a/src/index.js b/src/index.js
index 6b188ea362..96d66cb95e 100644
--- a/src/index.js
+++ b/src/index.js
@@ -35,6 +35,7 @@ export { default as Range } from './range';
export { default as Rating } from './rating';
export { default as Search } from './search';
export { default as Select } from './select';
+export { default as Shell } from './shell';
export { default as Slider } from './slider';
export { default as SplitButton } from './split-button';
export { default as Step } from './step';
@@ -47,5 +48,7 @@ export { default as Timeline } from './timeline';
export { default as Transfer } from './transfer';
export { default as Tree } from './tree';
export { default as TreeSelect } from './tree-select';
+export { default as Typography } from './typography';
export { default as Upload } from './upload';
export { default as VirtualList } from './virtual-list';
+export { default as Notification } from './notification';
diff --git a/src/menu/view/item.jsx b/src/menu/view/item.jsx
index 29a038572f..ad5118a678 100644
--- a/src/menu/view/item.jsx
+++ b/src/menu/view/item.jsx
@@ -210,7 +210,7 @@ export default class Item extends Component {
let role = 'menuitem';
if ('selectMode' in root.props) {
- role = 'listitem';
+ role = 'option';
}
return (
diff --git a/src/menu/view/sub-menu.jsx b/src/menu/view/sub-menu.jsx
index 521c9c937d..def7d43d89 100644
--- a/src/menu/view/sub-menu.jsx
+++ b/src/menu/view/sub-menu.jsx
@@ -189,6 +189,7 @@ export default class SubMenu extends Component {
'aria-expanded': open,
_key,
level,
+ role: 'listitem',
inlineLevel,
root,
type: 'submenu',
@@ -233,7 +234,7 @@ export default class SubMenu extends Component {
roleItem = 'menuitem';
if ('selectMode' in root.props) {
roleMenu = 'listbox';
- roleItem = 'listitem';
+ roleItem = 'option';
}
const subMenu = open ? (
diff --git a/src/nav/nav.jsx b/src/nav/nav.jsx
index e20b55e918..02490df4b1 100644
--- a/src/nav/nav.jsx
+++ b/src/nav/nav.jsx
@@ -152,6 +152,10 @@ class Nav extends Component {
hasArrow: PropTypes.bool,
};
+ static contextTypes = {
+ isCollapse: PropTypes.bool,
+ };
+
constructor(props) {
super(props);
@@ -168,10 +172,12 @@ class Nav extends Component {
hasArrow,
} = this.props;
+ const { isCollapse } = this.context;
+
return {
prefix,
mode: direction === 'hoz' ? 'popup' : mode,
- iconOnly,
+ iconOnly: 'iconOnly' in this.props ? iconOnly : isCollapse,
hasTooltip,
hasArrow,
};
@@ -206,6 +212,10 @@ class Nav extends Component {
...others
} = this.props;
+ const { isCollapse } = this.context;
+
+ const newIconOnly = 'iconOnly' in this.props ? iconOnly : isCollapse;
+
let realActiveDirection = activeDirection;
if (
realActiveDirection &&
@@ -219,7 +229,7 @@ class Nav extends Component {
realActiveDirection = null;
}
- if (!iconOnly && realActiveDirection === undefined) {
+ if (!newIconOnly && realActiveDirection === undefined) {
realActiveDirection =
direction === 'hoz'
? 'bottom'
@@ -233,12 +243,12 @@ class Nav extends Component {
[`${prefix}${type}`]: type,
[`${prefix}active`]: realActiveDirection,
[`${prefix}${realActiveDirection}`]: realActiveDirection,
- [`${prefix}icon-only`]: iconOnly,
+ [`${prefix}icon-only`]: newIconOnly,
[`${prefix}no-arrow`]: !hasArrow,
[`${prefix}nav-embeddable`]: embeddable,
[className]: !!className,
});
- const newStyle = iconOnly ? { ...style, width: '60px' } : style;
+ const newStyle = newIconOnly ? { ...style, width: '58px' } : style;
const props = {
prefix,
@@ -247,7 +257,7 @@ class Nav extends Component {
triggerType,
mode: direction === 'hoz' ? 'popup' : mode,
popupAlign: direction === 'hoz' ? 'follow' : popupAlign,
- inlineIndent: iconOnly ? 0 : inlineIndent,
+ inlineIndent: newIconOnly ? 0 : inlineIndent,
hasSelectedIcon: false,
popupAutoWidth: true,
selectMode: 'single',
@@ -256,7 +266,7 @@ class Nav extends Component {
[cls
.replace(`${prefix}icon-only`, '')
.replace(`${prefix}nav-embeddable`, '')]: mode === 'popup',
- [`${prefix}icon-only`]: iconOnly && mode === 'inline',
+ [`${prefix}icon-only`]: newIconOnly && mode === 'inline',
[popupClassName]: !!popupClassName,
}),
popupProps: popupItemProps => {
diff --git a/src/paragraph/scss/variable.scss b/src/paragraph/scss/variable.scss
index 94d6031039..6b1c580f7b 100644
--- a/src/paragraph/scss/variable.scss
+++ b/src/paragraph/scss/variable.scss
@@ -1,5 +1,5 @@
////
-/// @module paragraph: 段落
+/// @module paragraph: 段落(已废弃)
/// @tag Paragraph
/// @category component
/// @family general
diff --git a/src/shell/base.jsx b/src/shell/base.jsx
new file mode 100644
index 0000000000..86493f3dd3
--- /dev/null
+++ b/src/shell/base.jsx
@@ -0,0 +1,104 @@
+import React, { Component } from 'react';
+import classnames from 'classnames';
+import PropTypes from 'prop-types';
+
+export default function Base(props) {
+ const { componentName } = props;
+ class Shell extends Component {
+ static displayName = componentName;
+
+ static _typeMark = `Shell_${componentName}`;
+
+ static propTypes = {
+ prefix: PropTypes.string,
+ collapse: PropTypes.bool,
+ miniable: PropTypes.bool,
+ component: PropTypes.string,
+ trigger: PropTypes.node,
+ triggerProps: PropTypes.object,
+ direction: PropTypes.oneOf(['hoz', 'ver']),
+ /**
+ * 弹层显示或隐藏时触发的回调函数
+ * @param {Boolean} collapse 弹层是否显示
+ */
+ onCollapseChange: PropTypes.func,
+ };
+
+ static defaultProps = {
+ prefix: 'next-',
+ component: 'div',
+ onCollapseChange: () => {},
+ };
+
+ static childContextTypes = {
+ isCollapse: PropTypes.bool,
+ };
+
+ static contextTypes = {
+ shellPrefix: PropTypes.string,
+ };
+
+ getChildContext() {
+ const { collapse } = this.props;
+
+ return {
+ isCollapse: collapse,
+ };
+ }
+
+ render() {
+ const {
+ prefix,
+ className,
+ miniable,
+ device,
+ direction,
+ children,
+ collapse,
+ triggerProps,
+ onCollapseChange,
+ component,
+ ...others
+ } = this.props;
+
+ const basePrefix = this.context.prefix || prefix;
+
+ let Tag = component;
+
+ const cls = classnames({
+ [`${basePrefix}shell-${componentName.toLowerCase()}`]: true,
+ [`${basePrefix}shell-collapse`]: !!collapse,
+ [`${basePrefix}shell-mini`]: miniable,
+ [className]: !!className,
+ });
+
+ let newChildren = children;
+ if (componentName === 'Content') {
+ newChildren = (
+
+ {children}
+
+ );
+ }
+
+ if (componentName === 'Page') {
+ return children;
+ }
+
+ if (
+ ['ToolDock'].indexOf(componentName) > -1 ||
+ (componentName === 'Navigation' && direction === 'ver')
+ ) {
+ Tag = 'aside';
+ }
+
+ return (
+
+ {newChildren}
+
+ );
+ }
+ }
+
+ return Shell;
+}
diff --git a/src/shell/index.jsx b/src/shell/index.jsx
new file mode 100644
index 0000000000..c0d04f3cf1
--- /dev/null
+++ b/src/shell/index.jsx
@@ -0,0 +1,44 @@
+import ShellBase from './shell';
+import Base from './base';
+import ConfigProvider from '../config-provider';
+
+const Shell = ShellBase({
+ componentName: 'Shell',
+});
+
+[
+ 'Branding',
+ 'Navigation',
+ 'Action',
+ 'MultiTask',
+ 'LocalNavigation',
+ 'AppBar',
+ 'Content',
+ 'Footer',
+ 'Ancillary',
+ 'ToolDock',
+ 'ToolDockItem',
+].forEach(key => {
+ Shell[key] = Base({
+ componentName: key,
+ });
+});
+
+Shell.Page = ShellBase({
+ componentName: 'Page',
+});
+
+export default ConfigProvider.config(Shell, {
+ transform: /* istanbul ignore next */ (props, deprecated) => {
+ if ('Component' in props) {
+ deprecated('Component', 'component', 'Shell');
+ const { Component, component, ...others } = props;
+ if ('component' in props) {
+ props = { component, ...others };
+ } else {
+ props = { component: Component, ...others };
+ }
+ }
+ return props;
+ },
+});
diff --git a/src/shell/main.scss b/src/shell/main.scss
new file mode 100644
index 0000000000..085803610e
--- /dev/null
+++ b/src/shell/main.scss
@@ -0,0 +1,586 @@
+@charset "UTF-8";
+
+@import "../core/index-noreset.scss";
+@import "scss/mixin";
+@import "scss/variable";
+@import "./rtl.scss";
+
+#{$shell-prefix} {
+ @include box-sizing;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ transition: all .2s $motion-ease;
+
+ &-content-wrapper {
+ overflow: auto;
+ }
+
+ &-header {
+ display: flex;
+ width: 100%;
+ justify-content: space-between;
+ align-items: center;
+ z-index: 9;
+
+ .dock-trigger,
+ .nav-trigger {
+ outline: 0;
+ // background: $shell-dark-header-background;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ cursor: pointer;
+ width: 32px;
+ height: 32px;
+ }
+
+ .nav-trigger {
+ margin-right: 10px;
+ }
+ .dock-trigger {
+ margin-left: 10px;
+ }
+
+ #{$shell-prefix}-navigation {
+ flex: 1;
+ display: flex;
+ align-items: center;
+ flex-direction: row;
+ overflow: hidden;
+ }
+ #{$shell-prefix}-branding {
+ display: flex;
+ align-items: center;
+ }
+ #{$shell-prefix}-action {
+ display: flex;
+ align-items: center;
+ }
+ }
+
+ &-sub-main {
+ flex: 1;
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ overflow: auto;
+ outline: 0;
+ }
+ &-main {
+ display: flex;
+ flex: 1;
+ flex-direction: row;
+ position: relative;
+ height: 100%;
+ box-sizing: content-box;
+ overflow: auto;
+ transition: all .2s $motion-ease;
+
+ #{$shell-prefix}-content {
+ flex: 1;
+ }
+
+ #{$shell-prefix}-content-inner {
+ margin: 0 auto;
+ // display: grid;
+ }
+
+ #{$shell-prefix}-footer {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ }
+ }
+
+ &-aside {
+ transition: all .2s $motion-ease;
+
+ .aside-trigger {
+ cursor: pointer;
+ outline: 0;
+ position: absolute;
+ right: 0;
+ top: 50%;
+ width: 20px;
+ height: 48px;
+ display: flex;
+ border: 1px solid #DDD;
+ align-items: center;
+ justify-content: center;
+ }
+ .local-nav-trigger {
+ outline: 0;
+ border-left: none;
+ transform: translate(100%, -50%);
+ right: 0;
+ }
+ .ancillary-trigger {
+ outline: 0;
+ transform: translate(-100%, -50%);
+ border-right: 0;
+ left: 1px;
+ }
+
+ &.#{$css-prefix}aside-localnavigation {
+ position: relative;
+ }
+
+ &.#{$css-prefix}aside-ancillary {
+ position: relative;
+ }
+
+
+ {$shell-prefix}-navigation {
+ overflow-x: auto;
+ display: flex;
+ flex-direction: column;
+ justify-self: flex-start;
+ transition: all .2s $motion-ease;
+ }
+
+ {$shell-prefix}-tooldock {
+ overflow-x: auto;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ }
+
+ #{$shell-prefix}-tooldockitem {
+ width: 100%;
+ text-align: center;
+ }
+
+ #{$shell-prefix}-localnavigation {
+ position: relative;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-self: flex-start;
+ transition: all .2s $motion-ease;
+ }
+
+ #{$shell-prefix}-ancillary {
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+ justify-self: flex-start;
+ transition: all .2s $motion-ease;
+ }
+ }
+
+ &-light {
+ @include shell-trigger-background(
+ $shell-light-header-background,
+ $shell-light-header-background,
+ $shell-light-local-navigation-background,
+ $shell-light-ancillary-background
+ );
+
+ #{$shell-prefix}-header {
+ @include shell-header-type(
+ $shell-light-header-color,
+ $shell-light-header-height,
+ $shell-light-header-background,
+ $shell-light-header-divider,
+ $shell-light-header-shadow,
+ $shell-light-header-paddingLeft
+ );
+
+ #{$shell-prefix}-navigation {
+ @include shell-header-navigation(
+ $shell-light-navigation-hoz-align,
+ $shell-light-header-height,
+ $shell-light-header-height,
+ $shell-light-navigation-hoz-marginLeft
+ );
+ }
+ }
+
+ #{$shell-prefix}-task-header {
+ @include shell-task-header(
+ $shell-light-multitask-min-height,
+ $shell-light-multitask-background,
+ $shell-light-multitask-divider,
+ $shell-light-multitask-shadow,
+ $shell-light-multitask-paddingLeft
+ );
+ }
+
+ #{$shell-prefix}-main {
+ background: $shell-light-content-background;
+
+ #{$shell-prefix}-appbar {
+ @include shell-appbar(
+ $shell-light-appbar-min-height,
+ $shell-light-appbar-background,
+ $shell-light-appbar-divider,
+ $shell-light-appbar-shadow,
+ $shell-light-appbar-paddingLeft
+ );
+ }
+
+ @include shell-content(
+ $shell-light-content-paddingTop,
+ $shell-light-content-paddingLeft,
+ $shell-light-content-max-width,
+ $shell-light-content-gutter-row,
+ $shell-light-content-gutter-column,
+ $shell-light-content-columns
+ );
+
+ #{$shell-prefix}-footer {
+ background: $shell-light-footer-background;
+ min-height: $shell-light-footer-min-height;
+ color: $shell-light-footer-color;
+ font-size: $shell-light-footer-font-size;
+ }
+ }
+
+ #{$shell-prefix}-aside {
+ {$shell-prefix}-navigation {
+ @include shell-navigation(
+ $shell-light-navigation-ver-width,
+ $shell-light-navigation-ver-background,
+ $shell-light-navigation-ver-divider,
+ $shell-light-navigation-ver-shadow,
+ $shell-light-navigation-ver-paddingTop,
+ $shell-light-navigation-ver-paddingBottom,
+ $shell-light-navigation-ver-width-mini
+ );
+ }
+ {$shell-prefix}-tooldock {
+ @include shell-tooldock(
+ $shell-light-tooldock-width,
+ $shell-light-tooldock-background,
+ $shell-light-tooldock-divider,
+ $shell-light-tooldock-shadow,
+ $shell-light-tooldock-paddingTop,
+ $shell-light-tooldock-paddingBottom
+ );
+ }
+ #{$shell-prefix}-tooldockitem {
+ @include shell-tooldock-item(
+ $shell-light-tooldock-item-paddingTop,
+ $shell-light-tooldock-item-color,
+ $shell-light-tooldock-item-background,
+ $shell-light-tooldock-item-color-hover,
+ $shell-light-tooldock-item-background-hover
+ );
+ }
+ #{$shell-prefix}-localnavigation {
+ @include shell-localnavigation(
+ $shell-light-local-navigation-width,
+ $shell-light-local-navigation-background,
+ $shell-light-local-navigation-divider,
+ $shell-light-local-navigation-shadow,
+ $shell-light-local-navigation-paddingTop,
+ $shell-light-local-navigation-paddingBottom
+ );
+ }
+ #{$shell-prefix}-ancillary {
+ @include shell-ancillary(
+ $shell-light-ancillary-width,
+ $shell-light-ancillary-background,
+ $shell-light-ancillary-divider,
+ $shell-light-ancillary-shadow,
+ $shell-light-ancillary-paddingTop,
+ $shell-light-ancillary-paddingBottom
+ );
+ }
+ }
+ }
+
+ &-dark {
+ @include shell-trigger-background(
+ $shell-dark-header-background,
+ $shell-dark-header-background,
+ $shell-dark-local-navigation-background,
+ $shell-dark-ancillary-background
+ );
+
+ #{$shell-prefix}-header {
+ @include shell-header-type(
+ $shell-dark-header-color,
+ $shell-dark-header-height,
+ $shell-dark-header-background,
+ $shell-dark-header-divider,
+ $shell-dark-header-shadow,
+ $shell-dark-header-paddingLeft
+ );
+
+ #{$shell-prefix}-navigation {
+ @include shell-header-navigation(
+ $shell-dark-navigation-hoz-align,
+ $shell-dark-header-height,
+ $shell-dark-header-height,
+ $shell-dark-navigation-hoz-marginLeft
+ );
+ }
+ }
+
+ #{$shell-prefix}-task-header {
+ @include shell-task-header(
+ $shell-dark-multitask-min-height,
+ $shell-dark-multitask-background,
+ $shell-dark-multitask-divider,
+ $shell-dark-multitask-shadow,
+ $shell-dark-multitask-paddingLeft
+ );
+ }
+
+ #{$shell-prefix}-main {
+ background: $shell-dark-content-background;
+
+ #{$shell-prefix}-appbar {
+ @include shell-appbar(
+ $shell-dark-appbar-min-height,
+ $shell-dark-appbar-background,
+ $shell-dark-appbar-divider,
+ $shell-dark-appbar-shadow,
+ $shell-dark-appbar-paddingLeft
+ );
+ }
+
+ @include shell-content(
+ $shell-dark-content-paddingTop,
+ $shell-dark-content-paddingLeft,
+ $shell-dark-content-max-width,
+ $shell-dark-content-gutter-row,
+ $shell-dark-content-gutter-column,
+ $shell-dark-content-columns
+ );
+
+ #{$shell-prefix}-footer {
+ background: $shell-dark-footer-background;
+ min-height: $shell-dark-footer-min-height;
+ color: $shell-dark-footer-color;
+ font-size: $shell-dark-footer-font-size;
+ }
+ }
+
+ #{$shell-prefix}-aside {
+ {$shell-prefix}-navigation {
+ @include shell-navigation(
+ $shell-dark-navigation-ver-width,
+ $shell-dark-navigation-ver-background,
+ $shell-dark-navigation-ver-divider,
+ $shell-dark-navigation-ver-shadow,
+ $shell-dark-navigation-ver-paddingTop,
+ $shell-dark-navigation-ver-paddingBottom,
+ $shell-dark-navigation-ver-width-mini
+ );
+ }
+ {$shell-prefix}-tooldock {
+ @include shell-tooldock(
+ $shell-dark-tooldock-width,
+ $shell-dark-tooldock-background,
+ $shell-dark-tooldock-divider,
+ $shell-dark-tooldock-shadow,
+ $shell-dark-tooldock-paddingTop,
+ $shell-dark-tooldock-paddingBottom
+ );
+ }
+ #{$shell-prefix}-tooldockitem {
+ @include shell-tooldock-item(
+ $shell-dark-tooldock-item-paddingTop,
+ $shell-dark-tooldock-item-color,
+ $shell-dark-tooldock-item-background,
+ $shell-dark-tooldock-item-color-hover,
+ $shell-dark-tooldock-item-background-hover
+ );
+ }
+ #{$shell-prefix}-localnavigation {
+ @include shell-localnavigation(
+ $shell-dark-local-navigation-width,
+ $shell-dark-local-navigation-background,
+ $shell-dark-local-navigation-divider,
+ $shell-dark-local-navigation-shadow,
+ $shell-dark-local-navigation-paddingTop,
+ $shell-dark-local-navigation-paddingBottom
+ );
+ }
+ #{$shell-prefix}-ancillary {
+ @include shell-ancillary(
+ $shell-dark-ancillary-width,
+ $shell-dark-ancillary-background,
+ $shell-dark-ancillary-divider,
+ $shell-dark-ancillary-shadow,
+ $shell-dark-ancillary-paddingTop,
+ $shell-dark-ancillary-paddingBottom
+ );
+ }
+ }
+ }
+
+ &-brand {
+ @include shell-trigger-background(
+ $shell-brand-header-background,
+ $shell-brand-header-background,
+ $shell-brand-local-navigation-background,
+ $shell-brand-ancillary-background
+ );
+
+ #{$shell-prefix}-header {
+ @include shell-header-type(
+ $shell-brand-header-color,
+ $shell-brand-header-height,
+ $shell-brand-header-background,
+ $shell-brand-header-divider,
+ $shell-brand-header-shadow,
+ $shell-brand-header-paddingLeft
+ );
+
+ #{$shell-prefix}-navigation {
+ @include shell-header-navigation(
+ $shell-brand-navigation-hoz-align,
+ $shell-brand-header-height,
+ $shell-brand-header-height,
+ $shell-brand-navigation-hoz-marginLeft
+ );
+ }
+ }
+
+ #{$shell-prefix}-task-header {
+ @include shell-task-header(
+ $shell-brand-multitask-min-height,
+ $shell-brand-multitask-background,
+ $shell-brand-multitask-divider,
+ $shell-brand-multitask-shadow,
+ $shell-brand-multitask-paddingLeft
+ );
+ }
+
+ #{$shell-prefix}-main {
+ background: $shell-brand-content-background;
+
+ #{$shell-prefix}-appbar {
+ @include shell-appbar(
+ $shell-brand-appbar-min-height,
+ $shell-brand-appbar-background,
+ $shell-brand-appbar-divider,
+ $shell-brand-appbar-shadow,
+ $shell-brand-appbar-paddingLeft
+ );
+ }
+
+ @include shell-content(
+ $shell-brand-content-paddingTop,
+ $shell-brand-content-paddingLeft,
+ $shell-brand-content-max-width,
+ $shell-brand-content-gutter-row,
+ $shell-brand-content-gutter-column,
+ $shell-brand-content-columns
+ );
+
+ #{$shell-prefix}-footer {
+ background: $shell-brand-footer-background;
+ min-height: $shell-brand-footer-min-height;
+ color: $shell-brand-footer-color;
+ font-size: $shell-brand-footer-font-size;
+ }
+ }
+
+ #{$shell-prefix}-aside {
+ {$shell-prefix}-navigation {
+ @include shell-navigation(
+ $shell-brand-navigation-ver-width,
+ $shell-brand-navigation-ver-background,
+ $shell-brand-navigation-ver-divider,
+ $shell-brand-navigation-ver-shadow,
+ $shell-brand-navigation-ver-paddingTop,
+ $shell-brand-navigation-ver-paddingBottom,
+ $shell-brand-navigation-ver-width-mini
+ );
+ }
+
+ {$shell-prefix}-tooldock {
+ @include shell-tooldock(
+ $shell-brand-tooldock-width,
+ $shell-brand-tooldock-background,
+ $shell-brand-tooldock-divider,
+ $shell-brand-tooldock-shadow,
+ $shell-brand-tooldock-paddingTop,
+ $shell-brand-tooldock-paddingBottom
+ );
+ }
+ #{$shell-prefix}-tooldockitem {
+ @include shell-tooldock-item(
+ $shell-brand-tooldock-item-paddingTop,
+ $shell-brand-tooldock-item-color,
+ $shell-brand-tooldock-item-background,
+ $shell-brand-tooldock-item-color-hover,
+ $shell-brand-tooldock-item-background-hover
+ );
+ }
+ #{$shell-prefix}-localnavigation {
+ @include shell-localnavigation(
+ $shell-brand-local-navigation-width,
+ $shell-brand-local-navigation-background,
+ $shell-brand-local-navigation-divider,
+ $shell-brand-local-navigation-shadow,
+ $shell-brand-local-navigation-paddingTop,
+ $shell-brand-local-navigation-paddingBottom
+ );
+ }
+ #{$shell-prefix}-ancillary {
+ @include shell-ancillary(
+ $shell-brand-ancillary-width,
+ $shell-brand-ancillary-background,
+ $shell-brand-ancillary-divider,
+ $shell-brand-ancillary-shadow,
+ $shell-brand-ancillary-paddingTop,
+ $shell-brand-ancillary-paddingBottom
+ );
+ }
+ }
+ }
+
+
+ {$shell-prefix}-phone {
+
+ #{$shell-prefix}-header #{$shell-prefix}-navigation {
+ display: none;
+ }
+ #{$shell-prefix}-navigation {
+ width: 100%;
+ height: 100%;
+ transition: height .2s $motion-ease;
+ {$shell-prefix}-collapse {
+ padding: 0;
+ height: 0;
+ transition: height .2s $motion-ease;
+ }
+ }
+ #{$shell-prefix}-tooldock {
+ height: $shell-dark-tooldock-height;
+ left: 0;
+ right: 0;
+ position: absolute;
+ width: 100%;
+ flex-direction: row;
+ justify-content: center;
+ {$shell-prefix}-collapse {
+ display: none;
+ height: 0;
+ padding: 0;
+ transition: all .2s $motion-ease;
+ }
+ }
+ }
+
+ {$shell-prefix}-tablet,
+ {$shell-prefix}-phone {
+ #{$shell-prefix}-aside.#{$css-prefix}aside-ancillary {
+ width: 0;
+ }
+ #{$shell-prefix}-ancillary {
+ transform: translateX(-100%);
+ }
+ #{$shell-prefix}-aside.#{$css-prefix}aside-localnavigation {
+ width: 0;
+ }
+ }
+}
diff --git a/src/shell/rtl.scss b/src/shell/rtl.scss
new file mode 100644
index 0000000000..9f44090c94
--- /dev/null
+++ b/src/shell/rtl.scss
@@ -0,0 +1 @@
+@charset "UTF-8";
diff --git a/src/shell/scss/mixin.scss b/src/shell/scss/mixin.scss
new file mode 100755
index 0000000000..543be6f82b
--- /dev/null
+++ b/src/shell/scss/mixin.scss
@@ -0,0 +1,194 @@
+@charset "UTF-8";
+
+@mixin shell-header-type(
+ $color,
+ $height,
+ $background,
+ $divider,
+ $shadow,
+ $paddingLeft
+) {
+ color: $color;
+ height: $height;
+ background: $background;
+ border-bottom: $divider;
+ box-shadow: $shadow;
+ padding: 0 $paddingLeft;
+}
+
+@mixin shell-header-navigation(
+ $direction,
+ $height,
+ $lineHight,
+ $paddingLeft
+) {
+ justify-content: $direction;
+ height: $height;
+ line-height: $lineHight;
+ margin: 0 $paddingLeft;
+}
+
+@mixin shell-task-header(
+ $min-height,
+ $background,
+ $divider,
+ $shadow,
+ $paddingLeft
+) {
+ width: 100%;
+ min-height: $min-height;
+ background: $background;
+ border-bottom: $divider;
+ box-shadow: $shadow;
+ padding: 0 $paddingLeft;
+ overflow: auto;
+}
+
+@mixin shell-appbar(
+ $min-height,
+ $background,
+ $divider,
+ $shadow,
+ $paddingLeft
+) {
+ min-height: $min-height;
+ background: $background;
+ border-bottom: $divider;
+ box-shadow: $shadow;
+ padding: 0 $paddingLeft;
+}
+
+@mixin shell-content(
+ $paddingTop,
+ $paddingLeft,
+ $max-width,
+ $gutter-row,
+ $gutter-column,
+ $columns
+) {
+ #{$shell-prefix}-content {
+ padding: $paddingTop $paddingLeft;
+ }
+
+ // #{$shell-prefix}-content-inner {
+ // max-width: $max-width;
+ // grid-row-gap: $gutter-row;
+ // grid-column-gap: $gutter-column;
+ // grid-template-columns: repeat($columns, 1fr);
+ // }
+}
+
+@mixin shell-trigger-background(
+ $nav-trigger-bg,
+ $dock-trigger-bg,
+ $local-nav-trigger-bg,
+ $ancillary-trigger-bg
+) {
+ #{$shell-prefix}-header {
+ .dock-trigger,
+ .nav-trigger {
+ background: $nav-trigger-bg;
+ }
+ }
+
+ #{$shell-prefix}-aside {
+ .local-nav-trigger {
+ background: $local-nav-trigger-bg;
+ }
+ .ancillary-trigger {
+ background: $ancillary-trigger-bg;
+ }
+ }
+}
+
+@mixin shell-navigation(
+ $width,
+ $background,
+ $divider,
+ $shadow,
+ $paddingTop,
+ $paddingBottom,
+ $width-mini
+) {
+ width: $width;
+ background: $background;
+ border-right: $divider;
+ box-shadow: $shadow;
+ padding: $paddingTop 0 $paddingBottom;
+
+ {$shell-prefix}-collapse#{$shell-prefix}-mini {
+ width: $width-mini;
+ }
+
+ {$shell-prefix}-collapse {
+ width: 0;
+ }
+}
+
+@mixin shell-tooldock(
+ $width,
+ $background,
+ $divider,
+ $shadow,
+ $paddingTop,
+ $paddingBottom
+) {
+ width: $width;
+ background: $background;
+ border-left: $divider;
+ box-shadow: $shadow;
+ padding: $paddingTop 0 $paddingBottom;
+}
+
+@mixin shell-tooldock-item(
+ $paddingTop,
+ $color,
+ $background,
+ $color-hover,
+ $background-hover
+) {
+ padding: $paddingTop 0;
+ color: $color;
+ background: $background;
+
+ &:hover {
+ color: $color-hover;
+ background: $background-hover;
+ }
+}
+
+@mixin shell-localnavigation(
+ $width,
+ $background,
+ $divider,
+ $shadow,
+ $paddingTop,
+ $paddingBottom
+) {
+ width: $width;
+ background: $background;
+ border-right: $divider;
+ box-shadow: $shadow;
+ padding: $paddingTop 0 $paddingBottom;
+ {$shell-prefix}-collapse {
+ width: 0;
+ }
+}
+
+@mixin shell-ancillary(
+ $width,
+ $background,
+ $divider,
+ $shadow,
+ $paddingTop,
+ $paddingBottom
+) {
+ width: $width;
+ background: $background;
+ border-left: $divider;
+ box-shadow: $shadow;
+ padding: $paddingTop 0 $paddingBottom;
+ {$shell-prefix}-collapse {
+ width: 0;
+ }
+}
diff --git a/src/shell/scss/variable.scss b/src/shell/scss/variable.scss
new file mode 100644
index 0000000000..88086dcd5b
--- /dev/null
+++ b/src/shell/scss/variable.scss
@@ -0,0 +1,745 @@
+@charset "UTF-8";
+
+////
+/// @module shell: 布局框架
+/// @tag Shell
+/// @category component
+/// @family data-entry
+/// @varPrefix $shell-
+/// @classPrefix {prefix}-shell
+/// @order {}
+////
+// shell variables
+// --------------------------------------------------
+$shell-prefix: '.#{$css-prefix}shell' !default;
+
+
+
+/** light **/
+/// color
+/// @namespace statement/header
+$shell-light-header-color: $color-black !default;
+/// height
+/// @namespace statement/header
+$shell-light-header-height: $s-13 !default;
+/// background
+/// @namespace statement/header
+$shell-light-header-background: $color-white !default;
+/// shadow
+/// @namespace statement/header
+$shell-light-header-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/header/divider
+$shell-light-header-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/header/divider
+$shell-light-header-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/header/divider
+$shell-light-header-divider-color: $color-line1-1 !default;
+$shell-light-header-divider: $shell-light-header-divider-size $shell-light-header-divider-style $shell-light-header-divider-color;
+/// padding (l, r)
+/// @namespace statement/header
+$shell-light-header-paddingLeft: $s-4 !default;
+
+/// min-height
+/// @namespace statement/multitask
+$shell-light-multitask-min-height: $s-10 !default;
+/// background
+/// @namespace statement/multitask
+$shell-light-multitask-background: $color-white !default;
+/// shadow
+/// @namespace statement/multitask
+$shell-light-multitask-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/multitask/divider
+$shell-light-multitask-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/multitask/divider
+$shell-light-multitask-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/multitask/divider
+$shell-light-multitask-divider-color: $color-line1-1 !default;
+$shell-light-multitask-divider: $shell-light-multitask-divider-size $shell-light-multitask-divider-style $shell-light-multitask-divider-color;
+/// padding (l, r)
+/// @namespace statement/multitask
+$shell-light-multitask-paddingLeft: $s-zero !default;
+
+
+/// margin (l, r)
+/// @namespace statement/navigation
+$shell-light-navigation-hoz-marginLeft: $s-12 !default;
+$shell-light-navigation-hoz-align: flex-end !default; // flex-start flex-end center space-evenly space-around space-between
+
+
+/// width
+/// @namespace statement/navigation
+$shell-light-navigation-ver-width: $s-42 !default;
+/// shadow
+/// @namespace statement/navigation
+$shell-light-navigation-ver-shadow: $shadow-zero !default;
+/// padding (t)
+/// @namespace statement/navigation
+$shell-light-navigation-ver-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/navigation
+$shell-light-navigation-ver-paddingBottom: $s-2 !default;
+/// mini-width
+/// @namespace statement/navigation
+$shell-light-navigation-ver-width-mini: $s-15 !default;
+/// background
+/// @namespace statement/navigation
+$shell-light-navigation-ver-background: $color-white !default;
+/// size
+/// @namespace statement/navigation/divider
+$shell-light-navigation-ver-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/navigation/divider
+$shell-light-navigation-ver-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/navigation/divider
+$shell-light-navigation-ver-divider-color: $color-line1-1 !default;
+$shell-light-navigation-ver-divider: $shell-light-navigation-ver-divider-size $shell-light-navigation-ver-divider-style $shell-light-navigation-ver-divider-color;
+
+/// width
+/// @namespace statement/local-navigation
+$shell-light-local-navigation-width: $s-42 !default;
+/// background
+/// @namespace statement/local-navigation
+$shell-light-local-navigation-background: $color-fill1-4 !default;
+/// padding (t)
+/// @namespace statement/local-navigation
+$shell-light-local-navigation-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/local-navigation
+$shell-light-local-navigation-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/local-navigation
+$shell-light-local-navigation-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/local-navigation/divider
+$shell-light-local-navigation-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/local-navigation/divider
+$shell-light-local-navigation-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/local-navigation/divider
+$shell-light-local-navigation-divider-color: $color-line1-1 !default;
+$shell-light-local-navigation-divider: $shell-light-local-navigation-divider-size $shell-light-local-navigation-divider-style $shell-light-local-navigation-divider-color;
+
+/// background
+/// @namespace statement/appbar
+$shell-light-appbar-background: $color-white !default;
+/// min-height
+/// @namespace statement/appbar
+$shell-light-appbar-min-height: $s-12 !default;
+/// shadow
+/// @namespace statement/appbar
+$shell-light-appbar-shadow: $shadow-zero !default;
+/// padding (l, r)
+/// @namespace statement/appbar
+$shell-light-appbar-paddingLeft: $s-6 !default;
+/// size
+/// @namespace statement/appbar/divider
+$shell-light-appbar-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/appbar/divider
+$shell-light-appbar-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/appbar/divider
+$shell-light-appbar-divider-color: $color-line1-1 !default;
+$shell-light-appbar-divider: $shell-light-appbar-divider-size $shell-light-appbar-divider-style $shell-light-appbar-divider-color;
+
+
+$shell-light-content-max-width: unset !default;
+/// background
+/// @namespace statement/content
+$shell-light-content-background: $color-fill1-3 !default;
+/// padding (l, r)
+/// @namespace statement/content
+$shell-light-content-paddingLeft: $s-5 !default;
+/// padding (t, b)
+/// @namespace statement/content
+$shell-light-content-paddingTop: $s-5 !default;
+
+$shell-light-content-gutter-row: $s-4 !default;
+$shell-light-content-gutter-column: $s-4 !default;
+$shell-light-content-columns: 1 !default;
+
+/// min-height
+/// @namespace statement/footer
+$shell-light-footer-min-height: $s-14 !default;
+/// background
+/// @namespace statement/footer
+$shell-light-footer-background: $color-transparent !default;
+/// color
+/// @namespace statement/footer
+$shell-light-footer-color: $color-text1-1 !default;
+/// font-size
+/// @namespace statement/footer
+$shell-light-footer-font-size: $font-size-body-2 !default;
+
+/// width
+/// @namespace statement/ancillary
+$shell-light-ancillary-width: $s-42 !default;
+/// background
+/// @namespace statement/ancillary
+$shell-light-ancillary-background: $color-white !default;
+/// padding (t)
+/// @namespace statement/ancillary
+$shell-light-ancillary-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/ancillary
+$shell-light-ancillary-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/ancillary
+$shell-light-ancillary-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/ancillary/divider
+$shell-light-ancillary-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/ancillary/divider
+$shell-light-ancillary-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/ancillary/divider
+$shell-light-ancillary-divider-color: $color-line1-1 !default;
+$shell-light-ancillary-divider: $shell-light-ancillary-divider-size $shell-light-ancillary-divider-style $shell-light-ancillary-divider-color;
+
+
+/// height
+/// @namespace statement/tooldock
+$shell-light-tooldock-height: $s-13 !default;
+/// width
+/// @namespace statement/tooldock
+$shell-light-tooldock-width: $s-13 !default;
+/// background
+/// @namespace statement/tooldock
+$shell-light-tooldock-background: $color-fill1-4 !default;
+/// padding (t)
+/// @namespace statement/tooldock
+$shell-light-tooldock-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/tooldock
+$shell-light-tooldock-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/tooldock
+$shell-light-tooldock-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/tooldock/divider
+$shell-light-tooldock-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/tooldock/divider
+$shell-light-tooldock-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/tooldock/divider
+$shell-light-tooldock-divider-color: $color-line1-1 !default;
+$shell-light-tooldock-divider: $shell-light-tooldock-divider-size $shell-light-tooldock-divider-style $shell-light-tooldock-divider-color;
+
+/// padding (t)
+/// @namespace statement/tooldock-item
+$shell-light-tooldock-item-paddingTop: $s-2 !default;
+/// color
+/// @namespace statement/tooldock-item
+$shell-light-tooldock-item-color: $color-text1-3 !default;
+/// color
+/// @namespace statement/tooldock-item/hover
+$shell-light-tooldock-item-color-hover: $color-text1-4 !default;
+/// color
+/// @namespace statement/tooldock-item/active
+$shell-light-tooldock-item-color-active: $color-text1-4 !default;
+/// background
+/// @namespace statement/tooldock-item
+$shell-light-tooldock-item-background: $color-transparent !default;
+/// background
+/// @namespace statement/tooldock-item/hover
+$shell-light-tooldock-item-background-hover: $color-fill1-3 !default;
+/// background
+/// @namespace statement/tooldock-item/active
+$shell-light-tooldock-item-background-active: $color-fill1-3 !default;
+
+
+
+/** dark **/
+/// color
+/// @namespace statement/header
+$shell-dark-header-color: $color-white !default;
+/// height
+/// @namespace statement/header
+$shell-dark-header-height: $s-13 !default;
+/// background
+/// @namespace statement/header
+$shell-dark-header-background: $color-black !default;
+/// shadow
+/// @namespace statement/header
+$shell-dark-header-shadow: $shadow-1-down !default;
+/// size
+/// @namespace statement/header/divider
+$shell-dark-header-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/header/divider
+$shell-dark-header-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/header/divider
+$shell-dark-header-divider-color: #1F1F1F !default;
+$shell-dark-header-divider: $shell-dark-header-divider-size $shell-dark-header-divider-style $shell-dark-header-divider-color;
+/// padding (l, r)
+/// @namespace statement/header
+$shell-dark-header-paddingLeft: $s-4 !default;
+
+/// min-height
+/// @namespace statement/multitask
+$shell-dark-multitask-min-height: $s-10 !default;
+/// background
+/// @namespace statement/multitask
+$shell-dark-multitask-background: $color-white !default;
+/// shadow
+/// @namespace statement/multitask
+$shell-dark-multitask-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/multitask/divider
+$shell-dark-multitask-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/multitask/divider
+$shell-dark-multitask-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/multitask/divider
+$shell-dark-multitask-divider-color: $color-line1-1 !default;
+$shell-dark-multitask-divider: $shell-dark-multitask-divider-size $shell-dark-multitask-divider-style $shell-dark-multitask-divider-color;
+/// padding (l, r)
+/// @namespace statement/multitask
+$shell-dark-multitask-paddingLeft: $s-zero !default;
+
+
+/// margin (l, r)
+/// @namespace statement/navigation
+$shell-dark-navigation-hoz-marginLeft: $s-12 !default;
+$shell-dark-navigation-hoz-align: flex-end !default; // flex-start flex-end center space-evenly space-around space-between
+
+
+/// width
+/// @namespace statement/navigation
+$shell-dark-navigation-ver-width: $s-42 !default;
+/// shadow
+/// @namespace statement/navigation
+$shell-dark-navigation-ver-shadow: $shadow-zero !default;
+/// padding (t)
+/// @namespace statement/navigation
+$shell-dark-navigation-ver-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/navigation
+$shell-dark-navigation-ver-paddingBottom: $s-2 !default;
+/// mini-width
+/// @namespace statement/navigation
+$shell-dark-navigation-ver-width-mini: $s-15 !default;
+/// background
+/// @namespace statement/navigation
+$shell-dark-navigation-ver-background: $color-white !default;
+/// size
+/// @namespace statement/navigation/divider
+$shell-dark-navigation-ver-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/navigation/divider
+$shell-dark-navigation-ver-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/navigation/divider
+$shell-dark-navigation-ver-divider-color: $color-line1-1 !default;
+$shell-dark-navigation-ver-divider: $shell-dark-navigation-ver-divider-size $shell-dark-navigation-ver-divider-style $shell-dark-navigation-ver-divider-color;
+
+/// width
+/// @namespace statement/local-navigation
+$shell-dark-local-navigation-width: $s-42 !default;
+/// background
+/// @namespace statement/local-navigation
+$shell-dark-local-navigation-background: $color-fill1-4 !default;
+/// padding (t)
+/// @namespace statement/local-navigation
+$shell-dark-local-navigation-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/local-navigation
+$shell-dark-local-navigation-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/local-navigation
+$shell-dark-local-navigation-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/local-navigation/divider
+$shell-dark-local-navigation-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/local-navigation/divider
+$shell-dark-local-navigation-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/local-navigation/divider
+$shell-dark-local-navigation-divider-color: $color-line1-1 !default;
+$shell-dark-local-navigation-divider: $shell-dark-local-navigation-divider-size $shell-dark-local-navigation-divider-style $shell-dark-local-navigation-divider-color;
+
+/// background
+/// @namespace statement/appbar
+$shell-dark-appbar-background: $color-white !default;
+/// min-height
+/// @namespace statement/appbar
+$shell-dark-appbar-min-height: $s-12 !default;
+/// shadow
+/// @namespace statement/appbar
+$shell-dark-appbar-shadow: $shadow-zero !default;
+/// padding (l, r)
+/// @namespace statement/appbar
+$shell-dark-appbar-paddingLeft: $s-6 !default;
+/// size
+/// @namespace statement/appbar/divider
+$shell-dark-appbar-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/appbar/divider
+$shell-dark-appbar-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/appbar/divider
+$shell-dark-appbar-divider-color: $color-line1-1 !default;
+$shell-dark-appbar-divider: $shell-dark-appbar-divider-size $shell-dark-appbar-divider-style $shell-dark-appbar-divider-color;
+
+
+$shell-dark-content-max-width: unset !default;
+/// background
+/// @namespace statement/content
+$shell-dark-content-background: $color-fill1-3 !default;
+/// padding (l, r)
+/// @namespace statement/content
+$shell-dark-content-paddingLeft: $s-5 !default;
+/// padding (t, b)
+/// @namespace statement/content
+$shell-dark-content-paddingTop: $s-5 !default;
+
+$shell-dark-content-gutter-row: $s-4 !default;
+$shell-dark-content-gutter-column: $s-4 !default;
+$shell-dark-content-columns: 1 !default;
+
+/// min-height
+/// @namespace statement/footer
+$shell-dark-footer-min-height: $s-14 !default;
+/// background
+/// @namespace statement/footer
+$shell-dark-footer-background: $color-transparent !default;
+/// color
+/// @namespace statement/footer
+$shell-dark-footer-color: $color-text1-1 !default;
+/// font-size
+/// @namespace statement/footer
+$shell-dark-footer-font-size: $font-size-body-2 !default;
+
+/// width
+/// @namespace statement/ancillary
+$shell-dark-ancillary-width: $s-42 !default;
+/// background
+/// @namespace statement/ancillary
+$shell-dark-ancillary-background: $color-white !default;
+/// padding (t)
+/// @namespace statement/ancillary
+$shell-dark-ancillary-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/ancillary
+$shell-dark-ancillary-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/ancillary
+$shell-dark-ancillary-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/ancillary/divider
+$shell-dark-ancillary-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/ancillary/divider
+$shell-dark-ancillary-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/ancillary/divider
+$shell-dark-ancillary-divider-color: $color-line1-1 !default;
+$shell-dark-ancillary-divider: $shell-dark-ancillary-divider-size $shell-dark-ancillary-divider-style $shell-dark-ancillary-divider-color;
+
+
+/// height
+/// @namespace statement/tooldock
+$shell-dark-tooldock-height: $s-13 !default;
+/// width
+/// @namespace statement/tooldock
+$shell-dark-tooldock-width: $s-13 !default;
+/// background
+/// @namespace statement/tooldock
+$shell-dark-tooldock-background: $color-fill1-4 !default;
+/// padding (t)
+/// @namespace statement/tooldock
+$shell-dark-tooldock-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/tooldock
+$shell-dark-tooldock-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/tooldock
+$shell-dark-tooldock-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/tooldock/divider
+$shell-dark-tooldock-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/tooldock/divider
+$shell-dark-tooldock-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/tooldock/divider
+$shell-dark-tooldock-divider-color: $color-line1-1 !default;
+$shell-dark-tooldock-divider: $shell-dark-tooldock-divider-size $shell-dark-tooldock-divider-style $shell-dark-tooldock-divider-color;
+
+/// padding (t)
+/// @namespace statement/tooldock-item
+$shell-dark-tooldock-item-paddingTop: $s-2 !default;
+/// color
+/// @namespace statement/tooldock-item
+$shell-dark-tooldock-item-color: $color-text1-3 !default;
+/// color
+/// @namespace statement/tooldock-item/hover
+$shell-dark-tooldock-item-color-hover: $color-text1-4 !default;
+/// color
+/// @namespace statement/tooldock-item/active
+$shell-dark-tooldock-item-color-active: $color-text1-4 !default;
+/// background
+/// @namespace statement/tooldock-item
+$shell-dark-tooldock-item-background: $color-transparent !default;
+/// background
+/// @namespace statement/tooldock-item/hover
+$shell-dark-tooldock-item-background-hover: $color-fill1-3 !default;
+/// background
+/// @namespace statement/tooldock-item/active
+$shell-dark-tooldock-item-background-active: $color-fill1-3 !default;
+
+
+/** brand **/
+/// color
+/// @namespace statement/header
+$shell-brand-header-color: $color-white !default;
+/// height
+/// @namespace statement/header
+$shell-brand-header-height: $s-13 !default;
+/// background
+/// @namespace statement/header
+$shell-brand-header-background: $color-brand1-6 !default;
+/// shadow
+/// @namespace statement/header
+$shell-brand-header-shadow: $shadow-1-down !default;
+/// size
+/// @namespace statement/header/divider
+$shell-brand-header-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/header/divider
+$shell-brand-header-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/header/divider
+$shell-brand-header-divider-color: $color-line1-1 !default;
+$shell-brand-header-divider: $shell-brand-header-divider-size $shell-brand-header-divider-style $shell-brand-header-divider-color;
+/// padding (l, r)
+/// @namespace statement/header
+$shell-brand-header-paddingLeft: $s-4 !default;
+
+/// min-height
+/// @namespace statement/multitask
+$shell-brand-multitask-min-height: $s-10 !default;
+/// background
+/// @namespace statement/multitask
+$shell-brand-multitask-background: $color-white !default;
+/// shadow
+/// @namespace statement/multitask
+$shell-brand-multitask-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/multitask/divider
+$shell-brand-multitask-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/multitask/divider
+$shell-brand-multitask-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/multitask/divider
+$shell-brand-multitask-divider-color: $color-line1-1 !default;
+$shell-brand-multitask-divider: $shell-brand-multitask-divider-size $shell-brand-multitask-divider-style $shell-brand-multitask-divider-color;
+/// padding (l, r)
+/// @namespace statement/multitask
+$shell-brand-multitask-paddingLeft: $s-zero !default;
+
+
+/// margin (l, r)
+/// @namespace statement/navigation
+$shell-brand-navigation-hoz-marginLeft: $s-12 !default;
+$shell-brand-navigation-hoz-align: flex-end !default; // flex-start flex-end center space-evenly space-around space-between
+
+
+/// width
+/// @namespace statement/navigation
+$shell-brand-navigation-ver-width: $s-42 !default;
+/// shadow
+/// @namespace statement/navigation
+$shell-brand-navigation-ver-shadow: $shadow-zero !default;
+/// padding (t)
+/// @namespace statement/navigation
+$shell-brand-navigation-ver-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/navigation
+$shell-brand-navigation-ver-paddingBottom: $s-2 !default;
+/// mini-width
+/// @namespace statement/navigation
+$shell-brand-navigation-ver-width-mini: $s-15 !default;
+/// background
+/// @namespace statement/navigation
+$shell-brand-navigation-ver-background: $color-white !default;
+/// size
+/// @namespace statement/navigation/divider
+$shell-brand-navigation-ver-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/navigation/divider
+$shell-brand-navigation-ver-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/navigation/divider
+$shell-brand-navigation-ver-divider-color: $color-line1-1 !default;
+$shell-brand-navigation-ver-divider: $shell-brand-navigation-ver-divider-size $shell-brand-navigation-ver-divider-style $shell-brand-navigation-ver-divider-color;
+
+/// width
+/// @namespace statement/local-navigation
+$shell-brand-local-navigation-width: $s-42 !default;
+/// background
+/// @namespace statement/local-navigation
+$shell-brand-local-navigation-background: $color-fill1-4 !default;
+/// padding (t)
+/// @namespace statement/local-navigation
+$shell-brand-local-navigation-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/local-navigation
+$shell-brand-local-navigation-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/local-navigation
+$shell-brand-local-navigation-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/local-navigation/divider
+$shell-brand-local-navigation-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/local-navigation/divider
+$shell-brand-local-navigation-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/local-navigation/divider
+$shell-brand-local-navigation-divider-color: $color-line1-1 !default;
+$shell-brand-local-navigation-divider: $shell-brand-local-navigation-divider-size $shell-brand-local-navigation-divider-style $shell-brand-local-navigation-divider-color;
+
+/// background
+/// @namespace statement/appbar
+$shell-brand-appbar-background: $color-white !default;
+/// min-height
+/// @namespace statement/appbar
+$shell-brand-appbar-min-height: $s-12 !default;
+/// shadow
+/// @namespace statement/appbar
+$shell-brand-appbar-shadow: $shadow-zero !default;
+/// padding (l, r)
+/// @namespace statement/appbar
+$shell-brand-appbar-paddingLeft: $s-6 !default;
+/// size
+/// @namespace statement/appbar/divider
+$shell-brand-appbar-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/appbar/divider
+$shell-brand-appbar-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/appbar/divider
+$shell-brand-appbar-divider-color: $color-line1-1 !default;
+$shell-brand-appbar-divider: $shell-brand-appbar-divider-size $shell-brand-appbar-divider-style $shell-brand-appbar-divider-color;
+
+
+$shell-brand-content-max-width: unset !default;
+/// background
+/// @namespace statement/content
+$shell-brand-content-background: $color-fill1-3 !default;
+/// padding (l, r)
+/// @namespace statement/content
+$shell-brand-content-paddingLeft: $s-5 !default;
+/// padding (t, b)
+/// @namespace statement/content
+$shell-brand-content-paddingTop: $s-5 !default;
+
+$shell-brand-content-gutter-row: $s-4 !default;
+$shell-brand-content-gutter-column: $s-4 !default;
+$shell-brand-content-columns: 1 !default;
+
+/// min-height
+/// @namespace statement/footer
+$shell-brand-footer-min-height: $s-14 !default;
+/// background
+/// @namespace statement/footer
+$shell-brand-footer-background: $color-transparent !default;
+/// color
+/// @namespace statement/footer
+$shell-brand-footer-color: $color-text1-1 !default;
+/// font-size
+/// @namespace statement/footer
+$shell-brand-footer-font-size: $font-size-body-2 !default;
+
+/// width
+/// @namespace statement/ancillary
+$shell-brand-ancillary-width: $s-42 !default;
+/// background
+/// @namespace statement/ancillary
+$shell-brand-ancillary-background: $color-white !default;
+/// padding (t)
+/// @namespace statement/ancillary
+$shell-brand-ancillary-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/ancillary
+$shell-brand-ancillary-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/ancillary
+$shell-brand-ancillary-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/ancillary/divider
+$shell-brand-ancillary-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/ancillary/divider
+$shell-brand-ancillary-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/ancillary/divider
+$shell-brand-ancillary-divider-color: $color-line1-1 !default;
+$shell-brand-ancillary-divider: $shell-brand-ancillary-divider-size $shell-brand-ancillary-divider-style $shell-brand-ancillary-divider-color;
+
+
+/// height
+/// @namespace statement/tooldock
+$shell-brand-tooldock-height: $s-13 !default;
+/// width
+/// @namespace statement/tooldock
+$shell-brand-tooldock-width: $s-13 !default;
+/// background
+/// @namespace statement/tooldock
+$shell-brand-tooldock-background: $color-fill1-4 !default;
+/// padding (t)
+/// @namespace statement/tooldock
+$shell-brand-tooldock-paddingTop: $s-2 !default;
+/// padding (b)
+/// @namespace statement/tooldock
+$shell-brand-tooldock-paddingBottom: $s-2 !default;
+/// shadow
+/// @namespace statement/tooldock
+$shell-brand-tooldock-shadow: $shadow-zero !default;
+/// size
+/// @namespace statement/tooldock/divider
+$shell-brand-tooldock-divider-size: $line-1 !default;
+/// style
+/// @namespace statement/tooldock/divider
+$shell-brand-tooldock-divider-style: $line-solid !default;
+/// color
+/// @namespace statement/tooldock/divider
+$shell-brand-tooldock-divider-color: $color-line1-1 !default;
+$shell-brand-tooldock-divider: $shell-brand-tooldock-divider-size $shell-brand-tooldock-divider-style $shell-brand-tooldock-divider-color;
+
+/// padding (t)
+/// @namespace statement/tooldock-item
+$shell-brand-tooldock-item-paddingTop: $s-2 !default;
+/// color
+/// @namespace statement/tooldock-item
+$shell-brand-tooldock-item-color: $color-text1-3 !default;
+/// color
+/// @namespace statement/tooldock-item/hover
+$shell-brand-tooldock-item-color-hover: $color-text1-4 !default;
+/// color
+/// @namespace statement/tooldock-item/active
+$shell-brand-tooldock-item-color-active: $color-text1-4 !default;
+/// background
+/// @namespace statement/tooldock-item
+$shell-brand-tooldock-item-background: $color-transparent !default;
+/// background
+/// @namespace statement/tooldock-item/hover
+$shell-brand-tooldock-item-background-hover: $color-fill1-3 !default;
+/// background
+/// @namespace statement/tooldock-item/active
+$shell-brand-tooldock-item-background-active: $color-fill1-3 !default;
diff --git a/src/shell/shell.jsx b/src/shell/shell.jsx
new file mode 100644
index 0000000000..6886ecc689
--- /dev/null
+++ b/src/shell/shell.jsx
@@ -0,0 +1,592 @@
+import React, { Component } from 'react';
+import classnames from 'classnames';
+import PropTypes from 'prop-types';
+import Icon from '../icon';
+import { isBoolean, getCollapseMap } from './util';
+import { KEYCODE } from '../util';
+
+/**
+ * Shell
+ */
+export default function ShellBase(props) {
+ const { componentName } = props;
+ class Shell extends Component {
+ static displayName = componentName;
+
+ static _typeMark = componentName;
+
+ static propTypes = {
+ prefix: PropTypes.string,
+ /**
+ * 设备类型
+ * @enumdesc 手机, 平板, PC电脑
+ */
+ device: PropTypes.oneOf(['phone', 'tablet', 'desktop']),
+ /**
+ * 设备类型
+ * @enumdesc 浅色, 深色, 主题色
+ */
+ type: PropTypes.oneOf(['light', 'dark', 'brand']),
+ };
+
+ static defaultProps = {
+ prefix: 'next-',
+ device: 'desktop',
+ type: 'light',
+ };
+
+ static childContextTypes = {
+ shellPrefix: PropTypes.string,
+ };
+
+ constructor(props) {
+ super(props);
+
+ const deviceMap = getCollapseMap(props.device);
+ this.layout = {};
+
+ this.state = {
+ controll: false,
+ collapseMap: deviceMap,
+ device: props.device,
+ };
+ }
+
+ getChildContext() {
+ return {
+ shellPrefix: this.props.prefix,
+ };
+ }
+
+ componentWillReceiveProps(nextProps) {
+ const { device } = this.props;
+
+ if (nextProps.device !== device) {
+ const deviceMap = getCollapseMap(nextProps.device);
+ const { collapseMap } = this.state;
+
+ Object.keys(deviceMap).forEach(block => {
+ const { props } = this.layout[block] || {};
+ if (collapseMap[block] !== deviceMap[block]) {
+ if (
+ props &&
+ typeof props.onCollapseChange === 'function'
+ ) {
+ props.onCollapseChange(deviceMap[block]);
+ }
+ }
+ });
+
+ this.setState({
+ controll: false,
+ collapseMap: deviceMap,
+ device: nextProps.device,
+ });
+ }
+ }
+
+ setChildCollapse = (child, mark) => {
+ const { device, collapseMap, controll } = this.state;
+ const { collapse } = child.props;
+ const deviceMap = getCollapseMap(device);
+ const props = {};
+
+ // 非受控模式
+ if (isBoolean(collapse) === false) {
+ props.collapse = controll ? collapseMap[mark] : deviceMap[mark];
+ // props.collapse = collapseMap[mark];
+ }
+
+ if (device !== 'phone' && mark === 'Navigation') {
+ props.miniable = true;
+ }
+
+ return React.cloneElement(child, props);
+ };
+
+ toggleAside = (mark, props, e) => {
+ const { device, collapseMap } = this.state;
+ const deviceMap = getCollapseMap(device);
+ const current = props.collapse;
+
+ const newCollapseMap = {
+ ...deviceMap,
+ ...collapseMap,
+ [mark]: !current,
+ };
+ this.setState({
+ controll: true,
+ collapseMap: newCollapseMap,
+ });
+
+ if (props && typeof props.onCollapseChange === 'function') {
+ props.onCollapseChange(newCollapseMap[mark]);
+ }
+
+ const { children } = this.props;
+ let com;
+ if (mark === 'Navigation') {
+ com = children
+ .filter(
+ child =>
+ child &&
+ child.type._typeMark.replace('Shell_', '') ===
+ mark &&
+ child.props.direction !== 'hoz'
+ )
+ .pop();
+ } else {
+ com = children
+ .filter(
+ child =>
+ child &&
+ child.type._typeMark.replace('Shell_', '') === mark
+ )
+ .pop();
+ }
+
+ const { triggerProps = {} } = com.props;
+
+ if (typeof triggerProps.onClick === 'function') {
+ triggerProps.onClick(e, this.state.collapseMap[mark]);
+ }
+ };
+
+ toggleNavigation = e => {
+ const mark = 'Navigation';
+ const { props } = this.layout[mark];
+
+ if ('keyCode' in e && e.keyCode !== KEYCODE.ENTER) {
+ return;
+ }
+
+ this.toggleAside(mark, props, e);
+ };
+
+ toggleLocalNavigation = e => {
+ const mark = 'LocalNavigation';
+ const { props } = this.layout[mark];
+
+ if ('keyCode' in e && e.keyCode !== KEYCODE.ENTER) {
+ return;
+ }
+
+ this.toggleAside(mark, props, e);
+ };
+
+ toggleAncillary = e => {
+ const mark = 'Ancillary';
+ const { props } = this.layout[mark];
+
+ if ('keyCode' in e && e.keyCode !== KEYCODE.ENTER) {
+ return;
+ }
+
+ this.toggleAside(mark, props, e);
+ };
+
+ toggleToolDock = e => {
+ const mark = 'ToolDock';
+ const { props } = this.layout[mark];
+
+ if ('keyCode' in e && e.keyCode !== KEYCODE.ENTER) {
+ return;
+ }
+
+ this.toggleAside(mark, props, e);
+ };
+
+ renderShell = props => {
+ const { prefix, children, className, type, ...others } = props;
+
+ const { device } = this.state;
+
+ const layout = {};
+ let hasToolDock = false,
+ needNavigationTrigger = false,
+ needDockTrigger = false;
+
+ React.Children.map(children, child => {
+ if (child && typeof child.type === 'function') {
+ const mark = child.type._typeMark.replace('Shell_', '');
+ switch (mark) {
+ case 'Branding':
+ case 'Action':
+ if (!layout.header) {
+ layout.header = {};
+ }
+ layout.header[mark] = child;
+ break;
+ case 'MultiTask':
+ layout.taskHeader = child;
+ break;
+ case 'LocalNavigation':
+ if (!layout[mark]) {
+ layout[mark] = [];
+ }
+ layout[mark] = this.setChildCollapse(child, mark);
+ break;
+ case 'Ancillary':
+ if (!layout[mark]) {
+ layout[mark] = [];
+ }
+
+ layout[mark] = this.setChildCollapse(child, mark);
+ break;
+ case 'ToolDock':
+ hasToolDock = true;
+
+ if (!layout[mark]) {
+ layout[mark] = [];
+ }
+
+ const childT = this.setChildCollapse(child, mark);
+ layout[mark] = childT;
+
+ if (!layout.header && device === 'phone') {
+ layout.header = {};
+ }
+
+ break;
+ case 'AppBar':
+ case 'Content':
+ case 'Footer':
+ layout.content || (layout.content = []);
+ layout.content.push(child);
+ break;
+ case 'Page':
+ layout.page || (layout.page = []);
+ layout.page = child;
+ break;
+ case 'Navigation':
+ if (!layout.header) {
+ layout.header = {};
+ }
+
+ if (child.props.direction === 'hoz') {
+ layout.header[mark] = child;
+ } else {
+ if (!layout[mark]) {
+ layout[mark] = [];
+ }
+
+ needNavigationTrigger = true;
+
+ const childN = this.setChildCollapse(
+ child,
+ mark
+ );
+ layout[mark] = childN;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ });
+
+ const headerCls = classnames({
+ [`${prefix}shell-header`]: true,
+ });
+
+ const mainCls = classnames({
+ [`${prefix}shell-main`]: true,
+ });
+
+ const submainCls = classnames({
+ [`${prefix}shell-sub-main`]: true,
+ });
+
+ const asideCls = classnames({
+ [`${prefix}shell-aside`]: true,
+ });
+
+ if (hasToolDock) {
+ if (device === 'phone') {
+ needDockTrigger = true;
+ }
+ }
+
+ // 如果存在垂直模式的 Navigation, 则需要在 Branding 上出现 trigger
+ if (needNavigationTrigger) {
+ const branding = layout.header.Branding;
+ let { trigger, collapse } = layout.Navigation.props;
+
+ if ('trigger' in layout.Navigation.props) {
+ trigger =
+ (trigger &&
+ React.cloneElement(trigger, {
+ onClick: this.toggleNavigation,
+ 'aria-expanded': !collapse,
+ })) ||
+ trigger;
+ } else {
+ trigger = (
+
+ {collapse ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+
+ if (!branding) {
+ layout.header.Branding = trigger;
+ } else {
+ layout.header.Branding = React.cloneElement(branding, {}, [
+ trigger,
+ branding.props.children,
+ ]);
+ }
+ }
+
+ // 如果存在 toolDock, 则需要在 Action 上出现 trigger
+ if (needDockTrigger) {
+ const action = layout.header && layout.header.Action;
+ let { trigger, collapse } = layout.ToolDock.props;
+
+ if ('trigger' in layout.ToolDock.props) {
+ trigger =
+ (trigger &&
+ React.cloneElement(trigger, {
+ onClick: this.toggleToolDock,
+ 'aria-expanded': !collapse,
+ })) ||
+ trigger;
+ } else {
+ trigger = (
+
+
+
+ );
+ }
+
+ if (!action) {
+ layout.header.Action = trigger;
+ } else {
+ layout.header.Action = React.cloneElement(action, {}, [
+ action.props.children,
+ trigger,
+ ]);
+ }
+ }
+
+ let headerDom = [],
+ contentArr = [],
+ innerArr = [],
+ taskHeaderDom = null;
+
+ if (layout.taskHeader) {
+ const taskHeaderCls = classnames({
+ [`${prefix}shell-task-header`]: true,
+ });
+
+ taskHeaderDom = (
+
+ );
+ }
+
+ // 按照dom结构,innerArr 包括 LocalNavigation content Ancillary
+ if (layout.LocalNavigation) {
+ let { trigger, collapse } = layout.LocalNavigation.props;
+
+ if ('trigger' in layout.LocalNavigation.props) {
+ trigger =
+ (trigger &&
+ React.cloneElement(trigger, {
+ onClick: this.toggleLocalNavigation,
+ 'aria-expanded': !collapse,
+ })) ||
+ trigger;
+ } else {
+ trigger = (
+
+ {collapse ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+
+ const localNavCls = classnames(asideCls, {
+ [`${prefix}aside-localnavigation`]: true,
+ });
+
+ innerArr.push(
+
+ );
+ }
+
+ if (layout.content) {
+ innerArr.push(
+
+ );
+ }
+
+ if (layout.Ancillary) {
+ let { trigger, collapse } = layout.Ancillary.props;
+
+ if ('trigger' in layout.Ancillary.props) {
+ trigger =
+ (trigger &&
+ React.cloneElement(trigger, {
+ onClick: this.toggleAncillary,
+ 'aria-expanded': !collapse,
+ })) ||
+ trigger;
+ } else {
+ trigger = (
+
+ {collapse ? (
+
+ ) : (
+
+ )}
+
+ );
+ }
+
+ const ancillaryCls = classnames(asideCls, {
+ [`${prefix}aside-ancillary`]: true,
+ });
+
+ innerArr.push(
+
+ );
+ }
+
+ // 按照dom结构, arr 包括 header Navigation ToolDock 和 innerArr
+ if (layout.header) {
+ headerDom = (
+
+ {layout.header.Branding}
+ {layout.header.Navigation}
+ {layout.header.Action}
+
+ );
+ }
+
+ layout.Navigation &&
+ contentArr.push(
+ React.cloneElement(layout.Navigation, {
+ className: classnames(
+ asideCls,
+ layout.Navigation.props.className
+ ),
+ key: 'navigation',
+ })
+ );
+
+ // const contentArea = innerArr.length > 0
+ // ?
+ // : layout.page;
+
+ // contentArr.push(contentArea);
+ contentArr = contentArr.concat(
+ innerArr.length > 0 ? innerArr : [layout.page]
+ );
+
+ layout.ToolDock &&
+ contentArr.push(
+ React.cloneElement(layout.ToolDock, {
+ className: classnames(
+ asideCls,
+ layout.ToolDock.props.className
+ ),
+ key: 'tooldock',
+ })
+ );
+
+ const cls = classnames({
+ [`${prefix}shell`]: true,
+ [`${prefix}shell-${device}`]: true,
+ [`${prefix}shell-${type}`]: true,
+ [className]: !!className,
+ });
+
+ if (componentName === 'Page') {
+ return ;
+ }
+
+ this.layout = layout;
+
+ return (
+
+ {headerDom}
+ {taskHeaderDom}
+
+
+ );
+ };
+
+ render() {
+ return this.renderShell(this.props);
+ }
+ }
+
+ return Shell;
+}
diff --git a/src/shell/style.js b/src/shell/style.js
new file mode 100644
index 0000000000..65cfc7e394
--- /dev/null
+++ b/src/shell/style.js
@@ -0,0 +1,2 @@
+import '../icon/style.js';
+import './main.scss';
diff --git a/src/shell/util.js b/src/shell/util.js
new file mode 100644
index 0000000000..9271b868b4
--- /dev/null
+++ b/src/shell/util.js
@@ -0,0 +1,42 @@
+/**
+ * 判断是否为布尔类型
+ * @param {any} val 例:'str' / undefined / null / true / false / 0
+ * @return {bool} 例: false / false / false / true / false / false
+ */
+export function isBoolean(val) {
+ return typeof val === 'boolean';
+}
+
+export function getCollapseMap(device) {
+ // by default all of them are collapsed
+ const origin = {
+ Navigation: true,
+ LocalNavigation: true,
+ Ancillary: true,
+ ToolDock: true,
+ };
+
+ let map = [];
+
+ switch (device) {
+ case 'phone':
+ break;
+ case 'pad':
+ case 'tablet':
+ map = ['ToolDock'];
+ break;
+ case 'desktop':
+ map = ['Navigation', 'LocalNavigation', 'Ancillary', 'ToolDock'];
+ break;
+ default:
+ break;
+ }
+
+ Object.keys(origin).forEach(key => {
+ if (map.indexOf(key) > -1) {
+ origin[key] = false;
+ }
+ });
+
+ return origin;
+}
diff --git a/test/menu-button/index-spec.js b/test/menu-button/index-spec.js
index 1f9a7db9b5..eeebb84fa1 100644
--- a/test/menu-button/index-spec.js
+++ b/test/menu-button/index-spec.js
@@ -45,7 +45,7 @@ describe('MenuButton', () => {
wrapper.setProps({ selectedKeys: ['b'] });
assert(
wrapper
- .find('li[title="b"][role="listitem"]')
+ .find('li[title="b"][role="option"]')
.hasClass('next-selected')
);
});
@@ -82,10 +82,10 @@ describe('MenuButton', () => {
{menu}
);
- wrapper.find('li[title="b"][role="listitem"]').simulate('click');
+ wrapper.find('li[title="b"][role="option"]').simulate('click');
assert(
wrapper
- .find('li[title="b"][role="listitem"]')
+ .find('li[title="b"][role="option"]')
.hasClass('next-selected')
);
});
@@ -101,10 +101,10 @@ describe('MenuButton', () => {
{menu}
);
- wrapper.find('li[title="b"][role="listitem"]').simulate('click');
+ wrapper.find('li[title="b"][role="option"]').simulate('click');
assert(
wrapper
- .find('li[title="a"][role="listitem"]')
+ .find('li[title="a"][role="option"]')
.hasClass('next-selected')
);
});
@@ -117,7 +117,7 @@ describe('MenuButton', () => {
{menu}
);
- wrapper.find('li[title="b"][role="listitem"]').simulate('click');
+ wrapper.find('li[title="b"][role="option"]').simulate('click');
assert(onItemClick.calledOnce);
assert(onVisibleChange.notCalled);
})
diff --git a/test/nav/index-spec.js b/test/nav/index-spec.js
index cc72912ff4..927b3360b8 100644
--- a/test/nav/index-spec.js
+++ b/test/nav/index-spec.js
@@ -304,7 +304,7 @@ describe('Nav', () => {
let nav = wrapper.find('ul.next-nav');
assert(nav.hasClass('next-icon-only'));
- assert(nav.prop('style').width === '60px');
+ assert(nav.prop('style').width === '58px');
let items = nav.find('li.next-nav-item');
assert(items.at(0).find('i.next-nav-icon').length === 1);
diff --git a/test/shell/a11y-spec.js b/test/shell/a11y-spec.js
new file mode 100644
index 0000000000..72cae60772
--- /dev/null
+++ b/test/shell/a11y-spec.js
@@ -0,0 +1,52 @@
+import React from 'react';
+import Enzyme from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import { unmount, testReact } from '../util/a11y/validate';
+import Shell from '../../src/shell/index';
+import Search from '../../src/search/index';
+import '../../src/shell/style.js';
+import '../../src/search/style.js';
+import './index.scss';
+
+Enzyme.configure({ adapter: new Adapter() });
+
+/* eslint-disable no-undef, react/jsx-filename-extension */
+describe('Shell A11y', () => {
+ let wrapper;
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.unmount();
+ wrapper = null;
+ }
+ unmount();
+ });
+
+ it('should not have any violations', async () => {
+ wrapper = await testReact(
+
+
+
+ App Name
+
+
+
+
+
+
+ MyName
+
+
+
+
+
+
+
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+
+ );
+ return wrapper;
+ });
+});
diff --git a/test/shell/index-spec.js b/test/shell/index-spec.js
new file mode 100644
index 0000000000..07b7a507a0
--- /dev/null
+++ b/test/shell/index-spec.js
@@ -0,0 +1,232 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import Enzyme, { mount } from 'enzyme';
+import Adapter from 'enzyme-adapter-react-16';
+import assert from 'power-assert';
+import Shell from '../../src/shell/index';
+import Search from '../../src/search/index';
+import Radio from '../../src/radio/index';
+import Icon from '../../src/icon/index';
+import Nav from '../../src/nav/index';
+import '../../src/shell/style.js';
+import '../../src/search/style.js';
+import '../../src/nav/style.js';
+import '../../src/icon/style.js';
+import './index.scss';
+
+const Item = Nav.Item;
+Enzyme.configure({ adapter: new Adapter() });
+
+const render = element => {
+ let inc;
+ const container = document.createElement('div');
+ document.body.appendChild(container);
+ ReactDOM.render(element, container, function() {
+ inc = this;
+ });
+ return {
+ setProps: props => {
+ const clonedElement = React.cloneElement(element, props);
+ ReactDOM.render(clonedElement, container);
+ },
+ unmount: () => {
+ ReactDOM.unmountComponentAtNode(container);
+ document.body.removeChild(container);
+ },
+ instance: () => {
+ return inc;
+ },
+ find: selector => {
+ return container.querySelectorAll(selector);
+ },
+ };
+};
+
+
+class App extends React.Component {
+ state = {
+ device: 'desktop'
+ }
+ onChange = device => {
+ this.setState({
+ device
+ });
+ }
+
+ btnClick = () => {
+ this.setState({
+ navcollapse: !this.state.navcollapse
+ });
+ }
+
+ onCollapseChange = (visible, e) => {
+ console.log('onCollapseChange:',visible, e);
+ const { onCollapseNavigationChange } = this.props;
+
+ this.setState({
+ navcollapse: visible
+ });
+
+ onCollapseNavigationChange(visible);
+ }
+
+ render() {
+ const { onCollapseLocalNavChange, onCollapseAncilleryChange } = this.props;
+ // eslint-disable-next-line react/jsx-filename-extension
+ return (
+
+ phone
+ tablet
+ desktop
+
+
+
+
+ App Name
+
+
+
+
+
+
+ MyName
+
+
+
+
+ - Nav Item 1
+ - Nav Item 2
+ - Nav Item 3
+ - Nav Item 4
+ - Nav Item 5
+ - Nav Item 6
+ - Nav Item 7
+
+
+ { this.state.navcollapse ? : }
+
+
+
+
+
+
+ - Local Nav1
+
+
+ - Local Nav2
+
+
+ - Local Nav3
+
+ - Local Nav4
+ - Local Nav5
+ - Local Nav6
+ - Local Nav7
+ - Local Nav8
+ - Local Nav4
+ - Local Nav5
+ - Local Nav6
+ - Local Nav7
+ - Local Nav8
+
+
+
+
+
+
+
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
+ }
+}
+
+/* eslint-disable */
+describe('Shell', () => {
+ describe('render', () => {
+ let wrapper;
+
+ afterEach(() => {
+ wrapper.unmount();
+ });
+
+ it('default should work', () => {
+ wrapper = render(
+
+
+
+ App Name
+
+
+
+
+
+
+ MyName
+
+
+
+
+
+
+
+ Alibaba Fusion
+ @ 2019 Alibaba Piecework 版权所有
+
+
+ );
+ });
+
+ it('default collapse should work', () => {
+ let navCollapseCount = 0, localCollapseCount = 0, anciCollapseCount = 0;
+ let navCollapse = false, localCollapse = false, anciCollapse = false;
+ wrapper = render(
+ {
+ navCollapseCount++;
+ navCollapse = visible;
+ console.log('global nav:', navCollapseCount, navCollapse)
+ }}
+ onCollapseLocalNavChange={(visible) => {
+ localCollapseCount++;
+ localCollapse = visible;
+ console.log('local nav:', localCollapseCount, localCollapse)
+ }}
+ onCollapseAncilleryChange={(visible) => {
+ anciCollapseCount++;
+ anciCollapse = visible;
+ console.log('ancillery nav:', anciCollapseCount, anciCollapse)
+ }}
+ />
+ );
+
+ wrapper.find('.local-nav-trigger')[0].click();
+ wrapper.find('.ancillary-trigger')[0].click();
+ wrapper.find('.nav-trigger')[0].click();
+ wrapper.find('.nav-trigger')[0].click();
+
+ assert(navCollapseCount === 2 && localCollapseCount === 1 && anciCollapseCount === 1 && !navCollapse && localCollapse && anciCollapse);
+
+ wrapper.find('#custom-nav-trigger')[0].click();
+
+ assert(wrapper.find('.next-shell-navigation.next-shell-collapse'));
+ });
+ });
+});
diff --git a/test/shell/index.scss b/test/shell/index.scss
new file mode 100644
index 0000000000..f1fbb2b9e5
--- /dev/null
+++ b/test/shell/index.scss
@@ -0,0 +1,16 @@
+.avatar {
+ width: 24px;
+ height: 24px;
+ border-radius: 50%;
+ vertical-align: middle;
+ }
+ .rectangular {
+ width: 32px;
+ height: 32px;
+ background: rgba(0, 0, 0, 0.04);
+ }
+
+ .iframe-hack {
+ width: 100%;
+ height: 500px;
+ }
diff --git a/test/split-button/index-spec.js b/test/split-button/index-spec.js
index f51a750d27..d251461156 100644
--- a/test/split-button/index-spec.js
+++ b/test/split-button/index-spec.js
@@ -44,7 +44,7 @@ describe('SplitButton', () => {
wrapper.setProps({ selectedKeys: ['b'] });
assert(
wrapper
- .find('li[title="b"][role="listitem"]')
+ .find('li[title="b"][role="option"]')
.hasClass('next-selected')
);
});
@@ -81,10 +81,10 @@ describe('SplitButton', () => {
{menu}
);
- wrapper.find('li[title="b"][role="listitem"]').simulate('click');
+ wrapper.find('li[title="b"][role="option"]').simulate('click');
assert(
wrapper
- .find('li[title="b"][role="listitem"]')
+ .find('li[title="b"][role="option"]')
.hasClass('next-selected')
);
});
@@ -100,10 +100,10 @@ describe('SplitButton', () => {
{menu}
);
- wrapper.find('li[title="b"][role="listitem"]').simulate('click');
+ wrapper.find('li[title="b"][role="option"]').simulate('click');
assert(
wrapper
- .find('li[title="a"][role="listitem"]')
+ .find('li[title="a"][role="option"]')
.hasClass('next-selected')
);
});
diff --git a/types/config-provider/index.d.ts b/types/config-provider/index.d.ts
index 2701b1f8be..e7478e2156 100644
--- a/types/config-provider/index.d.ts
+++ b/types/config-provider/index.d.ts
@@ -43,7 +43,7 @@ export interface ConfigProviderProps {
/**
* 设备类型,针对不同的设备类型组件做出对应的响应式变化
*/
- device?: 'tablet' | 'desktop' | 'phone',
+ device?: 'tablet' | 'desktop' | 'phone';
/**
* 组件树
*/
diff --git a/types/index.d.ts b/types/index.d.ts
index d71b5a8747..5ca9078759 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -35,6 +35,7 @@ export { default as Range } from './range';
export { default as Rating } from './rating';
export { default as Search } from './search';
export { default as Select } from './select';
+export { default as Shell } from './shell';
export { default as Slider } from './slider';
export { default as SplitButton } from './split-button';
export { default as Step } from './step';
@@ -49,4 +50,5 @@ export { default as Tree } from './tree';
export { default as TreeSelect } from './tree-select';
export { default as Upload } from './upload';
export { default as VirtualList } from './virtual-list';
+export { default as Typography } from './typography';
export const Field: any;
diff --git a/types/shell/index.d.ts b/types/shell/index.d.ts
new file mode 100644
index 0000000000..1ec01482ea
--- /dev/null
+++ b/types/shell/index.d.ts
@@ -0,0 +1,46 @@
+import { HTMLAttributes, ElementType, Component, ComponentType } from "react";
+import CommonProps from '../util';
+
+export interface ShellProps extends HTMLAttributes, CommonProps {
+ /**
+ * 设备类型,针对不同的设备类型组件做出对应的响应式变化
+ */
+ device?: 'tablet' | 'desktop' | 'phone';
+ type?: 'light' | 'dark' | 'brand';
+}
+
+export interface ShellCommonProps extends HTMLAttributes, CommonProps {
+
+}
+
+export interface ShellNavigationProps extends ShellCommonProps {
+ collapse?: boolean;
+ direction?: 'hoz' | 'ver';
+}
+
+export interface ShellLocalNavigationProps extends ShellCommonProps {
+ collapse?: boolean;
+}
+
+export interface ShellToolDockProps extends ShellCommonProps {
+ collapse?: boolean;
+}
+
+export interface ShellAncillaryProps extends ShellCommonProps {
+ collapse?: boolean;
+}
+
+export default class Shell extends Component {
+ static Branding: ComponentType;
+ static Action: ComponentType;
+ static MultiTask: ComponentType;
+ static AppBar: ComponentType;
+ static Content: ComponentType;
+ static Footer: ComponentType;
+ static ToolDockItem: ComponentType;
+
+ static Navigation: ComponentType;
+ static LocalNavigation: ComponentType;
+ static Ancillary: ComponentType;
+ static ToolDock: ComponentType;
+}
diff --git a/variables.scss b/variables.scss
index 01bc20a113..ab7a4ace1a 100644
--- a/variables.scss
+++ b/variables.scss
@@ -56,4 +56,8 @@
@import "lib/tree/scss/variable.scss";
@import "lib/tree-select/scss/variable.scss";
@import "lib/upload/scss/variable.scss";
-@import "lib/virtual-list/scss/variable.scss";
\ No newline at end of file
+@import "lib/virtual-list/scss/variable.scss";
+@import "lib/shell/scss/variable.scss";
+@import "lib/notification/scss/variable.scss";
+@import "lib/typography/scss/variable.scss";
+