diff --git a/app/riot/src/client/preview/__snapshots__/render-riot.test.js.snap b/app/riot/src/client/preview/__snapshots__/render-riot.test.js.snap
index 6e5c63342819..b67db362d53c 100644
--- a/app/riot/src/client/preview/__snapshots__/render-riot.test.js.snap
+++ b/app/riot/src/client/preview/__snapshots__/render-riot.test.js.snap
@@ -1,7 +1,72 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`render a riot element can accept a constructor 1`] = `"HACKED : true ; simple test (with a parameter). Oh, by the way (value is mapped to riotValue)
"`;
+exports[`render a riot element can accept a constructor 1`] = `
+
+
+ HACKED : true ; simple test (with a parameter). Oh, by the way (value is mapped to riotValue)
+
+
+`;
-exports[`render a riot element can nest several tags 1`] = `""`;
+exports[`render a riot element can nest several tags 1`] = `
+
+
+
+`;
-exports[`render a riot element can template some vars 1`] = `"simple test (with a parameter). Oh, by the way (value is mapped to riotValue)
"`;
+exports[`render a riot element can template some vars 1`] = `
+
+
+ simple test (with a parameter). Oh, by the way (value is mapped to riotValue)
+
+
+`;
diff --git a/jest.config.js b/jest.config.js
index 6c222f69f539..463d034d6425 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -75,7 +75,7 @@ module.exports = {
DOCS_MODE: false,
PREVIEW_URL: undefined,
},
- snapshotSerializers: ['jest-emotion', 'enzyme-to-json/serializer'],
+ snapshotSerializers: ['jest-emotion', 'enzyme-to-json/serializer', 'jest-serializer-html'],
coverageDirectory: 'coverage',
setupFilesAfterEnv: ['./scripts/jest.init.js'],
coverageReporters: ['lcov'],
diff --git a/lib/components/package.json b/lib/components/package.json
index be47b1f58ee3..b7b0bbf13abd 100644
--- a/lib/components/package.json
+++ b/lib/components/package.json
@@ -30,6 +30,7 @@
"dependencies": {
"@storybook/client-logger": "6.0.0-alpha.22",
"@storybook/theming": "6.0.0-alpha.22",
+ "@types/overlayscrollbars": "^1.9.0",
"@types/react-syntax-highlighter": "11.0.4",
"@types/react-textarea-autosize": "^4.3.3",
"core-js": "^3.0.1",
@@ -37,6 +38,8 @@
"lodash": "^4.17.15",
"markdown-to-jsx": "^6.9.1",
"memoizerific": "^1.11.3",
+ "overlayscrollbars": "^1.10.2",
+ "overlayscrollbars-react": "^0.2.1",
"polished": "^3.4.4",
"popper.js": "^1.14.7",
"react": "^16.8.3",
@@ -46,10 +49,10 @@
"react-popper-tooltip": "^2.8.3",
"react-syntax-highlighter": "^11.0.2",
"react-textarea-autosize": "^7.1.0",
- "simplebar-react": "^1.0.0-alpha.6",
"ts-dedent": "^1.1.1"
},
"devDependencies": {
+ "css": "^2.2.4",
"enzyme": "^3.9.0",
"jest": "^25.1.0",
"jest-enzyme": "^7.0.2"
diff --git a/lib/components/scripts/writeCssScript.js b/lib/components/scripts/writeCssScript.js
new file mode 100644
index 000000000000..07fa841d93f5
--- /dev/null
+++ b/lib/components/scripts/writeCssScript.js
@@ -0,0 +1,132 @@
+/* eslint-disable no-underscore-dangle */
+/* eslint-disable no-param-reassign */
+
+// This little script converts the overflowscrollbars CSS file into the css-in-js file
+// it's normal you have to run prettier over the file after
+
+const fs = require('fs');
+const { parse } = require('css');
+const { isNaN } = require('global');
+
+const INPUT = require.resolve('overlayscrollbars/css/OverlayScrollbars.min.css');
+const OUTPUT = `${__dirname}/../src/ScrollArea/ScrollAreaStyles.ts`;
+const OPTIONS = { camelCase: true, numbers: true };
+
+const read = file => {
+ return fs
+ .readFileSync(file)
+ .toString()
+ .replace(/(?:\r\n|\r|\n)/g, '');
+};
+
+const convert = (css, opts) => {
+ const ast = parse(css, { source: css });
+ const obj = cssToObject(opts)(ast.stylesheet.rules);
+ return obj;
+};
+
+const cssToObject = opts => (rules, result = {}) => {
+ rules.forEach(rule => {
+ if (rule.type === 'media') {
+ const key = `@media ${rule.media}`;
+ const decs = cssToObject(opts)(rule.rules);
+ result[key] = decs;
+ return;
+ }
+ if (rule.type === 'keyframes') {
+ result.__keyframes = Object.assign(result.__keyframes || {}, { [camel(rule.name)]: rule });
+ return;
+ }
+ if (rule.type === 'comment') {
+ return;
+ }
+
+ const key = rule.selectors.filter(s => !s.includes('.os-theme-none')).join(', ');
+
+ if (key.length) {
+ Object.assign(result, {
+ [key]: Object.assign(result[key] || {}, getDeclarations(rule.declarations, opts)),
+ });
+ }
+ });
+ return result;
+};
+
+const getDeclarations = (decs, opts = {}) => {
+ const result = decs
+ .filter(d => {
+ const filtered = d.type === 'comment' || d.property.match(/^(?:-webkit-|-ms-|-moz-)/);
+ return !filtered;
+ })
+ .map(d => ({
+ key: opts.camelCase ? camel(d.property) : d.property,
+ value: opts.numbers ? parsePx(d.value) : d.value,
+ }))
+ .reduce((a, b) => {
+ a[b.key] = b.value;
+ return a;
+ }, {});
+ return result;
+};
+
+const camel = str => str.replace(/(-[a-z])/g, x => x.toUpperCase()).replace(/-/g, '');
+
+const parsePx = val => {
+ return /px$/.test(val) || val === '' || (val.match(/\d$/) && !isNaN(parseInt(val, 10)))
+ ? parseFloat(val.replace(/px$/, ''))
+ : val;
+};
+
+const { __keyframes, ...styles } = convert(read(INPUT), OPTIONS);
+
+const stringifiedKeyFrames = Object.values(__keyframes)
+ .map(k => {
+ return `const ${camel(k.name)} = keyframes\`${k.keyframes.reduce(
+ (acc, item) =>
+ `${acc}${k.position.source.substring(
+ item.position.start.column - 1,
+ item.position.end.column - 1
+ )}`,
+ ''
+ )}\`;`;
+ })
+ .join('\n');
+
+const stringifiedStyles = JSON.stringify(
+ Object.entries(styles).reduce((acc, [key, item]) => {
+ if (item.animationName && __keyframes[camel(item.animationName)]) {
+ item.animationName = camel(item.animationName);
+ }
+
+ if (item.backgroundImage && item.backgroundImage.match(/^url/)) {
+ item.backgroundImage =
+ 'linear-gradient(135deg, rgba(0,0,0,0) 0%, rgba(0,0,0,0) 50%, rgba(0,0,0,0.4) 50%, rgba(0,0,0,0.4) 100%)';
+ }
+
+ acc[key] = item;
+ return acc;
+ }, {}),
+ null,
+ 2
+);
+
+const stringifiedStylesWithReplacedKeyframes = Object.keys(__keyframes)
+ .reduce((acc, item) => {
+ // replace keyframes
+ return acc.replace(`"${item}"`, `\`\${${item}}\``);
+ }, stringifiedStyles)
+ .replace(/"([^\s]+)!important"/g, (f, p1) => {
+ // make "!important" rules work with TS
+ const v = parsePx(p1);
+ return `"${p1}!important" as any as ${JSON.stringify(v)}`;
+ });
+
+const result = `
+ import { Theme, CSSObject, keyframes } from '@storybook/theming';
+
+ ${stringifiedKeyFrames}
+
+ export const getScrollAreaStyles: (theme: Theme) => CSSObject = (theme: Theme) => (${stringifiedStylesWithReplacedKeyframes});
+`;
+
+fs.writeFileSync(OUTPUT, result);
diff --git a/lib/components/src/ScrollArea/ScrollArea.tsx b/lib/components/src/ScrollArea/ScrollArea.tsx
index 04d05f9779d2..e0834fc2f437 100644
--- a/lib/components/src/ScrollArea/ScrollArea.tsx
+++ b/lib/components/src/ScrollArea/ScrollArea.tsx
@@ -1,10 +1,7 @@
-// Storybook's implementation of SimpleBar https://github.com/Grsmto/simplebar
-// Note: "SimpleBar can't be used on the
,