Repository: sm-react/storybook-addon-material-ui
Branch: version-1
Commit: 7afdfba6b0f0
Files: 63
Total size: 142.9 KB
Directory structure:
gitextract_qtgx2lmx/
├── .babelrc
├── .eslintignore
├── .eslintrc.js
├── .github/
│ └── workflows/
│ └── codacy-analysis.yml
├── .gitignore
├── .npmignore
├── .scripts/
│ ├── deployer/
│ │ ├── index.js
│ │ └── utils.js
│ ├── lint.js
│ ├── npm-postpublish.js
│ ├── npm-prepare.js
│ ├── npm-status.js
│ ├── run_tests/
│ │ ├── index.js
│ │ └── mocha_runner.js
│ ├── ver.js
│ └── watch.js
├── .storybook/
│ ├── .themes/
│ │ ├── customTheme1.js
│ │ ├── customTheme2.js
│ │ ├── customTheme3.js
│ │ ├── customTheme4.js
│ │ └── customTheme5.js
│ ├── addons.js
│ ├── config.js
│ └── stories.js
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── docs/
│ └── screenshorts.md
├── package.json
├── public/
│ ├── index.html
│ └── manifest.json
├── register.js
├── src/
│ ├── .themes/
│ │ └── index.js
│ ├── UI/
│ │ ├── AddonPanel.js
│ │ ├── FullTheme.js
│ │ ├── MuiDecorator.js
│ │ ├── Overridings.js
│ │ └── Palette.js
│ ├── Utils/
│ │ ├── index.js
│ │ ├── svg_package.js
│ │ ├── uiTheme.js
│ │ └── ui_package.jsx
│ ├── adk/
│ │ ├── ChannelHOC.js
│ │ ├── ChannelStore.js
│ │ ├── WithChannel.js
│ │ ├── decorator.js
│ │ └── panel.js
│ ├── components/
│ │ ├── AddonPanel.jsx
│ │ ├── ThemePropBlock.jsx
│ │ ├── ThemePropItem.jsx
│ │ └── ThemeSideBar.jsx
│ ├── config.js
│ ├── containers/
│ │ ├── MuiTheme.jsx
│ │ └── PanelContainer.jsx
│ ├── index.js
│ ├── material-desktop/
│ │ ├── SclAvatar.jsx
│ │ ├── SclToggle.jsx
│ │ ├── SvgButton.jsx
│ │ └── SvgIcon.jsx
│ ├── muiTheme.js
│ ├── preset.js
│ └── register.js
└── storybook-addon-material-ui.d.ts
================================================
FILE CONTENTS
================================================
================================================
FILE: .babelrc
================================================
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-proposal-class-properties"]
}
================================================
FILE: .eslintignore
================================================
*.d.ts
================================================
FILE: .eslintrc.js
================================================
const error = 2;
const warn = 1;
const ignore = 0;
module.exports = {
root: true,
extends: ['eslint-config-airbnb', 'plugin:jest/recommended', 'prettier'],
plugins: ['prettier', 'jest', 'json'],
parser: 'babel-eslint',
parserOptions: {
sourceType: 'module'
},
env: {
es6: true,
node: true,
'jest/globals': true
},
rules: {
// "prettier/prettier": error,
'no-console': ignore,
'react/jsx-filename-extension': ignore,
'react/destructuring-assignment': ignore,
'import/prefer-default-export': ignore,
}
};
================================================
FILE: .github/workflows/codacy-analysis.yml
================================================
# This workflow checks out code, performs a Codacy security scan
# and integrates the results with the
# GitHub Advanced Security code scanning feature. For more information on
# the Codacy security scan action usage and parameters, see
# https://github.com/codacy/codacy-analysis-cli-action.
# For more information on Codacy Analysis CLI in general, see
# https://github.com/codacy/codacy-analysis-cli.
name: Codacy Security Scan
on:
push:
branches: [ version-1 ]
pull_request:
branches: [ version-1 ]
jobs:
codacy-security-scan:
name: Codacy Security Scan
runs-on: ubuntu-latest
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v2
# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
uses: codacy/codacy-analysis-cli-action@1.1.0
with:
# Check https://github.com/codacy/codacy-analysis-cli#project-token to get your project token from your Codacy repository
# You can also omit the token and run the tools that support default configurations
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
verbose: true
output: results.sarif
format: sarif
# Adjust severity of non-security issues
gh-code-scanning-compat: true
# Force 0 exit code to allow SARIF file generation
# This will handover control about PR rejection to the GitHub side
max-allowed-issues: 50
# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v1
with:
sarif_file: results.sarif
================================================
FILE: .gitignore
================================================
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.idea
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
/dist
.vscode/settings.json
================================================
FILE: .npmignore
================================================
node_modules
develop
example
src
docs
.babelrc
.eslintrc
.scripts
.storybook
================================================
FILE: .scripts/deployer/index.js
================================================
var shell = require('shelljs');
var chalk = require('chalk');
var publishUtils = require('./utils');
var path = require('path');
var packageJson = require(path.resolve('./package.json'));
var OUTPUT_DIR = 'out' + Math.ceil(Math.random() * 9999);
shell.echo(chalk.bold(`${packageJson.name}@${packageJson.version}\n`));
// get GIT url
console.log(chalk.grey('=> Getting the git remote URL'));
var GIT_URL = publishUtils.exec('git config --get remote.origin.url');
if (!GIT_URL) {
console.log('This project is not configured with a remote git repo');
process.exit(-1);
}
// clear and re-create the out directory
shell.rm('-rf', OUTPUT_DIR);
shell.mkdir(OUTPUT_DIR);
// run our compile script
console.log(chalk.grey('=> Building storybook'));
if (packageJson.scripts['build-storybook']) {
publishUtils.exec('npm run build-storybook -- -o ' + OUTPUT_DIR);
} else {
publishUtils.exec('build-storybook -o ' + OUTPUT_DIR);
}
// go to the out directory and create a *new* Git repo
shell.cd(OUTPUT_DIR);
publishUtils.exec('git init');
// inside this git repo we'll pretend to be a new user
publishUtils.exec('git config user.name "GH Pages Bot"');
publishUtils.exec('git config user.email "hello@ghbot.com"');
// The first and only commit to this new Git repo contains all the
// files present with the commit message "Deploy to GitHub Pages".
publishUtils.exec('git add .');
publishUtils.exec('git commit -m "Deploy Storybook to GitHub Pages"');
// Force push from the current repo's master branch to the remote
// repo's gh-pages branch. (All previous history on the gh-pages branch
// will be lost, since we are overwriting it.) We redirect any output to
// /dev/null to hide any sensitive credential data that might otherwise be exposed.
console.log(chalk.grey('=> Deploying storybook'));
publishUtils.exec('git push --force --quiet ' + GIT_URL + ' master:gh-pages')
shell.cd('..');
shell.rm('-rf', OUTPUT_DIR);
console.log();
console.log(chalk.grey('=> Storybook deployed to: ') +
chalk.cyan(publishUtils.getGHPagesUrl(GIT_URL)));
================================================
FILE: .scripts/deployer/utils.js
================================================
var shell = require('shelljs');
var chalk = require('chalk');
var parseGitUrl = require('git-url-parse');
module.exports.exec = function exec(command) {
shell.echo(chalk.grey(" executing: ") + command);
const options = { silent: true };
const ref = shell.exec(command, options);
if (ref.code === 0) {
return ref.stdout.trim();
}
const message =
'Exec code(' + ref.code + ') on executing: ' + command + '\n' +
shell.stderr;
throw new Error(message);
};
module.exports.getGHPagesUrl = function getGHPagesUrl(ghUrl) {
var parsedUrl = parseGitUrl(ghUrl);
var ghPagesUrl = 'https://' + parsedUrl.owner + '.github.io/' + parsedUrl.name + '/';
return ghPagesUrl;
};
================================================
FILE: .scripts/lint.js
================================================
const path = require('path');
const shell = require('shelljs');
const chalk = require('chalk');
const isJSON = process.argv.includes('-f') && process.argv.includes('json');
const out = isJSON ? ['-o .scripts/lintresult.json'] : [];
const lint = ['node_modules', '.bin', 'eslint'].join(path.sep);
const args = [
'src',
'--ext .jsx,.js',
'--color',
...process.argv.slice(2),
...out,
].join(' ');
const cmd = `${lint} ${args}`;
if(isJSON) {
shell.echo('\nESLint:');
} else {
require('./ver');
}
shell.echo(chalk.gray(cmd));
shell.exec(cmd);
if(isJSON) {
shell.echo('');
const lintresult = require('./lintresult.json');
lintresult.forEach( val => {
const err = val.errorCount;
const war = val.warningCount;
const fpath = path.relative(process.cwd(), val.filePath);
if (err || war) {
shell.echo(`${chalk.grey(fpath)} ${err ? chalk.red(`errors: ${err}` + (war ? ', ' : '')) : ''}${war ? chalk.yellow(`warnings: ${war}`) : ''}`);
}
})
shell.rm('.scripts/lintresult.json');
}
================================================
FILE: .scripts/npm-postpublish.js
================================================
var shell = require('shelljs');
var chalk = require('chalk');
const packageJson = require('../package.json');
shell.echo(chalk.grey(`${packageJson.name}@${packageJson.version} was successfully published.`));
================================================
FILE: .scripts/npm-prepare.js
================================================
var path = require('path');
var shell = require('shelljs');
var chalk = require('chalk');
var babel = ['node_modules', '.bin', 'babel'].join(path.sep);
require('./ver');
const args = '--ignore tests,stories,story.jsx,story.js src --out-dir dist --verbose';
const cmd = `${babel} ${args}`;
shell.echo(chalk.gray(cmd));
shell.rm('-rf', 'dist');
shell.echo('');
shell.echo(chalk.gray('Transpiling \'src\' into ES5 ...'));
shell.exec(cmd);
shell.echo(chalk.gray('Transpiling completed.'));
shell.echo('');
================================================
FILE: .scripts/npm-status.js
================================================
var path = require('path');
var shell = require('shelljs');
var chalk = require('chalk');
var semver = require('semver');
var dateFormat = require('dateformat');
const packageJson = require('../package.json');
const ref = shell.exec('npm view --json', { silent: true });
if (ref.code === 0) {
const data = JSON.parse(ref.stdout);
const lastVersion = data.version;
const lastName = data.name;
const lastPublish = data.time[lastVersion];
const maintainers = data.maintainers.reduce((str, val) => `${str}, ${val}` );
if (lastVersion === packageJson.version) {
shell.echo(chalk.bold(`\n${packageJson.name}@${packageJson.version}`));
shell.echo(chalk.grey('was published to NPM at ' + dateFormat(lastPublish, 'dd-mmm-yyyy, HH:MM')));
} else {
const diff = semver.diff(lastVersion, packageJson.version);
const verColor = diff.match(/major/) ? 'red' : diff.match(/minor/) ? 'yellow' : 'bold';
shell.echo(chalk.grey('\nthe current version: ') + chalk.white(`${packageJson.name}`) + chalk[verColor](`@${packageJson.version}`));
shell.echo(chalk.grey('the latest published version: ') + chalk.white(`${lastName}@${lastVersion}`));
shell.echo(
chalk.grey('was published to NPM at ') +
chalk.white(dateFormat(lastPublish, 'dd-mmm-yyyy, HH:MM')) +
chalk.grey(` by ${maintainers}`)
);
}
} else {
if ( ref.stderr.match('npm ERR! code E404')) {
shell.echo(chalk.bold(`\n${packageJson.name}@${packageJson.version}`));
shell.echo(chalk.grey('wasn\'t published to NPM yet'));
} else {
console.log(ref.stderr);
}
}
================================================
FILE: .scripts/run_tests/index.js
================================================
const path = require('path');
const shell = require('shelljs');
const chalk = require('chalk');
const isMin = process.argv.includes('-R') && process.argv.includes('min');
const mocha = ['node_modules', '.bin', 'mocha'].join(path.sep);
const args = [
'--require .scripts/run_tests/mocha_runner',
'src/**/tests/**/*.js',
'--colors',
...process.argv.slice(2),
].join(' ');
const cmd = `${mocha} ${args}`;
shell.echo(`${isMin ? '\nMocha:\n' : ''}${chalk.grey(cmd)}`);
shell.exec(cmd);
================================================
FILE: .scripts/run_tests/mocha_runner.js
================================================
// This is an auto generated file with React CDK.
require('babel-core/register');
require('babel-polyfill');
// pass images
require.extensions['.svg'] = function(){ return null; }
require.extensions['.png'] = function(){ return null; }
require.extensions['.gif'] = function(){ return null; }
require.extensions['.jpg'] = function(){ return null; }
var packageJson = require('../../package.json');
// Add jsdom support, which is required for enzyme.
var jsdom = require('jsdom').jsdom;
var exposedProperties = ['window', 'navigator', 'document'];
global.document = jsdom('');
global.window = document.defaultView;
Object.keys(document.defaultView).forEach((property) => {
if (typeof global[property] === 'undefined') {
exposedProperties.push(property);
global[property] = document.defaultView[property];
}
});
global.navigator = {
userAgent: 'node.js'
};
// Add packageJson to have it accessible from any folder
global.packageJson = packageJson;
process.on('unhandledRejection', function (error) {
console.error('Unhandled Promise Rejection:');
console.error(error && error.stack || error);
});
================================================
FILE: .scripts/ver.js
================================================
const shell = require('shelljs');
const chalk = require('chalk');
const packageJson = require('../package.json');
shell.echo(chalk.bold(`${packageJson.name}@${packageJson.version}`));
================================================
FILE: .scripts/watch.js
================================================
const shell = require('shelljs');
const chalk = require('chalk');
shell.exec('nodemon src -e js,jsx,json --exec "npm run status"');
================================================
FILE: .storybook/.themes/customTheme1.js
================================================
import { createMuiTheme } from '@material-ui/core/styles';
import green from '@material-ui/core/colors/green';
import purple from '@material-ui/core/colors/purple';
import blue from '@material-ui/core/colors/blue';
import red from '@material-ui/core/colors/red';
import yellow from '@material-ui/core/colors/yellow';
const primaryGreen = green[500];
const accentGreen = green.A200;
const darkGreen = green[900];
const primaryPurple = purple[500];
const accentPurple = purple.A200;
const darkPurple = purple[900];
export const overridings = {
palette: {
primary: {
light: accentGreen,
main: primaryGreen,
dark: darkGreen,
contrastText: '#fff'
},
secondary: {
light: accentPurple,
main: primaryPurple,
dark: darkPurple,
contrastText: '#fff'
}
},
themeName: 'Custom Light Theme'
};
export default createMuiTheme(overridings);
================================================
FILE: .storybook/.themes/customTheme2.js
================================================
import { createMuiTheme } from '@material-ui/core/styles';
import green from '@material-ui/core/colors/green';
import purple from '@material-ui/core/colors/purple';
const primaryGreen = green[500];
const accentGreen = green.A200;
const darkGreen = green[900];
const primaryPurple = purple[500];
const accentPurple = purple.A200;
const darkPurple = purple[900];
export const overridings = {
palette: {
primary: {
light: accentPurple,
main: primaryPurple,
dark: darkPurple,
contrastText: '#fff'
},
type: 'dark',
secondary: {
light: accentGreen,
main: primaryGreen,
dark: darkGreen,
contrastText: '#fff'
}
},
themeName: 'Custom Dark Theme'
};
export default createMuiTheme(overridings);
================================================
FILE: .storybook/.themes/customTheme3.js
================================================
import { createMuiTheme } from '@material-ui/core/styles';
import green from '@material-ui/core/colors/green';
import purple from '@material-ui/core/colors/purple';
import blue from '@material-ui/core/colors/blue';
const darkGreen = green[900];
const accentPurple = purple.A200;
const darkPurple = purple[900];
export const overridings = {
palette: {
primary: {
light: accentPurple,
main: blue[200],
dark: darkPurple,
},
secondary: {
main: darkGreen,
},
type: 'dark'
},
themeName: 'Pale Blue Theme'
};
export default createMuiTheme(overridings);
================================================
FILE: .storybook/.themes/customTheme4.js
================================================
import { createMuiTheme } from '@material-ui/core/styles';
import red from '@material-ui/core/colors/red';
import yellow from '@material-ui/core/colors/yellow';
export const overridings = {
palette: {
primary: {
main: yellow[500],
contrastText: '#000'
},
secondary: {
main: red[500],
contrastText: '#fff'
},
type: 'dark'
},
themeName: 'Yellow and Red Theme'
};
export default createMuiTheme(overridings);
================================================
FILE: .storybook/.themes/customTheme5.js
================================================
import { createMuiTheme } from '@material-ui/core/styles';
import blue from '@material-ui/core/colors/blue';
import yellow from '@material-ui/core/colors/yellow';
export const overridings = {
palette: {
primary: {
main: yellow[500],
contrastText: '#000'
},
secondary: {
main: blue[500],
contrastText: '#fff'
},
type: 'dark'
},
themeName: 'Yellow and Blue Theme'
};
export default createMuiTheme(overridings);
================================================
FILE: .storybook/addons.js
================================================
import '../src/register';
import '@storybook/addon-actions/register';
import '@storybook/addon-links/register';
import '@storybook/addon-backgrounds/register';
================================================
FILE: .storybook/config.js
================================================
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
import { configure } from '@storybook/react';
function loadStories() {
require('./stories');
}
configure(loadStories, module);
================================================
FILE: .storybook/stories.js
================================================
import React from 'react';
import { storiesOf } from '@storybook/react';
import Button from '@material-ui/core/Button';
import { muiTheme } from '../src';
import { overridings as theme1 } from './.themes/customTheme1';
import { overridings as theme2 } from './.themes/customTheme2';
import themeF3, { overridings as theme3 } from './.themes/customTheme3';
import { overridings as theme4 } from './.themes/customTheme4';
import { overridings as theme5 } from './.themes/customTheme5';
const buttonStyle = {
margin: 16
};
storiesOf('Material Custom theme', module)
.addParameters({
backgrounds: [
{ name: 'init', value: '#FFFFFF' },
{ name: 'twitter', value: '#00aced' },
{ name: 'facebook', value: '#3b5998' }
]
})
.addDecorator(muiTheme([theme1, theme2, theme3, theme4, theme5]))
.add('Raised buttons', () => (
<div>
<Button variant="contained" color="primary" style={buttonStyle}>
Raised primary
</Button>
<Button variant="contained" color="secondary" style={buttonStyle}>
Raised secondary
</Button>
<Button variant="contained" style={buttonStyle}>
Raised default
</Button>
</div>
))
.add('Outlined buttons', () => (
<div>
<Button variant="outlined" color="primary" style={buttonStyle}>
Outlined primary
</Button>
<Button variant="outlined" color="secondary" style={buttonStyle}>
Outlined secondary
</Button>
<Button variant="outlined" style={buttonStyle}>
Outlined default
</Button>
</div>
))
.add('Flat buttons', () => (
<div>
<Button variant="flat" color="primary" style={buttonStyle}>
Flat primary
</Button>
<Button variant="flat" color="secondary" style={buttonStyle}>
Flat secondary
</Button>
<Button variant="flat" style={buttonStyle}>
Flat default
</Button>
</div>
));
storiesOf('Clone Custom theme', module)
// .addDecorator(muiTheme([theme4, theme5]))
.add(' Raised buttons', () => (
<div>
<Button variant="contained" color="primary" style={buttonStyle}>
Raised primary
</Button>
<Button variant="contained" color="secondary" style={buttonStyle}>
Raised secondary
</Button>
<Button variant="contained" style={buttonStyle}>
Raised default
</Button>
</div>
));
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as
contributors and maintainers pledge to making participation in our project and
our community a harassment-free experience for everyone, regardless of age, body
size, disability, ethnicity, gender identity and expression, level of experience,
nationality, personal appearance, race, religion, or sexual identity and
orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment
include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or
advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic
address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable
behavior and are expected to take appropriate and fair corrective action in
response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community. Examples of
representing a project or community include using an official project e-mail
address, posting via an official social media account, or acting as an appointed
representative at an online or offline event. Representation of a project may be
further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting the project team at welcome@sm-artlight.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. The project team is
obligated to maintain confidentiality with regard to the reporter of an incident.
Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good
faith may face temporary or permanent repercussions as determined by other
members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Oleg Proskurin
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
[](https://app.codacy.com/gh/react-theming/storybook-addon-material-ui?utm_source=github.com&utm_medium=referral&utm_content=react-theming/storybook-addon-material-ui&utm_campaign=Badge_Grade)
[](https://badge.fury.io/js/storybook-addon-material-ui)
[](https://sm-react.github.io/storybook-boilerplate/?theme-ind=0&theme-sidebar=false&theme-full=false&knob-Title=Welcome%20to%20React-Theming&knob-Subtitle=Storybook%20Boilerplate%20Project&knob-Label1=Hello%20Button&knob-Label2=Hello%20Button&selectedKind=Material-UI&selectedStory=Components&full=0&down=1&left=1&panelRight=0&downPanel=sm%2Fstorybook-addon-material-ui%2Fmaterial-panel)
# Storybook Addon Material-UI
[<img src="https://raw.githubusercontent.com/react-theming/storybook-addon-material-ui/master/docs/logos/Storybook.png" align="left" class="logo" height="60" title="Storybook Addon" alt="Storybook Addon" />](https://storybooks.js.org/docs/react-storybook/addons/addon-gallery/)
[<img src="https://raw.githubusercontent.com/react-theming/storybook-addon-material-ui/version-1/docs/logos/material-ui.png" align="left" class="logo" height="60" title="Material UI" alt="Storybook Addon" />](https://material-ui.com/styles/advanced/#theming)
Provides development environment which helps creating [Material-UI Components](http://www.material-ui.com/). This is addon for [React Storybook](https://github.com/storybooks/react-storybook) which wraps your components into MuiThemeProvider. This accelerates and simplifies the [development](#getting-started-bookmark_tabs) process for Material-UI based applications.
You can use this [project's demo page](https://sm-react.github.io/storybook-boilerplate/?theme-ind=0&theme-sidebar=false&theme-full=false&knob-Title=Welcome%20to%20React-Theming&knob-Subtitle=Storybook%20Boilerplate%20Project&knob-Label1=Hello%20Button&knob-Label2=Hello%20Button&selectedKind=Material-UI&selectedStory=Components&full=0&down=1&left=1&panelRight=0&downPanel=sm%2Fstorybook-addon-material-ui%2Fmaterial-panel) to discover `Material-UI Theme Settings` for any component and create your `own new themes` right online. But to take [full advantage](#features-dizzy) of this project [run it locally](#quick-start) in your work environment.
[](https://raw.githubusercontent.com/react-theming/storybook-addon-material-ui/master/docs/WatchMe.gif)
## Features
[](https://sm-react.github.io/storybook-boilerplate/?theme-ind=0&theme-sidebar=false&theme-full=false&knob-Title=Welcome%20to%20React-Theming&knob-Subtitle=Storybook%20Boilerplate%20Project&knob-Label1=Hello%20Button&knob-Label2=Hello%20Button&selectedKind=Material-UI&selectedStory=Components&full=0&down=1&left=1&panelRight=0&downPanel=sm%2Fstorybook-addon-material-ui%2Fmaterial-panel)
- Wrapped in the theme provider. Just start to develop with base light theme.
- Injected TapEvent Plugin. Test on mobile devices.
- Switching themes. See how it looks in one click.
- Creating your custom theme. By code or in visual editor.
- Dynamic visual themes editing. Discover the all avalibale theme properties.
- Google [material color](https://material.google.com/style/color.html#color-color-palette) palette [picker](https://github.com/sm-react/react-material-color-picker)
- Save made changes and download in JSON file
- Part of [React Theming](https://github.com/react-theming/react-theming). Create themable React Components.
- Works with Storybook 3.0
## Quick Start
In order to quick start with the latest `storybook-addon-material-ui` you can check out [create-material-ui-app](https://github.com/react-theming/create-material-ui-app)
It contains the working setup with:
- create-react-app
- Storybook
- Material-UI
- storybook-addon-material-ui
---
## Getting Started
First, install the addon
```shell
npm i storybook-addon-material-ui --save-dev
```
### Storybook 6.1
Add `storybook-addon-material-ui` to the storybook addons:
```js
//.storybook/main.js
module.exports = {
stories: ['../stories/**/*.stories.(js|mdx)'],
addons: [
'storybook-addon-material-ui'
],
};
```
Add the decorator to storybook preview:
```js
//.storybook/preview.js
import { muiTheme } from 'storybook-addon-material-ui'
export const decorators = [
muiTheme()
];
```
> Note : You can switch between the loaded themes. Out of the box, you have two base themes, but you can simply add your custom themes like this:
```js
//.storybook/preview.js
import { muiTheme } from 'storybook-addon-material-ui'
// Create your own theme like this.
// Note: you can specify theme name in `themeName` field. Otherwise it will be displayed by the number.
// you can specify only required fields overriding the `Light Base Theme`
const newTheme = {
themeName: 'Grey Theme',
palette: {
primary1Color: '#00bcd4',
alternateTextColor: '#4a4a4a',
canvasColor: '#616161',
textColor: '#bdbdbd',
secondaryTextColor: 'rgba(255, 255, 255, 0.54)',
disabledColor: '#757575',
accent1Color: '#607d8b',
},
};
export const decorators = [
muiTheme([newTheme])
];
```
or even import from elsewhere
```js
//.storybook/preview.js
import { muiTheme } from 'storybook-addon-material-ui'
import theme1 from './src/theme/theme1'
import theme2 from './src/theme/theme2'
export const decorators = [
muiTheme([theme1, theme2])
];
```
### Storybook 5 (and older versions)
Now, write your stories with Material-UI Addon. By default your stories will be provided with [`Light Base Theme`](https://github.com/callemall/material-ui/blob/master/src/styles/baseThemes/lightBaseTheme.js) and [`Dark Base Theme`](https://github.com/callemall/material-ui/blob/master/src/styles/baseThemes/darkBaseTheme.js)
```js
import React from 'react';
import { storiesOf, addDecorator } from '@storybook/react';
import {muiTheme} from 'storybook-addon-material-ui';
// Import some examples from react-theming https://github.com/react-theming/react-theme-provider/blob/master/example/
import CardExampleControlled from '../CardExampleControlled.jsx';
import RaisedButtonExampleSimple from '../RaisedButtonExampleSimple.jsx';
import DatePickerExampleSimple from '../DatePickerExampleSimple.jsx';
storiesOf('Material-UI', module)
// Add the `muiTheme` decorator to provide material-ui support to your stories.
// If you do not specify any arguments it starts with two default themes
// You can also configure `muiTheme` as a global decorator.
.addDecorator(muiTheme())
.add('Card Example Controlled', () => (
<CardExampleControlled />
))
.add('Raised Button Example Simple', () => (
<RaisedButtonExampleSimple />
))
.add('Date Picker Example Simple', () => (
<DatePickerExampleSimple />
));
```
> Note : You can switch between the loaded themes. Out of the box, you have two base themes, but you can simply add your custom themes like this:
```js
import React from 'react';
import { storiesOf, addDecorator } from '@storybook/react';
import {muiTheme} from 'storybook-addon-material-ui';
import CardExampleControlled from '../CardExampleControlled.jsx';
import RaisedButtonExampleSimple from '../RaisedButtonExampleSimple.jsx';
import DatePickerExampleSimple from '../DatePickerExampleSimple.jsx';
// Create your own theme like this.
// Note: you can specify theme name in `themeName` field. Otherwise it will be displayed by the number.
// you can specify only required fields overriding the `Light Base Theme`
const newTheme = {
themeName: 'Grey Theme',
palette: {
primary1Color: '#00bcd4',
alternateTextColor: '#4a4a4a',
canvasColor: '#616161',
textColor: '#bdbdbd',
secondaryTextColor: 'rgba(255, 255, 255, 0.54)',
disabledColor: '#757575',
accent1Color: '#607d8b',
},
};
storiesOf('Material-UI', module)
.addDecorator(muiTheme([newTheme]))
.add('Card Example Controlled', () => (
<CardExampleControlled />
))
.add('Raised Button Example Simple', () => (
<RaisedButtonExampleSimple />
))
.add('Date Picker Example Simple', () => (
<DatePickerExampleSimple />
));
```
## Feedback
**You can left your opinion about this project via anonymous [survey](https://app.qpointsurvey.com/s.aspx?c=**F2VOSpTXOlnHHqMaZKSSV5a1ylaCDoRfhut3oNCox34~**).**
## Query string parameters
As you select themes and other options it stores in adress bar line. So this state is retained when you refresh the page and you can use direct links to the desired states.
```
http://localhost:9001/?theme-ind=0&theme-sidebar=true&theme-full=true
```
## CONTRIBUTING
[](./.eslintrc)
### Developers:
Our team welcome all contributing, testing, bug fixing. If you would like
to help contribute to the project feel free to make an issue, PR or get in touch with me.
### Designers:
We would really welcome the involvement of designers in this project. We are very interested in your opinion about working with this tool, the possibility of joint work of the designer and developer as well as its appearance and capabilities
#### Credits
<div align="left" style="height: 16px;">Created with ❤︎ to <b>Storybook</b> and <b>Material-UI</b> by <a
href="https://twitter.com/UsulPro">Oleg Proskurin</a> [<a href="https://github.com/react-theming">React Theming</a>]
</div>
================================================
FILE: docs/screenshorts.md
================================================
### default `Light base theme`
>quick start for component development

### default `Dark base theme`
>Check a different appearance

### Visual color adjusting
>Results instantly on the screen

### User created theme

### Full theme settings

### After overriding
>you will have only chanded setting in your theme

================================================
FILE: package.json
================================================
{
"name": "storybook-addon-material-ui",
"version": "0.9.0-alpha.24",
"description": "Storybook Addon for Material UI Library",
"main": "dist/index.js",
"types": "storybook-addon-material-ui.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/react-theming/storybook-addon-material-ui.git"
},
"keywords": [
"storybook-addons",
"style",
"debug",
"storybook",
"react",
"material",
"ui",
"material-ui",
"addon",
"decorator",
"theme",
"editor",
"customization",
"dark theme",
"light theme",
"storybook-addon"
],
"storybook": {
"displayName": "Material-UI",
"supportedFrameworks": [
"React"
],
"icon": "https://github.com/react-theming/storybook-addon-material-ui/blob/b0ac1c444bd33212d693af182ac6fed1b069c3db/docs/logos/material-ui.png"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/react-theming/storybook-addon-material-ui/issues"
},
"homepage": "https://github.com/react-theming/storybook-addon-material-ui",
"dependencies": {
"@emotion/core": "^10.0.4",
"@emotion/styled": "^10.0.4",
"global": "^4.3.2",
"js-beautify": "^1.8.9",
"react-inspector": "^2.3.1",
"@usulpro/color-picker": "^1.1.3"
},
"scripts": {
"start": "start-storybook -p 9001",
"build-storybook": "build-storybook -s public",
"deploy": "node .scripts/deployer",
"prepare": "node .scripts/npm-prepare.js",
"postpublish": "node .scripts/npm-postpublish.js"
},
"devDependencies": {
"@babel/cli": "^7.2.3",
"@babel/core": "^7.2.2",
"@babel/plugin-proposal-class-properties": "^7.2.3",
"@babel/preset-env": "^7.2.3",
"@babel/preset-react": "^7.0.0",
"@material-ui/core": "^3.9.3",
"@material-ui/icons": "^3.0.2",
"@storybook/addon-actions": "^5.0.6",
"@storybook/addon-backgrounds": "^5.0.6",
"@storybook/addon-links": "^5.0.6",
"@storybook/addons": "^5.0.6",
"@storybook/react": "^5.0.6",
"babel-eslint": "^8.2.6",
"babel-jest": "^23.4.2",
"babel-loader": "^8.0.2",
"chalk": "^2.4.1",
"emotion-theming": "^10.0.10",
"eslint": "^5.3.0",
"eslint-config-airbnb": "^17.0.0",
"eslint-config-prettier": "^2.9.0",
"eslint-plugin-import": "^2.14.0",
"eslint-plugin-jest": "^21.21.0",
"eslint-plugin-json": "^1.2.1",
"eslint-plugin-jsx-a11y": "^6.1.1",
"eslint-plugin-prettier": "^2.6.2",
"eslint-plugin-react": "^7.10.0",
"gh-pages": "^1.2.0",
"jest": "^23.5.0",
"prettier": "^1.14.2",
"prop-types": "^15.6.2",
"react": "16.7.0-alpha.2",
"react-dom": "16.7.0-alpha.2",
"react-scripts": "1.1.5",
"shelljs": "^0.8.2"
},
"peerDependencies": {
"@material-ui/core": "^1.0.0 || ^3.0.0 || ^4.0.0",
"@storybook/addons": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0",
"@storybook/react": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0",
"prop-types": "^15.5.8",
"react": "^16.0.0 || ^17.0.0",
"react-dom": "^16.0.0 || ^17.0.0"
}
}
================================================
FILE: public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>
================================================
FILE: public/manifest.json
================================================
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
================================================
FILE: register.js
================================================
require('./dist/register.js');
================================================
FILE: src/.themes/index.js
================================================
import { createMuiTheme } from '@material-ui/core/styles';
export const lightTheme = createMuiTheme({
palette: {
primary: {
main: 'rgb(98, 126, 157)'
}
}
});
================================================
FILE: src/UI/AddonPanel.js
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { cx, css } from '@emotion/core';
import styled from '@emotion/styled';
import { ObjectInspector } from 'react-inspector';
import { Toggle, Link, Button, Dropdown, Paper } from '../Utils/ui_package';
import withChannel from '../adk/WithChannel';
import { EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK } from '../config';
import FullTheme from './FullTheme';
import Overridings from './Overridings';
import Palette from './Palette';
const genNameList = themesAppliedList =>
themesAppliedList.map((val, ind) => val.themeName || `Theme ${ind + 1}`);
const FlexBlock = styled('div')(props => ({
minWidth: 160,
padding: 16,
display: 'flex',
flexDirection: props.direction || 'column',
justifyContent: 'space-between',
flexGrow: props.main ? 1 : 0
}));
const ModeSection = styled('div')(props => ({
display: 'flex',
flexDirection: 'column',
alignItems: props.left ? 'center' : 'stretch',
// height: 1,
flexGrow: props.left ? 0 : 1,
padding: props.left ? 2 : 0,
marginRight: props.left ? 0 : 8,
border: '1px solid rgba(0, 0, 0, 0.15)',
borderRight: props.left ? 'none' : null,
borderLeft: props.left ? null : 'none',
backgroundColor: props.left ? 'rgba(0, 0, 0, 0.04)' : 'rgba(0, 0, 0, 0.01)',
overflow: 'auto'
}));
const RadioButton = styled('button')(props => ({
minWidth: 8,
minHeight: 8,
padding: 4,
backgroundColor: props.active
? 'rgba(255, 255, 255, 0.99)'
: 'rgba(255, 255, 255, 0.9)',
border: props.active
? '1px solid rgba(0, 0, 0, 0.5)'
: '1px solid rgba(0, 0, 0, 0.2)',
borderRadius: 2,
outline: 'none',
margin: 4,
// fontFamily:
// '-apple-system, ".SFNSText-Regular", "San Francisco", Roboto, "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif', // eslint-disable-line
cursor: 'pointer',
fontSize: 9,
fontWeight: 500,
textDecoration: 'none',
color: props.active ? 'rgba(0, 0, 0, 1)' : 'rgba(0, 0, 0, 0.8)',
'&:hover': {
backgroundColor: 'white',
border: '1px solid rgba(0, 0, 0, 0.5)'
},
'&[disabled]': {
border: '1px solid rgba(0, 0, 0, 0.1)',
color: 'rgba(0, 0, 0, 0.4)',
cursor: 'default'
}
}));
const CMTButton = styled('div')`
cursor: pointer;
border: 1px solid #c5c5c5;
background-color: #f7f7f7;
border-radius: 2px;
&:hover {
background-color: rgba(0, 0, 0, 0.1)
}
`;
const MODS_LIST = [
{
title: 'Palette',
id: 'palette',
label: 'P'
},
{
title: 'Overridings',
id: 'overridings',
label: 'O'
},
{
title: 'Spacing',
id: 'spacing',
label: 'S',
disabled: true
},
{
title: 'Typography',
id: 'typography',
label: 'T',
disabled: true
},
{
title: 'Full',
id: 'full',
label: 'F'
}
];
class AddonPanel extends React.Component {
state = {
value: this.props.defautThemeInd,
isThemeEditing: false,
isThemeValid: true,
theme: this.props.themeJSON,
currentMode: MODS_LIST[0].id
};
setMode = currentMode => () => this.setState({ currentMode });
handleChange = value => {
this.setState({ value }, this.props.onThemeSelect(value));
};
handleThemeChange = ev => this.setState({ theme: ev.target.value });
onChangePalette = palette => {
const { themeInd, themes } = this.props.data;
themes[themeInd].palette = palette;
this.props.sendData({ themes });
};
render() {
const { data } = this.props;
const { currentMode } = this.state;
if (!data) return 'Waiting for theme';
const { themes } = data;
let theme;
try {
theme = themes[data.themeInd];
} catch (err) {
return 'Error...';
}
const themeStr = JSON.stringify(theme);
const styleArea = {
width: '100%',
// height: '100%',
outlineColor: this.props.isThemeInvalid ? '#cc5858' : '#26acd8',
flexGrow: 1
};
const buttonStyle = {
height: 34,
width: 34,
fontSize: 10,
fontFamily:
'-apple-system, ".SFNSText-Regular", "San Francisco", Roboto, "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif',
marginBottom: 4
};
return (
<div
style={{
width: '100%',
height: '100%',
display: 'flex',
justifyContent: 'space-between'
// flexWrap: 'wrap'
// backgroundColor: 'brown', // this.context.muiTheme.palette.canvasColor,
}}
>
<FlexBlock
style={{
minWidth: 160,
padding: 16,
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between'
}}
>
<div style={{ marginLeft: -4 }}>
<Dropdown
selected={data.themeInd}
title="Current Theme"
list={genNameList(themes)}
onSelect={themeInd => this.props.sendData({ themeInd })}
/>
</div>
<div
style={{
// width: '100%',
minHeight: 60,
display: 'flex',
justifyContent: 'space-between',
marginLeft: -4,
marginBottom: -8,
flexDirection: 'column'
}}
>
<CMTButton>
<Button
icon="library_add"
title="Clone Theme"
label="Clone Theme"
>
Clone Theme
</Button>
<Button
icon="highlight_off"
title="Clear Theme"
label="Clear Theme"
/>
<Button
icon="get_app"
title="Download Theme"
label="Download Theme"
/>
</CMTButton>
</div>
</FlexBlock>
<FlexBlock direction="row" main>
<ModeSection left>
{MODS_LIST.map(item => (
<RadioButton
key={item.id}
title={item.title}
disabled={item.disabled}
active={item.id === this.state.currentMode}
onClick={this.setMode(item.id)}
>
{item.label}
</RadioButton>
))}
</ModeSection>
<ModeSection>
{currentMode === 'palette' && (
<Palette
theme={theme}
onChangePalette={this.onChangePalette}
key={`#${data.themeInd}@${theme.themeName}`}
/>
)}
{currentMode === 'overridings' && <Overridings theme={theme} />}
{currentMode === 'full' && <FullTheme theme={theme} />}
</ModeSection>
</FlexBlock>
<div
style={{
width: 130,
padding: '16px 8px 16px 0px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between'
}}
>
<Paper
style={{
backgroundColor: 'rgba(0, 0, 0, 0.08)',
paddingTop: 16,
paddingBottom: 16
}}
>
<Link
icon="announcement"
title="Material-UI V3"
label="Material-UI V3"
href="https://app.qpointsurvey.com/s.aspx?c=F2VOSpTXOlnHHqMaZKSSV5a1ylaCDoRfhut3oNCox34~"
/>
<p
style={{
textDecoration: 'none',
margin: 'auto',
textAlign: 'center'
}}
>
<a
href="https://app.qpointsurvey.com/s.aspx?c=F2VOSpTXOlnHHqMaZKSSV5a1ylaCDoRfhut3oNCox34~"
target="_blank"
rel="noopener noreferrer"
>
{'> HERE <'}
</a>
</p>
</Paper>
<div
style={{
display: 'flex',
flexDirection: 'column',
marginBottom: -8
}}
>
<Link
icon="pageview"
title="Documentation"
label="Documentation"
href="https://github.com/sm-react/storybook-addon-material-ui"
/>
<Link
icon="help_outline"
title="ask for help"
label="Help"
href={this.props.issuesLink}
/>
</div>
</div>
</div>
);
}
}
export default withChannel({ EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK })(
AddonPanel
);
================================================
FILE: src/UI/FullTheme.js
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { cx, css } from '@emotion/core';
import styled from '@emotion/styled';
import { ObjectInspector } from 'react-inspector';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
const sortObjectKeys = (a, b) => {
if (a === 'themeName') return -2;
if (b === 'themeName') return 2;
if (a === 'palette') return -1;
if (b === 'palette') return 1;
return a.charCodeAt(0) - b.charCodeAt(0);
};
const Holder = styled('div')`
height: 1px;
flex-grow: 1;
display: flex;
flex-direction: column;
label: PaletteHolder;
padding: 8px;
`;
export default ({ theme }) => (
<Holder>
<ObjectInspector
expandLevel={1}
expandPaths="$.palette"
sortObjectKeys={sortObjectKeys}
data={createMuiTheme(theme)}
/>
</Holder>
);
================================================
FILE: src/UI/MuiDecorator.js
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import withChannel from '../adk/WithChannel';
import { EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK } from '../config';
const currentTheme = data => {
try {
const theme = data.themes[data.themeInd];
return createMuiTheme(theme);
} catch (err) {
return createMuiTheme({});
}
};
const MuiDecorator = ({ data, story }) => (
<MuiThemeProvider theme={currentTheme(data)}>
{story}
</MuiThemeProvider>
);
export default withChannel({ EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK })(
MuiDecorator
);
================================================
FILE: src/UI/Overridings.js
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { cx, css } from '@emotion/core';
import styled from '@emotion/styled';
import { ObjectInspector } from 'react-inspector';
const sortObjectKeys = (a, b) => {
if (a === 'themeName') return -2;
if (b === 'themeName') return 2;
if (a === 'palette') return -1;
if (b === 'palette') return 1;
return a.charCodeAt(0) - b.charCodeAt(0);
};
const Holder = styled('div')`
height: 1px;
flex-grow: 1;
display: flex;
flex-direction: column;
label: PaletteHolder;
padding: 8px;
`;
export default ({ theme }) => (
<Holder>
<ObjectInspector
expandLevel={1}
expandPaths="$.palette"
sortObjectKeys={sortObjectKeys}
data={theme}
/>
</Holder>
);
================================================
FILE: src/UI/Palette.js
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { cx, css } from '@emotion/core';
import styled from '@emotion/styled';
import { ObjectInspector } from 'react-inspector';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import MaterialColorPicker from '@usulpro/color-picker';
const sortObjectKeys = (a, b) => {
if (a === 'themeName') return -2;
if (b === 'themeName') return 2;
if (a === 'palette') return -1;
if (b === 'palette') return 1;
return a.charCodeAt(0) - b.charCodeAt(0);
};
const PaletteHolder = styled('div')`
height: 1px;
flex-grow: 1;
display: flex;
flex-direction: column;
background-color: ${props =>
props.dark ? 'hsl(0, 0%, 44%)' : 'hsl(0, 0%, 90%)'};
color: ${props => (props.dark ? 'hsl(0, 0%, 90%)' : 'hsl(0, 0%, 44%)')};
label: PaletteHolder;
padding: 8px;
position: relative;
`;
const PickerOverlap = styled('div')`
position: absolute;
background-color: hsl(0, 0%, 0%, 0.8);
left: 0px;
right: 0px;
top: 0px;
bottom: 0px;
display: flex;
justify-content: center;
align-items: center;
`;
const PickerHolder = styled('div')`
width: 70%;
max-width: 500px;
min-width: 250px;
background-color: hsl(0, 0%, 50%);
`;
const ColorInput = styled('div')`
margin-left: 2px;
margin-top: 8px;
color: hsl(0, 0%, 30%);
& input {
margin-right: 4px;
}
`;
export default class Palette extends React.Component {
static propTypes = {
theme: PropTypes.shape()
};
state = {
isPickerOpen: false,
editColor: '',
palette: this.props.theme.palette,
path: []
};
prevColor = '';
onChange = () => {
this.props.onChangePalette(this.state.palette);
};
setPath = (path, isPickerOpen) => () => {
const { palette } = this.state;
this.setState(
{
path,
editColor: createMuiTheme({ palette }).palette[path[0]][path[1]],
isPickerOpen
},
() => {
this.prevColor = this.state.editColor;
}
);
};
updPalette = (ev, cb) => {
const { path, palette } = this.state;
const editColor = ev.target.value || this.prevColor;
const newPalette = {
...palette,
[path[0]]: {
...palette[path[0]],
[path[1]]: editColor
}
};
this.setState({ editColor, palette: newPalette }, cb);
};
onSubmit = ev => {
this.updPalette(ev, () => {
this.onChange();
this.setState({ isPickerOpen: false });
this.prevColor = this.state.editColor;
});
};
onReset = ev => {
this.updPalette(ev, () => {
this.onChange();
this.setState({ isPickerOpen: false });
});
};
onHover = ev => {
this.updPalette(ev, () => {
this.onChange();
});
};
renderColorInput = () => (
<ColorInput>
<input
type="text"
onChange={this.updPalette}
value={this.state.editColor}
/>
<button onClick={this.onChange}>ok</button>
</ColorInput>
);
renderColorSet = (colorSet, name, isDark) => {
const { main, light, dark, contrastText } = colorSet;
const Plate = styled('div')`
display: flex;
justify-content: space-between;
height: 20px;
margin: 2px;
margin-bottom: ${props => (props.up ? '0px' : '2px')};
margin-top: ${props => (!props.up ? '0px' : '2px')};
`;
const ColorBox = styled('div')`
background-color: ${props => props.color || 'rgba(0, 0, 0, 0.1)'};
width: 1px;
flex-grow: 1;
border: 1px solid ${isDark ? 'hsl(0, 0%, 80%)' : 'hsl(0, 0%, 44%)'};
border: ${props => (props.color ? '' : 'none')};
cursor: ${props => (props.color ? 'pointer' : 'text')};
`;
const ColorName = styled('div')`
background-color: rgba(0, 0, 0, 0.1);
width: 80px;
padding-left: 4px;
`;
return (
<>
<Plate up>
<ColorName>{name}</ColorName>
<ColorBox
color={light}
onClick={this.setPath([name, 'light'], true)}
/>
<ColorBox color={main} onClick={this.setPath([name, 'main'], true)} />
<ColorBox color={dark} onClick={this.setPath([name, 'dark'], true)} />
<ColorBox
color={contrastText}
onClick={this.setPath([name, 'contrastText'], true)}
/>
</Plate>
<Plate>
<ColorName />
<ColorBox onClick={this.setPath([name, 'light'])}>
{`light: ${light}`}
</ColorBox>
<ColorBox onClick={this.setPath([name, 'main'])}>
{`main: ${main}`}
</ColorBox>
<ColorBox onClick={this.setPath([name, 'dark'])}>
{`dark: ${dark}`}
</ColorBox>
<ColorBox onClick={this.setPath([name, 'contrastText'])}>
{`contrastText: ${contrastText}`}
</ColorBox>
</Plate>
</>
);
};
render() {
const { palette } = createMuiTheme({ palette: this.state.palette });
const colorSet = name =>
this.renderColorSet(
palette[name],
name,
this.state.palette.type === 'dark'
);
return (
<PaletteHolder dark={this.state.palette.type === 'dark'}>
{colorSet('primary')}
{colorSet('secondary')}
{colorSet('error')}
{this.renderColorInput()}
{this.state.isPickerOpen && (
<PickerOverlap>
<PickerHolder>
<MaterialColorPicker
initColor={this.prevColor}
onSubmit={this.onSubmit}
onSelect={this.onHover}
onHover={this.onHover}
onReset={this.onReset}
/>
</PickerHolder>
</PickerOverlap>
)}
</PaletteHolder>
);
}
}
================================================
FILE: src/Utils/index.js
================================================
export function copyToClipboard(text) {
console.log(text);
const copyText = text;
return () => {
console.info(copyText);
const textElem = document.createElement('textarea');
document.body.appendChild(textElem);
textElem.value = text;
textElem.select();
let successful;
try {
successful = document.execCommand('copy');
} catch (err) {
console.warn('cant copy to clipboard');
}
textElem.remove();
return successful;
};
}
export function copyToClipboardThis(text) {
const textElem = document.createElement('textarea');
document.body.appendChild(textElem);
textElem.value = text;
textElem.select();
let successful;
try {
successful = document.execCommand('copy');
} catch (err) {
console.warn('cant copy to clipboard');
}
textElem.remove();
return successful;
}
================================================
FILE: src/Utils/svg_package.js
================================================
(function webpackUniversalModuleDefinition(root, factory) {
if (typeof exports === 'object' && typeof module === 'object') { module.exports = factory(); } else if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { exports.svg_package = factory(); } else { root.svg_package = factory(); }
}(this, function () {
return /** ****/ (function (modules) { // webpackBootstrap
/** ****/ // The module cache
/** ****/ const installedModules = {};
/** ****/ // The require function
/** ****/ function __webpack_require__(moduleId) {
/** ****/ // Check if module is in cache
/** ****/ if (installedModules[moduleId])
/** ****/ { return installedModules[moduleId].exports; }
/** ****/ // Create a new module (and put it into the cache)
/** ****/ const module = installedModules[moduleId] = {
/** ****/ i: moduleId,
/** ****/ l: false,
/** ****/ exports: {},
/** ****/ };
/** ****/ // Execute the module function
/** ****/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/** ****/ // Flag the module as loaded
/** ****/ module.l = true;
/** ****/ // Return the exports of the module
/** ****/ return module.exports;
/** ****/ }
/** ****/ // expose the modules object (__webpack_modules__)
/** ****/ __webpack_require__.m = modules;
/** ****/ // expose the module cache
/** ****/ __webpack_require__.c = installedModules;
/** ****/ // identity function for calling harmony imports with the correct context
/** ****/ __webpack_require__.i = function (value) { return value; };
/** ****/ // define getter function for harmony exports
/** ****/ __webpack_require__.d = function (exports, name, getter) {
/** ****/ if (!__webpack_require__.o(exports, name)) {
/** ****/ Object.defineProperty(exports, name, {
/** ****/ configurable: false,
/** ****/ enumerable: true,
/** ****/ get: getter,
/** ****/ });
/** ****/ }
/** ****/ };
/** ****/ // getDefaultExport function for compatibility with non-harmony modules
/** ****/ __webpack_require__.n = function (module) {
/** ****/ const getter = module && module.__esModule ?
/** ****/ function getDefault() { return module.default; } :
/** ****/ function getModuleExports() { return module; };
/** ****/ __webpack_require__.d(getter, 'a', getter);
/** ****/ return getter;
/** ****/ };
/** ****/ // Object.prototype.hasOwnProperty.call
/** ****/ __webpack_require__.o = function (object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/** ****/ // __webpack_public_path__
/** ****/ __webpack_require__.p = '';
/** ****/ // Load entry module and return exports
/** ****/ return __webpack_require__(__webpack_require__.s = 35);
/** ****/ }([
/* 0 */
/** */ (function (module, exports) {
module.exports = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAIAAADYYG7QAAAAB3RJTUUH4QEaBzIA+ze+OAAAAaBJREFUeJztl82RhiAMQHEbgBK+DqAT6ABLsAPsBEqwE+wkJbAHZ5yIQvwWZ9YD78SBn2eABIeUEnsTP/8tkNOFKLoQRRei6EIUXYgkVQGAEIIxRinVsopSyhgTQgCA+opFIQCY51kI8dSXbwgh5nmuaF0LAUBjSOoopUpOF0IA8HhgzgghLp1yoXNsOOfOuRjj1iHG6JzjnLc7XcYpF3LO4THW2svvAABrbbuTc64mlG2W1vqsgml3Om/cQch7v3flnJNXFADa9857j+c8JMZlWfb2NE3k0RZCTNPUKIQXZeyYGPFx3k9xnRhjo5BSCk84JPTXMQwDFr05Ix71N/Bar6tlByEp5d5e1/XO+JvdKuBFc6HP57O387NW4Ga3CnhRxljx2pdSe3bt24tMdu3zxIjzijGmLjSOY6PNOdsRpcMYUyod7TaMLB0b2SnbXjC4uD71TpJS0sU1PVQQSEqlqfhAy+L0LJexqQltPPXuwWyvq6+fsDhU3nutdWPApJRaa+89mUoOtewNvLuWvYEuRNGFKLoQRRei6EIUrxP6BcmQ7xzbjmd9AAAAAElFTkSuQmCC';
/** */ }),
/* 1 */
/** */ (function (module, exports) {
module.exports = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAACBklEQVRoQ+1X7TEEQRB9FwEhEAEyIAIyQASIABkQASJABGSACAiBCKhXtaN253pmenau72rp+XVV19Pb773+mhkmfmYTjx8OYNUKugKuQCMDnkKNBDZfdwWaKWx08K8UWAewD+AAwAaA7Uby4uuvAD4APAB4BPCp8a9RgIGfADgFwN/LOAz+CsB1CUgJAAN+MmBbSwJV2cuByAFg8O9LZD0FimpspkCkAFgz/9WlCPOdLPOwplhfTNW1CE1SiRSACwDnWp0r7e66IFNFSvKY/4eR30sAjGtwJACWqcPgj5SAqQ67XjhiKkkA+IEb5UdqzJg2bL+q9tjVHttqP52OAdz2PyoBiJHXBJmzFVOg4DxOZc4H1snvkQC8GLXNnV7BaklhYTOecFjM9JMF8K31XmlXmjkpd3E8Az+S08kDoExblexqzBeRQm9xev/JIrZqo9mVQJBQmkeqNsqLcf/VpIjGhj2cQWjOfdQyxTmyilWCIM4yA40EcpAO+j0A9SpBdujk2aiY6T/s+xxM/WWOq4P07pgr3iBhaZ22SiVNCgWb7ApSGi7WSpSAkPndsQ+a4JwgKKu0p5cCGPt/eC/Mrc+xw5ICfXsCYWGFR/2ihx3ZDo96LpSqrbUGwFg2Te85AFN6Fc5dAQVJpiaugCm9CueugIIkUxNXwJRehXNXQEGSqcnkFfgBKMNcMdUsPWUAAAAASUVORK5CYII=';
/** */ }),
/* 2 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0yMCAySDRjLTEuMSAwLTEuOTkuOS0xLjk5IDJMMiAyMmw0LTRoMTRjMS4xIDAgMi0uOSAyLTJWNGMwLTEuMS0uOS0yLTItMnptLTcgOWgtMlY1aDJ2NnptMCA0aC0ydi0yaDJ2MnoiLz4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KPC9zdmc+';
/** */ }),
/* 3 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xMiA2djNsNC00LTQtNHYzYy00LjQyIDAtOCAzLjU4LTggOCAwIDEuNTcuNDYgMy4wMyAxLjI0IDQuMjZMNi43IDE0LjhjLS40NS0uODMtLjctMS43OS0uNy0yLjggMC0zLjMxIDIuNjktNiA2LTZ6bTYuNzYgMS43NEwxNy4zIDkuMmMuNDQuODQuNyAxLjc5LjcgMi44IDAgMy4zMS0yLjY5IDYtNiA2di0zbC00IDQgNCA0di0zYzQuNDIgMCA4LTMuNTggOC04IDAtMS41Ny0uNDYtMy4wMy0xLjI0LTQuMjZ6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==';
/** */ }),
/* 4 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xNyAzSDdjLTEuMSAwLTEuOTkuOS0xLjk5IDJMNSAyMWw3LTMgNyAzVjVjMC0xLjEtLjktMi0yLTJ6bTAgMTVsLTUtMi4xOEw3IDE4VjVoMTB2MTN6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==';
/** */ }),
/* 5 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGNsaXAtcnVsZT0iZXZlbm9kZCIgZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPgogICAgPHBhdGggZD0iTTIyLjcgMTlsLTkuMS05LjFjLjktMi4zLjQtNS0xLjUtNi45LTItMi01LTIuNC03LjQtMS4zTDkgNiA2IDkgMS42IDQuN0MuNCA3LjEuOSAxMC4xIDIuOSAxMi4xYzEuOSAxLjkgNC42IDIuNCA2LjkgMS41bDkuMSA5LjFjLjQuNCAxIC40IDEuNCAwbDIuMy0yLjNjLjUtLjQuNS0xLjEuMS0xLjR6Ii8+Cjwvc3ZnPg==';
/** */ }),
/* 6 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xOSAzSDVjLTEuMTEgMC0yIC45LTIgMnYxNGMwIDEuMS44OSAyIDIgMmgxNGMxLjExIDAgMi0uOSAyLTJWNWMwLTEuMS0uODktMi0yLTJ6bS05IDE0bC01LTUgMS40MS0xLjQxTDEwIDE0LjE3bDcuNTktNy41OUwxOSA4bC05IDl6Ii8+Cjwvc3ZnPg==';
/** */ }),
/* 7 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xOSA1djE0SDVWNWgxNG0wLTJINWMtMS4xIDAtMiAuOS0yIDJ2MTRjMCAxLjEuOSAyIDIgMmgxNGMxLjEgMCAyLS45IDItMlY1YzAtMS4xLS45LTItMi0yeiIvPgogICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPgo8L3N2Zz4=';
/** */ }),
/* 8 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xOSA2LjQxTDE3LjU5IDUgMTIgMTAuNTkgNi40MSA1IDUgNi40MSAxMC41OSAxMiA1IDE3LjU5IDYuNDEgMTkgMTIgMTMuNDEgMTcuNTkgMTkgMTkgMTcuNTkgMTMuNDEgMTJ6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==';
/** */ }),
/* 9 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPgogICAgPHBhdGggZD0iTTkuNCAxNi42TDQuOCAxMmw0LjYtNC42TDggNmwtNiA2IDYgNiAxLjQtMS40em01LjIgMGw0LjYtNC42LTQuNi00LjZMMTYgNmw2IDYtNiA2LTEuNC0xLjR6Ii8+Cjwvc3ZnPg==';
/** */ }),
/* 10 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xNiAxSDRjLTEuMSAwLTIgLjktMiAydjE0aDJWM2gxMlYxem0zIDRIOGMtMS4xIDAtMiAuOS0yIDJ2MTRjMCAxLjEuOSAyIDIgMmgxMWMxLjEgMCAyLS45IDItMlY3YzAtMS4xLS45LTItMi0yem0wIDE2SDhWN2gxMXYxNHoiLz4KPC9zdmc+';
/** */ }),
/* 11 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxjaXJjbGUgY3g9IjYiIGN5PSIxOCIgZmlsbD0ibm9uZSIgcj0iMiIvPgogICAgPGNpcmNsZSBjeD0iMTIiIGN5PSIxMiIgZmlsbD0ibm9uZSIgcj0iLjUiLz4KICAgIDxjaXJjbGUgY3g9IjYiIGN5PSI2IiBmaWxsPSJub25lIiByPSIyIi8+CiAgICA8cGF0aCBkPSJNOS42NCA3LjY0Yy4yMy0uNS4zNi0xLjA1LjM2LTEuNjQgMC0yLjIxLTEuNzktNC00LTRTMiAzLjc5IDIgNnMxLjc5IDQgNCA0Yy41OSAwIDEuMTQtLjEzIDEuNjQtLjM2TDEwIDEybC0yLjM2IDIuMzZDNy4xNCAxNC4xMyA2LjU5IDE0IDYgMTRjLTIuMjEgMC00IDEuNzktNCA0czEuNzkgNCA0IDQgNC0xLjc5IDQtNGMwLS41OS0uMTMtMS4xNC0uMzYtMS42NEwxMiAxNGw3IDdoM3YtMUw5LjY0IDcuNjR6TTYgOGMtMS4xIDAtMi0uODktMi0ycy45LTIgMi0yIDIgLjg5IDIgMi0uOSAyLTIgMnptMCAxMmMtMS4xIDAtMi0uODktMi0ycy45LTIgMi0yIDIgLjg5IDIgMi0uOSAyLTIgMnptNi03LjVjLS4yOCAwLS41LS4yMi0uNS0uNXMuMjItLjUuNS0uNS41LjIyLjUuNS0uMjIuNS0uNS41ek0xOSAzbC02IDYgMiAyIDctN1YzeiIvPgo8L3N2Zz4=';
/** */ }),
/* 12 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xOSAyaC00LjE4QzE0LjQuODQgMTMuMyAwIDEyIDBjLTEuMyAwLTIuNC44NC0yLjgyIDJINWMtMS4xIDAtMiAuOS0yIDJ2MTZjMCAxLjEuOSAyIDIgMmgxNGMxLjEgMCAyLS45IDItMlY0YzAtMS4xLS45LTItMi0yem0tNyAwYy41NSAwIDEgLjQ1IDEgMXMtLjQ1IDEtMSAxLTEtLjQ1LTEtMSAuNDUtMSAxLTF6bTcgMThINVY0aDJ2M2gxMFY0aDJ2MTZ6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==';
/** */ }),
/* 13 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik02IDE5YzAgMS4xLjkgMiAyIDJoOGMxLjEgMCAyLS45IDItMlY3SDZ2MTJ6TTE5IDRoLTMuNWwtMS0xaC01bC0xIDFINXYyaDE0VjR6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==';
/** */ }),
/* 14 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMFYweiIgZmlsbD0ibm9uZSIvPgogICAgPHBhdGggZD0iTTYgMTljMCAxLjEuOSAyIDIgMmg4YzEuMSAwIDItLjkgMi0yVjdINnYxMnptMi40Ni03LjEybDEuNDEtMS40MUwxMiAxMi41OWwyLjEyLTIuMTIgMS40MSAxLjQxTDEzLjQxIDE0bDIuMTIgMi4xMi0xLjQxIDEuNDFMMTIgMTUuNDFsLTIuMTIgMi4xMi0xLjQxLTEuNDFMMTAuNTkgMTRsLTIuMTMtMi4xMnpNMTUuNSA0bC0xLTFoLTVsLTEgMUg1djJoMTRWNHoiLz4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KPC9zdmc+';
/** */ }),
/* 15 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik00IDE4bDguNS02TDQgNnYxMnptOS0xMnYxMmw4LjUtNkwxMyA2eiIvPgogICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPgo8L3N2Zz4=';
/** */ }),
/* 16 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xMSAxOFY2bC04LjUgNiA4LjUgNnptLjUtNmw4LjUgNlY2bC04LjUgNnoiLz4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KPC9zdmc+';
/** */ }),
/* 17 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xOSA5aC00VjNIOXY2SDVsNyA3IDctN3pNNSAxOHYyaDE0di0ySDV6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==';
/** */ }),
/* 18 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xMSAxOGgydi0yaC0ydjJ6bTEtMTZDNi40OCAyIDIgNi40OCAyIDEyczQuNDggMTAgMTAgMTAgMTAtNC40OCAxMC0xMFMxNy41MiAyIDEyIDJ6bTAgMThjLTQuNDEgMC04LTMuNTktOC04czMuNTktOCA4LTggOCAzLjU5IDggOC0zLjU5IDgtOCA4em0wLTE0Yy0yLjIxIDAtNCAxLjc5LTQgNGgyYzAtMS4xLjktMiAyLTJzMiAuOSAyIDJjMCAyLTMgMS43NS0zIDVoMmMwLTIuMjUgMy0yLjUgMy01IDAtMi4yMS0xLjc5LTQtNC00eiIvPgo8L3N2Zz4=';
/** */ }),
/* 19 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xNC41OSA4TDEyIDEwLjU5IDkuNDEgOCA4IDkuNDEgMTAuNTkgMTIgOCAxNC41OSA5LjQxIDE2IDEyIDEzLjQxIDE0LjU5IDE2IDE2IDE0LjU5IDEzLjQxIDEyIDE2IDkuNDEgMTQuNTkgOHpNMTIgMkM2LjQ3IDIgMiA2LjQ3IDIgMTJzNC40NyAxMCAxMCAxMCAxMC00LjQ3IDEwLTEwUzE3LjUzIDIgMTIgMnptMCAxOGMtNC40MSAwLTgtMy41OS04LThzMy41OS04IDgtOCA4IDMuNTkgOCA4LTMuNTkgOC04IDh6Ii8+Cjwvc3ZnPg==';
/** */ }),
/* 20 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xMyAzYy00Ljk3IDAtOSA0LjAzLTkgOUgxbDMuODkgMy44OS4wNy4xNEw5IDEySDZjMC0zLjg3IDMuMTMtNyA3LTdzNyAzLjEzIDcgNy0zLjEzIDctNyA3Yy0xLjkzIDAtMy42OC0uNzktNC45NC0yLjA2bC0xLjQyIDEuNDJDOC4yNyAxOS45OSAxMC41MSAyMSAxMyAyMWM0Ljk3IDAgOS00LjAzIDktOXMtNC4wMy05LTktOXptLTEgNXY1bDQuMjggMi41NC43Mi0xLjIxLTMuNS0yLjA4VjhIMTJ6Ii8+Cjwvc3ZnPg==';
/** */ }),
/* 21 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik00IDZIMnYxNGMwIDEuMS45IDIgMiAyaDE0di0ySDRWNnptMTYtNEg4Yy0xLjEgMC0yIC45LTIgMnYxMmMwIDEuMS45IDIgMiAyaDEyYzEuMSAwIDItLjkgMi0yVjRjMC0xLjEtLjktMi0yLTJ6bS0xIDloLTR2NGgtMnYtNEg5VjloNFY1aDJ2NGg0djJ6Ii8+Cjwvc3ZnPg==';
/** */ }),
/* 22 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0zIDE4aDE4di0ySDN2MnptMC01aDE4di0ySDN2MnptMC03djJoMThWNkgzeiIvPgo8L3N2Zz4=';
/** */ }),
/* 23 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQyIDAtOC0zLjU4LTgtOCAwLTEuODUuNjMtMy41NSAxLjY5LTQuOUwxNi45IDE4LjMxQzE1LjU1IDE5LjM3IDEzLjg1IDIwIDEyIDIwem02LjMxLTMuMUw3LjEgNS42OUM4LjQ1IDQuNjMgMTAuMTUgNCAxMiA0YzQuNDIgMCA4IDMuNTggOCA4IDAgMS44NS0uNjMgMy41NS0xLjY5IDQuOXoiLz4KPC9zdmc+';
/** */ }),
/* 24 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xOSAxOUg1VjVoN1YzSDVjLTEuMTEgMC0yIC45LTIgMnYxNGMwIDEuMS44OSAyIDIgMmgxNGMxLjEgMCAyLS45IDItMnYtN2gtMnY3ek0xNCAzdjJoMy41OWwtOS44MyA5LjgzIDEuNDEgMS40MUwxOSA2LjQxVjEwaDJWM2gtN3oiLz4KPC9zdmc+';
/** */ }),
/* 25 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xMS41IDlDMTAuMTIgOSA5IDEwLjEyIDkgMTEuNXMxLjEyIDIuNSAyLjUgMi41IDIuNS0xLjEyIDIuNS0yLjVTMTIuODggOSAxMS41IDl6TTIwIDRINGMtMS4xIDAtMiAuOS0yIDJ2MTJjMCAxLjEuOSAyIDIgMmgxNmMxLjEgMCAyLS45IDItMlY2YzAtMS4xLS45LTItMi0yem0tMy4yMSAxNC4yMWwtMi45MS0yLjkxYy0uNjkuNDQtMS41MS43LTIuMzkuN0M5LjAxIDE2IDcgMTMuOTkgNyAxMS41UzkuMDEgNyAxMS41IDcgMTYgOS4wMSAxNiAxMS41YzAgLjg4LS4yNiAxLjY5LS43IDIuMzlsMi45MSAyLjktMS40MiAxLjQyeiIvPgo8L3N2Zz4=';
/** */ }),
/* 26 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xNCAxMEgydjJoMTJ2LTJ6bTAtNEgydjJoMTJWNnptNCA4di00aC0ydjRoLTR2Mmg0djRoMnYtNGg0di0yaC00ek0yIDE2aDh2LTJIMnYyeiIvPgo8L3N2Zz4=';
/** */ }),
/* 27 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xMiA3Yy0yLjc2IDAtNSAyLjI0LTUgNXMyLjI0IDUgNSA1IDUtMi4yNCA1LTUtMi4yNC01LTUtNXptMC01QzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQyIDAtOC0zLjU4LTgtOHMzLjU4LTggOC04IDggMy41OCA4IDgtMy41OCA4LTggOHoiLz4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KPC9zdmc+';
/** */ }),
/* 28 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjI0IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xMiAyQzYuNDggMiAyIDYuNDggMiAxMnM0LjQ4IDEwIDEwIDEwIDEwLTQuNDggMTAtMTBTMTcuNTIgMiAxMiAyem0wIDE4Yy00LjQyIDAtOC0zLjU4LTgtOHMzLjU4LTggOC04IDggMy41OCA4IDgtMy41OCA4LTggOHoiLz4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KPC9zdmc+';
/** */ }),
/* 29 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xOC40IDEwLjZDMTYuNTUgOC45OSAxNC4xNSA4IDExLjUgOGMtNC42NSAwLTguNTggMy4wMy05Ljk2IDcuMjJMMy45IDE2YzEuMDUtMy4xOSA0LjA1LTUuNSA3LjYtNS41IDEuOTUgMCAzLjczLjcyIDUuMTIgMS44OEwxMyAxNmg5VjdsLTMuNiAzLjZ6Ii8+Cjwvc3ZnPg==';
/** */ }),
/* 30 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0xNCAySDZjLTEuMSAwLTEuOTkuOS0xLjk5IDJMNCAyMGMwIDEuMS44OSAyIDEuOTkgMkgxOGMxLjEgMCAyLS45IDItMlY4bC02LTZ6bS0yIDE2Yy0yLjA1IDAtMy44MS0xLjI0LTQuNTgtM2gxLjcxYy42My45IDEuNjggMS41IDIuODcgMS41IDEuOTMgMCAzLjUtMS41NyAzLjUtMy41UzEzLjkzIDkuNSAxMiA5LjVjLTEuMzUgMC0yLjUyLjc4LTMuMSAxLjlsMS42IDEuNmgtNFY5bDEuMyAxLjNDOC42OSA4LjkyIDEwLjIzIDggMTIgOGMyLjc2IDAgNSAyLjI0IDUgNXMtMi4yNCA1LTUgNXoiLz4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KPC9zdmc+';
/** */ }),
/* 31 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xOS40MyAxMi45OGMuMDQtLjMyLjA3LS42NC4wNy0uOThzLS4wMy0uNjYtLjA3LS45OGwyLjExLTEuNjVjLjE5LS4xNS4yNC0uNDIuMTItLjY0bC0yLTMuNDZjLS4xMi0uMjItLjM5LS4zLS42MS0uMjJsLTIuNDkgMWMtLjUyLS40LTEuMDgtLjczLTEuNjktLjk4bC0uMzgtMi42NUMxNC40NiAyLjE4IDE0LjI1IDIgMTQgMmgtNGMtLjI1IDAtLjQ2LjE4LS40OS40MmwtLjM4IDIuNjVjLS42MS4yNS0xLjE3LjU5LTEuNjkuOThsLTIuNDktMWMtLjIzLS4wOS0uNDkgMC0uNjEuMjJsLTIgMy40NmMtLjEzLjIyLS4wNy40OS4xMi42NGwyLjExIDEuNjVjLS4wNC4zMi0uMDcuNjUtLjA3Ljk4cy4wMy42Ni4wNy45OGwtMi4xMSAxLjY1Yy0uMTkuMTUtLjI0LjQyLS4xMi42NGwyIDMuNDZjLjEyLjIyLjM5LjMuNjEuMjJsMi40OS0xYy41Mi40IDEuMDguNzMgMS42OS45OGwuMzggMi42NWMuMDMuMjQuMjQuNDIuNDkuNDJoNGMuMjUgMCAuNDYtLjE4LjQ5LS40MmwuMzgtMi42NWMuNjEtLjI1IDEuMTctLjU5IDEuNjktLjk4bDIuNDkgMWMuMjMuMDkuNDkgMCAuNjEtLjIybDItMy40NmMuMTItLjIyLjA3LS40OS0uMTItLjY0bC0yLjExLTEuNjV6TTEyIDE1LjVjLTEuOTMgMC0zLjUtMS41Ny0zLjUtMy41czEuNTctMy41IDMuNS0zLjUgMy41IDEuNTcgMy41IDMuNS0xLjU3IDMuNS0zLjUgMy41eiIvPgo8L3N2Zz4=';
/** */ }),
/* 32 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik02IDE4bDguNS02TDYgNnYxMnpNMTYgNnYxMmgyVjZoLTJ6Ii8+CiAgICA8cGF0aCBkPSJNMCAwaDI0djI0SDB6IiBmaWxsPSJub25lIi8+Cjwvc3ZnPg==';
/** */ }),
/* 33 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik02IDZoMnYxMkg2em0zLjUgNmw4LjUgNlY2eiIvPgogICAgPHBhdGggZD0iTTAgMGgyNHYyNEgweiIgZmlsbD0ibm9uZSIvPgo8L3N2Zz4=';
/** */ }),
/* 34 */
/** */ (function (module, exports) {
module.exports = 'data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiBoZWlnaHQ9IjE4IiB2aWV3Qm94PSIwIDAgMjQgMjQiIHdpZHRoPSIxOCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KICAgIDxwYXRoIGQ9Ik0wIDBoMjR2MjRIMHoiIGZpbGw9Im5vbmUiLz4KICAgIDxwYXRoIGQ9Ik0xMi41IDhjLTIuNjUgMC01LjA1Ljk5LTYuOSAyLjZMMiA3djloOWwtMy42Mi0zLjYyYzEuMzktMS4xNiAzLjE2LTEuODggNS4xMi0xLjg4IDMuNTQgMCA2LjU1IDIuMzEgNy42IDUuNWwyLjM3LS43OEMyMS4wOCAxMS4wMyAxNy4xNSA4IDEyLjUgOHoiLz4KPC9zdmc+';
/** */ }),
/* 35 */
/** */ (function (module, exports, __webpack_require__) {
Object.defineProperty(exports, '__esModule', {
value: true,
});
exports.credits = undefined;
exports.checkBox = checkBox;
exports.toggle = toggle;
const _toggle_on = __webpack_require__(1);
const _toggle_on2 = _interopRequireDefault(_toggle_on);
const _toggle_off = __webpack_require__(0);
const _toggle_off2 = _interopRequireDefault(_toggle_off);
const _ic_announcement_black_18px = __webpack_require__(2);
const _ic_announcement_black_18px2 = _interopRequireDefault(_ic_announcement_black_18px);
const _ic_autorenew_black_18px = __webpack_require__(3);
const _ic_autorenew_black_18px2 = _interopRequireDefault(_ic_autorenew_black_18px);
const _ic_bookmark_border_black_18px = __webpack_require__(4);
const _ic_bookmark_border_black_18px2 = _interopRequireDefault(_ic_bookmark_border_black_18px);
const _ic_build_black_18px = __webpack_require__(5);
const _ic_build_black_18px2 = _interopRequireDefault(_ic_build_black_18px);
const _ic_check_box_black_24px = __webpack_require__(6);
const _ic_check_box_black_24px2 = _interopRequireDefault(_ic_check_box_black_24px);
const _ic_check_box_outline_blank_black_24px = __webpack_require__(7);
const _ic_check_box_outline_blank_black_24px2 = _interopRequireDefault(_ic_check_box_outline_blank_black_24px);
const _ic_clear_black_18px = __webpack_require__(8);
const _ic_clear_black_18px2 = _interopRequireDefault(_ic_clear_black_18px);
const _ic_code_black_18px = __webpack_require__(9);
const _ic_code_black_18px2 = _interopRequireDefault(_ic_code_black_18px);
const _ic_content_copy_black_18px = __webpack_require__(10);
const _ic_content_copy_black_18px2 = _interopRequireDefault(_ic_content_copy_black_18px);
const _ic_content_cut_black_18px = __webpack_require__(11);
const _ic_content_cut_black_18px2 = _interopRequireDefault(_ic_content_cut_black_18px);
const _ic_content_paste_black_18px = __webpack_require__(12);
const _ic_content_paste_black_18px2 = _interopRequireDefault(_ic_content_paste_black_18px);
const _ic_delete_black_18px = __webpack_require__(13);
const _ic_delete_black_18px2 = _interopRequireDefault(_ic_delete_black_18px);
const _ic_delete_forever_black_18px = __webpack_require__(14);
const _ic_delete_forever_black_18px2 = _interopRequireDefault(_ic_delete_forever_black_18px);
const _ic_fast_forward_black_18px = __webpack_require__(15);
const _ic_fast_forward_black_18px2 = _interopRequireDefault(_ic_fast_forward_black_18px);
const _ic_fast_rewind_black_18px = __webpack_require__(16);
const _ic_fast_rewind_black_18px2 = _interopRequireDefault(_ic_fast_rewind_black_18px);
const _ic_get_app_black_18px = __webpack_require__(17);
const _ic_get_app_black_18px2 = _interopRequireDefault(_ic_get_app_black_18px);
const _ic_help_outline_black_18px = __webpack_require__(18);
const _ic_help_outline_black_18px2 = _interopRequireDefault(_ic_help_outline_black_18px);
const _ic_highlight_off_black_18px = __webpack_require__(19);
const _ic_highlight_off_black_18px2 = _interopRequireDefault(_ic_highlight_off_black_18px);
const _ic_history_black_18px = __webpack_require__(20);
const _ic_history_black_18px2 = _interopRequireDefault(_ic_history_black_18px);
const _ic_library_add_black_18px = __webpack_require__(21);
const _ic_library_add_black_18px2 = _interopRequireDefault(_ic_library_add_black_18px);
const _ic_menu_black_18px = __webpack_require__(22);
const _ic_menu_black_18px2 = _interopRequireDefault(_ic_menu_black_18px);
const _ic_not_interested_black_18px = __webpack_require__(23);
const _ic_not_interested_black_18px2 = _interopRequireDefault(_ic_not_interested_black_18px);
const _ic_open_in_new_black_18px = __webpack_require__(24);
const _ic_open_in_new_black_18px2 = _interopRequireDefault(_ic_open_in_new_black_18px);
const _ic_playlist_add_black_18px = __webpack_require__(26);
const _ic_playlist_add_black_18px2 = _interopRequireDefault(_ic_playlist_add_black_18px);
const _ic_radio_button_checked_black_24px = __webpack_require__(27);
const _ic_radio_button_checked_black_24px2 = _interopRequireDefault(_ic_radio_button_checked_black_24px);
const _ic_radio_button_unchecked_black_24px = __webpack_require__(28);
const _ic_radio_button_unchecked_black_24px2 = _interopRequireDefault(_ic_radio_button_unchecked_black_24px);
const _ic_redo_black_18px = __webpack_require__(29);
const _ic_redo_black_18px2 = _interopRequireDefault(_ic_redo_black_18px);
const _ic_restore_page_black_18px = __webpack_require__(30);
const _ic_restore_page_black_18px2 = _interopRequireDefault(_ic_restore_page_black_18px);
const _ic_settings_black_18px = __webpack_require__(31);
const _ic_settings_black_18px2 = _interopRequireDefault(_ic_settings_black_18px);
const _ic_skip_next_black_18px = __webpack_require__(32);
const _ic_skip_next_black_18px2 = _interopRequireDefault(_ic_skip_next_black_18px);
const _ic_skip_previous_black_18px = __webpack_require__(33);
const _ic_skip_previous_black_18px2 = _interopRequireDefault(_ic_skip_previous_black_18px);
const _ic_undo_black_18px = __webpack_require__(34);
const _ic_undo_black_18px2 = _interopRequireDefault(_ic_undo_black_18px);
const _ic_pageview_black_24px = __webpack_require__(25);
const _ic_pageview_black_24px2 = _interopRequireDefault(_ic_pageview_black_24px);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const images = {
announcement: _ic_announcement_black_18px2.default,
autorenew: _ic_autorenew_black_18px2.default,
bookmark_border: _ic_bookmark_border_black_18px2.default,
build: _ic_build_black_18px2.default,
check_box: _ic_check_box_black_24px2.default,
check_box_outline_blank: _ic_check_box_outline_blank_black_24px2.default,
clear: _ic_clear_black_18px2.default,
code: _ic_code_black_18px2.default,
content_copy: _ic_content_copy_black_18px2.default,
content_cut: _ic_content_cut_black_18px2.default,
content_paste: _ic_content_paste_black_18px2.default,
delete_: _ic_delete_black_18px2.default,
delete_forever: _ic_delete_forever_black_18px2.default,
fast_forward: _ic_fast_forward_black_18px2.default,
fast_rewind: _ic_fast_rewind_black_18px2.default,
get_app: _ic_get_app_black_18px2.default,
help_outline: _ic_help_outline_black_18px2.default,
highlight_off: _ic_highlight_off_black_18px2.default,
history: _ic_history_black_18px2.default,
library_add: _ic_library_add_black_18px2.default,
menu: _ic_menu_black_18px2.default,
not_interested: _ic_not_interested_black_18px2.default,
open_in_new: _ic_open_in_new_black_18px2.default,
playlist_add: _ic_playlist_add_black_18px2.default,
radio_button_checked: _ic_radio_button_checked_black_24px2.default,
radio_button_unchecked: _ic_radio_button_unchecked_black_24px2.default,
redo: _ic_redo_black_18px2.default,
restore_page: _ic_restore_page_black_18px2.default,
settings: _ic_settings_black_18px2.default,
skip_next: _ic_skip_next_black_18px2.default,
skip_previous: _ic_skip_previous_black_18px2.default,
undo: _ic_undo_black_18px2.default,
toggle_on: _toggle_on2.default,
toggle_off: _toggle_off2.default,
pageview: _ic_pageview_black_24px2.default,
};
exports.default = images;
function checkBox(isOn) {
if (isOn) return checked_box;
return unchecked_box;
}
function toggle(isOn) {
if (isOn) return _toggle_on2.default;
return _toggle_off2.default;
}
const credits = exports.credits = '\nthis package uses:\n- Google Material Design svg icons (https://material.io/icons/)\n- Icons8 free png icon (https://icons8.com/)\n';
/** */ }),
/** ****/ ]));
}));
================================================
FILE: src/Utils/uiTheme.js
================================================
const uiThemeLight = {
palette: {
borderColor: '#e0e0e0',
textColor: 'rgba(0, 0, 0, 0.87)',
secondaryTextColor: 'rgba(0, 0, 0, 0.54)',
inputTextColor: 'rgb(46, 84, 128)',
canvas: '#ffffff',
},
};
const currentTheme = {
theme: uiThemeLight,
};
export default function getCurrentTheme() {
return currentTheme.theme;
}
================================================
FILE: src/Utils/ui_package.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
// import images from './svg_package';
const images = {};
const iconStyle = {
width: 18,
opacity: 0.6,
marginRight: 8
};
const buttonStyle = {
backgroundColor: 'rgba(0, 0, 0, 0)',
border: 'none',
outline: 'none',
padding: 0,
margin: 4,
display: 'flex',
alignItems: 'center',
fontFamily:
'-apple-system, ".SFNSText-Regular", "San Francisco", Roboto, "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif', // eslint-disable-line
cursor: 'pointer',
fontSize: 12,
textDecoration: 'none',
color: 'black'
};
const selectStyle = {
...buttonStyle,
border: '#d9d9d9 1px solid',
borderRadius: 2,
backgroundColor: '#e8e8e8',
padding: 2,
boxShadow: '0px 0px 2px 0px rgba(0, 0, 0, 0.5)',
fontSize: 14,
width: '100%'
};
const optionsStyle = {
backgroundColor: '#fcfcfc',
height: 50
// border: '#2e63ac 4px solid',
};
export function Button({ icon, label, title, onClick, compact, disabled }) {
// const iconStyleAply = iconStyle;
const iconOverride = !label || compact ? { margin: 0 } : {};
// if (!label || compact) iconStyleAply.margin = 0;
return (
<button
style={{ ...buttonStyle, ...(disabled && { opacity: 0.5 }) }}
title={title}
onClick={onClick}
>
<img
src={images[icon]}
alt={images[icon]}
style={{ ...iconStyle, ...iconOverride }}
/>
{(!compact && label) || ''}
</button>
);
}
Button.propTypes = {
icon: PropTypes.string,
label: PropTypes.string,
title: PropTypes.string,
onClick: PropTypes.func
};
export function Link({ icon, label, title, href }) {
return (
<a
href={href}
style={buttonStyle}
title={title}
target="_blank"
rel="noopener noreferrer"
>
<img src={images[icon]} alt={images[icon]} style={iconStyle} />
{label}
</a>
);
}
Link.propTypes = {
icon: PropTypes.string,
label: PropTypes.string,
title: PropTypes.string,
href: PropTypes.string
};
Button.propTypes = {
icon: PropTypes.string,
label: PropTypes.string,
title: PropTypes.string
};
export function CheckBox({ checked, label, title, onToggle }) {
const toggle = () => onToggle(!checked);
const selectTitle = is => (is ? title[1] : title[0]);
const titleString = typeof title === 'string' ? title : selectTitle(checked);
return (
<button style={buttonStyle} title={titleString} onClick={toggle}>
<img
src={checked ? images.check_box : images.check_box_outline_blank}
alt="check"
style={iconStyle}
/>
{label}
</button>
);
}
CheckBox.propTypes = {
checked: PropTypes.bool,
label: PropTypes.string,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
onToggle: PropTypes.func
};
export function Toggle({ checked, label, title, onToggle }) {
const toggle = () => onToggle(!checked);
const selectTitle = is => (is ? title[1] : title[0]);
const titleString = typeof title === 'string' ? title : selectTitle(checked);
return (
<button
style={{ ...buttonStyle, margin: 0 }}
title={titleString}
onClick={toggle}
>
<img
src={checked ? images.toggle_on : images.toggle_off}
alt="check"
style={{
...iconStyle,
width: 26,
marginRight: 4,
opacity: checked ? 0.7 : 0.6
}}
/>
<span style={{ height: 18 }}>{label}</span>
</button>
);
}
Toggle.propTypes = {
checked: PropTypes.bool,
label: PropTypes.string,
title: PropTypes.oneOfType([PropTypes.string, PropTypes.array]),
onToggle: PropTypes.func
};
export function Dropdown({ selected, list, title, onSelect }) {
const options = list.map((val, ind) => (
<option value={ind} key={`${ind}@${list[ind]}`} style={optionsStyle}>
{val}
</option>
));
const select = event => onSelect(parseInt(event.target.value, 10));
return (
<select
value={selected}
onChange={select}
style={selectStyle}
title={title}
>
{options}
</select>
);
}
Dropdown.propTypes = {
selected: PropTypes.number,
title: PropTypes.string,
list: PropTypes.arrayOf(PropTypes.string),
onSelect: PropTypes.func
};
const paperStyle = {
boxShadow: 'rgba(0, 0, 0, 0.2) 0px 1px 6px',
// padding: '8px 8px 8px 16px',
borderRadius: 2,
boxSizing: 'border-box',
fontFamily:
'-apple-system, ".SFNSText-Regular", "San Francisco", Roboto, "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif', // eslint-disable-line
fontSize: 12,
marginBottom: 10
};
export function Paper({ children, style }) {
return <div style={{ ...paperStyle, ...style }}>{children}</div>;
}
Paper.propTypes = {
children: PropTypes.node,
style: PropTypes.shape()
};
const tagStyle = {
backgroundColor: 'rgb(224, 224, 224)',
border: 'black',
borderRadius: 11,
display: 'flex',
alignItems: 'center',
fontSize: 11,
cursor: 'pointer'
};
const avaStyle = {
width: 22,
height: 22,
borderRadius: 11,
backgroundColor: 'rgb(188, 188, 188)',
color: '#efefef',
fontSize: 14,
fontWeight: 600,
textTransform: 'uppercase',
display: 'inline-flex',
alignItems: 'center',
justifyContent: 'center'
};
export function Tag({ label, onClick }) {
return (
<div style={tagStyle} onClick={onClick}>
<div style={avaStyle}>
<span>{label[0] || '!'}</span>
</div>
<span style={{ margin: '0px 12px 0px 6px', height: 17 }}>{label}</span>
</div>
);
}
Paper.propTypes = {
label: PropTypes.string,
onClick: PropTypes.func
};
================================================
FILE: src/adk/ChannelHOC.js
================================================
import React from 'react';
import PropTypes from 'prop-types';
// class WithChannel extends React.Component {
// state = {
// data: { lala: 123 }
// };
// render() {
// const { component: Component, extProps } = this.props;
// const { data } = this.state;
// const dname = Component.displayName;
// console.log('TCL: WithChannel -> render -> dname', dname);
// return <Component {...extProps} />;
// }
// }
function getDisplayName(WrappedComponent) {
return WrappedComponent.displayName || WrappedComponent.name || 'Component';
}
function withChannel(WrappedComponent) {
class WithChannel extends React.Component {
state = {
data: 123
};
render() {
return <WrappedComponent />;
}
}
WithChannel.displayName = `WithSubscription(${getDisplayName(
WrappedComponent
)})`;
return WithChannel;
}
// const withChannel = params => Component => props => (
// <WithChannel extProps={props} component={Component} />
// );
export default withChannel;
================================================
FILE: src/adk/ChannelStore.js
================================================
import addons from '@storybook/addons';
export default class ChannelStore {
constructor({
EVENT_ID_INIT,
EVENT_ID_DATA,
EVENT_ID_BACK,
name = 'store',
initData = {},
isPanel = false,
}) {
this.store = initData;
this.name = name;
this.subscriber = () => {};
this.onConnectedFn = () => {};
this.channel = addons.getChannel();
this.connect = () => {
this.channel.on(EVENT_ID_INIT, this.onInitChannel);
this.channel.on(isPanel ? EVENT_ID_DATA : EVENT_ID_BACK, this.onDataChannel);
this.onConnectedFn();
};
this.emit = data => this.channel.emit(isPanel ? EVENT_ID_BACK : EVENT_ID_DATA, data);
this.init = data => this.channel.emit(EVENT_ID_INIT, data);
this.removeInit = () =>
this.channel.removeListener(EVENT_ID_INIT, this.onInitChannel);
this.removeData = () =>
this.channel.removeListener(EVENT_ID_DATA, this.onDataChannel);
}
onInitChannel = initData => {
this.store = initData;
this.subscriber(this.store);
};
onDataChannel = updData => {
this.store = {
...this.store,
...updData
};
this.subscriber(this.store);
};
onData = subscriberFn => {
this.subscriber = subscriberFn;
};
onConnected = onConnectedFn => {
this.onConnectedFn = onConnectedFn;
};
send = data => {
this.store = {
...this.store,
...data
};
this.emit(this.store);
this.subscriber(this.store);
};
sendInit = data => {
this.init(data);
};
disconnect = () => {
this.removeInit();
this.removeData();
};
}
================================================
FILE: src/adk/WithChannel.js
================================================
import React from 'react';
import ChannelStore from './ChannelStore';
const getDisplayName = WrappedComponent =>
WrappedComponent.displayName || WrappedComponent.name || 'Component';
const withChannel = ({
EVENT_ID_INIT,
EVENT_ID_DATA,
EVENT_ID_BACK,
initData,
panel
}) => WrappedComponent =>
class extends React.Component {
static displayName = `WithChannel(${getDisplayName(WrappedComponent)})`;
state = {
data: initData || this.props.initData
};
store = new ChannelStore({
EVENT_ID_INIT,
EVENT_ID_DATA,
EVENT_ID_BACK,
name: this.props.pointName,
initData: initData || this.props.initData,
isPanel: panel || this.props.panel
});
componentDidMount() {
this.store.onData(this.onData);
if (this.state.data) {
this.store.onConnected(() => this.store.send(this.state.data));
}
this.store.connect();
}
componentWillUnmount() {
this.store.disconnect();
}
onData = data => this.setState({ data });
render() {
const { pointName, initData, active, ...props } = this.props;
if (active === false) return null;
return (
<WrappedComponent
data={this.state.data}
sendData={this.store.send}
store={this.store}
{...props}
/>
);
}
};
export default withChannel;
================================================
FILE: src/adk/decorator.js
================================================
import ChannelStore from './ChannelStore';
let decoratorStore;
export const createStore = (...args) => {
decoratorStore = new ChannelStore(...args);
return decoratorStore;
};
export const getStore = () => decoratorStore;
================================================
FILE: src/adk/panel.js
================================================
import ChannelStore from './ChannelStore';
let panelStore;
export const createStore = (EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK) => {
panelStore = new ChannelStore(EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK);
return panelStore;
};
export const getStore = () => panelStore;
================================================
FILE: src/components/AddonPanel.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { Toggle, Link, Button, Dropdown, Paper } from '../Utils/ui_package';
const propTypes = {
themesNameList: PropTypes.arrayOf(PropTypes.string).isRequired,
defautThemeInd: PropTypes.number.isRequired,
onThemeSelect: PropTypes.func.isRequired,
onToggleSideBar: PropTypes.func.isRequired,
isSideBarOpen: PropTypes.bool.isRequired,
isThemeInvalid: PropTypes.bool.isRequired,
themeJSON: PropTypes.string.isRequired,
onChangeTheme: PropTypes.func.isRequired,
onThemeEditing: PropTypes.func.isRequired,
onCloneTheme: PropTypes.func.isRequired,
onDnLoadTheme: PropTypes.func.isRequired,
onCleanTheme: PropTypes.func.isRequired,
issuesLink: PropTypes.string,
};
const defaultProps = {
themesNameList: ['BaseLight', 'BaseDark'],
defautThemeInd: 0,
onThemeSelect: () => {},
onToggleSideBar: () => {},
isSideBarOpen: false,
onCloneTheme: () => {},
onDnLoadTheme: () => {},
onCleanTheme: () => {},
issuesLink: 'https://github.com/sm-react/storybook-addon-material-ui/issues/new',
};
const contextTypes = {
muiTheme: PropTypes.object,
};
export default class AddonPanel extends React.Component {
constructor(props) {
super(props);
this.state = {
value: props.defautThemeInd,
isThemeEditing: false,
isThemeValid: true,
theme: props.themeJSON,
};
this.handleChange = this.handleChange.bind(this);
}
handleChange(value) {
this.setState({ value }, this.props.onThemeSelect(value));
}
handleThemeChange = ev => this.setState({ theme: ev.target.value });
render() {
const styleArea = {
width: '100%',
// height: '100%',
outlineColor: this.props.isThemeInvalid ? '#cc5858' : '#26acd8',
flexGrow: 1,
};
const buttonStyle = {
height: 34,
width: 34,
fontSize: 10,
fontFamily:
'-apple-system, ".SFNSText-Regular", "San Francisco", Roboto, "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif',
marginBottom: 4,
};
return (
<div
style={{
width: '100%',
display: 'flex',
justifyContent: 'space-between',
flexWrap: 'wrap',
// backgroundColor: 'brown', // this.context.muiTheme.palette.canvasColor,
}}
>
<div
style={{
minWidth: 160,
padding: 16,
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
}}
>
<div style={{ marginLeft: -4 }}>
<Dropdown
selected={this.state.value}
title="Current Theme"
list={this.props.themesNameList}
onSelect={this.handleChange}
/>
</div>
<div
style={{
// width: '100%',
minHeight: 60,
display: 'flex',
justifyContent: 'space-between',
marginLeft: -4,
marginBottom: -8,
flexDirection: 'column',
}}
>
<Button
icon="library_add"
title="Clone Theme"
label="Clone Theme"
onClick={this.props.onCloneTheme}
/>
<Button
icon="highlight_off"
title="Clear Theme"
label="Clear Theme"
onClick={this.props.onCleanTheme}
/>
<Button
icon="get_app"
title="Download Theme"
label="Download Theme"
onClick={this.props.onDnLoadTheme}
/>
</div>
</div>
<div
style={{
width: 200,
minWidth: 150,
flexGrow: 1,
paddingLeft: 16,
display: 'flex',
flexDirection: 'row',
}}
>
<div
style={{
paddingTop: 16,
display: 'flex',
flexDirection: 'column',
}}
>
<Button icon="bookmark_border" title="Palette" label="Pal" compact disabled />
<Button icon="bookmark_border" title="Typography" label="Typ" compact disabled />
<Button icon="bookmark_border" title="Spacing" label="Spc" compact disabled />
<Button icon="bookmark_border" title="Theme overrides" label="Ove" compact disabled />
<Button icon="bookmark_border" title="Full Theme" label="Thm" compact />
</div>
<div
style={{
width: '100%',
// flexGrow: 1,
padding: 16,
paddingLeft: 4,
display: 'flex',
flexDirection: 'column',
}}
>
<textarea
style={styleArea}
value={this.state.theme}
onChange={this.handleThemeChange}
onFocus={this.props.onThemeEditing(true)}
onBlur={this.props.onThemeEditing(false)}
/>
<button onClick={() => this.props.onChangeTheme(this.state.theme)}>Apply</button>
</div>
</div>
<div
style={{
width: 130,
padding: '16px 8px 16px 0px',
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
}}
>
<Paper
style={{
backgroundColor: 'lightgoldenrodyellow',
paddingTop: 16,
paddingBottom: 16,
}}
>
<Link
icon="announcement"
title="Material-UI V1 support announcement"
label="Material-UI V1 support announcement"
href="https://app.qpointsurvey.com/s.aspx?c=F2VOSpTXOlnHHqMaZKSSV5a1ylaCDoRfhut3oNCox34~"
/>
<p
style={{
margin: 4,
textAlign: 'center',
fontStyle: 'italic',
fontSize: 11,
}}
>
Vote for the most useful features
</p>
<p style={{ textDecoration: 'none', margin: 'auto', textAlign: 'center' }}>
<a
href="https://app.qpointsurvey.com/s.aspx?c=F2VOSpTXOlnHHqMaZKSSV5a1ylaCDoRfhut3oNCox34~"
target="_blank"
rel="noopener noreferrer"
>
{'> HERE <'}
</a>
</p>
</Paper>
<div style={{ display: 'flex', flexDirection: 'column', marginBottom: -8 }}>
<Link
icon="pageview"
title="Documentation"
label="Documentation"
href="https://github.com/sm-react/storybook-addon-material-ui"
/>
<Link
icon="help_outline"
title="ask for help"
label="Help"
href={this.props.issuesLink}
/>
</div>
</div>
</div>
);
}
}
AddonPanel.propTypes = propTypes;
AddonPanel.defaultProps = defaultProps;
AddonPanel.contextTypes = contextTypes;
================================================
FILE: src/components/ThemePropBlock.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import Paper from '@material-ui/core/Paper';
import SclToggle from '../material-desktop/SclToggle';
import SclAvatar from '../material-desktop/SclAvatar';
import { CSS_CLASS } from '../';
import ThemePropItem from './ThemePropItem';
const propTypes = {
settingsObj: PropTypes.object.isRequired,
settingsName: PropTypes.string.isRequired,
open: PropTypes.func.isRequired,
onThemeTableOverride: PropTypes.func.isRequired,
onSelect: PropTypes.func.isRequired,
};
const contextTypes = {
muiTheme: PropTypes.object.isRequired,
};
export default class ThemePropBlock extends React.Component {
constructor(props, ...args) {
super(props, ...args);
this.state = {
toolCollapsedList: {},
};
this.needComponentUpdate = false;
this.valueHandler = this.valueHandler.bind(this);
this.onToolCollapse = this.onToolCollapse.bind(this);
this.onSelect = this.onSelect.bind(this);
this.renderProp = this.renderProp.bind(this);
this.renderColl = this.renderColl.bind(this);
}
shouldComponentUpdate() {
const f = this.needComponentUpdate;
this.needComponentUpdate = false;
return f;
}
onToolCollapse(val) {
return (isCol) => {
const { toolCollapsedList } = this.state;
toolCollapsedList[val] = isCol;
this.needComponentUpdate = true;
this.setState({ toolCollapsedList });
};
}
onSelect(sel) {
const select = {
selectedTable: this.props.settingsName,
selectedProp: '',
selectedVal: '',
};
const fullSelect = Object.assign(select, sel);
this.props.onSelect(fullSelect);
}
valueHandler(propName) {
return (event) => {
this.needComponentUpdate = true;
this.props.onThemeTableOverride(propName, event.target.value);
};
}
renderProp(val, ind, isOpen, isHeader) {
return (
<div key={`${val}${ind}`}>
{isOpen ? <ThemePropItem
val={val}
ind={ind}
settingsObj={this.props.settingsObj}
valueHandler={this.valueHandler}
isCollapsed={this.state.toolCollapsedList[val]}
onCollapsed={this.onToolCollapse(val)}
isOpen={isOpen || false}
isHeader={isHeader || false}
onSelect={this.onSelect}
/> : null}
</div>
);
}
renderColl() {
const settingsObj = this.props.settingsObj;
const keyList = Object.keys(settingsObj);
const rowList = keyList.map((val, ind) => (this.renderProp(val, ind, this.props.open())));
return (
<div>
{this.renderProp(`${this.props.settingsName}-header`, 0, this.props.open(), true)}
{rowList}
</div>);
}
render() {
const { settingsName, open } = this.props;
const onSelect = this.onSelect;
const openThis = (f) => {
if (typeof (f) === 'undefined') return open();
this.needComponentUpdate = true;
open(f);
return null;
};
return (
<Paper
style={{
paddingLeft: 16,
paddingRight: 4,
paddingTop: 8,
paddingBottom: 8,
marginTop: 8,
}}
>
<BlockHeader {...{ settingsName, openThis, onSelect }} />
<div style={{ /* height: 16*/}} />
{this.renderColl()}
</Paper>
);
}
}
ThemePropBlock.propTypes = propTypes;
ThemePropBlock.contextTypes = contextTypes;
function BlockHeader(props, context) {
const toggleHeadStyle = {
color: context.muiTheme.palette.primary1Color,
fontSize: context.muiTheme.flatButton.fontSize,
};
const toggleOpen = () => {
props.openThis(!props.openThis());
};
return (
<div
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
}}
>
<SclAvatar
onClick={props.onSelect}
text={props.settingsName}
/>
{/* <Chip onTouchTap={copyToClipboard(props.settingsName)} >
<Avatar size={18}>{props.settingsName[0]}</Avatar>
{props.settingsName}
</Chip>*/}
<div>
<SclToggle
label=""
// labelPosition="right"
labelStyle={toggleHeadStyle}
toggled={props.openThis() || false}
onToggle={toggleOpen}
/>
</div>
</div>
);
}
BlockHeader.contextTypes = contextTypes;
BlockHeader.propTypes = {
openThis: PropTypes.func.isRequired,
onSelect: PropTypes.func.isRequired,
settingsName: PropTypes.string.isRequired,
};
================================================
FILE: src/components/ThemePropItem.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import Tab from '@material-ui/core/Tab';
import Tabs from '@material-ui/core/Tabs';
import Slider from '@material-ui/core/Slide';
import MaterialColorPicker from '@usulpro/color-picker';
import { CSS_CLASS } from '../';
const propTypes = {
val: PropTypes.string.isRequired,
ind: PropTypes.number.isRequired,
settingsObj: PropTypes.object.isRequired,
valueHandler: PropTypes.func.isRequired,
isCollapsed: PropTypes.bool.isRequired,
onCollapsed: PropTypes.func.isRequired,
onSelect: PropTypes.func.isRequired,
isOpen: PropTypes.bool.isRequired,
isHeader: PropTypes.bool.isRequired,
};
const defaultProps = {
val: 'val',
ind: 7,
settingsObj: {},
valueHandler: () => {},
isCollapsed: true,
isOpen: true,
isHeader: true,
};
const contextTypes = {
muiTheme: PropTypes.object.isRequired,
};
export default class ThemePropItem extends React.Component {
constructor(props, ...args) {
super(props, ...args);
this.onToolTogle = this.onToolTogle.bind(this);
this.renderProp = this.renderProp.bind(this);
}
shouldComponentUpdate(nextProps) {
return true;
// future: shouldComponentUpdate
// const val = this.props.val;
// const shouldCollapsed = (nextProps.isCollapsed !== this.props.isCollapsed);
// const shouldOpen = (nextProps.isOpen !== this.props.isOpen);
// const shouldsettingsObj = (nextProps.settingsObj[val] !== this.props.settingsObj[val]);
// const shouldUpdate = (shouldCollapsed || shouldOpen || shouldsettingsObj);
// if (shouldUpdate) {
// console.log(
// `shouldUpdate: ${val} ${shouldCollapsed} ${shouldOpen} ${shouldsettingsObj}`
// );
// }
// return shouldUpdate;
}
onToolTogle() {
this.props.onCollapsed(!this.props.isCollapsed);
}
renderProp(isNotHeader) {
const { palette } = this.context.muiTheme;
const { ind, val, valueHandler, isCollapsed, isOpen, onSelect } = this.props;
const settingsObj = this.props.settingsObj || { isNotHeader };
const onToolTogle = this.onToolTogle;
const styleHR = { borderBottom: `solid ${palette.borderColor} 1px` };
return (
<div>
<PropItem
{...{
ind, val, settingsObj, valueHandler, isNotHeader, onToolTogle, isOpen, onSelect,
}}
/>
<PropToolPicker
{...{ isCollapsed, onToolTogle }}
settingsObj={isNotHeader ? settingsObj[val] : ''}
valueHandler={valueHandler(val)}
/>
<div style={{ height: isOpen ? 1 : 0, overflow: 'hidden' }}>
<div style={styleHR} />
</div>
</div>
);
}
render() {
return (
<div>
{this.renderProp(!this.props.isHeader)}
</div>
);
}
}
ThemePropItem.propTypes = propTypes;
ThemePropItem.defaultProps = defaultProps;
ThemePropItem.contextTypes = contextTypes;
function PropItem(props, context) {
const { palette } = context.muiTheme;
const { settingsObj, val, ind, valueHandler, /* isOpen,*/ isNotHeader } = props;
const color = typeof (settingsObj[val]) === 'string' ? settingsObj[val] : '';
const onSelect = () => {
const select = {
selectedProp: val,
selectedVal: `'${settingsObj[val]}'`,
};
props.onSelect(select);
};
return (
<div
className={`${CSS_CLASS}-prop-item`}
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'baseline',
flexWrap: 'wrap',
paddingRight: 4,
paddingTop: isNotHeader ? 4 : 16,
fontSize: 12,
// height: isOpen ? 24 : 0,
transition: 'all 100ms ease 0ms',
overflow: 'hidden',
color: isNotHeader ? '' : palette.secondaryTextColor,
}}
onClick={onSelect}
>
<PropHeader
{...{ val, ind, isNotHeader }}
/>
<div
className={`${CSS_CLASS}-prop-value`}
style={{
width: 'auto',
flexShrink: 1,
flexGrow: 1,
display: 'flex',
justifyContent: 'space-between',
}}
>
<PropInput
valueHandler={valueHandler(val) || null}
settingsObj={settingsObj[val] || ''}
isNotHeader={isNotHeader}
/>
<PropTool
color={color}
onTool={props.onToolTogle}
isNotHeader={isNotHeader}
/>
</div>
</div>
);
}
PropItem.propTypes = {
settingsObj: PropTypes.shape().isRequired,
val: PropTypes.string.isRequired,
ind: PropTypes.number.isRequired,
onToolTogle: PropTypes.func.isRequired,
onSelect: PropTypes.func.isRequired,
valueHandler: PropTypes.func.isRequired,
// isOpen: PropTypes.bool.isRequired,
isNotHeader: PropTypes.bool.isRequired,
};
PropItem.contextTypes = contextTypes;
function PropHeader(props, context) {
const { ind, val, isNotHeader } = props;
return (
<div
className={`${CSS_CLASS}-prop-header`}
title={val}
style={{
display: 'flex',
justifyContent: 'flex-start',
overflowX: 'hidden',
flexShrink: 2,
flexGrow: 10,
width: 90,
}}
>
<div style={{ color: context.muiTheme.palette.secondaryTextColor }} >
{isNotHeader ? ind + 1 : '#'}
</div>
<div
style={{
marginLeft: 16,
marginRight: 16,
minWidth: 100,
textAlign: 'left',
overflowX: 'hidden',
}}
>
<div>{isNotHeader ? val : 'Prop Name'}</div>
</div>
</div>
);
}
PropHeader.propTypes = {
val: PropTypes.string.isRequired,
ind: PropTypes.number.isRequired,
isNotHeader: PropTypes.bool.isRequired,
};
PropHeader.contextTypes = contextTypes;
function PropInput(props, context) {
const { palette } = context.muiTheme;
const { valueHandler, settingsObj, isNotHeader } = props;
const isInt = (settingsObj === parseInt(settingsObj, 10));
const strStyle = {
width: isInt ? 40 : 'auto',
textAlign: isInt ? 'right' : 'left',
};
return (isNotHeader ?
<input
type="text"
onChange={valueHandler}
value={settingsObj}
title={settingsObj}
style={{
border: 'none',
fontStyle: 'italic',
padding: 2,
backgroundColor: palette.canvasColor,
color: palette.primary2Color,
...strStyle,
}}
/> :
<div
style={{
border: 'none',
minWidth: 162,
padding: 2,
...strStyle,
}}
>
Prop Value
</div>
);
}
PropInput.propTypes = {
settingsObj: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]).isRequired,
valueHandler: PropTypes.func.isRequired,
isNotHeader: PropTypes.bool.isRequired,
};
PropInput.contextTypes = contextTypes;
function PropTool(props, context) {
const { palette } = context.muiTheme;
const { isNotHeader } = props;
const blockStyle = {
width: 16,
height: 16,
marginLeft: 4,
border: `solid 1px ${palette.borderColor}`,
backgroundColor: isNotHeader ? props.color : 'rgba(0, 0, 0, 0)',
cursor: isNotHeader ? 'pointer' : '',
};
const toolProps = {
style: blockStyle,
title: isNotHeader ? props.color : 'view',
onClick: isNotHeader ? props.onTool : null,
};
return <div {...toolProps} />;
}
PropTool.propTypes = {
isNotHeader: PropTypes.bool.isRequired,
color: PropTypes.string.isRequired,
onTool: PropTypes.func.isRequired,
};
PropTool.contextTypes = contextTypes;
function PropToolPicker(props, context) {
const { settingsObj, valueHandler, onToolTogle } = props;
const initColor = `${settingsObj}`;
const style = {
height: props.isCollapsed ? 0 : 200,
transition: 'height 300ms ease 0ms',
overflow: 'hidden',
};
const onSubmit = (event) => {
valueHandler(event);
onToolTogle();
};
// fixme: check onReset
return (
<div {...{ style }}>
<div style={{ border: 'solid 1px grey' }}>
<MaterialColorPicker
initColor={initColor}
onSubmit={onSubmit}
onSelect={valueHandler}
onHover={valueHandler}
onReset={onSubmit}
/>
</div>
</div>
);
}
PropToolPicker.propTypes = {
settingsObj: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]).isRequired,
isCollapsed: PropTypes.bool.isRequired,
valueHandler: PropTypes.func.isRequired,
onToolTogle: PropTypes.func.isRequired,
};
PropToolPicker.contextTypes = contextTypes;
// future: we will use when all components be ready
function PropToolPickerFull(props, context) {
const { settingsObj, valueHandler, onToolTogle } = props;
const initColor = `${settingsObj}`;
const style = {
height: props.isCollapsed ? 0 : 200,
transition: 'height 300ms ease 0ms',
overflow: 'hidden',
};
const tabStyle = { height: 16, marginTop: -12, fontSize: 12 };
const onSubmit = (event) => {
valueHandler(event);
onToolTogle();
};
return (
<div {...{ style }}>
<Tabs
tabItemContainerStyle={{ height: 24 }}
>
<Tab
label="Color"
style={tabStyle}
>
<div style={{ border: 'solid 1px grey' }}>
<MaterialColorPicker
initColor={initColor}
onSubmit={onSubmit}
onSelect={valueHandler}
onReset={onSubmit}
/>
</div>
</Tab>
<Tab label="Number" style={tabStyle} >
<div>
<h2>Tab Two</h2>
<p>
This is another example tab.
</p>
{/* <Slider name="slider0" defaultValue={0.5} />*/}
</div>
</Tab>
<Tab
label="String"
data-route="/home"
onActive={null}
style={tabStyle}
>
<div>
<h2>Tab Three</h2>
<p>
This is a third example tab.
</p>
</div>
</Tab>
<Tab label="Palette" style={tabStyle} >
<div>
<h2>Tab Two</h2>
<p>
This is another example tab.
</p>
<Slider name="slider0" defaultValue={0.5} />
</div>
</Tab>
<Tab label="Icon" style={tabStyle} >
<div>
<h2>Tab Two</h2>
<p>
This is another example tab.
</p>
<Slider name="slider0" defaultValue={0.5} />
</div>
</Tab>
</Tabs>
</div>
);
}
PropToolPickerFull.propTypes = {
settingsObj: PropTypes.shape().isRequired,
isCollapsed: PropTypes.bool.isRequired,
valueHandler: PropTypes.func.isRequired,
onToolTogle: PropTypes.func.isRequired,
};
PropToolPickerFull.contextTypes = contextTypes;
================================================
FILE: src/components/ThemeSideBar.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import Paper from '@material-ui/core/Paper';
import IconCopy from '@material-ui/icons/ContentCopy';
import IconSwch from '@material-ui/icons/SwitchCamera';
import SclToggle from '../material-desktop/SclToggle';
import SvgButton from '../material-desktop/SvgButton';
import { CSS_CLASS } from '../';
import ThemePropBlock from './ThemePropBlock';
import { copyToClipboardThis } from '../Utils';
const BAR_WIDTH = 400;
const propTypes = {
open: PropTypes.bool.isRequired,
themeName: PropTypes.string.isRequired,
theme: PropTypes.object.isRequired,
muiTheme: PropTypes.object.isRequired,
fullTheme: PropTypes.func.isRequired,
shouldComponentUpdate: PropTypes.bool.isRequired,
shouldShowData: PropTypes.bool.isRequired,
};
export default class ThemeSideBar extends React.Component {
constructor(props) {
super(props);
this.state = {
selectedTable: '',
selectedProp: '',
selectedVal: '',
isSelectedStyleObj: true,
};
this.clipString = this.clipString.bind(this);
this.onSelect = this.onSelect.bind(this);
this.onSwitchStyleObj = this.onSwitchStyleObj.bind(this);
this.onCopy = this.onCopy.bind(this);
}
shouldComponentUpdate(nextProps, nextState) {
// fixme shouldComponentUpdate - remove
return nextProps.shouldComponentUpdate;
}
onSelect(sel) {
this.setState(sel);
}
onSwitchStyleObj() {
const isObj = this.state.isSelectedStyleObj;
this.setState({ isSelectedStyleObj: !isObj });
}
onCopy() {
const text = this.clipString();
copyToClipboardThis(text);
}
clipString() {
const table = this.state.selectedTable;
const prop = this.state.selectedProp;
const val = this.state.selectedVal;
const isObj = this.state.isSelectedStyleObj;
const strTbl = table;
const strVal = isObj ? `${prop}: ${val},` : `${table}.${prop} = ${val};`;
return prop ? strVal : strTbl;
}
renderContent() {
const { palette } = this.context.muiTheme;
const styleHR = { borderBottom: `solid ${palette.borderColor} 1px` };
const blockStyle = {
width: 21,
height: 21,
marginLeft: 4,
border: `solid 1px ${palette.borderColor}`,
backgroundColor: 'rgba(0, 0, 0, 0)',
cursor: 'pointer',
};
return (
<div
className={`${CSS_CLASS}-theme_sidebar-content`}
style={{
height: '100%',
display: 'flex',
flexDirection: 'column',
alignItems: 'stretch',
}}
>
<div style={{ paddingLeft: 3, paddingBottom: 6 }} >
<Paper style={{ paddingLeft: 16, paddingRight: 8, paddingTop: 8 }} >
<h3
style={{
margin: 0,
marginBottom: 4,
color: palette.secondaryTextColor,
fontSize: 16,
}}
>
{`${this.props.themeName} properties`}
</h3>
<div style={styleHR} />
<div
style={{
marginTop: 8,
display: 'flex',
alignItems: 'center',
fontSize: 14,
color: palette.secondaryTextColor,
}}
>
<div
style={{
color: !this.props.fullTheme() ? palette.textColor : '',
}}
>
Theme Settings
</div>
<SclToggle
label=""
// labelPosition="right"
labelStyle={this.toggleHeadStyle}
toggled={this.props.fullTheme()}
onToggle={() => this.props.fullTheme(!this.props.fullTheme())}
/>
<div
style={{
color: this.props.fullTheme() ? palette.textColor : '',
}}
>Full Settings</div>
</div>
<div
style={{
paddingBottom: 8,
paddingRight: 8,
}}
>
<div
style={{
marginTop: 8,
// paddingBottom: 8,
// padding: 2,
width: '100%',
height: 24,
display: 'flex',
alignItems: 'center',
border: '1px grey solid',
borderColor: palette.borderColor,
backgroundColor: 'rgba(128, 128, 128, 0.1)',
}}
>
<input
type="text"
onChange={null}
value={this.clipString()}
title={'click to copy to clipboard'}
disabled
style={{
width: '100%',
padding: 2,
margin: 0,
border: 'none',
backgroundColor: 'rgba(0, 0, 0, 0)',
color: palette.secondaryTextColor,
cursor: 'text',
}}
/>
<SvgButton
icon={<IconCopy />}
tooltip="Copy to clipboard"
width={48}
onTouchTap={this.onCopy}
/>
<div style={{ width: 4 }} />
<SvgButton
icon={<IconSwch />}
tooltip="switch style"
width={48}
onTouchTap={this.onSwitchStyleObj}
/>
</div>
</div>
</Paper>
</div>
{this.props.shouldShowData ?
themesList(
this.props.fullTheme() ? this.props.muiTheme : this.props.theme,
this.props, this.onSelect,
)
: null}
</div>
);
}
render() {
// const barWidth = this.props.open ? BAR_WIDTH : 0; // fixme BAR_WIDTH
return (
<div
className={`${CSS_CLASS}-theme_sidebar`}
style={{ width: '100%', height: '100%' }}
>
{this.props.open ? this.renderContent() : null}
</div>
);
}
}
ThemeSideBar.propTypes = propTypes;
ThemeSideBar.contextTypes = {
muiTheme: PropTypes.object.isRequired,
};
function forTable(tableTame, objListFunc) {
return (val) => {
const objList = objListFunc();
const obj = objList[tableTame];
if (val == undefined) {
return obj;
}
objList[tableTame] = val;
objListFunc(objList);
return val;
};
}
function themesList(themeObj, _props, onSelect) {
const onThemeTableOverride = (tableName) => {
return (propName, value) => {
const overTheme = {};
if (tableName === 'miscellaneous') {
overTheme[propName] = value;
_props.onThemeOverride(overTheme);
return;
}
overTheme[tableName] = {};
overTheme[tableName][propName] = value;
_props.onThemeOverride(overTheme);
};
};
const themePropTable = (tableName, table) => (
<ThemePropBlock
key={tableName}
settingsObj={table}
settingsName={tableName}
open={forTable(tableName, _props.collapseList)}
override={forTable(tableName, _props.themesOverrideList)}
onThemeTableOverride={onThemeTableOverride(tableName)}
onSelect={onSelect}
/>
);
const keyList = Object.keys(themeObj);
const strList = {};
keyList.forEach((val) => {
if (typeof (themeObj[val]) === 'string') {
strList[val] = themeObj[val];
}
});
const strListNode = themePropTable('miscellaneous', strList);
const paletteList = themeObj.palette ? themePropTable('palette', themeObj.palette)
: <div> {'No palette here'} </div>;
const tablesListObj = keyList.map((val) => {
if (typeof (themeObj[val]) === 'object' && val !== 'palette') {
return (themePropTable(val, themeObj[val])
);
}
return null;
});
const scrollStyle = {
height: '100%',
overflowY: 'scroll',
};
return (
<div
className={`${CSS_CLASS}-theme_sidebar-tables`}
style={{
height: 100,
flexGrow: 1,
flexShrink: 1,
}}
>
<div
className={`${CSS_CLASS}-theme_sidebar-tables-scroll`}
style={scrollStyle}
>
<div
style={{
paddingLeft: 3,
paddingRight: 12,
}}
>
<div style={{ backgroundColor: 'rgba(128, 128, 128, 0.04)' }}>
{paletteList}
{tablesListObj}
{strListNode}
<div style={{ height: 16 }} />
</div>
</div>
</div>
</div>
);
}
================================================
FILE: src/config.js
================================================
export const ADDON_ID = 'sm/storybook-addon-material-ui';
export const PANEL_ID = `${ADDON_ID}/material-panel`;
export const EVENT_ID_INIT = `${ADDON_ID}/material-event/init`;
export const EVENT_ID_DATA = `${ADDON_ID}/material-event/data`;
export const EVENT_ID_BACK = `${ADDON_ID}/material-event/back`;
export const CSS_CLASS = 'sb-addon-material-ui';
================================================
FILE: src/containers/MuiTheme.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import createPalette from '@material-ui/core/styles/createPalette';
import purple from '@material-ui/core/colors/purple';
import green from '@material-ui/core/colors/green';
import red from '@material-ui/core/colors/red';
import { EVENT_ID_DATA, EVENT_ID_BACK } from '../config';
import { lightTheme } from '../.themes';
// future: [x] remove ThemeToolbar
// import ThemeSideBar from '../components/ThemeSideBar';
// const stringify = require('json-stringify-safe');
const propTypes = {
themesAppliedListInit: PropTypes.arrayOf(PropTypes.object).isRequired,
story: PropTypes.shape().isRequired,
onChangeState: PropTypes.func.isRequired,
onThemeOverride: PropTypes.func.isRequired,
themesInitList: PropTypes.array.isRequired,
// themeListRender: PropTypes.func.isRequired,
initState: PropTypes.shape().isRequired,
// channel: PropTypes.object.isRequired
store: PropTypes.shape().isRequired
};
export default class MuiTheme extends React.Component {
constructor(props, context) {
super(props, context);
this.state = props.initState;
this.state.themesAppliedList = props.themesAppliedListInit;
this.state.currentTheme = {};
// this.state.muiTheme = createMuiTheme(props.themesAppliedListInit[props.initState.themeInd]); // Not working yet
this.state.muiTheme = createMuiTheme();
this.state.isMount = false;
this.isChannelData = false;
this.UpdateList = {};
this.changeTheme = this.changeTheme.bind(this);
this.onChannel = this.onChannel.bind(this);
this.openSideBar = this.openSideBar.bind(this);
this.onThemeOverride = this.onThemeOverride.bind(this);
this.subState = this.subState.bind(this);
this.wouldComponentUpdate = this.wouldComponentUpdate.bind(this);
this.needComponentUpdate = this.needComponentUpdate.bind(this);
// this.dataChannelSend = this.dataChannelSend.bind(this);
}
componentDidMount() {
// this.props.channel.on(EVENT_ID_BACK, this.onChannel);
// if (!this.state.isMount) {
// setTimeout(() => {
// this.needComponentUpdate('ThemeSideBar');
// this.setState({ isMount: true });
// }, 1);
// }
this.props.store.onData(this.onChannel);
this.props.store.connect();
}
shouldComponentUpdate() {
return true; // fixme: shouldComponentUpdate
}
componentDidUpdate() {
this.props.onChangeState(this.state);
// this.dataChannelSend(this.state);
this.isChannelData = false;
}
componentWillUnmount() {
// this.props.channel.removeListener(EVENT_ID_BACK, this.onChannel);
this.store.disconnect();
}
onChannel = theme => {
this.setState({ currentTheme: theme });
};
onThemeOverride() {
const propsThemeOverFunc = this.props.onThemeOverride(this.state.themeInd);
return overTheme => {
const themesAppliedList = propsThemeOverFunc(overTheme);
this.needComponentUpdate('ThemeSideBar');
this.setState({ themesAppliedList });
};
}
changeTheme(ind) {
this.needComponentUpdate('ThemeSideBar');
this.setState({
// muiTheme: createMuiTheme(this.state.themesAppliedList[ind]),
muiTheme: createMuiTheme(),
themeInd: ind
});
}
openSideBar(f) {
this.needComponentUpdate('ThemeSideBar');
this.setState({
isSideBarOpen: f
});
}
subState(componentName, prop) {
return val => {
if (val == undefined) {
return this.state[prop];
}
const subState = {};
subState[prop] = val;
this.setState(subState);
this.needComponentUpdate(componentName);
return val;
};
}
wouldComponentUpdate(componentName) {
if (this.UpdateList[componentName] == undefined) {
this.UpdateList[componentName] = false;
}
const upd = this.UpdateList[componentName];
this.UpdateList[componentName] = false;
return upd;
}
needComponentUpdate(componentName) {
this.UpdateList[componentName] = true;
}
render() {
const theme = createMuiTheme(this.state.currentTheme);
return (
<MuiThemeProvider theme={theme}>
<div>{this.props.story}</div>
</MuiThemeProvider>
);
}
}
MuiTheme.propTypes = propTypes;
================================================
FILE: src/containers/PanelContainer.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles';
import * as beauti from 'js-beautify';
import AddonPanel from '../components/AddonPanel';
import withChannel from '../adk/WithChannel';
import {
EVENT_ID_INIT,
EVENT_ID_DATA,
EVENT_ID_BACK,
} from '../config';
const { document, window } = global;
const logger = console;
const lightBaseTheme = createMuiTheme();
const PROGRESS_STATUS = {
'button-clone': 'soon', // todo: [] button_clone
'button-download': 'done', // todo: [x] button_download
'button-clean': 'soon', // todo: [] button_clean
'textarea-edit': 'done', // todo: [x] textarea-edit
'textarea-update': 'done' // todo: [x] textarea-update
};
const progressInfo = () => {
const keys = Object.keys(PROGRESS_STATUS);
logger.group('PROGRESS_STATUS:');
keys.forEach(val => {
if (PROGRESS_STATUS[val] === 'done') {
logger.info(`${val}: ${PROGRESS_STATUS[val]}`);
return;
}
logger.warn(`${val}: ${PROGRESS_STATUS[val]}`);
});
logger.groupEnd('PROGRESS_STATUS:');
};
const genNameList = themesAppliedList =>
themesAppliedList.map((val, ind) => val.themeName || `Theme ${ind + 1}`);
class PanelContainer extends React.Component {
static propTypes = {
store: PropTypes.shape().isRequired,
api: PropTypes.shape().isRequired
};
constructor(props, ...args) {
super(props, ...args);
this.state = {
isReady: false,
isThemeInvalid: false,
isThemeEditing: false,
themeString: '',
themeInd: 0,
};
this.isChannelData = false;
// future: get from state with own theme ind
this.muiTheme = lightBaseTheme;
}
componentDidMount() {
// this.props.channel.on(EVENT_ID_INIT, this.onInitChannel);
// this.props.channel.on(EVENT_ID_DATA, this.onDataChannel);
this.props.store.connect();
this.props.store.onData(this.onInitChannel);
}
componentDidUpdate() {
// if (!this.isChannelData) this.props.channel.emit(EVENT_ID_DATA, nextState);
this.querySet(this.state);
this.dataChannelSend(this.state);
this.isChannelData = false;
}
componentWillUnmount() {
this.props.store.disconnect();
// this.props.channel.removeListener(EVENT_ID_INIT, this.onInitChannel);
// this.props.channel.removeListener(EVENT_ID_DATA, this.onDataChannel);
}
onInitChannel = initData => {
// const _themesNameList = genNameList(initData.themesAppliedList);
const themesNameList = genNameList(initData);
const queryData = this.queryFetch();
this.setState({
themesAppliedList: initData,
...queryData,
themesNameList,
isReady: true
});
console.log('TCL: PanelContainer -> initData', initData);
};
onDataChannel = stateData => {
// const stateData = JSON.parse(strData);
const themesNameList = genNameList(stateData.themesAppliedList);
this.isChannelData = true; // note: this state received by channel, don't need to send back
this.setState({ ...stateData, themesNameList });
};
onThemeSelect = ind => {
this.setState({
themeInd: ind
});
};
onChangeTheme = str => {
// const str = event.target.value;
try {
const newTheme = JSON.parse(str);
const themesAppliedList = this.state.themesAppliedList;
themesAppliedList[this.state.themeInd] = newTheme;
this.setState({
themesAppliedList,
isThemeInvalid: false,
themeString: str
});
} catch (e) {
this.setState({
isThemeInvalid: true,
themeString: str
});
}
};
onThemeEditing = isFocus => () => {
const themeString = this.getCurrentTheme(1);
this.setState({
isThemeEditing: isFocus,
themeString
});
};
onToggleSideBar = f => {
this.setState({
isSideBarOpen: f
});
};
onDnLoadTheme = () => {
const uri = `data:application/json;charset=utf-8;base64,
${window.btoa(this.getCurrentTheme(4))}`;
const fileName =
this.state.themesAppliedList[this.state.themeInd].themeFile ||
'theme.json';
const downloadTheme = document.createElement('a');
downloadTheme.href = uri;
downloadTheme.download = fileName;
document.body.appendChild(downloadTheme);
downloadTheme.click();
document.body.removeChild(downloadTheme);
};
onCloneTheme = () => {
progressInfo(this);
return null;
// const themesAppliedList = this.state.themesAppliedList;
// const newTheme = Object.assign({}, themesAppliedList[this.state.themeInd]); // fixme: deeper
// newTheme.themeName = `${themesAppliedList[this.state.themeInd].themeName} clone`;
// newTheme.themeFile = `${themesAppliedList[this.state.themeInd].themeFile}.clone`;
// const newAppliedList = themesAppliedList.slice(0, this.state.themeInd + 1)
// .concat(newTheme, themesAppliedList.slice(this.state.themeInd + 1));
// const themesNameList = genNameList(newAppliedList);
// logger.log(themesNameList);
// this.setState({ themesAppliedList: newAppliedList, themesNameList });
};
onCleanTheme = () => {
progressInfo(this);
return null;
// const themesAppliedList = this.state.themesAppliedList;
// const newTheme = {};
// newTheme.themeName = themesAppliedList[this.state.themeInd].themeName;
// newTheme.themeFile = themesAppliedList[this.state.themeInd].themeFile;
// themesAppliedList[this.state.themeInd] = newTheme;
// const themesNameList = genNameList(themesAppliedList);
// this.setState({ themesAppliedList, themesNameList });
};
getCurrentTheme = (indent = 2) =>
beauti.js_beautify(
JSON.stringify(this.state.themesAppliedList[this.state.themeInd]),
{
indent_size: indent,
indent_char: ' ',
eol: '\n',
end_with_newline: true
}
);
dataChannelSend = data => {
if (this.isChannelData) return false;
// this.props.channel.emit(EVENT_ID_BACK, data);
try {
const theme = this.state.themesRenderedList[this.state.themeInd];
this.props.store.send(theme);
return true;
} catch (err) {
return false;
}
};
queryFetch = () => {
const themeInd = this.props.api.getQueryParam('theme-ind');
const isSideBarOpen = this.props.api.getQueryParam('theme-sidebar');
const isFullTheme = this.props.api.getQueryParam('theme-full');
const data = JSON.parse(
JSON.stringify({ themeInd, isSideBarOpen, isFullTheme })
);
const keys = Object.keys(data);
keys.forEach(val => {
data[val] = JSON.parse(data[val]);
});
return data;
};
querySet = state => {
if (state.isReady) {
const { themeInd, isSideBarOpen, isFullTheme } = state;
const queryParams = {
'theme-ind': themeInd,
'theme-sidebar': isSideBarOpen,
'theme-full': isFullTheme
};
this.props.api.setQueryParams(queryParams);
}
};
render() {
return this.state.isReady ? (
<MuiThemeProvider theme={this.muiTheme}>
<AddonPanel
themesNameList={this.state.themesNameList}
defautThemeInd={this.state.themeInd}
isSideBarOpen={this.state.isSideBarOpen}
onThemeSelect={this.onThemeSelect}
onToggleSideBar={this.onToggleSideBar}
themeJSON={
this.state.isThemeInvalid || this.state.isThemeEditing
? this.state.themeString
: this.getCurrentTheme(1)
}
isThemeInvalid={this.state.isThemeInvalid}
onThemeEditing={this.onThemeEditing}
onChangeTheme={this.onChangeTheme}
onDnLoadTheme={this.onDnLoadTheme}
onCloneTheme={this.onCloneTheme}
onCleanTheme={this.onCleanTheme}
/>
</MuiThemeProvider>
) : (
<div
style={{
padding: 16,
fontFamily:
'"San Francisco", Roboto, "Segoe UI", "Helvetica Neue", "Lucida Grande", sans-serif',
color: 'rgb(68, 68, 68)'
}}
>
waiting for muiTheme decorator...
</div>
);
}
}
export default withChannel({EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK})(PanelContainer)
================================================
FILE: src/index.js
================================================
export { muiTheme } from './muiTheme';
================================================
FILE: src/material-desktop/SclAvatar.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import Chip from '@material-ui/core/Chip';
import Avatar from '@material-ui/core/Avatar';
const defaultProps = {
scale: 0.8,
text: 'dummy text',
};
const propTypes = {
scale: PropTypes.number,
text: PropTypes.string,
};
export default function SclAvatar(props) {
const style = {
transform: `scale(${props.scale})`,
transformOrigin: 'left',
// left: -95 * (1 - props.scale) / 2,
// position: 'absolute',
};
const chipProps = Object.assign({}, props);
delete chipProps.text;
return (
<div>
<div style={style} >
<Chip {...chipProps} >
{<Avatar>{props.text[0].toUpperCase()}</Avatar>}
{props.text}
</Chip>
</div>
</div>
);
}
SclAvatar.defaultProps = defaultProps;
SclAvatar.propTypes = propTypes;
================================================
FILE: src/material-desktop/SclToggle.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import Toggle from '@material-ui/core/Switch';
const defaultProps = {
scale: 0.7,
};
const propTypes = {
scale: PropTypes.number,
};
export default function SclToggle(props) {
const style = {
transform: `scale(${props.scale})`,
};
return (
<div style={style} >
<Toggle {...props} />
</div>
);
}
SclToggle.defaultProps = defaultProps;
SclToggle.propTypes = propTypes;
================================================
FILE: src/material-desktop/SvgButton.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
import IconButton from '@material-ui/core/IconButton';
const propTypes = {
iconScale: PropTypes.number.isRequired,
icon: PropTypes.element.isRequired,
tooltip: PropTypes.string,
width: PropTypes.number,
onTouchTap: PropTypes.func,
};
const defaultProps = {
iconScale: 0.8,
tooltipPosition: 'top-center',
width: 32,
tooltip: '',
onTouchTap: () => {},
};
// const contextTypes = {
// muiTheme: PropTypes.object.isRequired,
// };
export default class SvgButton extends React.Component {
constructor(props, context) {
super(props, context);
this.scaleProp = {
style: {
transform: `scale(${props.iconScale})`,
width: 24,
margin: '0 auto',
},
};
this.butnProp = {
style: {
marginLeft: (24 - props.width) / 2,
width: props.width,
display: 'flex',
justifyContent: 'center',
overflow: 'hidden',
},
title: props.tooltip,
onClick: props.onClick,
};
}
render() {
const icon = React.cloneElement(this.props.icon, {
// color: this.context.muiTheme.palette.secondaryTextColor,
});
return (
<div
style={{
width: 24,
}}
>
<div {...this.butnProp} >
<div style={{ width: 48 }}>
<IconButton
tooltip={null}
style={{ padding: 0 }}
>
<div>
<div {...this.scaleProp} >
{icon}
</div>
</div>
</IconButton>
</div>
</div>
</div>
);
}
}
SvgButton.propTypes = propTypes;
SvgButton.defaultProps = defaultProps;
// SvgButton.contextTypes = contextTypes;
================================================
FILE: src/material-desktop/SvgIcon.jsx
================================================
import React from 'react';
import PropTypes from 'prop-types';
const propTypes = {
scale: PropTypes.number.isRequired,
};
const defaultProps = {
scale: 0.8,
};
const contextTypes = {
muiTheme: PropTypes.object.isRequired,
};
export default class SvgIcon extends React.Component {
constructor(props, context) {
super(props, context);
require.ensure([], (require) => {
const Icon = require('@material-ui/core/SvgIcon');
this.ActionHome = Icon.default;
});
this.scaleProp = {
style: { transform: `scale(${props.scale})` },
};
}
render() {
return (
<div>
<div {...this.scaleProp} >
{<this.ActionHome
color={this.context.muiTheme.palette.secondaryTextColor}
/>}
</div>
</div>
);
}
}
SvgIcon.propTypes = propTypes;
SvgIcon.defaultProps = defaultProps;
SvgIcon.contextTypes = contextTypes;
================================================
FILE: src/muiTheme.js
================================================
import React from 'react';
import { createMuiTheme } from '@material-ui/core/styles';
import { EVENT_ID_INIT, EVENT_ID_DATA, EVENT_ID_BACK } from './config';
import MuiDecorator from './UI/MuiDecorator';
import { createStore } from './adk/decorator';
const lightBaseTheme = createMuiTheme({
typography: {
useNextVariants: true
}
});
const darkBaseTheme = createMuiTheme({
palette: {
type: 'dark'
},
typography: {
useNextVariants: true
}
});
lightBaseTheme.themeName = 'Light Theme';
darkBaseTheme.themeName = 'Dark Theme';
export function muiTheme(themes) {
const store = createStore(
EVENT_ID_INIT,
EVENT_ID_DATA,
EVENT_ID_BACK,
'iframe'
);
let themesInitList = [lightBaseTheme, darkBaseTheme];
if (themes) {
if (Array.isArray(themes)) {
themesInitList = themes;
themesInitList.forEach((val, ind) => {
if (typeof val === 'string') {
/* note: unsupported names goes as lightBaseTheme
if (val === lightBaseTheme.themeName) {
themesInitList[ind] = lightBaseTheme;
}
*/
if (val === darkBaseTheme.themeName) {
themesInitList[ind] = darkBaseTheme;
} else {
themesInitList[ind] = lightBaseTheme;
}
}
});
} else {
themesInitList = [themes];
}
}
store.onConnected(() =>
store.sendInit({ themes: themesInitList, themeInd: 0 })
);
return story => {
const storyItem = story();
return (
<MuiDecorator
story={storyItem}
initData={{ themes: themesInitList, themeInd: 0 }}
/>
);
};
}
================================================
FILE: src/preset.js
================================================
export function managerEntries(entry = []) {
return [...entry, require.resolve("./register")]; //👈 addon implementation
}
================================================
FILE: src/register.js
================================================
import React from 'react';
import addons from '@storybook/addons';
import AddonPanel from './UI/AddonPanel';
import { ADDON_ID, PANEL_ID } from './config';
addons.register(ADDON_ID, api => {
addons.addPanel(PANEL_ID, {
title: 'Material-UI',
render: ({ active, key } = {}) => (
<AddonPanel key={key} api={api} active={active} panel pointName="addon panel" />
)
});
});
================================================
FILE: storybook-addon-material-ui.d.ts
================================================
import {DecoratorFunction} from "@storybook/addons";
import {Theme} from "@material-ui/core";
export declare function muiTheme<T = {}>(arg?: Array<Theme>): DecoratorFunction<T>;
gitextract_qtgx2lmx/ ├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github/ │ └── workflows/ │ └── codacy-analysis.yml ├── .gitignore ├── .npmignore ├── .scripts/ │ ├── deployer/ │ │ ├── index.js │ │ └── utils.js │ ├── lint.js │ ├── npm-postpublish.js │ ├── npm-prepare.js │ ├── npm-status.js │ ├── run_tests/ │ │ ├── index.js │ │ └── mocha_runner.js │ ├── ver.js │ └── watch.js ├── .storybook/ │ ├── .themes/ │ │ ├── customTheme1.js │ │ ├── customTheme2.js │ │ ├── customTheme3.js │ │ ├── customTheme4.js │ │ └── customTheme5.js │ ├── addons.js │ ├── config.js │ └── stories.js ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── docs/ │ └── screenshorts.md ├── package.json ├── public/ │ ├── index.html │ └── manifest.json ├── register.js ├── src/ │ ├── .themes/ │ │ └── index.js │ ├── UI/ │ │ ├── AddonPanel.js │ │ ├── FullTheme.js │ │ ├── MuiDecorator.js │ │ ├── Overridings.js │ │ └── Palette.js │ ├── Utils/ │ │ ├── index.js │ │ ├── svg_package.js │ │ ├── uiTheme.js │ │ └── ui_package.jsx │ ├── adk/ │ │ ├── ChannelHOC.js │ │ ├── ChannelStore.js │ │ ├── WithChannel.js │ │ ├── decorator.js │ │ └── panel.js │ ├── components/ │ │ ├── AddonPanel.jsx │ │ ├── ThemePropBlock.jsx │ │ ├── ThemePropItem.jsx │ │ └── ThemeSideBar.jsx │ ├── config.js │ ├── containers/ │ │ ├── MuiTheme.jsx │ │ └── PanelContainer.jsx │ ├── index.js │ ├── material-desktop/ │ │ ├── SclAvatar.jsx │ │ ├── SclToggle.jsx │ │ ├── SvgButton.jsx │ │ └── SvgIcon.jsx │ ├── muiTheme.js │ ├── preset.js │ └── register.js └── storybook-addon-material-ui.d.ts
SYMBOL INDEX (101 symbols across 23 files)
FILE: .storybook/config.js
function loadStories (line 5) | function loadStories() {
FILE: src/UI/AddonPanel.js
constant MODS_LIST (line 82) | const MODS_LIST = [
class AddonPanel (line 112) | class AddonPanel extends React.Component {
method render (line 135) | render() {
FILE: src/UI/Palette.js
class Palette (line 58) | class Palette extends React.Component {
method render (line 193) | render() {
FILE: src/Utils/index.js
function copyToClipboard (line 3) | function copyToClipboard(text) {
function copyToClipboardThis (line 24) | function copyToClipboardThis(text) {
FILE: src/Utils/svg_package.js
function __webpack_require__ (line 9) | function __webpack_require__(moduleId) {
function _interopRequireDefault (line 359) | function _interopRequireDefault(obj) { return obj && obj.__esModule ? ob...
function checkBox (line 400) | function checkBox(isOn) {
function toggle (line 405) | function toggle(isOn) {
FILE: src/Utils/uiTheme.js
function getCurrentTheme (line 15) | function getCurrentTheme() {
FILE: src/Utils/ui_package.jsx
function Button (line 46) | function Button({ icon, label, title, onClick, compact, disabled }) {
function Link (line 74) | function Link({ icon, label, title, href }) {
function CheckBox (line 102) | function CheckBox({ checked, label, title, onToggle }) {
function Toggle (line 126) | function Toggle({ checked, label, title, onToggle }) {
function Dropdown (line 159) | function Dropdown({ selected, list, title, onSelect }) {
function Paper (line 197) | function Paper({ children, style }) {
function Tag (line 230) | function Tag({ label, onClick }) {
FILE: src/adk/ChannelHOC.js
function getDisplayName (line 18) | function getDisplayName(WrappedComponent) {
function withChannel (line 22) | function withChannel(WrappedComponent) {
FILE: src/adk/ChannelStore.js
class ChannelStore (line 3) | class ChannelStore {
method constructor (line 4) | constructor({
FILE: src/adk/WithChannel.js
method componentDidMount (line 31) | componentDidMount() {
method componentWillUnmount (line 39) | componentWillUnmount() {
method render (line 45) | render() {
FILE: src/components/AddonPanel.jsx
class AddonPanel (line 37) | class AddonPanel extends React.Component {
method constructor (line 38) | constructor(props) {
method handleChange (line 51) | handleChange(value) {
method render (line 57) | render() {
FILE: src/components/ThemePropBlock.jsx
class ThemePropBlock (line 23) | class ThemePropBlock extends React.Component {
method constructor (line 24) | constructor(props, ...args) {
method shouldComponentUpdate (line 37) | shouldComponentUpdate() {
method onToolCollapse (line 43) | onToolCollapse(val) {
method onSelect (line 52) | onSelect(sel) {
method valueHandler (line 62) | valueHandler(propName) {
method renderProp (line 69) | renderProp(val, ind, isOpen, isHeader) {
method renderColl (line 88) | renderColl() {
method render (line 99) | render() {
function BlockHeader (line 131) | function BlockHeader(props, context) {
FILE: src/components/ThemePropItem.jsx
class ThemePropItem (line 36) | class ThemePropItem extends React.Component {
method constructor (line 37) | constructor(props, ...args) {
method shouldComponentUpdate (line 44) | shouldComponentUpdate(nextProps) {
method onToolTogle (line 60) | onToolTogle() {
method renderProp (line 64) | renderProp(isNotHeader) {
method render (line 89) | render() {
function PropItem (line 103) | function PropItem(props, context) {
function PropHeader (line 172) | function PropHeader(props, context) {
function PropInput (line 211) | function PropInput(props, context) {
function PropTool (line 256) | function PropTool(props, context) {
function PropToolPicker (line 282) | function PropToolPicker(props, context) {
function PropToolPickerFull (line 321) | function PropToolPickerFull(props, context) {
FILE: src/components/ThemeSideBar.jsx
constant BAR_WIDTH (line 15) | const BAR_WIDTH = 400;
class ThemeSideBar (line 27) | class ThemeSideBar extends React.Component {
method constructor (line 28) | constructor(props) {
method shouldComponentUpdate (line 43) | shouldComponentUpdate(nextProps, nextState) {
method onSelect (line 48) | onSelect(sel) {
method onSwitchStyleObj (line 52) | onSwitchStyleObj() {
method onCopy (line 57) | onCopy() {
method clipString (line 62) | clipString() {
method renderContent (line 73) | renderContent() {
method render (line 200) | render() {
function forTable (line 221) | function forTable(tableTame, objListFunc) {
function themesList (line 234) | function themesList(themeObj, _props, onSelect) {
FILE: src/config.js
constant ADDON_ID (line 1) | const ADDON_ID = 'sm/storybook-addon-material-ui';
constant PANEL_ID (line 2) | const PANEL_ID = `${ADDON_ID}/material-panel`;
constant EVENT_ID_INIT (line 3) | const EVENT_ID_INIT = `${ADDON_ID}/material-event/init`;
constant EVENT_ID_DATA (line 4) | const EVENT_ID_DATA = `${ADDON_ID}/material-event/data`;
constant EVENT_ID_BACK (line 5) | const EVENT_ID_BACK = `${ADDON_ID}/material-event/back`;
constant CSS_CLASS (line 6) | const CSS_CLASS = 'sb-addon-material-ui';
FILE: src/containers/MuiTheme.jsx
class MuiTheme (line 28) | class MuiTheme extends React.Component {
method constructor (line 29) | constructor(props, context) {
method componentDidMount (line 52) | componentDidMount() {
method shouldComponentUpdate (line 64) | shouldComponentUpdate() {
method componentDidUpdate (line 68) | componentDidUpdate() {
method componentWillUnmount (line 74) | componentWillUnmount() {
method onThemeOverride (line 83) | onThemeOverride() {
method changeTheme (line 92) | changeTheme(ind) {
method openSideBar (line 101) | openSideBar(f) {
method subState (line 108) | subState(componentName, prop) {
method wouldComponentUpdate (line 121) | wouldComponentUpdate(componentName) {
method needComponentUpdate (line 130) | needComponentUpdate(componentName) {
method render (line 134) | render() {
FILE: src/containers/PanelContainer.jsx
constant PROGRESS_STATUS (line 20) | const PROGRESS_STATUS = {
class PanelContainer (line 44) | class PanelContainer extends React.Component {
method constructor (line 50) | constructor(props, ...args) {
method componentDidMount (line 66) | componentDidMount() {
method componentDidUpdate (line 73) | componentDidUpdate() {
method componentWillUnmount (line 80) | componentWillUnmount() {
method render (line 236) | render() {
FILE: src/material-desktop/SclAvatar.jsx
function SclAvatar (line 17) | function SclAvatar(props) {
FILE: src/material-desktop/SclToggle.jsx
function SclToggle (line 13) | function SclToggle(props) {
FILE: src/material-desktop/SvgButton.jsx
class SvgButton (line 26) | class SvgButton extends React.Component {
method constructor (line 27) | constructor(props, context) {
method render (line 50) | render() {
FILE: src/material-desktop/SvgIcon.jsx
class SvgIcon (line 17) | class SvgIcon extends React.Component {
method constructor (line 18) | constructor(props, context) {
method render (line 31) | render() {
FILE: src/muiTheme.js
function muiTheme (line 25) | function muiTheme(themes) {
FILE: src/preset.js
function managerEntries (line 1) | function managerEntries(entry = []) {
Condensed preview — 63 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (155K chars).
[
{
"path": ".babelrc",
"chars": 120,
"preview": "{\n \"presets\": [\"@babel/preset-env\", \"@babel/preset-react\"],\n \"plugins\": [\"@babel/plugin-proposal-class-properties\"]\n}\n"
},
{
"path": ".eslintignore",
"chars": 7,
"preview": "*.d.ts\n"
},
{
"path": ".eslintrc.js",
"chars": 560,
"preview": "const error = 2;\nconst warn = 1;\nconst ignore = 0;\n\nmodule.exports = {\n root: true,\n extends: ['eslint-config-airbnb',"
},
{
"path": ".github/workflows/codacy-analysis.yml",
"chars": 1800,
"preview": "# This workflow checks out code, performs a Codacy security scan\n# and integrates the results with the\n# GitHub Advanced"
},
{
"path": ".gitignore",
"chars": 321,
"preview": "# See https://help.github.com/ignore-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n\n# testing\n/cov"
},
{
"path": ".npmignore",
"chars": 77,
"preview": "node_modules\ndevelop\nexample\nsrc\ndocs\n.babelrc\n.eslintrc\n.scripts\n.storybook\n"
},
{
"path": ".scripts/deployer/index.js",
"chars": 2111,
"preview": "var shell = require('shelljs');\r\nvar chalk = require('chalk');\r\nvar publishUtils = require('./utils');\r\nvar path = requi"
},
{
"path": ".scripts/deployer/utils.js",
"chars": 720,
"preview": "var shell = require('shelljs');\r\nvar chalk = require('chalk');\r\nvar parseGitUrl = require('git-url-parse');\r\n\r\nmodule.ex"
},
{
"path": ".scripts/lint.js",
"chars": 1066,
"preview": "const path = require('path');\r\nconst shell = require('shelljs');\r\nconst chalk = require('chalk');\r\n\r\n\r\nconst isJSON = pr"
},
{
"path": ".scripts/npm-postpublish.js",
"chars": 214,
"preview": "var shell = require('shelljs');\r\nvar chalk = require('chalk');\r\nconst packageJson = require('../package.json');\r\n\r\nshell"
},
{
"path": ".scripts/npm-prepare.js",
"chars": 524,
"preview": "var path = require('path');\r\nvar shell = require('shelljs');\r\nvar chalk = require('chalk');\r\nvar babel = ['node_modules'"
},
{
"path": ".scripts/npm-status.js",
"chars": 1622,
"preview": "var path = require('path');\r\nvar shell = require('shelljs');\r\nvar chalk = require('chalk');\r\nvar semver = require('semve"
},
{
"path": ".scripts/run_tests/index.js",
"chars": 511,
"preview": "const path = require('path');\r\nconst shell = require('shelljs');\r\nconst chalk = require('chalk');\r\n\r\nconst isMin = proce"
},
{
"path": ".scripts/run_tests/mocha_runner.js",
"chars": 1163,
"preview": "// This is an auto generated file with React CDK.\r\n\r\nrequire('babel-core/register');\r\nrequire('babel-polyfill');\r\n\r\n// p"
},
{
"path": ".scripts/ver.js",
"chars": 190,
"preview": "const shell = require('shelljs');\r\nconst chalk = require('chalk');\r\nconst packageJson = require('../package.json');\r\n\r\ns"
},
{
"path": ".scripts/watch.js",
"chars": 137,
"preview": "const shell = require('shelljs');\r\nconst chalk = require('chalk');\r\n\r\nshell.exec('nodemon src -e js,jsx,json --exec \"npm"
},
{
"path": ".storybook/.themes/customTheme1.js",
"chars": 896,
"preview": "import { createMuiTheme } from '@material-ui/core/styles';\nimport green from '@material-ui/core/colors/green';\nimport pu"
},
{
"path": ".storybook/.themes/customTheme2.js",
"chars": 761,
"preview": "import { createMuiTheme } from '@material-ui/core/styles';\nimport green from '@material-ui/core/colors/green';\nimport pu"
},
{
"path": ".storybook/.themes/customTheme3.js",
"chars": 599,
"preview": "import { createMuiTheme } from '@material-ui/core/styles';\nimport green from '@material-ui/core/colors/green';\nimport pu"
},
{
"path": ".storybook/.themes/customTheme4.js",
"chars": 458,
"preview": "import { createMuiTheme } from '@material-ui/core/styles';\nimport red from '@material-ui/core/colors/red';\nimport yellow"
},
{
"path": ".storybook/.themes/customTheme5.js",
"chars": 462,
"preview": "import { createMuiTheme } from '@material-ui/core/styles';\nimport blue from '@material-ui/core/colors/blue';\nimport yell"
},
{
"path": ".storybook/addons.js",
"chars": 160,
"preview": "import '../src/register';\nimport '@storybook/addon-actions/register';\nimport '@storybook/addon-links/register';\nimport '"
},
{
"path": ".storybook/config.js",
"chars": 228,
"preview": "/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */\n\nimport { configure } fr"
},
{
"path": ".storybook/stories.js",
"chars": 2401,
"preview": "import React from 'react';\n\nimport { storiesOf } from '@storybook/react';\n\nimport Button from '@material-ui/core/Button'"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 3231,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nIn the interest of fostering an open and welcoming environment, w"
},
{
"path": "LICENSE",
"chars": 1071,
"preview": "MIT License\n\nCopyright (c) 2021 Oleg Proskurin\n\nPermission is hereby granted, free of charge, to any person obtaining a "
},
{
"path": "README.md",
"chars": 9873,
"preview": "[](https://app.codacy.com/gh"
},
{
"path": "docs/screenshorts.md",
"chars": 451,
"preview": "### default `Light base theme`\n>quick start for component development\n\n### default `Dark base the"
},
{
"path": "package.json",
"chars": 3033,
"preview": "{\n \"name\": \"storybook-addon-material-ui\",\n \"version\": \"0.9.0-alpha.24\",\n \"description\": \"Storybook Addon for Material"
},
{
"path": "public/index.html",
"chars": 1590,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n <head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-wid"
},
{
"path": "public/manifest.json",
"chars": 317,
"preview": "{\n \"short_name\": \"React App\",\n \"name\": \"Create React App Sample\",\n \"icons\": [\n {\n \"src\": \"favicon.ico\",\n "
},
{
"path": "register.js",
"chars": 31,
"preview": "require('./dist/register.js');\n"
},
{
"path": "src/.themes/index.js",
"chars": 178,
"preview": "import { createMuiTheme } from '@material-ui/core/styles';\n\n\nexport const lightTheme = createMuiTheme({\n palette: {\n "
},
{
"path": "src/UI/AddonPanel.js",
"chars": 8607,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { cx, css } from '@emotion/core';\nimport styled fr"
},
{
"path": "src/UI/FullTheme.js",
"chars": 851,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { cx, css } from '@emotion/core';\nimport styled fr"
},
{
"path": "src/UI/MuiDecorator.js",
"chars": 662,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { MuiThemeProvider, createMuiTheme } from '@materi"
},
{
"path": "src/UI/Overridings.js",
"chars": 758,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { cx, css } from '@emotion/core';\nimport styled fr"
},
{
"path": "src/UI/Palette.js",
"chars": 5773,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { cx, css } from '@emotion/core';\nimport styled fr"
},
{
"path": "src/Utils/index.js",
"chars": 856,
"preview": "\n\nexport function copyToClipboard(text) {\n console.log(text);\n const copyText = text;\n return () => {\n console.inf"
},
{
"path": "src/Utils/svg_package.js",
"chars": 30696,
"preview": "(function webpackUniversalModuleDefinition(root, factory) {\n if (typeof exports === 'object' && typeof module === 'obje"
},
{
"path": "src/Utils/uiTheme.js",
"chars": 346,
"preview": "const uiThemeLight = {\n palette: {\n borderColor: '#e0e0e0',\n textColor: 'rgba(0, 0, 0, 0.87)',\n secondaryTextC"
},
{
"path": "src/Utils/ui_package.jsx",
"chars": 5625,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n// import images from './svg_package';\n\nconst images = {}"
},
{
"path": "src/adk/ChannelHOC.js",
"chars": 1023,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\n// class WithChannel extends React.Component {\n// stat"
},
{
"path": "src/adk/ChannelStore.js",
"chars": 1589,
"preview": "import addons from '@storybook/addons';\n\nexport default class ChannelStore {\n constructor({\n EVENT_ID_INIT,\n EVEN"
},
{
"path": "src/adk/WithChannel.js",
"chars": 1380,
"preview": "import React from 'react';\n\nimport ChannelStore from './ChannelStore';\n\nconst getDisplayName = WrappedComponent =>\n Wra"
},
{
"path": "src/adk/decorator.js",
"chars": 228,
"preview": "import ChannelStore from './ChannelStore';\n\nlet decoratorStore;\n\nexport const createStore = (...args) => {\n decoratorSt"
},
{
"path": "src/adk/panel.js",
"chars": 284,
"preview": "import ChannelStore from './ChannelStore';\n\nlet panelStore;\n\nexport const createStore = (EVENT_ID_INIT, EVENT_ID_DATA, E"
},
{
"path": "src/components/AddonPanel.jsx",
"chars": 7217,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport { Toggle, Link, Button, Dropdown, Paper } from '.."
},
{
"path": "src/components/ThemePropBlock.jsx",
"chars": 4529,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Paper from '@material-ui/core/Paper';\nimport SclTo"
},
{
"path": "src/components/ThemePropItem.jsx",
"chars": 10825,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Tab from '@material-ui/core/Tab';\nimport Tabs from"
},
{
"path": "src/components/ThemeSideBar.jsx",
"chars": 8789,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Paper from '@material-ui/core/Paper';\nimport IconC"
},
{
"path": "src/config.js",
"chars": 353,
"preview": "export const ADDON_ID = 'sm/storybook-addon-material-ui';\nexport const PANEL_ID = `${ADDON_ID}/material-panel`;\nexport c"
},
{
"path": "src/containers/MuiTheme.jsx",
"chars": 4319,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nimport { MuiThemeProvider, createMuiTheme } from '@mater"
},
{
"path": "src/containers/PanelContainer.jsx",
"chars": 8348,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nimport { MuiThemeProvider, createMuiTheme } from '@mater"
},
{
"path": "src/index.js",
"chars": 39,
"preview": "export { muiTheme } from './muiTheme';\n"
},
{
"path": "src/material-desktop/SclAvatar.jsx",
"chars": 860,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nimport Chip from '@material-ui/core/Chip';\nimport Avatar"
},
{
"path": "src/material-desktop/SclToggle.jsx",
"chars": 463,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport Toggle from '@material-ui/core/Switch';\n\nconst def"
},
{
"path": "src/material-desktop/SvgButton.jsx",
"chars": 1795,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\nimport IconButton from '@material-ui/core/IconButton';\n\nc"
},
{
"path": "src/material-desktop/SvgIcon.jsx",
"chars": 913,
"preview": "import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst propTypes = {\n scale: PropTypes.number.isRequired"
},
{
"path": "src/muiTheme.js",
"chars": 1638,
"preview": "import React from 'react';\nimport { createMuiTheme } from '@material-ui/core/styles';\n\nimport { EVENT_ID_INIT, EVENT_ID_"
},
{
"path": "src/preset.js",
"chars": 124,
"preview": "export function managerEntries(entry = []) {\n return [...entry, require.resolve(\"./register\")]; //👈 addon implementatio"
},
{
"path": "src/register.js",
"chars": 391,
"preview": "import React from 'react';\nimport addons from '@storybook/addons';\nimport AddonPanel from './UI/AddonPanel';\nimport { AD"
},
{
"path": "storybook-addon-material-ui.d.ts",
"chars": 179,
"preview": "import {DecoratorFunction} from \"@storybook/addons\";\nimport {Theme} from \"@material-ui/core\";\n\nexport declare function m"
}
]
About this extraction
This page contains the full source code of the sm-react/storybook-addon-material-ui GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 63 files (142.9 KB), approximately 44.7k tokens, and a symbol index with 101 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.