Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 35 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,40 @@ cd apexcharts.js
npx browser-sync start --server --files "." --directory --startPath "/samples"
```

#### Test Content Security Policy (CSP) related features

To test Content Security Policy (CSP) related features, you should use a specific configuration file. Run `browser-sync` with the `--config` flag:

```bash
npx browser-sync start --config browser-sync-config.js
```

This command uses the `browser-sync-config.js` file to set up the necessary `Content-Security-Policy` headers. Here is the content of the configuration file:

`browser-sync-config.js`

```js
const TEST_NONCE =
'47ebaa88ef82ffb86e4ccb0eab1c5ec6bd76767642358e8cf99487673d5904b5'

const cspPolicies = [`style-src 'self' 'nonce-${TEST_NONCE}'`]

module.exports = {
server: {
baseDir: '.',
directory: true,
},
files: ['.'],
startPath: '/samples',
middleware: [
function (req, res, next) {
res.setHeader('Content-Security-Policy', cspPolicies.join('; '))
next()
},
],
}
```

And start working on a feature or fix. Changes in source code should be immediately visible in the browser due to automatic reload on changes.

### Start a dependent new project
Expand Down Expand Up @@ -125,16 +159,4 @@ This way, when later working on a feature or fix, `npm run test` command will de

We'd love for you to contribute your changes back to `apexcharts.js`! To do that, it would be great if you could commit your changes to a separate feature branch and open a Pull Request for those changes.

Point your feature branch to use the `main` branch as the base of this PR. The exact commands used depends on how you've setup your local git copy, but the flow could look like this:

```sh
# Inside your own copy of `apexcharts.js` package...
git checkout --branch feature/branch-name-here upstream/main
# Then hack away, and commit your changes:
git add -A
git commit -m "Few words about the changes I did"
# Push your local changes back to your fork
git push --set-upstream origin feature/branch-name-here
```

After these steps, you should be able to create a new Pull Request for this repository. If you hit any issues following these instructions, please open an issue and we'll see if we can improve these instructions even further.
Point your feature branch to use the `main`
63 changes: 63 additions & 0 deletions browser-sync-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const TEST_NONCE =
'47ebaa88ef82ffb86e4ccb0eab1c5ec6bd76767642358e8cf99487673d5904b5'

const cspPolicies = [`style-src 'self' 'nonce-${TEST_NONCE}'`]

module.exports = {
server: {
baseDir: './samples',
directory: true,
routes: {
'/dist': './dist',
'/src/assets': './src/assets',
},
},
files: [
'./samples/vanilla-js/csp',
'./samples/react/csp',
'./samples/vue/csp',
],
startPath: '/',
middleware: [
function (req, res, next) {
const url = req.url
const allowedPrefixes = [
'/vanilla-js/csp',
'/react/csp',
'/vue/csp',
'/assets',
'/src',
'/dist',
]

if (url === '/') {
res.setHeader('Content-Type', 'text/html')
res.end(`
<h1>Content Security Policy Test Directories</h1>
<ul>
<li><a href="/vanilla-js/csp/">vanilla-js/csp/</a></li>
<li><a href="/react/csp/">react/csp/</a></li>
<li><a href="/vue/csp/">vue/csp/</a></li>
</ul>
`)
return
}

const isAllowed = allowedPrefixes.some(
(prefix) => url.startsWith(prefix + '/') || url === prefix
)

if (isAllowed) {
return next()
}

res.statusCode = 403
res.setHeader('Content-Type', 'text/plain')
res.end('Forbidden')
},
function (req, res, next) {
res.setHeader('Content-Security-Policy', cspPolicies.join('; '))
next()
},
],
}
4 changes: 4 additions & 0 deletions build/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ function rollupConfig(opts) {
files: 'src/assets/apexcharts.css',
dest: 'dist'
},
{
files: 'src/assets/apexcharts-legend.css',
dest: 'dist',
},
{
files: 'src/locales/*.*',
dest: 'dist/locales'
Expand Down
265 changes: 265 additions & 0 deletions samples/react/csp/css-injection-disabled.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,265 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>CSS Injection Control Demo - React</title>

<link
href="../../assets/styles.css"
rel="stylesheet"
nonce="47ebaa88ef82ffb86e4ccb0eab1c5ec6bd76767642358e8cf99487673d5904b5"
/>

<link
href="../../../src/assets/apexcharts.css"
rel="stylesheet"
nonce="47ebaa88ef82ffb86e4ccb0eab1c5ec6bd76767642358e8cf99487673d5904b5"
id="apexcharts-css"
/>

<link
href="../../../src/assets/apexcharts-legend.css"
rel="stylesheet"
nonce="47ebaa88ef82ffb86e4ccb0eab1c5ec6bd76767642358e8cf99487673d5904b5"
/>

<style
nonce="47ebaa88ef82ffb86e4ccb0eab1c5ec6bd76767642358e8cf99487673d5904b5"
>
.chart-container {
max-width: 650px;
margin: 35px auto;
padding: 20px;
border: 1px solid #e0e0e0;
border-radius: 8px;
}

.chart-title {
font-size: 18px;
font-weight: bold;
margin-bottom: 10px;
text-align: center;
color: #333;
}

.chart-description {
font-size: 14px;
color: #666;
margin-bottom: 15px;
text-align: center;
}

.main-title {
text-align: center;
font-size: 24px;
font-weight: bold;
margin: 20px 0;
color: #333;
}

.info-box {
background-color: #f8f9fa;
border: 1px solid #dee2e6;
border-radius: 5px;
padding: 15px;
margin: 20px auto;
max-width: 650px;
}

.info-box h3 {
margin: 0 0 10px 0;
color: #495057;
}

.info-box p {
margin: 5px 0;
color: #6c757d;
}

.warning {
color: #d74a0e;
}
</style>

<script
crossorigin
src="https://unpkg.com/react@16/umd/react.development.js"
></script>
<script
crossorigin
src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"
></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="../../../dist/apexcharts.js"></script>
</head>

<body>
<div id="app"></div>

<script type="text/babel">
class CSSInjectionDemo extends React.Component {
constructor(props) {
super(props)

this.state = {
baseOptions: {
series: [
{
name: 'Revenue',
type: 'column',
data: [
440, 505, 414, 671, 227, 413, 201, 352, 752, 320, 257, 160,
],
},
{
name: 'Profit',
type: 'area',
data: [23, 42, 35, 27, 43, 22, 17, 31, 22, 22, 12, 16],
},
{
name: 'Free Cash Flow',
type: 'line',
data: [35, 41, 36, 26, 45, 48, 52, 53, 41, 35, 25, 18],
},
],
chart: {
height: 350,
type: 'line',
stacked: false,
},
stroke: {
width: [0, 2, 2],
curve: 'smooth',
},
plotOptions: {
bar: {
columnWidth: '50%',
},
},
fill: {
opacity: [0.85, 0.25, 1],
gradient: {
inverseColors: false,
shade: 'light',
type: 'vertical',
opacityFrom: 0.85,
opacityTo: 0.55,
stops: [0, 100, 100, 100],
},
},
labels: [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec',
],
markers: {
size: 0,
},
xaxis: {
type: 'category',
},
yaxis: {
title: {
text: 'Amount ($)',
},
},
tooltip: {
shared: true,
intersect: false,
y: {
formatter: function (y) {
if (typeof y !== 'undefined') {
return '$' + y.toFixed(0) + 'k'
}
return y
},
},
},
legend: {
position: 'bottom',
horizontalAlign: 'left',
floating: true,
offsetY: 25,
offsetX: -5,
},
},
}
}

componentDidMount() {
/**
* CSS injection disabled.
* apexcharts.css and apexcharts-legend.css will not be injected into the SVG's foreign object automatically,
* it make the style broken, so we need to import css files manually.
*/
const options = JSON.parse(JSON.stringify(this.state.baseOptions))
options.injectStyleSheet = false
this.chart = new ApexCharts(this.refs.chart, options)
this.chart.render()
}

componentWillUnmount() {
if (this.chart) {
this.chart.destroy()
}
}

render() {
return (
<div>
<div className="main-title">
CSS Injection Control Demo - React
</div>

<div className="info-box">
<h3>About this demo</h3>
<p>
This demo shows the <code>injectStyleSheet</code> option in
action using React.
</p>
<p>
• <strong>true</strong>: Styles are injected into the SVG's
foreign object. <br />
<label className="warning">
And if csp policy is set, you can see csp error message in
browser console.
</label>
</p>
<br />
<p>
• <strong>false</strong>: Styles are not injected. <br />
Relying on external CSS or import apexcharts.css,
apexcharts-legend.css manually. <br />
<label className="warning">
It will resolve the csp error if csp policy is set.
</label>
</p>
</div>

<div className="chart-container">
<div className="chart-title">
Chart with CSS Injection Disabled
</div>
<div className="chart-description">injectStyleSheet: false</div>
<div ref="chart"></div>
</div>
</div>
)
}
}

ReactDOM.render(<CSSInjectionDemo />, document.getElementById('app'))
</script>
</body>
</html>
Loading