├── .eslintrc
├── .gitignore
├── README.md
├── example
├── basic.jsx
├── example.config.js
├── index.html
├── main.js
└── server.config.js
├── lib
├── css
│ └── default.css
├── index.js
├── tab.js
└── tabs.js
├── mocha.opts
├── package.json
├── src
├── css
│ └── default.css
├── index.jsx
├── tab.jsx
└── tabs.jsx
└── tests
├── setup.js
└── test.jsx
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "parser": "babel-eslint",
3 | "env": {
4 | "es6": true
5 | },
6 | "ecmaFeatures": {
7 | "blockBindings": true,
8 | "forOf": true,
9 | "jsx": true,
10 | "modules": true
11 | },
12 | "rules": {
13 | "indent": [2, 2],
14 | "max-len": 0,
15 | "semi": 0,
16 | "quotes": 0,
17 | "no-console": 0,
18 | "no-trailing-spaces": 0,
19 | "curly": 0,
20 | "camelcase": 0,
21 | "react/jsx-boolean-value": 1,
22 | "react/jsx-quotes": 1,
23 | "react/jsx-no-undef": 1,
24 | "react/jsx-uses-react": 1,
25 | "react/jsx-uses-vars": 1,
26 | "react/no-did-mount-set-state": 1,
27 | "react/no-did-update-set-state": 1,
28 | "react/no-multi-comp": 1,
29 | "react/no-unknown-property": 1,
30 | "react/prop-types": 1,
31 | "react/react-in-jsx-scope": 1,
32 | "react/self-closing-comp": 1,
33 | "react/sort-comp": 1,
34 | "react/wrap-multilines": 1,
35 | "new-cap": [1, {newIsCap: true, capIsNew: false}],
36 | },
37 | "plugins": [
38 | "react"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ##Tabs
2 |
3 | A basic tabs component, with a few customizable props.
4 |
5 | ##Install
6 |
7 | `npm install legit-tabs`
8 |
9 | ##Example
10 |
11 | ~~~js
12 | import {Tabs, Tab} from 'legit-tabs';
13 |
14 |
15 |
16 | hey
17 |
18 |
19 | whats up
20 |
21 |
22 | hello
23 |
24 |
25 | ~~~
26 |
27 | ##Props
28 |
29 | **Tabs**:
30 |
31 | - `active`: Name of the tab you want to be active, defaults to the first one if empty
32 | - anything else you'd like to set on the containing ul
33 |
34 | **Tab**:
35 |
36 | - `name`: a unique name for the tab, represents the tab title.
37 | - `liClass`, `liStyle`: class on the li for the tab.
38 | - `contentClass`: class on the div that holds the tab content.
39 | - anything else you'd like to set on the tab's containing div.
40 |
--------------------------------------------------------------------------------
/example/basic.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {Tabs, Tab} from '../src/index';
3 |
4 | require('../src/css/default.css');
5 |
6 | export default class Basic extends React.Component {
7 |
8 | render() {
9 | return (
10 |
11 |
12 | hey
13 |
14 |
15 | whats up
16 |
17 |
18 | hello
19 |
20 |
21 | );
22 | }
23 | }
24 |
25 | React.render(, document.getElementById('react'));
26 |
--------------------------------------------------------------------------------
/example/example.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 |
4 | module.exports = {
5 | entry: './example/basic.jsx',
6 | output: {
7 | path: __dirname,
8 | filename: "[name].js"
9 | },
10 | resolve: {
11 | extensions: ['', '.js', '.jsx', '.es6'],
12 | modulesDirectories: ['node_modules']
13 | },
14 | module: {
15 | loaders: [
16 | { test: /\.jsx$|\.es6$|\.js$/, loaders: ['babel-loader?stage=0'], exclude: /node_modules/ },
17 | { test: /\.css$/, loader: 'style-loader!css-loader' }
18 | ]
19 | },
20 | plugins: [
21 | new webpack.NoErrorsPlugin()
22 | ],
23 | devtool: "eval-source-map"
24 | };
25 |
--------------------------------------------------------------------------------
/example/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | Basic Example
4 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/example/server.config.js:
--------------------------------------------------------------------------------
1 | var webpack = require('webpack');
2 | var path = require('path');
3 |
4 | module.exports = {
5 | entry: {
6 | 'basic': [
7 | 'webpack-dev-server/client?http://localhost:8881/',
8 | 'webpack/hot/only-dev-server',
9 | './example/basic.jsx'
10 | ]
11 | },
12 | output: {
13 | path: __dirname,
14 | filename: "[name].js",
15 | publicPath: 'http://localhost:8881/',
16 | chunkFilename: '[id].chunk.js',
17 | sourceMapFilename: '[name].map'
18 | },
19 | resolve: {
20 | extensions: ['', '.js', '.jsx', '.es6', '.css'],
21 | modulesDirectories: ['node_modules']
22 | },
23 | module: {
24 | loaders: [
25 | { test: /\.jsx$|\.es6$|\.js$/, loaders: ['react-hot', 'babel-loader?stage=0'], exclude: /node_modules/ },
26 | { test: /\.css$/, loader: 'style-loader!style!css' },
27 | { test: /\.(jpe?g|png|gif)$/i, loader: 'url?limit=10000!img?progressive=true' }
28 | ]
29 | },
30 | plugins: [
31 | new webpack.NoErrorsPlugin()
32 | ],
33 | devtool: "eval-source-map"
34 | };
35 |
--------------------------------------------------------------------------------
/lib/css/default.css:
--------------------------------------------------------------------------------
1 | .accordion-tabs-minimal {
2 | line-height: 1.5;
3 | padding: 0;
4 | }
5 |
6 | .accordion-tabs-minimal::after {
7 | clear: both;
8 | content: "";
9 | }
10 |
11 | .accordion-tabs-minimal li.tab-header-and-content {
12 | list-style: none;
13 | display: inline;
14 | }
15 |
16 | .accordion-tabs-minimal a.tab-link {
17 | background-color: white;
18 | border-top: 0;
19 | color: #333;
20 | display: inline-block;
21 | padding: 0.75em 1em;
22 | text-decoration: none;
23 | }
24 |
25 | .accordion-tabs-minimal a.tab-link:hover {
26 | color: #477DCA;
27 | cursor: pointer;
28 | }
29 |
30 | .accordion-tabs-minimal a.tab-link:focus {
31 | outline: none;
32 | }
33 |
34 | .accordion-tabs-minimal a.tab-link.is-active {
35 | border: solid 1px gainsboro;
36 | border-bottom-color: transparent;
37 | margin-bottom: -1px;
38 | }
39 |
40 | .accordion-tabs-minimal .tab-content {
41 | padding: 1.5em 1em;
42 | width: 100%;
43 | border-top: solid 1px gainsboro;
44 | float: left;
45 | }
46 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
8 |
9 | var _tabs = require('./tabs');
10 |
11 | var _tabs2 = _interopRequireDefault(_tabs);
12 |
13 | var _tab = require('./tab');
14 |
15 | var _tab2 = _interopRequireDefault(_tab);
16 |
17 | exports.Tabs = _tabs2['default'];
18 | exports.Tab = _tab2['default'];
--------------------------------------------------------------------------------
/lib/tab.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
10 |
11 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
12 |
13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14 |
15 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
16 |
17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
18 |
19 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
20 |
21 | var _react = require('react');
22 |
23 | var _react2 = _interopRequireDefault(_react);
24 |
25 | var Tab = (function (_React$Component) {
26 | _inherits(Tab, _React$Component);
27 |
28 | _createClass(Tab, null, [{
29 | key: 'propTypes',
30 | value: {
31 | name: _react2['default'].PropTypes.string.isRequired,
32 | clicked: _react2['default'].PropTypes.func,
33 | active: _react2['default'].PropTypes.bool,
34 | children: _react2['default'].PropTypes.any.isRequired,
35 | liStyle: _react2['default'].PropTypes.object,
36 | liClass: _react2['default'].PropTypes.string
37 | },
38 | enumerable: true
39 | }]);
40 |
41 | function Tab(props) {
42 | var _this = this;
43 |
44 | _classCallCheck(this, Tab);
45 |
46 | _get(Object.getPrototypeOf(Tab.prototype), 'constructor', this).call(this, props);
47 |
48 | this.clicked = function () {
49 | _this.props.clicked(_this.props.name);
50 | };
51 |
52 | this.state = {};
53 | }
54 |
55 | _createClass(Tab, [{
56 | key: 'render',
57 | value: function render() {
58 | var _props = this.props;
59 | var liClass = _props.liClass;
60 | var liStyle = _props.liStyle;
61 | var contentClass = _props.contentClass;
62 | var active = _props.active;
63 | var name = _props.name;
64 | var children = _props.children;
65 |
66 | var rest = _objectWithoutProperties(_props, ['liClass', 'liStyle', 'contentClass', 'active', 'name', 'children']);
67 |
68 | delete rest.clicked;
69 | var linkClass = active ? 'is-active' : null;
70 |
71 | return _react2['default'].createElement(
72 | 'li',
73 | { className: 'tab-header-and-content ' + liClass, style: liStyle || null },
74 | _react2['default'].createElement(
75 | 'a',
76 | {
77 | className: 'tab-link ' + linkClass,
78 | onClick: this.clicked },
79 | name
80 | ),
81 | active ? _react2['default'].createElement(
82 | 'div',
83 | _extends({}, rest, { className: 'tab-content ' + contentClass }),
84 | children
85 | ) : null
86 | );
87 | }
88 | }]);
89 |
90 | return Tab;
91 | })(_react2['default'].Component);
92 |
93 | exports['default'] = Tab;
94 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/lib/tabs.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | Object.defineProperty(exports, '__esModule', {
4 | value: true
5 | });
6 |
7 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
8 |
9 | var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
10 |
11 | var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; desc = parent = undefined; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } };
12 |
13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
14 |
15 | function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
16 |
17 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
18 |
19 | function _inherits(subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
20 |
21 | var _react = require('react');
22 |
23 | var _react2 = _interopRequireDefault(_react);
24 |
25 | var Tabs = (function (_React$Component) {
26 | _inherits(Tabs, _React$Component);
27 |
28 | _createClass(Tabs, null, [{
29 | key: 'propTypes',
30 | value: {
31 | children: _react2['default'].PropTypes.array
32 | },
33 | enumerable: true
34 | }]);
35 |
36 | function Tabs(props) {
37 | var _this = this;
38 |
39 | _classCallCheck(this, Tabs);
40 |
41 | _get(Object.getPrototypeOf(Tabs.prototype), 'constructor', this).call(this, props);
42 |
43 | this.clicked = function (active) {
44 | _this.setState({ active: active });
45 | };
46 |
47 | this.state = {
48 | active: props.active || props.children[0].props.name
49 | };
50 | }
51 |
52 | _createClass(Tabs, [{
53 | key: 'renderChildren',
54 | value: function renderChildren() {
55 | var _this2 = this;
56 |
57 | return _react2['default'].Children.map(this.props.children, function (child) {
58 | return _react2['default'].cloneElement(child, _extends({}, child.props, {
59 | clicked: _this2.clicked,
60 | active: _this2.state.active === child.props.name ? true : false
61 | }));
62 | });
63 | }
64 | }, {
65 | key: 'render',
66 | value: function render() {
67 | var _props = this.props;
68 | var className = _props.className;
69 |
70 | var rest = _objectWithoutProperties(_props, ['className']);
71 |
72 | // This is a hack to make React 15 happy. We can't pass the `active` prop
73 | // through to the `ul` component. This component needs a bit of a rewrite
74 | // so we'll go ahead and just do this for now.
75 | delete rest.active;
76 |
77 | return _react2['default'].createElement(
78 | 'ul',
79 | _extends({ className: 'accordion-tabs-minimal ' + className }, rest),
80 | this.renderChildren()
81 | );
82 | }
83 | }]);
84 |
85 | return Tabs;
86 | })(_react2['default'].Component);
87 |
88 | exports['default'] = Tabs;
89 | module.exports = exports['default'];
--------------------------------------------------------------------------------
/mocha.opts:
--------------------------------------------------------------------------------
1 | --require ./tests/setup
2 | --full-trace
3 | --compilers js:babel/register
4 | --recursive ./tests/**/*.jsx
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "legit-tabs",
3 | "version": "0.2.4",
4 | "description": "tabs, done right",
5 | "main": "lib/index.js",
6 | "scripts": {
7 | "compile": "babel src --stage 0 --out-dir lib;",
8 | "prepublish": "babel src --stage 0 --out-dir lib;",
9 | "dev-server": "webpack-dev-server --config ./example/server.config.js --hot --port 8881",
10 | "example": "webpack --config ./example/example.config.js",
11 | "test": "mocha --opts ./mocha.opts; eslint ./src/ --ext .jsx,.js --global require,exports:true"
12 | },
13 | "repository": {
14 | "type": "git",
15 | "url": "git+ssh://git@github.com/legitcode/tabs.git"
16 | },
17 | "keywords": [
18 | "react-tabs",
19 | "react-component",
20 | "react",
21 | "table",
22 | "react-table",
23 | "bootstrap"
24 | ],
25 | "author": "Zach Silveira",
26 | "license": "ISC",
27 | "bugs": {
28 | "url": "https://github.com/legitcode/tabs/issues"
29 | },
30 | "homepage": "https://github.com/legitcode/tabs#readme",
31 | "devDependencies": {
32 | "babel": "^5.8.23",
33 | "babel-core": "^5.8.23",
34 | "babel-eslint": "^4.1.1",
35 | "babel-loader": "^5.3.2",
36 | "css-loader": "^0.18.0",
37 | "eslint": "^0.24.1",
38 | "eslint-plugin-react": "^2.7.0",
39 | "expect": "^1.8.0",
40 | "mocha": "^2.2.5",
41 | "mocha-babel": "^3.0.0",
42 | "node-jsdom": "^3.1.5",
43 | "react-hot-loader": "^1.3.0",
44 | "style-loader": "^0.12.4",
45 | "webpack": "^1.12.1",
46 | "webpack-dev-server": "^1.10.1"
47 | },
48 | "peerDependencies": {
49 | "react": ">=0.13.3"
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/css/default.css:
--------------------------------------------------------------------------------
1 | .accordion-tabs-minimal {
2 | line-height: 1.5;
3 | padding: 0;
4 | }
5 |
6 | .accordion-tabs-minimal::after {
7 | clear: both;
8 | content: "";
9 | }
10 |
11 | .accordion-tabs-minimal li.tab-header-and-content {
12 | list-style: none;
13 | display: inline;
14 | }
15 |
16 | .accordion-tabs-minimal a.tab-link {
17 | background-color: white;
18 | border-top: 0;
19 | color: #333;
20 | display: inline-block;
21 | padding: 0.75em 1em;
22 | text-decoration: none;
23 | }
24 |
25 | .accordion-tabs-minimal a.tab-link:hover {
26 | color: #477DCA;
27 | cursor: pointer;
28 | }
29 |
30 | .accordion-tabs-minimal a.tab-link:focus {
31 | outline: none;
32 | }
33 |
34 | .accordion-tabs-minimal a.tab-link.is-active {
35 | border: solid 1px gainsboro;
36 | border-bottom-color: transparent;
37 | margin-bottom: -1px;
38 | }
39 |
40 | .accordion-tabs-minimal .tab-content {
41 | padding: 1.5em 1em;
42 | width: 100%;
43 | border-top: solid 1px gainsboro;
44 | float: left;
45 | }
46 |
--------------------------------------------------------------------------------
/src/index.jsx:
--------------------------------------------------------------------------------
1 | import Tabs from './tabs'
2 | import Tab from './tab'
3 |
4 | export {
5 | Tabs,
6 | Tab
7 | }
8 |
--------------------------------------------------------------------------------
/src/tab.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Tab extends React.Component {
4 | static propTypes = {
5 | name: React.PropTypes.string.isRequired,
6 | clicked: React.PropTypes.func,
7 | active: React.PropTypes.bool,
8 | children: React.PropTypes.any.isRequired,
9 | liStyle: React.PropTypes.object,
10 | liClass: React.PropTypes.string
11 | }
12 |
13 | constructor(props) {
14 | super(props)
15 | this.state = {}
16 | }
17 |
18 | clicked = () => {
19 | this.props.clicked(this.props.name);
20 | }
21 |
22 | render() {
23 | const {
24 | liClass,
25 | liStyle,
26 | contentClass,
27 | active,
28 | name,
29 | children,
30 | ...rest
31 | } = this.props;
32 | delete rest.clicked;
33 | const linkClass = active ? 'is-active' : null;
34 |
35 | return (
36 |
37 |
40 | {name}
41 |
42 |
43 | {active ?
44 |
45 | { children }
46 |
47 | : null}
48 |
49 | )
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/tabs.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | export default class Tabs extends React.Component {
4 | static propTypes = {
5 | children: React.PropTypes.array
6 | }
7 |
8 | constructor(props) {
9 | super(props);
10 |
11 | this.state = {
12 | active: props.active || props.children[0].props.name
13 | };
14 | }
15 |
16 | renderChildren(){
17 | return React.Children.map(this.props.children, (child) => {
18 | return React.cloneElement(child, {
19 | ...child.props,
20 | clicked: this.clicked,
21 | active: this.state.active === child.props.name ? true : false
22 | });
23 | });
24 | }
25 |
26 | clicked = (active) => {
27 | this.setState({active});
28 | }
29 |
30 | render() {
31 | const { className, ...rest } = this.props;
32 |
33 | // This is a hack to make React 15 happy. We can't pass the `active` prop
34 | // through to the `ul` component. This component needs a bit of a rewrite
35 | // so we'll go ahead and just do this for now.
36 | delete rest.active;
37 |
38 | return (
39 |
40 | { this.renderChildren() }
41 |
42 | );
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/tests/setup.js:
--------------------------------------------------------------------------------
1 | /* globals global */
2 |
3 | require("babel/register")({
4 | stage: 0
5 | });
6 |
7 | function propagateToGlobal (window) {
8 | for (let key in window) {
9 | if (!window.hasOwnProperty(key)) continue
10 | if (key in global) continue
11 |
12 | global[key] = window[key]
13 | }
14 | }
15 |
16 | var jsdom = require('jsdom');
17 |
18 | var doc = jsdom.jsdom('');
19 | var win = doc.defaultView;
20 |
21 | global.document = doc;
22 | global.window = win;
23 |
24 | propagateToGlobal(win);
25 |
--------------------------------------------------------------------------------
/tests/test.jsx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Legitcode/tabs/36a1938264df966aa4e2e92510a37f68fd7e3023/tests/test.jsx
--------------------------------------------------------------------------------