diff --git a/packages/core/patternlab-config.json b/packages/core/patternlab-config.json
index 3169e05af..2571bb52f 100644
--- a/packages/core/patternlab-config.json
+++ b/packages/core/patternlab-config.json
@@ -97,5 +97,7 @@
"excludedPatternStates": [],
"excludedTags": []
}
- ]
+ ],
+ "patternWrapClassesEnable": false,
+ "patternWrapClassesKey": []
}
diff --git a/packages/core/src/lib/compose.js b/packages/core/src/lib/compose.js
index 3b8909b0a..c3494e123 100644
--- a/packages/core/src/lib/compose.js
+++ b/packages/core/src/lib/compose.js
@@ -10,6 +10,7 @@ const render = require('./render');
const uikitExcludePattern = require('./uikitExcludePattern');
const pm = require('./plugin_manager');
const dataMerger = require('./dataMerger');
+const patternWrapClassesChangePatternTemplate = require('./patternWrapClasses');
const pluginManager = new pm();
const Pattern = require('./object_factory').Pattern;
@@ -159,6 +160,7 @@ module.exports = async function (pattern, patternlab) {
const headHTML = intermediateResults[0]; //headPromise
pattern.patternPartialCode = intermediateResults[1]; //patternPartialPromise
const footerPartial = intermediateResults[2]; //footerPartialPromise
+ patternWrapClassesChangePatternTemplate(patternlab, pattern);
//finish up our footer data
let allFooterData;
diff --git a/packages/core/src/lib/patternWrapClasses.js b/packages/core/src/lib/patternWrapClasses.js
new file mode 100644
index 000000000..2810eef6b
--- /dev/null
+++ b/packages/core/src/lib/patternWrapClasses.js
@@ -0,0 +1,45 @@
+/**
+ * get the classes from pattern markdown and/or json
+ * @param {PatternLab} patternlab
+ * @param {Pattern} pattern
+ * @return {string}
+ */
+function getPatternWrapClasses(patternlab, pattern) {
+ const { patternWrapClassesEnable, patternWrapClassesKey } = patternlab.config;
+ if (
+ !patternWrapClassesEnable ||
+ !patternWrapClassesKey ||
+ patternWrapClassesKey.length === 0
+ ) {
+ return '';
+ }
+
+ const classes = [];
+ patternWrapClassesKey.forEach((key) => {
+ const { allMarkdown, jsonFileData } = pattern;
+
+ if (allMarkdown && allMarkdown[key]) {
+ classes.push(allMarkdown[key]);
+ }
+
+ if (jsonFileData && jsonFileData[key]) {
+ classes.push(jsonFileData[key]);
+ }
+ });
+
+ return classes.join(' ');
+}
+
+/**
+ * change pattern template and wrap with classes pattern wrapper
+ * @param {PatternLab} patternlab
+ * @param {Pattern} pattern
+ */
+function patternWrapClassesChangePatternTemplate(patternlab, pattern) {
+ const classes = getPatternWrapClasses(patternlab, pattern);
+ if (classes.length !== 0) {
+ pattern.patternPartialCode = `
${pattern.patternPartialCode}
`;
+ }
+}
+
+module.exports = patternWrapClassesChangePatternTemplate;
diff --git a/packages/core/test/files/_patterns/test/pattern-wrap-class-json.json b/packages/core/test/files/_patterns/test/pattern-wrap-class-json.json
new file mode 100644
index 000000000..1cb2a1d93
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/pattern-wrap-class-json.json
@@ -0,0 +1,3 @@
+{
+ "theme-class": "json-theme-class"
+}
diff --git a/packages/core/test/files/_patterns/test/pattern-wrap-class-json.mustache b/packages/core/test/files/_patterns/test/pattern-wrap-class-json.mustache
new file mode 100644
index 000000000..5716ca598
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/pattern-wrap-class-json.mustache
@@ -0,0 +1 @@
+bar
diff --git a/packages/core/test/files/_patterns/test/pattern-wrap-class-markdown.md b/packages/core/test/files/_patterns/test/pattern-wrap-class-markdown.md
new file mode 100644
index 000000000..358c8a525
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/pattern-wrap-class-markdown.md
@@ -0,0 +1,3 @@
+---
+theme-class: markdown-theme-class
+---
diff --git a/packages/core/test/files/_patterns/test/pattern-wrap-class-markdown.mustache b/packages/core/test/files/_patterns/test/pattern-wrap-class-markdown.mustache
new file mode 100644
index 000000000..5716ca598
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/pattern-wrap-class-markdown.mustache
@@ -0,0 +1 @@
+bar
diff --git a/packages/core/test/patternWrapClasses_tests.js b/packages/core/test/patternWrapClasses_tests.js
new file mode 100644
index 000000000..a00d06dd1
--- /dev/null
+++ b/packages/core/test/patternWrapClasses_tests.js
@@ -0,0 +1,53 @@
+'use strict';
+
+const path = require('path');
+const tap = require('tap');
+
+const loadPattern = require('../src/lib/loadPattern');
+const patternWrapClassesChangePatternTemplate = require('../src/lib/patternWrapClasses');
+const util = require('./util/test_utils.js');
+const patternEngines = require('../src/lib/pattern_engines');
+const config = require('./util/patternlab-config.json');
+
+patternEngines.loadAllEngines(config);
+
+const patterns_dir = `${__dirname}/files/_patterns`;
+
+tap.test('reading pattern wrap class from markdown', function (test) {
+ const patternlab = util.fakePatternLab(patterns_dir);
+ patternlab.config = {
+ ...patternlab.config,
+ patternWrapClassesEnable: true,
+ patternWrapClassesKey: ['theme-class'],
+ };
+
+ const patternPathMarkdown = path.join(
+ 'test',
+ 'pattern-wrap-class-markdown.mustache'
+ );
+ const patternMarkdown = loadPattern(patternPathMarkdown, patternlab);
+ patternWrapClassesChangePatternTemplate(patternlab, patternMarkdown);
+ const patternPartialMarkdown =
+ '';
+
+ test.equal(patternMarkdown.patternPartialCode, patternPartialMarkdown);
+ test.end();
+});
+
+tap.test('reading pattern wrap class from json', function (test) {
+ const patternlab = util.fakePatternLab(patterns_dir);
+ patternlab.config = {
+ ...patternlab.config,
+ patternWrapClassesEnable: true,
+ patternWrapClassesKey: ['theme-class'],
+ };
+
+ const patternPathJson = path.join('test', 'pattern-wrap-class-json.mustache');
+ const patternJson = loadPattern(patternPathJson, patternlab);
+ patternWrapClassesChangePatternTemplate(patternlab, patternJson);
+ const patternPartialJson =
+ '';
+
+ test.equal(patternJson.patternPartialCode, patternPartialJson);
+ test.end();
+});
diff --git a/packages/docs/src/docs/advanced-config-options.md b/packages/docs/src/docs/advanced-config-options.md
index 3804c5b30..7f2b5384c 100644
--- a/packages/docs/src/docs/advanced-config-options.md
+++ b/packages/docs/src/docs/advanced-config-options.md
@@ -210,7 +210,7 @@ For example, to export the navigation, header, and footer, one might do:
## patternMergeVariantArrays
-Used to override the merge behavior of pattern variants. For more information see [The Pseudo-Pattern File Data](docs/using-pseudo-patterns/#heading-the-pseudo-pattern-file-data).
+Used to override the merge behavior of pattern variants. For more information see [The Pseudo-Pattern File Data](/docs/using-pseudo-patterns/#heading-the-pseudo-pattern-file-data).
- `true` will merge arrays of the pattern and pseudo-pattern with [lodash merge](https://lodash.com/docs/4.17.15#merge)
- `false` will override arrays from the pattern with pseudo-patterns arrays
@@ -221,6 +221,29 @@ Used to override the merge behavior of pattern variants. For more information se
**default**: `true` | `undefined`
+## patternWrapClassesEnable
+
+Set to `true` to enable adding a wrapper div with css class(es) around a pattern.
+For more information see [Pattern Wrap Classes](/docs/pattern-wrap-classes/).
+
+```javascript
+"patternWrapClassesEnable": false,
+```
+
+**default**: `false`
+
+## patternWrapClassesKey
+
+Configure your class keys for `"patternWrapClassesEnable": true`.
+For more information see [Pattern Wrap Classes](/docs/pattern-wrap-classes/).
+
+
+```javascript
+"patternWrapClassesKey": ['theme-class'],
+```
+
+**default**: `[]`
+
## renderFlatPatternsOnViewAllPages
Used to activate rendering flat patterns on view all pages and generate view all pages if only flat patterns are available
diff --git a/packages/docs/src/docs/advanced-pattern-wrap-classes.md b/packages/docs/src/docs/advanced-pattern-wrap-classes.md
new file mode 100644
index 000000000..4c89bd010
--- /dev/null
+++ b/packages/docs/src/docs/advanced-pattern-wrap-classes.md
@@ -0,0 +1,105 @@
+---
+title: Pattern Wrap Classes
+tags:
+ - docs
+category: advanced
+eleventyNavigation:
+ title: Pattern Wrap Classes
+ key: advanced
+ order: 300
+sitemapPriority: '0.8'
+---
+
+This feature allows you to add a wrapper div with css class(es) around a pattern when shown in the single preview.
+If it gets included in another pattern, the wrapper is not added.
+
+This comes in handy if you, for example, use theming classes to visualize different backgrounds, colors etc.
+
+## Configuration
+
+Enable this feature with the configuration options
+[patternWrapClassesEnable](/docs/editing-the-configuration-options/#heading-patternwrapclassesenable) and
+[patternWrapClassesKey](/docs/editing-the-configuration-options/#heading-patternwrapclasseskey).
+
+## How does it work?
+
+Patternlab will look for any "data key" added to the `patternWrapClassesKey` array and adds that
+date to the wrapper element classes.
+
+Data key can be set inside the Markdown or JSON file of any pattern.
+
+### Example Config
+
+```json
+"patternWrapClassesKey": ["theme-class"]
+```
+
+## Use in Markdown
+
+Usage [Documenting Patterns](/docs/documenting-patterns/)
+
+### my-pattern.md
+```markdown
+---
+theme-class: my-theme-class
+---
+```
+
+### Result
+```html
+...markup of pattern...
+```
+
+## Use in JSON
+
+Usage [Creating Pattern-specific Values](/docs/creating-pattern-specific-values/)
+
+### my-pattern.json
+```json
+{
+ "theme-class": "my-other-theme-class"
+}
+```
+
+### Result
+```html
+...markup of pattern...
+```
+
+## Pseudo-Patterns
+
+This will work with pseudo-patterns too ([Using Pseudo-Patterns](/docs/using-pseudo-patterns/))
+
+### my-pattern~variant.json
+```json
+{
+ "theme-class": "my-variant-theme-class"
+}
+```
+
+### Result
+```html
+...markup of pattern...
+```
+
+## Multiple entries in "patternWrapClassesKey"
+
+Will result in multiple classes in the wrapper div.
+
+### Example Config
+```json
+"patternWrapClassesKey": ["theme-class", "other-class"]
+```
+
+### my-pattern.json
+```json
+{
+ "theme-class": "theme-class",
+ "other-class": "some-other-class"
+}
+```
+
+### Result
+```html
+...markup of pattern...
+```