diff --git a/.autorc b/.autorc
new file mode 100644
index 000000000..4a0ce55f1
--- /dev/null
+++ b/.autorc
@@ -0,0 +1,11 @@
+{
+ "plugins": [
+ [
+ "released",
+ {
+ "label": "released :rocket:",
+ "message": "%TYPE was released with %VERSION"
+ }
+ ]
+ ]
+}
\ No newline at end of file
diff --git a/.editorconfig b/.editorconfig
index 8951c3929..12280f30a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -9,3 +9,6 @@ end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/.eslintignore b/.eslintignore
new file mode 100644
index 000000000..a5ec49122
--- /dev/null
+++ b/.eslintignore
@@ -0,0 +1,9 @@
+**/node_modules/**
+node_modules
+**/vendor/**
+vendor
+**/test/**
+**/dist/**
+
+// being refactored / removed
+packages/uikit-workshop/src/scripts/components/styleguide.js
diff --git a/.eslintrc.js b/.eslintrc.js
new file mode 100644
index 000000000..826a1702e
--- /dev/null
+++ b/.eslintrc.js
@@ -0,0 +1,86 @@
+module.exports = {
+ root: true,
+ env: {
+ node: true,
+ builtin: true,
+ es6: true,
+ browser: true,
+ },
+ parser: 'babel-eslint',
+ parserOptions: {
+ ecmaVersion: 2018,
+ sourceType: 'module',
+ allowImportExportEverywhere: true,
+ ecmaFeatures: {
+ jsx: true,
+ experimentalDecorators: true,
+ },
+ },
+ globals: {},
+ plugins: ['prettier'],
+ extends: ['eslint-config-prettier'].map(require.resolve),
+ rules: {
+ 'prettier/prettier': 'error',
+ 'block-scoped-var': 0,
+ camelcase: 0,
+ 'consistent-return': 2,
+ curly: [2, 'all'],
+ 'dot-notation': [1, { allowKeywords: true }],
+ eqeqeq: [2, 'allow-null'],
+ 'global-strict': [0, 'never'],
+ 'guard-for-in': 2,
+ 'key-spacing': 0,
+ 'new-cap': 0,
+ 'no-alert': 2,
+ 'no-bitwise': 2,
+ 'no-caller': 2,
+ 'no-cond-assign': [2, 'except-parens'],
+ 'no-debugger': 2,
+ 'no-dupe-args': 2,
+ 'no-dupe-keys': 2,
+ 'no-empty': 2,
+ 'no-eval': 2,
+ 'no-extend-native': 2,
+ 'no-extra-bind': 2,
+ 'no-extra-parens': 0,
+ 'no-func-assign': 2,
+ 'no-implied-eval': 2,
+ 'no-invalid-regexp': 2,
+ 'no-irregular-whitespace': 1,
+ 'no-iterator': 2,
+ 'no-loop-func': 2,
+ 'no-mixed-requires': 0,
+ 'no-multi-str': 2,
+ 'no-native-reassign': 2,
+ 'no-new': 2,
+ 'no-param-reassign': 1,
+ 'no-proto': 2,
+ 'no-redeclare': 0,
+ 'no-script-url': 2,
+ 'no-self-assign': 2,
+ 'no-self-compare': 2,
+ 'no-sequences': 2,
+ 'no-shadow': 2,
+ 'no-undef': 2,
+ 'no-underscore-dangle': 0,
+ 'no-unreachable': 1,
+ 'no-unused-vars': 1,
+ 'no-use-before-define': 1,
+ 'no-useless-call': 2,
+ 'no-useless-concat': 2,
+ 'no-var': 2,
+ 'no-with': 2,
+ quotes: [0, 'single'],
+ radix: 2,
+ strict: 0,
+ 'valid-typeof': 2,
+ 'vars-on-top': 0,
+ 'prefer-const': [
+ 'error',
+ {
+ destructuring: 'any',
+ ignoreReadBeforeAssign: false,
+ },
+ ],
+ },
+};
diff --git a/.eslintrc.json b/.eslintrc.json
deleted file mode 100644
index d5dd0f115..000000000
--- a/.eslintrc.json
+++ /dev/null
@@ -1,78 +0,0 @@
-{
- "env": {
- "node": true,
- "builtin": true,
- "es6": true
- },
- "parserOptions": {
- "ecmaVersion": 6,
- "sourceType": "module"
- },
- "globals": {},
- "extends": ["prettier"],
- "plugins": ["prettier"],
- "rules": {
- "prettier/prettier": "error",
- "block-scoped-var": 0,
- "camelcase": 0,
- "consistent-return": 2,
- "curly": [2, "all"],
- "dot-notation": [1, { "allowKeywords": true }],
- "eqeqeq": [2, "allow-null"],
- "global-strict": [0, "never"],
- "guard-for-in": 2,
- "key-spacing": 0,
- "new-cap": 0,
- "no-alert": 2,
- "no-bitwise": 2,
- "no-caller": 2,
- "no-cond-assign": [2, "except-parens"],
- "no-debugger": 2,
- "no-dupe-args": 2,
- "no-dupe-keys": 2,
- "no-empty": 2,
- "no-eval": 2,
- "no-extend-native": 2,
- "no-extra-bind": 2,
- "no-extra-parens": 0,
- "no-func-assign": 2,
- "no-implied-eval": 2,
- "no-invalid-regexp": 2,
- "no-irregular-whitespace": 1,
- "no-iterator": 2,
- "no-loop-func": 2,
- "no-mixed-requires": 0,
- "no-multi-str": 2,
- "no-native-reassign": 2,
- "no-new": 2,
- "no-param-reassign": 1,
- "no-proto": 2,
- "no-redeclare": 0,
- "no-script-url": 2,
- "no-self-assign": 2,
- "no-self-compare": 2,
- "no-sequences": 2,
- "no-shadow": 2,
- "no-undef": 2,
- "no-underscore-dangle": 0,
- "no-unreachable": 1,
- "no-unused-vars": 1,
- "no-use-before-define": 1,
- "no-useless-call": 2,
- "no-useless-concat": 2,
- "no-var": 2,
- "no-with": 2,
- "quotes": [0, "single"],
- "radix": 2,
- "strict": 0,
- "valid-typeof": 2,
- "vars-on-top": 0,
- "prefer-const": [
- "error",
- {
- "destructuring": "any",
- "ignoreReadBeforeAssign": false
- }
- ]
- }
-}
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..b88ac72a2
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,208 @@
+# Automatically normalize line endings for all text-based files
+# https://git-scm.com/docs/gitattributes#_end_of_line_conversion
+#
+## GITATTRIBUTES FOR WEB PROJECTS
+#
+# These settings are for any web project.
+#
+# Details per file setting:
+# text These files should be normalized (i.e. convert CRLF to LF).
+# binary These files are binary and should be left untouched.
+#
+# Note that binary is a macro for -text -diff.
+######################################################################
+
+## AUTO-DETECT
+## Handle line endings automatically for files detected as
+## text and leave all files detected as binary untouched.
+## This will handle all files NOT defined below.
+* text=auto
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+# For the following file types, normalize line endings to LF on
+# checkin and prevent conversion to CRLF when they are checked out
+# (this is required in order to prevent newline related issues like,
+# for example, after the build script is run)
+
+.* text eol=lf
+*.css text eol=lf
+*.html text eol=lf
+*.js text eol=lf
+*.json text eol=lf
+*.md text eol=lf
+*.sh text eol=lf
+*.txt text eol=lf
+*.xml text eol=lf
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+## SOURCE CODE
+*.bat text eol=crlf
+*.coffee text
+*.htm text
+*.inc text
+*.ini text
+*.jsx text
+*.less text
+*.od text
+*.onlydata text
+*.php text
+*.pl text
+*.py text
+*.rb text
+*.sass text
+*.scm text
+*.scss text
+*.sql text
+*.styl text
+*.tag text
+*.ts text
+*.tsx text
+*.xhtml text
+
+## DOCKER
+*.dockerignore text
+Dockerfile text
+
+## DOCUMENTATION
+*.markdown text
+*.mdwn text
+*.mdown text
+*.mkd text
+*.mkdn text
+*.mdtxt text
+*.mdtext text
+AUTHORS text
+CHANGELOG text
+CHANGES text
+CONTRIBUTING text
+COPYING text
+copyright text
+*COPYRIGHT* text
+INSTALL text
+license text
+LICENSE text
+NEWS text
+readme text
+*README* text
+TODO text
+
+## TEMPLATES
+*.dot text
+*.ejs text
+*.haml text
+*.handlebars text
+*.hbs text
+*.hbt text
+*.jade text
+*.latte text
+*.mustache text
+*.njk text
+*.phtml text
+*.tmpl text
+*.tpl text
+*.twig text
+
+## LINTERS
+.babelrc text
+.csslintrc text
+.eslintrc text
+.htmlhintrc text
+.jscsrc text
+.jshintrc text
+.jshintignore text
+.prettierrc text
+.stylelintrc text
+
+## CONFIGS
+*.bowerrc text
+*.cnf text
+*.conf text
+*.config text
+.browserslistrc text
+.editorconfig text
+.gitattributes text
+.gitconfig text
+.gitignore text
+.htaccess text
+*.npmignore text
+*.yaml text
+*.yml text
+browserslist text
+Makefile text
+makefile text
+
+## HEROKU
+Procfile text
+.slugignore text
+
+## GRAPHICS
+*.ai binary
+*.bmp binary
+*.eps binary
+*.gif binary
+*.ico binary
+*.jng binary
+*.jp2 binary
+*.jpg binary
+*.jpeg binary
+*.jpx binary
+*.jxr binary
+*.pdf binary
+*.png binary
+*.psb binary
+*.psd binary
+*.svg text
+*.svgz binary
+*.tif binary
+*.tiff binary
+*.wbmp binary
+*.webp binary
+
+## AUDIO
+*.kar binary
+*.m4a binary
+*.mid binary
+*.midi binary
+*.mp3 binary
+*.ogg binary
+*.ra binary
+
+## VIDEO
+*.3gpp binary
+*.3gp binary
+*.as binary
+*.asf binary
+*.asx binary
+*.fla binary
+*.flv binary
+*.m4v binary
+*.mng binary
+*.mov binary
+*.mp4 binary
+*.mpeg binary
+*.mpg binary
+*.ogv binary
+*.swc binary
+*.swf binary
+*.webm binary
+
+## ARCHIVES
+*.7z binary
+*.gz binary
+*.jar binary
+*.rar binary
+*.tar binary
+*.zip binary
+
+## FONTS
+*.ttf binary
+*.eot binary
+*.otf binary
+*.woff binary
+*.woff2 binary
+
+## EXECUTABLES
+*.exe binary
+*.pyc binary
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 477f273af..fef054cce 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -2,7 +2,7 @@
If you'd like to contribute to Pattern Lab Node, please do so! There is always a lot of ground to cover and something for your wheelhouse.
-No pull request is too small. Check out any [help wanted 🆘](https://github.com/pattern-lab/patternlab-node/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted+%3Asos%3A%22) or [good first issues 🎓](https://github.com/pattern-lab/patternlab-node/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue+%3Amortar_board%3A%22)as a good way to get your feet wet, or add some more unit tests.
+No pull request is too small. Check out any [help wanted 🆘](https://github.com/pattern-lab/patternlab-node/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted+%3Asos%3A%22) or [good first issues 🎓](https://github.com/pattern-lab/patternlab-node/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue+%3Amortar_board%3A%22) as a good way to get your feet wet, or add some more unit tests.
## Prerequisites
@@ -18,7 +18,7 @@ nvm use <>
The best way to make changes to the Pattern Lab Node core and test them is through an edition.
* Fork this repository on Github.
-* `npm install && npm run bootstrap`
+* `yarn install && yarn run bootstrap`
* Create a new branch in your fork and push your changes in that fork.
* `cd packages/edition-node`
* Test your changes with the edition's api
@@ -28,15 +28,16 @@ The best way to make changes to the Pattern Lab Node core and test them is throu
To ensure that developers can bootstrap the repo from a fresh clone, do this in your working copy:
```sh
-git reset --hard && git clean -dfx && npm install && npm run bootstrap
+git reset --hard && git clean -dfx && yarn install && yarn run bootstrap
```
This ensures that any changes you've made will still result in a clean and functional developer experience. **Note**: be sure you've committed any outstanding work before doing this -- it will blow away whatever's still outstanding, including anything staged but not commited.
## Guidelines
-* _ALWAYS_ submit pull requests against the [dev branch](https://github.com/pattern-lab/patternlab-node/tree/dev). If this does not occur, I will first, try to redirect you gently, second, attempt to redirect the target branch myself, thirdly, port over your contribution manually if time allows, and/or lastly, close your pull request. If you have a major feature to stabilize over time, talk to @bmuenzenmeyer via an issue about making a dedicated `feature-branch`
+* _ALWAYS_ submit pull requests against the [dev branch](https://github.com/pattern-lab/patternlab-node/tree/dev). If this does not occur, we will first, try to redirect you gently, second, attempt to redirect the target branch myself, thirdly, port over your contribution manually if time allows, and/or lastly, close your pull request. If you have a major feature to stabilize over time, ping @pattern-lab/trusted-committers via an issue about making a dedicated `feature-branch`
* Keep your pull requests concise and limited to **ONE** substantive change at a time. This makes reviewing and testing so much easier.
+* If it takes you considerable time to finish your work, submit a [draft pull request](https://github.blog/2019-02-14-introducing-draft-pull-requests/). This is Github's way to indicate work in progress but allows for feedback.
* Commits should reference the issue you are adressing. For any Pull Request that you send, use the template provided.
* Commits are best formatted using the [conventional commits pattern](https://conventionalcommits.org/).
* If you can, add some unit tests using the existing patterns in the `.packages/core/test` directory
@@ -47,13 +48,13 @@ This ensures that any changes you've made will still result in a clean and funct
## Coding style
-Formatting is automated via [Prettier](https://prettier.io/), setup to run on precommit. We suggest [editor integration](https://prettier.io/docs/en/editors.html) for this and for eslint. Prettier is further configured within `.prettierrc`. Eslint validates syntax and usage that Prettier doesn't handle. Configuration for both is found within the `.eslintrc.json` file.
+Formatting is automated via [Prettier](https://prettier.io/), setup to run on precommit. We suggest [editor integration](https://prettier.io/docs/en/editors.html) for this and for eslint. Prettier is further configured within `.prettierrc`. Eslint validates syntax and usage that Prettier doesn't handle. Configuration for both is found within the `.eslintrc.js` file.
-The `.editorconfig` controls spaces / tabs within supported editors. Check out their [site](http://editorconfig.org/).
+The `.editorconfig` controls spaces / tabs within supported editors. Check out their [site](https://editorconfig.org/).
## Tests
-Add unit and integration tests if you can. It's always nice if our code coverage improves bit by bit (literally!). We are using [Node Tap](http://www.node-tap.org/) as test framework and [Rewire](https://github.com/jhnns/rewire) for mocking things like file system access.
+Add unit and integration tests if you can. It's always nice if our code coverage improves bit by bit (literally!). We are using [Node Tap](https://node-tap.org/) as test framework and [Rewire](https://github.com/jhnns/rewire) for mocking things like file system access.
## Branching Scheme
diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
index 9e5ad2464..be5b0bd4c 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE.md
@@ -1,6 +1,8 @@
-
+
+
+
I am using Pattern Lab Node `vX.X.X` on `Windows | Mac | Linux`, with Node `vX.X.X`, using a `Gulp | Grunt | Vanilla | Custom` Edition.
diff --git a/.github/gitgraph/README.md b/.github/gitgraph/README.md
index 02cc14ca4..fda47c7b9 100644
--- a/.github/gitgraph/README.md
+++ b/.github/gitgraph/README.md
@@ -1,8 +1,8 @@
Generating a new graph
======================
-This folder uses http://gitgraphjs.com/ for generating the git graph model.
+This folder uses https://www.nicoespeon.com/gitgraph.js for generating the git graph model.
-1. Change `patternlab-flow.js` to your needs according to the documentation on http://gitgraphjs.com/
+1. Change `patternlab-flow.js` to your needs according to the documentation on https://www.nicoespeon.com/gitgraph.js
2. Open branching-scheme.html in browse, right click the graph and "Save as...".
3. Overwrite `/.github/branching-scheme.png`
diff --git a/.github/gitgraph/branching-scheme.html b/.github/gitgraph/branching-scheme.html
index 32d2ffb80..2af1dbf13 100644
--- a/.github/gitgraph/branching-scheme.html
+++ b/.github/gitgraph/branching-scheme.html
@@ -1,17 +1,26 @@
-
-
-
-
-
-
-
-
-
-
-
+
+
+ Branching scheme
+
+
+
+
+
+
+
+
+
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
new file mode 100644
index 000000000..637f28bce
--- /dev/null
+++ b/.github/workflows/codeql-analysis.yml
@@ -0,0 +1,67 @@
+# For most projects, this workflow file will not need changing; you simply need
+# to commit it to your repository.
+#
+# You may wish to alter this file to override the set of languages analyzed,
+# or to provide custom queries or build logic.
+#
+# ******** NOTE ********
+# We have attempted to detect the languages in your repository. Please check
+# the `language` matrix defined below to confirm you have the correct set of
+# supported CodeQL languages.
+#
+name: 'CodeQL'
+
+on:
+ push:
+ branches: [dev, master]
+ pull_request:
+ # The branches below must be a subset of the branches above
+ branches: [dev]
+ schedule:
+ - cron: '0 18 1 * *'
+
+jobs:
+ analyze:
+ name: Analyze
+ runs-on: ubuntu-latest
+
+ strategy:
+ fail-fast: false
+ matrix:
+ language: ['javascript']
+ # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
+ # Learn more:
+ # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
+
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v3
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v2
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
+
+ # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
+ # If this step fails, then you should remove it and run the build manually (see below)
+ - name: Autobuild
+ uses: github/codeql-action/autobuild@v2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
+
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v2
diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml
new file mode 100644
index 000000000..12752d1c8
--- /dev/null
+++ b/.github/workflows/continuous-integration.yml
@@ -0,0 +1,28 @@
+name: Continuous Integration
+on: [push, pull_request]
+
+jobs:
+ build:
+ name: Build & Test
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out the source code
+ uses: actions/checkout@v3
+
+ - name: Set up NodeJS
+ uses: actions/setup-node@v3
+ with:
+ node-version: '16'
+
+ - name: Setup the project
+ run: |
+ yarn run setup
+ npx lerna add @pattern-lab/engine-mustache --scope=@pattern-lab/core
+ npx lerna add @pattern-lab/engine-handlebars --scope=@pattern-lab/core
+ npx lerna add @pattern-lab/engine-underscore --scope=@pattern-lab/core
+ npx lerna add @pattern-lab/engine-liquid --scope=@pattern-lab/core
+ npx lerna add @pattern-lab/engine-twig --scope=@pattern-lab/core
+ npx lerna add @pattern-lab/engine-react --scope=@pattern-lab/core
+
+ - name: Run Unit Tests
+ run: yarn run test
diff --git a/.gitignore b/.gitignore
index 74ad6c9b4..fd845fc5a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,11 +3,14 @@ pattern_exports/
.DS_Store
Thumbs.db
.nyc_output/
-.vscode/
.idea/
+.env
packages/core/test/public
packages/*/public
!packages/core/test/patterns/public/.gitkeep
!packages/core/test/patterns/testDependencyGraph.json
lerna-debug.log
packages/edition-node-gulp/dependencyGraph.json
+packages/uikit-workshop/dist
+
+yarn-error.log
diff --git a/.husky/pre-commit b/.husky/pre-commit
new file mode 100755
index 000000000..f91359dc2
--- /dev/null
+++ b/.husky/pre-commit
@@ -0,0 +1,4 @@
+#!/bin/sh
+. "$(dirname "$0")/_/husky.sh"
+
+npx --no-install pretty-quick --staged
diff --git a/.nvmrc b/.nvmrc
index a13e7b9c8..59ea99ee6 100644
--- a/.nvmrc
+++ b/.nvmrc
@@ -1 +1 @@
-10.0.0
+16.20
diff --git a/.prettierignore b/.prettierignore
index f25d454d3..bdfdbff8b 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -9,7 +9,9 @@ packages/core/scripts/api.handlebars
packages/core/scripts/events.handlebars
packages/core/test/files/annotations.js
packages/**/annotations.js
-**/uikit-workshop/src/js/**/*
*.json
*.md
-*.scss
+**/reset.scss
+**/_meta/_head.*
+**/_meta/_foot.*
+**/development-edition*/source/_patterns/**
diff --git a/.prettierrc b/.prettierrc
index c1a6f6671..3baced411 100644
--- a/.prettierrc
+++ b/.prettierrc
@@ -1,4 +1,4 @@
{
"singleQuote": true,
- "trailingComma": "es5"
+ "endOfLine": "auto"
}
diff --git a/.travis.yml b/.travis.yml
index e019fca93..3fb4c3593 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,17 +1,24 @@
language: node_js
+addons:
+ chrome: stable
+
before_install:
- - phantomjs --version
+ # version lifted from `.nvmrc`
+ - nvm install
+ - curl -o- -L https://yarnpkg.com/install.sh | bash -s -- --version 1.19.0
+ - export PATH="$HOME/.yarn/bin:$PATH"
before_script:
- - npm install -g lerna@3.2.1
- - npm run setup
- - lerna add @pattern-lab/engine-mustache --scope=@pattern-lab/core
- - lerna add @pattern-lab/engine-handlebars --scope=@pattern-lab/core
- - lerna add @pattern-lab/engine-underscore --scope=@pattern-lab/core
- - lerna add @pattern-lab/engine-liquid --scope=@pattern-lab/core
- - lerna add @pattern-lab/engine-twig --scope=@pattern-lab/core
- - lerna add @pattern-lab/engine-react --scope=@pattern-lab/core
+ - yarn run setup
+ - npx lerna add @pattern-lab/engine-mustache --scope=@pattern-lab/core
+ - npx lerna add @pattern-lab/engine-handlebars --scope=@pattern-lab/core
+ - npx lerna add @pattern-lab/engine-underscore --scope=@pattern-lab/core
+ - npx lerna add @pattern-lab/engine-liquid --scope=@pattern-lab/core
+ - npx lerna add @pattern-lab/engine-twig --scope=@pattern-lab/core
+ - npx lerna add @pattern-lab/engine-react --scope=@pattern-lab/core
+
+script: travis_wait yarn run test
branches:
only:
diff --git a/.vscode/extensions.adoc b/.vscode/extensions.adoc
new file mode 100644
index 000000000..a49aa22e9
--- /dev/null
+++ b/.vscode/extensions.adoc
@@ -0,0 +1,10 @@
+= Extensions configuration
+
+See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
+Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
+
+List of extensions which should be recommended for users of this workspace:
+`"recommendations"``
+
+List of extensions recommended by VS Code that should not be recommended for users of this workspace:
+`"unwantedRecommendations"``
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 000000000..6d97db0dc
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": ["editorconfig.editorconfig", "henrynguyen5-vsc.vsc-nvm"]
+}
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 000000000..52f197a05
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,812 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+
+### Features
+
+* **engine-twig-php:** update @basalt/twig-renderer to v3.0.1 using Twig v3.7.1 ([#1499](https://github.com/pattern-lab/patternlab-node/issues/1499)) ([2e5c9e1](https://github.com/pattern-lab/patternlab-node/commit/2e5c9e1c6a3318ba1cd3765d448c181e4a3a9a27)), closes [#1496](https://github.com/pattern-lab/patternlab-node/issues/1496) [#1496](https://github.com/pattern-lab/patternlab-node/issues/1496)
+
+
+
+
+
+## [6.0.3](https://github.com/pattern-lab/patternlab-node/compare/v6.0.2...v6.0.3) (2023-03-12)
+
+
+### Bug Fixes
+
+* subitems menu height restricted only for horizontal mode ([#1492](https://github.com/pattern-lab/patternlab-node/issues/1492)) ([e65f294](https://github.com/pattern-lab/patternlab-node/commit/e65f294d9cbf032fd7fd03d9f957500949db5440))
+
+
+
+
+
+## [6.0.2](https://github.com/pattern-lab/patternlab-node/compare/v6.0.1...v6.0.2) (2023-02-26)
+
+
+### Bug Fixes
+
+* **starterkit-twig-demo:** pages not rendering pattern-specific data from json ([#1490](https://github.com/pattern-lab/patternlab-node/issues/1490)) ([1c878df](https://github.com/pattern-lab/patternlab-node/commit/1c878dfa35d549f23e199b3e235ff79cb471ac86)), closes [#1486](https://github.com/pattern-lab/patternlab-node/issues/1486)
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+
+### Bug Fixes
+
+* **twig engine:** startup and running problems ([#1478](https://github.com/pattern-lab/patternlab-node/issues/1478)) ([e5a1904](https://github.com/pattern-lab/patternlab-node/commit/e5a19049f083315939406677b1c0480f4b420569))
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+
+### Bug Fixes
+
+* **engine-twig-php:** twig include function syntax not matched by findPartials ([#1472](https://github.com/pattern-lab/patternlab-node/issues/1472)) ([3677539](https://github.com/pattern-lab/patternlab-node/commit/3677539409ac41dfee71d90cc429be5c92890838)), closes [#1471](https://github.com/pattern-lab/patternlab-node/issues/1471)
+* **engine-twig:** twig include function syntax not matched by findPartials ([#1473](https://github.com/pattern-lab/patternlab-node/issues/1473)) ([cfa792b](https://github.com/pattern-lab/patternlab-node/commit/cfa792b2753d9f9f1840e08d55983c6c051b01fd)), closes [#1471](https://github.com/pattern-lab/patternlab-node/issues/1471)
+* hogan to handlebars migration leftovers ([#1461](https://github.com/pattern-lab/patternlab-node/issues/1461)) ([566485a](https://github.com/pattern-lab/patternlab-node/commit/566485a5c20d739bfe9c77c11b8ddfa09e292481))
+* HTML structure ([#1450](https://github.com/pattern-lab/patternlab-node/issues/1450)) ([8567e2b](https://github.com/pattern-lab/patternlab-node/commit/8567e2b218a4ef9df0e359ca77229dda54712200))
+* js error ([#1475](https://github.com/pattern-lab/patternlab-node/issues/1475)) ([209b9a1](https://github.com/pattern-lab/patternlab-node/commit/209b9a15871354ac4ae982d93d6be03272799005)), closes [/github.com/pattern-lab/patternlab-node/pull/1102/files#diff-9111c2e0138c935342632437be7178f25322b8f5c86431f2b85f4fe760d32980L96-R111](https://github.com//github.com/pattern-lab/patternlab-node/pull/1102/files/issues/diff-9111c2e0138c935342632437be7178f25322b8f5c86431f2b85f4fe760d32980L96-R111)
+* updated base template to handlebars ([#1463](https://github.com/pattern-lab/patternlab-node/issues/1463)) ([c69c658](https://github.com/pattern-lab/patternlab-node/commit/c69c658d06dab9a1bf04f77e7902ff3f07c94c3e))
+
+
+### Features
+
+* activate prettier for scss ([#1468](https://github.com/pattern-lab/patternlab-node/issues/1468)) ([fac6ad4](https://github.com/pattern-lab/patternlab-node/commit/fac6ad4be48c95eccfe890a280cad441ee84f677))
+* **docs:** added plugin ([#1469](https://github.com/pattern-lab/patternlab-node/issues/1469)) ([535c5f0](https://github.com/pattern-lab/patternlab-node/commit/535c5f0805936a25eeddde0e360cb6000c000b1b))
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+
+### Features
+
+* **engine-twig:** add custom twing extensions ([#1435](https://github.com/pattern-lab/patternlab-node/issues/1435)) ([c32a45c](https://github.com/pattern-lab/patternlab-node/commit/c32a45c02e3b71bb841e7ea15cae000a68857df3)), closes [#1230](https://github.com/pattern-lab/patternlab-node/issues/1230) [#1230](https://github.com/pattern-lab/patternlab-node/issues/1230)
+* integrate @hadl/patternlab-plugin-pattern-wrap into core ([#1433](https://github.com/pattern-lab/patternlab-node/issues/1433)) ([414e038](https://github.com/pattern-lab/patternlab-node/commit/414e0383732b4bc4682981000908d1e0d1292703)), closes [#1432](https://github.com/pattern-lab/patternlab-node/issues/1432) [#1432](https://github.com/pattern-lab/patternlab-node/issues/1432)
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+
+### Bug Fixes
+
+* code scanning alert ([#1442](https://github.com/pattern-lab/patternlab-node/issues/1442)) ([749a3e7](https://github.com/pattern-lab/patternlab-node/commit/749a3e722249846c522e3f7de6e73b5afa8531b1))
+* div isn't allowed in button elements ([#1438](https://github.com/pattern-lab/patternlab-node/issues/1438)) ([e5c6950](https://github.com/pattern-lab/patternlab-node/commit/e5c6950e6218df99f9d9d35388c36a0130236f28))
+* twig logo is rendered as "NaN" ([#1434](https://github.com/pattern-lab/patternlab-node/issues/1434)) ([ab6b133](https://github.com/pattern-lab/patternlab-node/commit/ab6b133019d9dfa3816e8fc9a9caa7b547e19097)), closes [#1407](https://github.com/pattern-lab/patternlab-node/issues/1407)
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+
+### Bug Fixes
+
+* transformed asset types is ignored ([#1426](https://github.com/pattern-lab/patternlab-node/issues/1426)) ([8cbe189](https://github.com/pattern-lab/patternlab-node/commit/8cbe189d45afaa753ce6de41bdd9de1596e074f3)), closes [#1339](https://github.com/pattern-lab/patternlab-node/issues/1339)
+
+
+### Features
+
+* remove sandbox attribute from iframe ([#1422](https://github.com/pattern-lab/patternlab-node/issues/1422)) ([4335660](https://github.com/pattern-lab/patternlab-node/commit/4335660bac6f87618baaef9d773e00d7e80c6eec))
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package patternlab-node-main
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+
+### Bug Fixes
+
+* **annotations:** displaying annotation tooltips correctly ([#1406](https://github.com/pattern-lab/patternlab-node/issues/1406)) ([3f33ce5](https://github.com/pattern-lab/patternlab-node/commit/3f33ce5c51f2f7a6afd86d3500b7659afd0198e6)), closes [#2](https://github.com/pattern-lab/patternlab-node/issues/2) [#1](https://github.com/pattern-lab/patternlab-node/issues/1)
+* **annotations:** hiding those correctly ([#1415](https://github.com/pattern-lab/patternlab-node/issues/1415)) ([ef0a60f](https://github.com/pattern-lab/patternlab-node/commit/ef0a60fcc8656acc6d83bb0723c02a658f7ff1f3))
+
+
+
+
+
+## [5.15.7](https://github.com/pattern-lab/patternlab-node/compare/v5.15.6...v5.15.7) (2021-12-07)
+
+**Note:** Version bump only for package patternlab-node-main
+
+
+
+
+
+## [5.15.6](https://github.com/pattern-lab/patternlab-node/compare/v5.15.5...v5.15.6) (2021-12-07)
+
+**Note:** Version bump only for package patternlab-node-main
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+
+### Bug Fixes
+
+* corrected some github urls ([#1388](https://github.com/pattern-lab/patternlab-node/issues/1388)) ([7f37e9d](https://github.com/pattern-lab/patternlab-node/commit/7f37e9d56b553dc4be53590766c0fc6251458829))
+
+
+### Features
+
+* define initial viewport ([#1386](https://github.com/pattern-lab/patternlab-node/issues/1386)) ([6fa630e](https://github.com/pattern-lab/patternlab-node/commit/6fa630e2353ed68295550e59c31148269f3b7cd0))
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+
+### Bug Fixes
+
+* corrected some github urls ([#1388](https://github.com/pattern-lab/patternlab-node/issues/1388)) ([7f37e9d](https://github.com/pattern-lab/patternlab-node/commit/7f37e9d56b553dc4be53590766c0fc6251458829))
+
+
+### Features
+
+* define initial viewport ([#1386](https://github.com/pattern-lab/patternlab-node/issues/1386)) ([6fa630e](https://github.com/pattern-lab/patternlab-node/commit/6fa630e2353ed68295550e59c31148269f3b7cd0))
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/patternlab-node/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+
+### Bug Fixes
+
+* **docs:** tiles z-index to not overlay the menu anymore ([#1370](https://github.com/pattern-lab/patternlab-node/issues/1370)) ([384dc89](https://github.com/pattern-lab/patternlab-node/commit/384dc8900ee5768f5a260fd00fe03d11ae047484))
+* **handlebars-demo:** move and modify the icon files ([#1377](https://github.com/pattern-lab/patternlab-node/issues/1377)) ([7c66f8a](https://github.com/pattern-lab/patternlab-node/commit/7c66f8ad4cd15e0a814f9808d0fbca727903aeb5))
+
+
+### Features
+
+* **vs-code:** added recommendations ([#1375](https://github.com/pattern-lab/patternlab-node/issues/1375)) ([cfa74c0](https://github.com/pattern-lab/patternlab-node/commit/cfa74c0d09c3aae78ef10654f48749a568f3e30d))
+* ensure consistent line endings across files ([#1372](https://github.com/pattern-lab/patternlab-node/issues/1372)) ([57efccb](https://github.com/pattern-lab/patternlab-node/commit/57efccb895f142d8a18e774d7b7c01b2f1266737))
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+
+### Bug Fixes
+
+* **core:** Subgroup cannot be hidden ([#1368](https://github.com/pattern-lab/patternlab-node/issues/1368)) ([3ce13ab](https://github.com/pattern-lab/patternlab-node/commit/3ce13abffaab2810194003aeca88be671fedd38f))
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+
+### Bug Fixes
+
+* **docs:** use "UIKits" instead of "StyleguideKits" ([#1345](https://github.com/pattern-lab/patternlab-node/issues/1345)) ([a2885ea](https://github.com/pattern-lab/patternlab-node/commit/a2885ea738c2d807dd99c6749ac6e6437d8d3e7e))
+* **initialize:** updating no-emit-webpack-plugin dependency [#1348](https://github.com/pattern-lab/patternlab-node/issues/1348) ([#1349](https://github.com/pattern-lab/patternlab-node/issues/1349)) ([a884897](https://github.com/pattern-lab/patternlab-node/commit/a884897cf9f98b61c9bdd20acf7e079de0782f10))
+* **node16:** prevent warning on installation process ([#1352](https://github.com/pattern-lab/patternlab-node/issues/1352)) ([d58e4c6](https://github.com/pattern-lab/patternlab-node/commit/d58e4c6f2979f5e0bba9a14e17e0dbc4afc64f75))
+
+
+### Features
+
+* added https description to the docs ([#1355](https://github.com/pattern-lab/patternlab-node/issues/1355)) ([4118f74](https://github.com/pattern-lab/patternlab-node/commit/4118f740810842b16cf86b9ee28bda2a623aa9c7))
+
+
+### Reverts
+
+* Revert "refactor: optimized engines directory retrieval (#1359)" (#1363) ([a275d36](https://github.com/pattern-lab/patternlab-node/commit/a275d36c50c3846fc51c78baf6e11dba5309f5dc)), closes [#1359](https://github.com/pattern-lab/patternlab-node/issues/1359) [#1363](https://github.com/pattern-lab/patternlab-node/issues/1363)
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+
+### Bug Fixes
+
+* **live-server:** testing ([#1331](https://github.com/pattern-lab/patternlab-node/issues/1331)) ([2b2e1b1](https://github.com/pattern-lab/patternlab-node/commit/2b2e1b1c2426ab578dc014ea99df520d17a7db92))
+
+
+### Features
+
+* **docs:** adding a sitemap.xml ([#1329](https://github.com/pattern-lab/patternlab-node/issues/1329)) ([0a7fd95](https://github.com/pattern-lab/patternlab-node/commit/0a7fd95d5f1c3ce690bbe89cc30580ff58d1ab9c))
+* **documentation:** added (sub)groups documentation again [#1262](https://github.com/pattern-lab/patternlab-node/issues/1262) ([#1334](https://github.com/pattern-lab/patternlab-node/issues/1334)) ([9fac269](https://github.com/pattern-lab/patternlab-node/commit/9fac2699d2f6c64c4544e8e4d8e18c1a1ce7e49f))
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+
+### Bug Fixes
+
+* **pseudopatterns:** use the template instead of the pseudo data file for template rendering [#1308](https://github.com/pattern-lab/patternlab-node/issues/1308) ([#1312](https://github.com/pattern-lab/patternlab-node/issues/1312)) ([7ecca69](https://github.com/pattern-lab/patternlab-node/commit/7ecca69bcfed4060d17390b76562e5f468b4a897))
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+
+### Bug Fixes
+
+* **core:** ReadDocumentation throw error on older node versions ([#1295](https://github.com/pattern-lab/patternlab-node/issues/1295)) ([399d0e1](https://github.com/pattern-lab/patternlab-node/commit/399d0e118ab77a414a926b078da9abbcb5347969))
+* **twig:** starter-kit-twig urls are incorrect on npm ([#1297](https://github.com/pattern-lab/patternlab-node/issues/1297)) ([4256d6b](https://github.com/pattern-lab/patternlab-node/commit/4256d6b13f9c2cfadf7620b0cb744cf71c3257f5))
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+
+### Bug Fixes
+
+* **demopage:** switched to HTTPS URLs for image placeholders ([#1289](https://github.com/pattern-lab/patternlab-node/issues/1289)) ([e09bf6a](https://github.com/pattern-lab/patternlab-node/commit/e09bf6aae9bad99365b5a01381e0df6de9ddeafe))
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package patternlab-node
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package patternlab-node-main
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package patternlab-node-main
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package patternlab-node-main
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package patternlab-node-main
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package patternlab-node
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+
+### Bug Fixes
+
+* update Viewport Size toggle to better handle async-loaded ishControl data + prevent rendering errors ([b937706](https://github.com/pattern-lab/patternlab-node/commit/b93770669c6f723128ba68e522c9398cc1d2d70c))
+* update Webpack config to point to the patched version of preact-dom ([d3660b7](https://github.com/pattern-lab/patternlab-node/commit/d3660b78bc0a74c52ed85b69b023c612b789c318))
+* update yarn.lock ([dca1948](https://github.com/pattern-lab/patternlab-node/commit/dca19489b85f715de3ade2294fa49df89b8bb59f))
+* visually hide NavToggle icon text; fix for visual regression after merging down https://github.com/pattern-lab/patternlab-node/pull/1227 ([3a2ad9f](https://github.com/pattern-lab/patternlab-node/commit/3a2ad9f12d83b6d21dcca62e89d944a6a46342f6))
+* **docs:** corrected a URL ([26ede14](https://github.com/pattern-lab/patternlab-node/commit/26ede14a6eafe8649cbc6b0076d84f1d323c3e20))
+* **docs:** fixed css code for custom patternstates color ([8995241](https://github.com/pattern-lab/patternlab-node/commit/89952416162c01d1e3e05221ce58a7755544131c)), closes [#1216](https://github.com/pattern-lab/patternlab-node/issues/1216)
+* **docs:** headlines styling breaks in edge cases [#1158](https://github.com/pattern-lab/patternlab-node/issues/1158) ([d8244a2](https://github.com/pattern-lab/patternlab-node/commit/d8244a2d307b0a81d0846491f8c5a12e0ae167a5))
+* **patternflyouts:** preventing horizontal scrollbar in pattern flyouts in Edge 18 [#1124](https://github.com/pattern-lab/patternlab-node/issues/1124) ([63300bc](https://github.com/pattern-lab/patternlab-node/commit/63300bc00ee797e38bfdb73fdc7694c188a423dc))
+* **patternstate:** added css color for pattern state "inprogress" [#1216](https://github.com/pattern-lab/patternlab-node/issues/1216) ([856bcda](https://github.com/pattern-lab/patternlab-node/commit/856bcda150239928bb5e8719246b97e9fa366468))
+* **resetcss:** selector in uikit-workshop [#1109](https://github.com/pattern-lab/patternlab-node/issues/1109) ([6893b7c](https://github.com/pattern-lab/patternlab-node/commit/6893b7cb5478309d4fdab0121edba3921718bd69))
+* enable partial build via option ([8aaa533](https://github.com/pattern-lab/patternlab-node/commit/8aaa53398563ade14123c481bf509f9ee0c768f5))
+* enable partial build via option ([4b9dbf9](https://github.com/pattern-lab/patternlab-node/commit/4b9dbf9095bfb8bfd2360b310dd7395dbfe3cf98))
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+
+### Bug Fixes
+
+* update Viewport Size toggle to better handle async-loaded ishControl data + prevent rendering errors ([b937706](https://github.com/pattern-lab/patternlab-node/commit/b93770669c6f723128ba68e522c9398cc1d2d70c))
+* update Webpack config to point to the patched version of preact-dom ([d3660b7](https://github.com/pattern-lab/patternlab-node/commit/d3660b78bc0a74c52ed85b69b023c612b789c318))
+* visually hide NavToggle icon text; fix for visual regression after merging down https://github.com/pattern-lab/patternlab-node/pull/1227 ([3a2ad9f](https://github.com/pattern-lab/patternlab-node/commit/3a2ad9f12d83b6d21dcca62e89d944a6a46342f6))
+* **docs:** corrected a URL ([26ede14](https://github.com/pattern-lab/patternlab-node/commit/26ede14a6eafe8649cbc6b0076d84f1d323c3e20))
+* **docs:** fixed css code for custom patternstates color ([8995241](https://github.com/pattern-lab/patternlab-node/commit/89952416162c01d1e3e05221ce58a7755544131c)), closes [#1216](https://github.com/pattern-lab/patternlab-node/issues/1216)
+* **docs:** headlines styling breaks in edge cases [#1158](https://github.com/pattern-lab/patternlab-node/issues/1158) ([d8244a2](https://github.com/pattern-lab/patternlab-node/commit/d8244a2d307b0a81d0846491f8c5a12e0ae167a5))
+* **patternflyouts:** preventing horizontal scrollbar in pattern flyouts in Edge 18 [#1124](https://github.com/pattern-lab/patternlab-node/issues/1124) ([63300bc](https://github.com/pattern-lab/patternlab-node/commit/63300bc00ee797e38bfdb73fdc7694c188a423dc))
+* **patternstate:** added css color for pattern state "inprogress" [#1216](https://github.com/pattern-lab/patternlab-node/issues/1216) ([856bcda](https://github.com/pattern-lab/patternlab-node/commit/856bcda150239928bb5e8719246b97e9fa366468))
+* **resetcss:** selector in uikit-workshop [#1109](https://github.com/pattern-lab/patternlab-node/issues/1109) ([6893b7c](https://github.com/pattern-lab/patternlab-node/commit/6893b7cb5478309d4fdab0121edba3921718bd69))
+* enable partial build via option ([8aaa533](https://github.com/pattern-lab/patternlab-node/commit/8aaa53398563ade14123c481bf509f9ee0c768f5))
+* enable partial build via option ([4b9dbf9](https://github.com/pattern-lab/patternlab-node/commit/4b9dbf9095bfb8bfd2360b310dd7395dbfe3cf98))
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/patternlab-node/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+
+### Bug Fixes
+
+* update link to new PL docs homepage ([831b467](https://github.com/pattern-lab/patternlab-node/commit/831b467c57b9259c32ce3d3ddf366fe1867a48a9))
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package pl-node
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** google lighthouse error - bg and text contrast ratio [#1197](https://github.com/pattern-lab/patternlab-node/issues/1197) ([f43978a](https://github.com/pattern-lab/patternlab-node/commit/f43978a3a121b661cfbf763ba72bcda2c36a5d3a))
+* **docs:** resolving broken link (new URL) in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([8dc020a](https://github.com/pattern-lab/patternlab-node/commit/8dc020a217b51cfafdd62ceca95fc42811a6c285))
+* **docs:** resolving broken link (new URL) in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([f557fdd](https://github.com/pattern-lab/patternlab-node/commit/f557fddeda640d88c7267d9d5fba8e8cc5e07929))
+* **docs:** resolving broken link (new URL) in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([0023a91](https://github.com/pattern-lab/patternlab-node/commit/0023a910126a635006c1ad468a412af0e93338fb))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([c9635ec](https://github.com/pattern-lab/patternlab-node/commit/c9635ec2d9eb700b23188d5c72b83b3d16e6deda))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([f56ad39](https://github.com/pattern-lab/patternlab-node/commit/f56ad3951ea0319a43f0b1aeabba0d3ad96c5553))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([cae9420](https://github.com/pattern-lab/patternlab-node/commit/cae94208c52e4068430e048e729f4ff97847715a))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([84138c3](https://github.com/pattern-lab/patternlab-node/commit/84138c36cdfe5b9a38b34e32b177a0416b077716))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([374c103](https://github.com/pattern-lab/patternlab-node/commit/374c103a59504ba239b16680f86a89b4d95e304f))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([cb0fcdb](https://github.com/pattern-lab/patternlab-node/commit/cb0fcdb5ad8504f9d78d4d5e040afa408aa2c356))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([48de8c2](https://github.com/pattern-lab/patternlab-node/commit/48de8c2e134a61c0b4440375254bc9590a3e2563))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([363f22c](https://github.com/pattern-lab/patternlab-node/commit/363f22c643239ef4ca48d6f5942111604fda5ead))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([487cc78](https://github.com/pattern-lab/patternlab-node/commit/487cc783388043ec16ab1e54a3bfd8490038d058))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([571017f](https://github.com/pattern-lab/patternlab-node/commit/571017ffafa2cf6e8fa01b7ea7effc88922b05d1))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([420e829](https://github.com/pattern-lab/patternlab-node/commit/420e8293c033557ede073bc13e68955a450a3c8e))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+* Contribution guidelines should refer to yarn ([c30cc81](https://github.com/pattern-lab/patternlab-node/commit/c30cc81a3e155072774438304b73d58b6635876d))
+* **uikitworkshop:** preventing cropping pattern parts [#1174](https://github.com/pattern-lab/patternlab-node/issues/1174) ([6a67d03](https://github.com/pattern-lab/patternlab-node/commit/6a67d039048129e9837c3b6eb3e195ed2e86a815))
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+
+### Bug Fixes
+
+* **plugintabs:** enabling multiple file formats [#1163](https://github.com/pattern-lab/patternlab-node/issues/1163) ([bb5e817](https://github.com/pattern-lab/patternlab-node/commit/bb5e8179e6b8553a6e1af0bede26db412b6c0b68))
+* adjust UIKit Nav updates to account for the noViewAll config variation ([73eac97](https://github.com/pattern-lab/patternlab-node/commit/73eac976461f4e587b0c30668942c4895aea319f))
+* make sure the top-level Dropdown menus always open/close ([7a8b418](https://github.com/pattern-lab/patternlab-node/commit/7a8b418bfcbd200ef8b2802b1a07964a9995bf9f))
+* only allow one top level nav item to be open at a time while rendering as a dropdown menu ([409bef3](https://github.com/pattern-lab/patternlab-node/commit/409bef37165260d9b728013ac33e7aa67541c832))
+* re-try Netlify preview to debug local vs prod rendering differences ([6da41a1](https://github.com/pattern-lab/patternlab-node/commit/6da41a14feea034f891c745dfeb062fa3b196235))
+* Update dependency on twing JS engine ([cfe88c6](https://github.com/pattern-lab/patternlab-node/commit/cfe88c6cdbf2219b9955eaa0ffcfc0e4a7683511))
+* **cli:** fix test script glob ([ff18eb5](https://github.com/pattern-lab/patternlab-node/commit/ff18eb51ce24fc5423b009168e85ede366069139))
+
+
+
+
+
+## [5.9.2](https://github.com/pattern-lab/patternlab-node/compare/v5.9.1...v5.9.2) (2020-04-24)
+
+**Note:** Version bump only for package pl-node
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+
+### Bug Fixes
+
+* **cli:** ensure specified directory exists prior to scaffold ([cc3b696](https://github.com/pattern-lab/patternlab-node/commit/cc3b69624d486c94ee3b1f4b1bbb0334a514fa59))
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+
+### Bug Fixes
+
+* **cli:** set current working directory before scaffolded npm init ([6d2186d](https://github.com/pattern-lab/patternlab-node/commit/6d2186d8e8a74634198a4474ca8ae83221dd70a9))
+* **core:** do not warn about uikit-polyfills ([6bb68e7](https://github.com/pattern-lab/patternlab-node/commit/6bb68e763769969546542bf7aaf6d1f4235c6622))
+* actually exit build when Twig render fails ([5d28a24](https://github.com/pattern-lab/patternlab-node/commit/5d28a24a53011396289c1e29e0a715cd82470185))
+* Update packages/engine-twig-php/lib/engine_twig_php.js ([c67d50e](https://github.com/pattern-lab/patternlab-node/commit/c67d50ebb5d69816b7514e85f129f8ecde984ad3))
+
+
+### Features
+
+* **docs:** yarnify ([5a47dc7](https://github.com/pattern-lab/patternlab-node/commit/5a47dc7b90dc5c43c12a51143b41943dcbd8564c))
+* **README:** add netlify badges ([941df8a](https://github.com/pattern-lab/patternlab-node/commit/941df8a59b6b75bc1255646005f329e40be68106))
+
+
+
+
+
+# [5.8.0](https://github.com/pattern-lab/patternlab-node/compare/v5.7.2...v5.8.0) (2020-04-03)
+
+
+### Bug Fixes
+
+* the namespace notation should not be mixed with PatternLab shorthand pattern naming & name is not defined in the textarea macro ([8250fe8](https://github.com/pattern-lab/patternlab-node/commit/8250fe88231d03735424d597eae40496da2cb48c))
+* Updated the README to reflect which issues are resolved. ([d90c3c4](https://github.com/pattern-lab/patternlab-node/commit/d90c3c4605f9a5bcd1153996e3f4d1a17d58bd92))
+
+
+### Features
+
+* switch engine-twig to use twing rather than node-twig ([daca95c](https://github.com/pattern-lab/patternlab-node/commit/daca95c4ffa48916fb6c67c5184bde9b624acd76))
+
+
+
+
+
+## [5.7.2](https://github.com/pattern-lab/patternlab-node/compare/v5.7.1...v5.7.2) (2020-03-24)
+
+
+### Bug Fixes
+
+* update iframe resizer UI to be hidden when iframe is full width ([9797c1a](https://github.com/pattern-lab/patternlab-node/commit/9797c1a047d746d21b88a1f57b57f618a03a54df))
+
+
+
+
+
+## [5.7.1](https://github.com/pattern-lab/patternlab-node/compare/v5.7.0...v5.7.1) (2020-02-24)
+
+
+### Bug Fixes
+
+* update twig-renderer ([46f53b7](https://github.com/pattern-lab/patternlab-node/commit/46f53b79f8bb0bb64a9c55fd32f29459cea6e28c))
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+
+### Features
+
+* **cli:** make options more user friendly ([ad845b3](https://github.com/pattern-lab/patternlab-node/commit/ad845b394ef81f90895ebb5bc6f12cc608e5e3d4))
+
+
+
+
+
+# [5.6.0](https://github.com/pattern-lab/patternlab-node/compare/v5.5.0...v5.6.0) (2020-01-18)
+
+
+### Bug Fixes
+
+* a11y fix on text contrast ([6d75b22](https://github.com/pattern-lab/patternlab-node/commit/6d75b226ce27228025b2915e5d402f7080faee31))
+* a11y issue on a missing description of that complementary icon ([4f13807](https://github.com/pattern-lab/patternlab-node/commit/4f13807cb93df33435088de3a51170b9c4515889))
+
+
+### Features
+
+* pass additional configuration into twig-php engine ([dff5a78](https://github.com/pattern-lab/patternlab-node/commit/dff5a7830918fa46e2692d9f9daed4121f803461))
+
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/patternlab-node/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+
+### Features
+
+* upgrade Twig to use new filter, map, reduce ([4218a5a](https://github.com/pattern-lab/patternlab-node/commit/4218a5a04b06027548afd9f417486297dd25fef8))
+
+
+
+
+
+## [5.4.2](https://github.com/pattern-lab/patternlab-node/compare/v5.4.1...v5.4.2) (2019-11-27)
+
+**Note:** Version bump only for package pl-node-pr
+
+
+
+
+
+## [5.4.1](https://github.com/pattern-lab/patternlab-node/compare/v5.4.0...v5.4.1) (2019-11-26)
+
+
+### Bug Fixes
+
+* temp workaround to address instance where the latest version of Edge supports ES modules but NOT Custom Elements ([ada3d82](https://github.com/pattern-lab/patternlab-node/commit/ada3d829019345fd33ed949f306972efdcb4fa57))
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+
+### Bug Fixes
+
+* re-add popstate listener ([6dbbd6a](https://github.com/pattern-lab/patternlab-node/commit/6dbbd6aae3709cc17544c12dd10588120eb9e71a))
+* **script:** remove quotes around starterkit ([e4897fb](https://github.com/pattern-lab/patternlab-node/commit/e4897fb6e4d4cd0985ab72397abd03ff04be514b))
+* add a new method to check if PL is currently compiling + add new method to get the config PL is using ([26e886c](https://github.com/pattern-lab/patternlab-node/commit/26e886c93db5d135c91de648724f7278c4d5b3e9))
+* check if dependency graph file exists before trying to remove ([f9af6a9](https://github.com/pattern-lab/patternlab-node/commit/f9af6a95025a22041e7ff8a4bfb19e4727385e98))
+* comment out example config to disable viewAll links ([ddb3fad](https://github.com/pattern-lab/patternlab-node/commit/ddb3fad5770d1d66432c4b583ae9af09a3a47d48))
+
+
+### Features
+
+* add the ability to disable Pattern Lab viewall links in the navigation ([156e609](https://github.com/pattern-lab/patternlab-node/commit/156e609a92e7f7e7ebd8f4f5cd77b5d695db8bad))
+* major improvements to local UIKit workflow ([4dc9173](https://github.com/pattern-lab/patternlab-node/commit/4dc9173a5a44b422e9677824de3728048b7c4f05))
+* test adding cross-env to Twig Edition test ([3f8bb01](https://github.com/pattern-lab/patternlab-node/commit/3f8bb01bc4e96a0aba61c213ea1619c02593defc))
+
+
+
+
+
+## [5.3.3](https://github.com/pattern-lab/patternlab-node/compare/v5.3.2...v5.3.3) (2019-11-22)
+
+
+### Bug Fixes
+
+* simplify overflow fix ([378cf42](https://github.com/pattern-lab/patternlab-node/commit/378cf4282a3e5b4f597287eb538270e3358c8c69))
+* testing potential FF fix for https://github.com/pattern-lab/patternlab-node/issues/1100 ([613bba1](https://github.com/pattern-lab/patternlab-node/commit/613bba104f2082be507938db78f1db7a07f6b8be))
+
+
+
+
+
+
+## [5.3.2](https://github.com/pattern-lab/patternlab-node/compare/v5.3.1...v5.3.2) (2019-11-14)
+
+**Note:** Version bump only for package pl-node
+
+
+
+
+
+## [5.3.1](https://github.com/pattern-lab/patternlab-node/compare/v5.3.0...v5.3.1) (2019-11-13)
+
+
+### Bug Fixes
+
+* CSS fix to properly highlight the correct active page / link in the Nav; improve dropdown open / close animation ([ec4ab84](https://github.com/pattern-lab/patternlab-node/commit/ec4ab84ddc8007796c9012a3f493822d76f039a7))
+* small UI fixes for the sticky Tabs header on smaller screens + drawer content collapsing on smaller screens + better handling of Nav link cleanup when changing pages ([347e2fe](https://github.com/pattern-lab/patternlab-node/commit/347e2fe29a78a1d168005a07c656b4f9f1124c7f))
+* tweak header and drawer padding when viewing on a device with curved edges ([98e9baf](https://github.com/pattern-lab/patternlab-node/commit/98e9baf649eceb9124218a924b6b08097b910e86))
+* uikit fixes and minor CSS updates intended for the v5.3.0 release ([26c4ced](https://github.com/pattern-lab/patternlab-node/commit/26c4ceddaae09fa4fa4873f092c924274498c5da))
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+
+### Bug Fixes
+
+* add PluginTab workaround for Safari ([2fa9367](https://github.com/pattern-lab/patternlab-node/commit/2fa936769be65484af52f242dca2536a3382462c))
+* **core:** re-add cleanPublic fix ([c100bbc](https://github.com/pattern-lab/patternlab-node/commit/c100bbca3f339e9132acb9c482e98c1c8a66b8b5))
+* **plugin-tab:** defensively call addPanels ([b82bd12](https://github.com/pattern-lab/patternlab-node/commit/b82bd129fdbe48de95b62d75fb7fe95cea896b7e))
+* port over missing UIKit Sass that wasn't added in the original PR ([f7659e6](https://github.com/pattern-lab/patternlab-node/commit/f7659e64d0eee13be20921dd5afc48ac20ae93e6))
+
+
+### Features
+
+* port latest UIKit updates + fixes upstream ([d07952c](https://github.com/pattern-lab/patternlab-node/commit/d07952cb07e3792b995dda2e589262ecf4153fdc))
+
+
+
+
+
+# [5.2.0](https://github.com/pattern-lab/patternlab-node/compare/v5.1.0...v5.2.0) (2019-11-12)
+
+
+### Bug Fixes
+
+* **deploy:** add setup command ([7c1d8d1](https://github.com/pattern-lab/patternlab-node/commit/7c1d8d14842a467bb301e2ede2ec83074ff35ae2))
+* add missing $ ([c95a06e](https://github.com/pattern-lab/patternlab-node/commit/c95a06ece78631b068f8721666caf33452e57a7a))
+* address bug causing viewport width to progressively decrease in size when resizing your screen / refreshing on certain devices ([41b11af](https://github.com/pattern-lab/patternlab-node/commit/41b11af8aaaf066fcf99abd2513eae8706122d32))
+* configure the Logo's `altText` config option when used as an HTML attribute ([ade34a2](https://github.com/pattern-lab/patternlab-node/commit/ade34a29435f5112f0449ad020bee7e9dc2c81e1))
+* fix classname typo ([da3c5f1](https://github.com/pattern-lab/patternlab-node/commit/da3c5f144d22b1ac3ad99680a264433d4438ebb2))
+* temp workaround to fix content exceeding the height of drawer container ([435243c](https://github.com/pattern-lab/patternlab-node/commit/435243cbfbd000a7d96a0e9fa7beff1a988ede64))
+* update drawer UI to not collapse content on smaller screen sizes ([7147085](https://github.com/pattern-lab/patternlab-node/commit/71470856b8b389421348366afd247a599d1e9c86))
+* update package.json description in `@pattern-lab/uikit-polyfills` ([22fc44a](https://github.com/pattern-lab/patternlab-node/commit/22fc44a4b3683753a469a98abfcdad8f1234f28a))
+* **engine_twig_php:** Allow additional flexibility with twig namespaces. ([07bfaa3](https://github.com/pattern-lab/patternlab-node/commit/07bfaa35a00ff62fd2016cc9f34e09cf5af36559))
+
+
+### Features
+
+* add lit-element, basic Typescript support to Webpack ([611f705](https://github.com/pattern-lab/patternlab-node/commit/611f705be85eea8a31091169750d64e988798cee))
+* add local copy of new Slotify library till published to NPM ([63b9d83](https://github.com/pattern-lab/patternlab-node/commit/63b9d833908151ce5cb5aa5184c72254125c7ed1))
+* add new component to make Button-like styles more reusable ([5e7b014](https://github.com/pattern-lab/patternlab-node/commit/5e7b0140622eb89154c38925769a6def6d669fb3))
+* add new component ([e8ce2a9](https://github.com/pattern-lab/patternlab-node/commit/e8ce2a927365b8d5316a7d8229c979ff31b04907))
+* add support for auto-closing Nav when clicking inside of the rendered iframe ([9d602fe](https://github.com/pattern-lab/patternlab-node/commit/9d602fe335a5d3b5bca5cac258c2465934d9a46a))
+* add support for optional chaining syntax via Babel plugin ([c8886b6](https://github.com/pattern-lab/patternlab-node/commit/c8886b6d9d91fea246fa3ab7947f289509dc26d5))
+* major refactoring + UI updates to address cross browser support; UI cleanup and conversion of the majority of the remaining components over to lit-element ([2ff8e1c](https://github.com/pattern-lab/patternlab-node/commit/2ff8e1c98cdd02e8077064c48eca5f7754a3db02))
+* refactor + convert pl-toggle-info to lit-element ([85cd9c5](https://github.com/pattern-lab/patternlab-node/commit/85cd9c50ca814066bf999badf2071d84964f00cc))
+* refactor + convert pl-toggle-layout to lit-element ([46009d9](https://github.com/pattern-lab/patternlab-node/commit/46009d91b1cb9ed613baa5a7626cba4f42883465))
+* refactor + convert pl-toggle-theme to lit-element ([95a3b21](https://github.com/pattern-lab/patternlab-node/commit/95a3b21a89dacd2d5b4df8c134ce438d4efdbd04))
+* refactor Drawer to render via lit-element + massively improve rendering performance ([28d47eb](https://github.com/pattern-lab/patternlab-node/commit/28d47eb3cbbce038204203e786e5188b4cefe64f))
+* remove mixin that was causing outlines to be removed from default UI styles ([622ed76](https://github.com/pattern-lab/patternlab-node/commit/622ed76d435b3b2e31e412266c3090506f98051b))
+* temp add unsafe-svg directive till upstream PR merged ([34de61c](https://github.com/pattern-lab/patternlab-node/commit/34de61ccd9c7bb3b48ca5ef386a87efc8e84babc))
+* update the Nav design to not bold the active item in order to not shift the layout ([0eda431](https://github.com/pattern-lab/patternlab-node/commit/0eda4312ba9f4c61afa6322c3ff45f9cda0efc9e))
+* update Webpack config to use the latest Style Loader + new SVG icon system ([2ed70e7](https://github.com/pattern-lab/patternlab-node/commit/2ed70e79d8656c7314d8b3109aa1c34160ad24f9))
+
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+
+### Features
+
+* **config:** add new default pattern export options ([a7487a0](https://github.com/pattern-lab/patternlab-node/commit/a7487a0681cb11e6f3c5c8eaefd62e5648ad5ea3))
+
+
+
+
+
+## [5.0.2](https://github.com/pattern-lab/patternlab-node/compare/v5.0.1...v5.0.2) (2019-10-28)
+
+
+### Bug Fixes
+
+* **uikit-workshop:** add template files to published bundle ([9005fce](https://github.com/pattern-lab/patternlab-node/commit/9005fcee9e129fb41d509f706195e1437bddc710))
+* **uikit-workshop:** add webpack config to published bundle ([060a573](https://github.com/pattern-lab/patternlab-node/commit/060a573cbddce9ee3d270d39337d0c8cac8372fa))
+
+
+
+
+
+## [5.0.1](https://github.com/pattern-lab/patternlab-node/compare/v5.0.0...v5.0.1) (2019-10-28)
+
+
+### Bug Fixes
+
+* add missing “dist” folder to array of files / folders published to NPM ([8829429](https://github.com/pattern-lab/patternlab-node/commit/88294296c438352570befd2eb6b9e1ca2ae3b750))
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* **1049:** Treat folders like patterns only if they're subfolders of pattern groupings ([4eb79ab](https://github.com/pattern-lab/patternlab-node/commit/4eb79ab48b335a35b2e5ed3b7053974b8e8bb6b6))
+* **cli:** add custom install logic to edition-node ([f04fd26](https://github.com/pattern-lab/patternlab-node/commit/f04fd266429cd806987dab747e6d69bff9b926a4))
+* **cli:** allow any package to be installed as a starterkit ([d2aa1be](https://github.com/pattern-lab/patternlab-node/commit/d2aa1be810a0a7473dcc52391a2263dacfdda0b8)), closes [#1067](https://github.com/pattern-lab/patternlab-node/issues/1067)
+* **cli:** merge config arrays via overwrite instead of concatenate ([42e5f7b](https://github.com/pattern-lab/patternlab-node/commit/42e5f7b42a26b4fc1f262c68ee4b474b546f2eac))
+* **cli:** proper path resolution to helpers ([a18fe5e](https://github.com/pattern-lab/patternlab-node/commit/a18fe5ef4d1c074a5eba8bfa255ebbee2261bf74))
+* **cli:** re-order and clarify engines ([e39e301](https://github.com/pattern-lab/patternlab-node/commit/e39e301a33306c6615fabf64262f1893ca682b97))
+* **core:** allow plugin resolution to follow normal algorithm ([3f6b83b](https://github.com/pattern-lab/patternlab-node/commit/3f6b83be080c88aec1d8b73bececb76f0f57a79d))
+* **core:** find plugins from config only and with simpler args ([fe7351c](https://github.com/pattern-lab/patternlab-node/commit/fe7351cba346425512cbb2ef3a1b7728ab06ae60))
+* **deploy:** add setup command ([74dd314](https://github.com/pattern-lab/patternlab-node/commit/74dd3142bf48873a9f1ec4e8dccb8aa2fef9001d))
+* **engine_twig_php:** Pseudo patterns Twig PHP ([226aa8b](https://github.com/pattern-lab/patternlab-node/commit/226aa8bbaaf5e418530ccf54a28f6c5657ee6dea)), closes [#1045](https://github.com/pattern-lab/patternlab-node/issues/1045)
+* **engine_twig_php:** Twig incremental rebuilds ([1ade945](https://github.com/pattern-lab/patternlab-node/commit/1ade9451840b2645706a0b01129e2b697dc22d4b)), closes [#1015](https://github.com/pattern-lab/patternlab-node/issues/1015)
+* **engine_twig_php:** Twig incremental rebuilds ([5d33f24](https://github.com/pattern-lab/patternlab-node/commit/5d33f24f156ebe50900701513a855de7de608dcf)), closes [#1015](https://github.com/pattern-lab/patternlab-node/issues/1015)
+* **lerna:** typo in config ([525a47b](https://github.com/pattern-lab/patternlab-node/commit/525a47b51fba91c1bf5b7439735f48eb7dfa073e))
+* **lint:** Use const instead of var ([ad1e782](https://github.com/pattern-lab/patternlab-node/commit/ad1e782ef71295eb610f56d019eaa35499fb3f85))
+* **plugin:** correct spelling error and function locations ([d4abd88](https://github.com/pattern-lab/patternlab-node/commit/d4abd88cb017550002407241b5045a2ad1adb1dc))
+* **plugin-tab:** bump lodash from 4.17.5 to 4.17.15 in /packages/plugin-tab ([#1081](https://github.com/pattern-lab/patternlab-node/issues/1081)) ([3f89dda](https://github.com/pattern-lab/patternlab-node/commit/3f89dda1685874e251f9777f969c0943e0080881))
+* **plugin-tab:** handle params correctly ([d248993](https://github.com/pattern-lab/patternlab-node/commit/d2489939bb0db1a1d67b0e7f47dfb1838b88b0a0))
+* **starterkit:** add css output and build command ([ccb2d35](https://github.com/pattern-lab/patternlab-node/commit/ccb2d3569b741220324a3fa738ab3d4d2eb97ffe))
+* add better pre-rendering support ([8ecd615](https://github.com/pattern-lab/patternlab-node/commit/8ecd6159a89232f42e0a9dc3c688b6e21de8fc30))
+* add eslint fixes ([00d7bbe](https://github.com/pattern-lab/patternlab-node/commit/00d7bbe319ea77a6ee8cc9cd0348856feaaf13ad))
+* add missing @babel/runtime package to address silent error getting thrown on Travis ([1918d04](https://github.com/pattern-lab/patternlab-node/commit/1918d042d7e90cc8aaa2fdfcd8649961c0a5dd50))
+* add missing preact-render-to-string library ([881296a](https://github.com/pattern-lab/patternlab-node/commit/881296a2c256424beac28bd560c5b1a5e1fed005))
+* add repo info to root package.json so Auto knows what repo to configure for ([85142e8](https://github.com/pattern-lab/patternlab-node/commit/85142e8e94549edd7980459e5975d0639c34864d))
+* address unrelated eslint errors from PL core ([6ada00d](https://github.com/pattern-lab/patternlab-node/commit/6ada00d396eb436837f7453664bfa50522a2ec10))
+* correct typo in build logging ([96d989f](https://github.com/pattern-lab/patternlab-node/commit/96d989f8869630ba9f59705bfca66755f20e35ab))
+* fall back to seeing the current pattern's query string to `all` or the defaultPattern value if undefined when the iframe page initially loads ([a368459](https://github.com/pattern-lab/patternlab-node/commit/a3684590fca02cf96b99421b87a0ad0a711893ad))
+* fix incorrect Webpack version in package.json ([9788e89](https://github.com/pattern-lab/patternlab-node/commit/9788e8977921e31fe43f2a1ec19d4684dd4709c5))
+* fix issue with viewport height exceeding the space available ([95cd1cf](https://github.com/pattern-lab/patternlab-node/commit/95cd1cfa57f086ecb84ac2e996ecda81f0c6a1a6))
+* fix Prism.js typo so languages not found / supported don't throw a JS error ([a8c19f9](https://github.com/pattern-lab/patternlab-node/commit/a8c19f9f9b11d4abbdcd9e573fb0cb418d665660))
+* fix Twig Edition examples by adding missing Twig namespaces to config ([b4c20ef](https://github.com/pattern-lab/patternlab-node/commit/b4c20ef88ee0d3010760584c6f05ff7f92b711a6))
+* minor CSS fixes + fresh prod build ([8ac2c1f](https://github.com/pattern-lab/patternlab-node/commit/8ac2c1fa1c7558ed2ac50755f599a438d682ee2a))
+* re-enable displaying the top level `All` link if PL isn't configured to hide this specific link in the ishControlsHide config option. Addresses [#1048](https://github.com/pattern-lab/patternlab-node/issues/1048) ([6bb4e1a](https://github.com/pattern-lab/patternlab-node/commit/6bb4e1ac6f38b47f93030c8c5bca62d5db2132e4))
+* re-enable using the defaultPattern config for the initial iframe page load if defined ([d645ea1](https://github.com/pattern-lab/patternlab-node/commit/d645ea15150061d7ad13741d2dc37b12b9786411))
+* regenerate fresh UIKit build after fixing main JS issues ([9ea34d2](https://github.com/pattern-lab/patternlab-node/commit/9ea34d2efe43cafacb3729ac113121ba51126344))
+* Rename Handlebars and Nunjucks extension setting to "extend" ([74e5af2](https://github.com/pattern-lab/patternlab-node/commit/74e5af28c4e714fdfc1db535b94c52f3dc14a3a4))
+* squashing minor UI bugs ([a8a606c](https://github.com/pattern-lab/patternlab-node/commit/a8a606cfb224f7041f53ff5026a84e13fa17914c))
+* temporarily disable Random and Disco viewport controls until the full JS logic for these is re-enabled ([14b9a19](https://github.com/pattern-lab/patternlab-node/commit/14b9a19e4dee9462f3784eae28066893cc893624))
+* temporarily downgrade Preact version so tooltip used for displaying viewport sizes renders correctly ([52dcf85](https://github.com/pattern-lab/patternlab-node/commit/52dcf85e756ee171ca993288d98f5b5ef9a0a24b))
+* update autoprefixer browserslist config to address warning messages ([5e52f2b](https://github.com/pattern-lab/patternlab-node/commit/5e52f2b0ed02e2002ca867368636c3c0dc79ff0a))
+* update initial PL iframe path default ([a26fbb9](https://github.com/pattern-lab/patternlab-node/commit/a26fbb956e13901d1751c435b76de65637191ca4))
+* update Javascript to address merge conflict issue with previous PR merge / recent release ([cf2ecc1](https://github.com/pattern-lab/patternlab-node/commit/cf2ecc154383c3e8abd56dc88484370bc58ac30b))
+* update styles for pattern state dots ([7728acc](https://github.com/pattern-lab/patternlab-node/commit/7728accc9a6e5cd83be451f7d74e522dfe721cad))
+* update the default pattern that displays in the Handlebars demo ([ff1d85f](https://github.com/pattern-lab/patternlab-node/commit/ff1d85f2852fc4f210841e8e0aaf14b55165ce58))
+* **starterkit:** remove config file ([f90e38a](https://github.com/pattern-lab/patternlab-node/commit/f90e38aa873dcff0dd08fe4dabc3b71bf95080b6))
+* **starterkit:** use handlebars meta files ([d8f5e12](https://github.com/pattern-lab/patternlab-node/commit/d8f5e12471bd783bd3755626701ecc17669fc761))
+* updates to address eslint / prettier issues ([d945acc](https://github.com/pattern-lab/patternlab-node/commit/d945acc13b8e4e36f3815b017fbc12266c323d1f))
+* updates to fix eslint / prettier issues; update packages/core to reuse root .eslintrc.js file ([5b7a057](https://github.com/pattern-lab/patternlab-node/commit/5b7a057d46ccd16b5832af1441030c7b76f237a8))
+* use 100% of the screen available when JS is disabled / the first time the iframe loads up ([c0c5bff](https://github.com/pattern-lab/patternlab-node/commit/c0c5bff7a63b157d5b81dc2bcecee9e732ecfd4e))
+* **uikit:** clear out "404" responses when loading tabs ([73874b1](https://github.com/pattern-lab/patternlab-node/commit/73874b1b0b66ca6425c2b74331d417efdb529e2e))
+* **uikit-workshop:** fix merge problem ([d245b3b](https://github.com/pattern-lab/patternlab-node/commit/d245b3bca044c29f281052bf2feb95eeffafcf6b))
+
+
+### Features
+
+* **core:** invoke registered plugin hooks ([a54d775](https://github.com/pattern-lab/patternlab-node/commit/a54d7753b6939fe6a58da543f4fb34f64dd8901a))
+* **edition-node:** switch to engine-handlebars ([b481e22](https://github.com/pattern-lab/patternlab-node/commit/b481e22dc1f41ddd4da709621640a15190fba257))
+* **engine-handlebars:** Default location for helpers, like engine-nunjucks ([11c4180](https://github.com/pattern-lab/patternlab-node/commit/11c41805e0c3dbebb7109719c4f3c780d32feab5))
+* **engine-handlebars:** Demonstration of custom Handlebars helper ([f330b5b](https://github.com/pattern-lab/patternlab-node/commit/f330b5bca72f2f34bfafe5c2c64e6b0b8823eb1c))
+* **engine-handlebars:** Document the Helpers feature ([a01e040](https://github.com/pattern-lab/patternlab-node/commit/a01e040429a7f77dfeb28d67c690e835b97881de))
+* **engine-handlebars:** Load Handlebars helpers specified in the config ([a12df36](https://github.com/pattern-lab/patternlab-node/commit/a12df36d2a644dfac8ded1dfd94b987e99c29d79))
+* **engine-nunjucks:** Configurable extension locations; Use usePatternlabConfig() ([e54e3b3](https://github.com/pattern-lab/patternlab-node/commit/e54e3b3d48f934d3a4d44b9f4ff262f742a4aaf9))
+* **engine-react:** set package to private ([3aea881](https://github.com/pattern-lab/patternlab-node/commit/3aea8815f19df5b527cdda0b75cf99a9a8c3bc1e))
+* **plugin-tab:** pivot to using hook functions ([d4b2598](https://github.com/pattern-lab/patternlab-node/commit/d4b25984fc2a2646cc1876a5c635f57593c35f09))
+* **plugin-tab, core:** initial plugin hook exploration ([2f3d39a](https://github.com/pattern-lab/patternlab-node/commit/2f3d39ac6b125ad4c6b872e27ee224ce2ea33a12))
+* **starterkits:** add starterkit-handlebars-demo ([384d2cf](https://github.com/pattern-lab/patternlab-node/commit/384d2cfa3440c1e6f456d39f56ca6381f82f7689))
+* **uikit-workshop:** add plugin-loader ([fc966d6](https://github.com/pattern-lab/patternlab-node/commit/fc966d6b151e24055bc2f4146d6a90b5fb392765))
+* introduce netlify preview ([6c5d332](https://github.com/pattern-lab/patternlab-node/commit/6c5d332479fb6836bd8bd5530a074d13440f8ae4))
+* remove pre-built uikit dist folder and switch to auto-building when bootstrapping OR when publishing to NPM ([b5dd553](https://github.com/pattern-lab/patternlab-node/commit/b5dd5538ee00ddf1da321851865fa1c223cedb43))
+* switch to Yarn + Yarn workspaces ([f4c4ec3](https://github.com/pattern-lab/patternlab-node/commit/f4c4ec33cd30d372c87ffa904fbe7d5b819ee14e))
+* update Node to v12 ([fcbb970](https://github.com/pattern-lab/patternlab-node/commit/fcbb970648cdd775c9a88078f14c1f24c5b62d73))
+
+
+### Reverts
+
+* don't flatten folders containing only one item inside ([77f1f46](https://github.com/pattern-lab/patternlab-node/commit/77f1f46595328bd96fba46347b532295c65802d1))
+
+
+### BREAKING CHANGES
+
+* **core:** plugins now use async functions instead of events
+* **plugin-tab:** event based listeners replaced with functions
+* **cli:** previously, we concatenated arrays, which is unlikely to be intended
+* **edition-node:** use handlebars over mustache
diff --git a/CODEOWNERS b/CODEOWNERS
index 75ecbe287..532d55de7 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -7,9 +7,6 @@
# review when someone opens a pull request.
@pattern-lab/trusted-committers
-# CLI owner
-/packages/cli @raphaelokon
-
# uikit-workshop owner
/packages/uikit-workshop @sghoweri
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
index 9f536bcc4..39d8d867a 100644
--- a/CODE_OF_CONDUCT.md
+++ b/CODE_OF_CONDUCT.md
@@ -34,13 +34,13 @@ This Code of Conduct applies both within project spaces and in public spaces whe
## Enforcement
-Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at brian.muenzenmeyer@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems 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.
+Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team by opening an issue. The project team will review and investigate all complaints, and will respond in a way that it deems 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]
+This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version]
-[homepage]: http://contributor-covenant.org
-[version]: http://contributor-covenant.org/version/1/4/
+[homepage]: https://contributor-covenant.org
+[version]: https://contributor-covenant.org/version/1/4/
diff --git a/CUTTING_A_RELEASE.md b/CUTTING_A_RELEASE.md
new file mode 100644
index 000000000..b90c8c9df
--- /dev/null
+++ b/CUTTING_A_RELEASE.md
@@ -0,0 +1,73 @@
+# How To Cut a Pattern Lab Release
+
+We use a handful of tools to help automate and simplify the process of cutting a new Pattern Lab release. The most important ones being [Lerna](https://github.com/lerna/lerna) and [Auto](https://intuit.github.io/auto/).
+
+## Release Prep
+
+1. Make sure any/all the code ready to get released is merged down to the `dev` branch and all CI checks, etc are passing as expected
+
+2. Git checkout the `dev` branch locally and make sure:
+- You've run `yarn` to install the latest dependencies
+- You don't have any local changes pending
+
+```
+git checkout dev
+git pull
+yarn
+git status # confirm no pending changes
+```
+
+3. Before running the publish command, I also like to run the `build` command to be extra sure everything compiles fine locally (ex. Node.js version matches with the version of Sass that's installed, gotchas like that)
+
+```
+yarn build
+```
+
+4. You'll also want to make sure you have a `.env` file in your PL Node repo root (and create one if you don't)
+
+You can grab the NPM + Github tokens needed here by heading to https://github.com/settings/tokens/new (grant repo access) and https://www.npmjs.com/settings/NPM_USER/tokens
+
+```
+## .env
+export GH_TOKEN=PASTE_GITHUB_TOKEN_HERE
+export NPM_TOKEN=PASTE_NPM_TOKEN_HERE
+```
+
+I personally like to use zsh's `env` plugin (already installed with Oh My ZSH) which has instructions for enabling here https://github.com/johnhamelink/env-zsh
+
+> Pro tip: you can quickly check to see if your env variable tokens are available for these CLI commands by running `npx auto release --dry-run` which will throw an error if the tokens above can't be found!
+
+5. Finally you'll also want to confirm that you're logged into your NPM account with access to publish to the Pattern Lab NPM org by running `npm login` and following the prompts.
+
+## Cutting The Release
+
+6. Run the `publish` command
+
+Ok - with all that prep out of the way, the actual release process is pretty quick and should be super straightforward.
+
+Simply run the `yarn run publish` command and include the type of SEMVER release you want to cut.
+
+So for example:
+
+```
+yarn run publish minor
+
+## alternatively you can include the exact version you want to publish
+yarn run publish v5.14.0
+```
+
+Lerna should prompt you with a confirmation that the version about to get released matches up with what you expect ^
+
+7. Manually (re)run the `auto release` command?
+
+Ok, if everything built and published successfully, this final step may or may not be required...
+
+Normally the `auto release` command should run automatically after Lerna finishes publishing to NPM. This command will create the Github release associated with the latest Git tag, add any relevant release notes, and comment on related PRs, however the last couple of releases required this last step to get re-run manually.
+
+Note that you'll need to replace the `from` and `use-version` version numbers to match the last previous Git tag and this next release getting cut.
+
+```
+npx auto release --from v5.11.1 --use-version v5.12.0
+```
+
+8. Confirm the [Github release](https://github.com/pattern-lab/patternlab-node/releases) was added and manually tweak any release notes as needed.
diff --git a/LICENSE b/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/README.md b/README.md
index da9e4eec4..3d82c45c7 100644
--- a/README.md
+++ b/README.md
@@ -1,20 +1,30 @@
+> [!IMPORTANT]
+> Pattern Lab is no longer actively maintained. All repositories, along with the rest of the @pattern-lab ecosystem on GitHub and npm, have been deprecated and archived. The code, releases, and history remain available so the work stays discoverable and forks can continue independently under the MIT license. No new releases, security patches, or issue triage will be performed.
+> [Read the full message](https://github.com/pattern-lab), and thank you.
+
-
+
# Pattern Lab
-This monorepo contains the core of Pattern Lab / Node and all related engines, UI kits, plugins and utilities. Pattern Lab helps you and your team build thoughtful, pattern-driven user interfaces using atomic design principles.
+This monorepo contains the core of Pattern Lab / Node and all related engines, UI kits, plugins, and utilities. Pattern Lab helps you and your team build thoughtful, pattern-driven user interfaces using atomic design principles.
-If you'd like to see what a front-end project built with Pattern Lab looks like, check out this [online demo of Pattern Lab output](http://demo.patternlab.io/).
+If you'd like to see what a front-end project built with Pattern Lab looks like, check out this [online demo of Pattern Lab output](https://demo.patternlab.io/).
-[](https://travis-ci.org/pattern-lab/patternlab-node)
+[](https://github.com/pattern-lab/patternlab-node/actions/workflows/continuous-integration.yml)
+[](https://github.com/pattern-lab/patternlab-node/actions/workflows/codeql-analysis.yml)


[](https://coveralls.io/github/pattern-lab/patternlab-node?branch=master)
[](https://github.com/prettier/prettier)
-[]()
+[]()
[](https://gitter.im/pattern-lab/node)
+[](https://discord.gg/UcZrYYE7ht)
+
+Docs @ [](https://app.netlify.com/sites/patternlab-docs-preview/deploys)
+
+Pattern Lab Preview @ [](https://app.netlify.com/sites/patternlab-handlebars-preview/deploys)
## Using Pattern Lab
@@ -22,29 +32,29 @@ Refer to the [core usage guidelines](https://github.com/pattern-lab/patternlab-n
### Installation
-As of Pattern Lab Node 3.0.0, installation of [Editions](http://patternlab.io/docs/advanced-ecosystem-overview.html) is accomplished via the command line interface.
+As of Pattern Lab Node 3.0.0, installation of [Editions](https://patternlab.io/docs/overview-of-pattern-lab's-ecosystem/) is accomplished via the command line interface.
The below assumes a new directory and project is required. This is likely what you want to do if starting from scratch. You could also run this within an existing project. The CLI will ask you for the installation location.
-1. Open a terminal window and following along below:
+1. Open a terminal window and follow along below:
```bash
mkdir new-project
cd new-project
npm create pattern-lab
```
> If you get an error stating that `npx` is not installed, ensure you are on `npm 5.2.0` or later by running `npm -v` or install it globally with `npm install -g npx`. [Learn more about npx.](https://medium.com/@maybekatz/introducing-npx-an-npm-package-runner-55f7d4bd282b)
-1. Follow the on-screen prompts to choose your Edition and a Starterkit should you want one.
- - If you chose `edition-node`, new commands in the "scripts" will be added in your `package.json`.
+1. Follow the on-screen prompts to choose your Edition and a Starter Kit should you want one.
+ - If you chose `edition-node`, new commands in the "scripts" will be added to your `package.json`.
- If you chose `edition-node-gulp`, a `gulpfile.js` will be added to your project.
- > Notice that `@pattern-lab/cli` was installed as a depdendency. Learn how to further [use the cli in your own project](https://github.com/pattern-lab/patternlab-node/blob/dev/packages/cli/readme.md#configuring-your-project-to-use-the-cli).
+ > Notice that `@pattern-lab/cli` was installed as a dependency. Learn how to further [use the cli in your own project](https://github.com/pattern-lab/patternlab-node/blob/dev/packages/cli/readme.md#configuring-your-project-to-use-the-cli).
## Ecosystem
-
+
-Core, and Editions, are part of the [Pattern Lab Ecosystem](http://patternlab.io/docs/advanced-ecosystem-overview.html). With this architecture, we encourage people to write and maintain their own Editions, Starterkits, and even PatternEngines.
+Core, and Editions, are part of the [Pattern Lab Ecosystem](https://patternlab.io/docs/overview-of-pattern-lab's-ecosystem/). With this architecture, we encourage people to write and maintain their own Editions, Starter kits, and even PatternEngines.
## Changelog
@@ -55,13 +65,27 @@ Core, and Editions, are part of the [Pattern Lab Ecosystem](http://patternlab.io
## Support for Pattern Lab
-Pattern Lab / Node wouldn't be what it is today without the support of the community. It will always be free and open source. Continued development is made possible in part from the support of [these wonderful project supporters](https://github.com/pattern-lab/patternlab-node/wiki/Thanks). If you want to learn more about supporting the project, visit the [Pattern Lab / Node Patreon page](https://www.patreon.com/patternlab).
+Pattern Lab / Node wouldn't be what it is today without the support of the community. It will always be free and open source. Continued development is made possible in part from the support of [contributors](https://github.com/pattern-lab/patternlab-node/graphs/contributors).
+
+Thanks to [Netlify](https://www.netlify.com/) for building tooling and hosting.
+
+## Node Support Policy
+
+We only support actively [maintained](https://github.com/nodejs/Release#release-schedule) versions of Node.
+
+We specifically limit our support to maintenance versions of Node, not because this package won't work on other versions, but because we have a limited amount of time, and supporting the oldest maintenance offers the greatest return on that investment while still providing the lowest standard level for installations on any possible actively maintained environment out there.
+
+This package may work correctly on newer versions of Node. It may even be possible to use this package on older versions of Node. However, that's more unlikely as we'll make every effort to take advantage of features available in the oldest maintenance Node version we support.
+
+As each Node maintenance version reaches its end-of-life, we will replace that version from the `node` `engines` property of our package's `package.json` file with the newer oldest one. As this replacement would be considered a breaking change, we will publish a new major version of this package. We will not accept any requests to support an end-of-life version of Node. Any merge requests or issues supporting an end-of-life version of Node will be closed.
+
+And we might even update the minor and patch version of that supported maintenance Node version regularly, without making this a breaking change than as it should be in everybody's interest even also to follow this concept of using patched software as their development system basis, especially on those older Node versions.
+
+We will accept code that allows this package to run on newer, non-maintenance versions of Node. Furthermore, we will attempt to ensure our changes work on the latest version of Node. To help in that commitment, we even test that out by ourselves and get feedback from the community regularly regarding all LTS versions of Node and the most recent Node release called current.
-**:100: Thanks for support from the following:**
+JavaScript package managers like e.g. [NVM](https://github.com/nvm-sh/nvm) should allow you to install this package with any version of Node, with, at most, a warning if your version of Node does not fall within the range specified by our `node` `engines` property. If you encounter issues installing this package, please report the issue to your package manager.
-* **[Brad Frost](http://bradfrost.com/)**
-* [Marcos Peebles](https://twitter.com/marcospeebles)
-* [Susan Simkins](https://twitter.com/susanmsimkins)
+This policy has been adapted from .
## Contributing
diff --git a/UPGRADE_GUIDE.md b/UPGRADE_GUIDE.md
new file mode 100644
index 000000000..b2318ecf2
--- /dev/null
+++ b/UPGRADE_GUIDE.md
@@ -0,0 +1,12 @@
+# Upgrading Pattern Lab Node
+
+To upgrade the Node version of Pattern Lab do the following:
+
+## Version 6 instructions
+
+- Ensure that you're using at least Node.js version 14, to which we've upgraded to with [!1430](https://github.com/pattern-lab/patternlab-node/pull/1430)
+- If you haven't migrated from `mustache` to `handlebars` engine and templates so far, now would be a good time as `mustache` has been replaced by `handlebars` as the default template language with version 5 of pattern lab, and `mustache` might get removed sooner rather than later. To make a long story short, `handlebars` is mostly compatible, but more mature than `mustache`, so a migration shouldn't be too hard, and even beneficial. Additionally using `mustache` templates most likely won't work anymore starting with this new major version 6 due to these potentially breaking changes for `mustache` usage:
+ - Removed `styleModifiers` with [!1452](https://github.com/pattern-lab/patternlab-node/pull/1452), that haven't been mentioned in the documentation any more anyhow.
+ - replaced `hogan.js` by `handlebars` rendering [!1456](https://github.com/pattern-lab/patternlab-node/pull/1456), that would expect the usage of block helpers instead of typical mustache iterations over objects.
+- Please explicitly configure your used engine within `patternlab-config.json` as described within the documentations section https://patternlab.io/docs/editing-the-configuration-options/#heading-engines. The previous way of scanning `node_modules` folder for pattern engines is deprecated and will be removed with version 7.
+
diff --git a/babel.config.js b/babel.config.js
new file mode 100644
index 000000000..6960ccf61
--- /dev/null
+++ b/babel.config.js
@@ -0,0 +1,27 @@
+module.exports = {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ node: 'current',
+ },
+ },
+ ],
+ ],
+ plugins: [
+ /**
+ * 1. Helps with our Web Component Preact renderer
+ */
+ '@babel/plugin-syntax-jsx' /* [1] */,
+ [
+ '@babel/plugin-transform-react-jsx' /* [1] */,
+ {
+ pragma: 'h',
+ pragmaFrag: '"span"',
+ throwIfNamespace: false,
+ useBuiltIns: false,
+ },
+ ],
+ ],
+};
diff --git a/lerna.json b/lerna.json
index 776f2c56b..7a57a21cc 100644
--- a/lerna.json
+++ b/lerna.json
@@ -1,27 +1,38 @@
{
- "lerna": "3.11.0",
+ "lerna": "4.0.0",
+ "version": "6.1.0",
"packages": [
"packages/*"
],
- "version": "independent",
"command": {
"init": {
"exact": true
},
- "bootstrap": {
- "hoist": [
- "tap",
- "eslin*",
- "husky",
- "prettier",
- "pretty-quick"
- ]
- },
"publish": {
- "allowBranch": "master"
+ "allowBranch": [
+ "master",
+ "dev"
+ ],
+ "conventionalCommits": true,
+ "gitReset": true,
+ "includeMergedTags": true,
+ "noCommitHooks": true,
+ "verifyAccess": true
+ },
+ "changed": {
+ "includeMergedTags": true
}
},
+ "ignoreChanges": [
+ "**/__fixtures__/**",
+ "**/__tests__/**",
+ "**/*.md",
+ "**/__snapshots__/**"
+ ],
+ "npmClient": "yarn",
"npmClientArgs": [
+ "--ignore-optional",
"--registry=https://registry.npmjs.org/"
- ]
+ ],
+ "useWorkspaces": true
}
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 000000000..94337a4da
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,2 @@
+[context.deploy-preview]
+ command = "yarn setup && yarn preview:hbs && yarn preview:docs"
diff --git a/package.json b/package.json
index 650a8a3a8..3a33784a5 100644
--- a/package.json
+++ b/package.json
@@ -1,16 +1,46 @@
{
- "devDependencies": {
- "lerna": "3.11.0"
+ "workspaces": {
+ "packages": [
+ "packages/*"
+ ],
+ "nohoist": [
+ "@pattern-lab/engine-*",
+ "**/@pattern-lab/engine-*",
+ "**/@pattern-lab/uikit-workshop"
+ ]
+ },
+ "dependencies": {
+ "@auto-it/released": "^10.27.0",
+ "@babel/plugin-proposal-decorators": "^7.13.5",
+ "@babel/plugin-syntax-jsx": "^7.12.13",
+ "auto": "^10.27.0",
+ "babel-eslint": "^10.0.2",
+ "eslint": "^6.1.0",
+ "eslint-config-prettier": "^6.0.0",
+ "eslint-plugin-prettier": "^3.1.0",
+ "lerna": "4.0.0",
+ "prettier": "^2.8.1",
+ "pretty-quick": "^3.1.3"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/pattern-lab/patternlab-node.git"
},
"private": true,
"scripts": {
- "bootstrap": "lerna bootstrap",
- "setup": "npm run bootstrap && npm run build:uikit",
- "build:uikit": "lerna exec --scope @pattern-lab/uikit-workshop -- npm run build",
+ "postinstall": "lerna run postbootstrap",
+ "setup": "yarn",
+ "build:uikit": "cd packages/uikit-workshop && npm run build",
"precommit": "pretty-quick --staged",
- "prettier": "prettier --config .prettierrc --write ./**/*.js --ignore-path .prettierignore",
+ "lint:fix": "npm run lint -- --fix",
+ "lint": "eslint --max-warnings 0 './packages/{core,cli,uikit-workshop}/**/*.js ' --ignore-path .eslintignore",
"test": "lerna run test",
- "clean": "git clean -dfx"
+ "clean": "git clean -dfx",
+ "publish": "npx lerna publish -m \"[skip travis] chore(release): publish %s\"",
+ "postpublish": "auto release",
+ "preview:docs": "cd packages/docs && yarn production",
+ "preview:hbs": "cd packages/development-edition-engine-handlebars && yarn pl:starterkit && yarn pl:build",
+ "prepare": "husky install"
},
"nyc": {
"exclude": [
@@ -19,5 +49,8 @@
"packages/core/test",
"packages/live-server"
]
+ },
+ "devDependencies": {
+ "husky": "^8.0.2"
}
}
diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore
index 55a89459b..511707a54 100644
--- a/packages/cli/.gitignore
+++ b/packages/cli/.gitignore
@@ -17,13 +17,13 @@ coverage
# nyc test coverage
.nyc_output
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
-# Compiled binary addons (http://nodejs.org/api/addons.html)
+# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
diff --git a/packages/cli/.nvmrc b/packages/cli/.nvmrc
index a13e7b9c8..59ea99ee6 100644
--- a/packages/cli/.nvmrc
+++ b/packages/cli/.nvmrc
@@ -1 +1 @@
-10.0.0
+16.20
diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md
index 02d65dc16..cadcbeb26 100644
--- a/packages/cli/CHANGELOG.md
+++ b/packages/cli/CHANGELOG.md
@@ -3,6 +3,373 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+
+### Bug Fixes
+
+* **cli:** fix test script glob ([ff18eb5](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/ff18eb51ce24fc5423b009168e85ede366069139))
+
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+
+### Bug Fixes
+
+* **cli:** ensure specified directory exists prior to scaffold ([cc3b696](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/cc3b69624d486c94ee3b1f4b1bbb0334a514fa59))
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+
+### Bug Fixes
+
+* **cli:** set current working directory before scaffolded npm init ([6d2186d](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/6d2186d8e8a74634198a4474ca8ae83221dd70a9))
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+
+### Features
+
+* **cli:** make options more user friendly ([ad845b3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/ad845b394ef81f90895ebb5bc6f12cc608e5e3d4))
+
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* updates to fix eslint / prettier issues; update packages/core to reuse root .eslintrc.js file ([5b7a057](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/5b7a057d46ccd16b5832af1441030c7b76f237a8))
+* **cli:** add custom install logic to edition-node ([f04fd26](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/f04fd266429cd806987dab747e6d69bff9b926a4))
+* **cli:** allow any package to be installed as a starterkit ([d2aa1be](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/d2aa1be810a0a7473dcc52391a2263dacfdda0b8)), closes [#1067](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/issues/1067)
+* **cli:** merge config arrays via overwrite instead of concatenate ([42e5f7b](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/42e5f7b42a26b4fc1f262c68ee4b474b546f2eac))
+* **cli:** proper path resolution to helpers ([a18fe5e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/a18fe5ef4d1c074a5eba8bfa255ebbee2261bf74))
+* **cli:** re-order and clarify engines ([e39e301](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/e39e301a33306c6615fabf64262f1893ca682b97))
+* **plugin:** correct spelling error and function locations ([d4abd88](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/d4abd88cb017550002407241b5045a2ad1adb1dc))
+
+
+### Features
+
+* **starterkits:** add starterkit-handlebars-demo ([384d2cf](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/384d2cfa3440c1e6f456d39f56ca6381f82f7689))
+
+
+### BREAKING CHANGES
+
+* **cli:** previously, we concatenated arrays, which is unlikely to be intended
+
+
+
+
+
+
+## [1.0.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/@pattern-lab/cli@1.0.2...@pattern-lab/cli@1.0.3) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
+
+# [1.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/@pattern-lab/cli@0.1.0...@pattern-lab/cli@1.0.0) (2019-08-23)
+
+
+### Bug Fixes
+
+* **cli:** merge config arrays via overwrite instead of concatenate ([42e5f7b](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/42e5f7b))
+* **cli:** proper path resolution to helpers ([a18fe5e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/a18fe5e))
+
+
+### BREAKING CHANGES
+
+* **cli:** previously, we concatenated arrays, which is unlikely to be intended
+
+
+
+
+
+# [0.1.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/@pattern-lab/cli@0.0.3...@pattern-lab/cli@0.1.0) (2019-08-23)
+
+
+### Bug Fixes
+
+* updates to fix eslint / prettier issues; update packages/core to reuse root .eslintrc.js file ([5b7a057](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/5b7a057))
+* **cli:** add custom install logic to edition-node ([f04fd26](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/f04fd26))
+* **cli:** re-order and clarify engines ([e39e301](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/e39e301))
+
+
+### Features
+
+* **starterkits:** add starterkit-handlebars-demo ([384d2cf](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/commit/384d2cf))
+
+
+
+
+
+
+## [0.0.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/@pattern-lab/cli@0.0.3-alpha.0...@pattern-lab/cli@0.0.3) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/cli
+
+
+
+
+
## [0.0.1-beta.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli/compare/@pattern-lab/cli@0.0.1-beta.0...@pattern-lab/cli@0.0.1-beta.2) (2019-02-09)
diff --git a/packages/cli/bin/archive.js b/packages/cli/bin/archive.js
index 9d7a6989c..e27696977 100644
--- a/packages/cli/bin/archive.js
+++ b/packages/cli/bin/archive.js
@@ -31,7 +31,7 @@ function exportPatterns(config) {
);
});
- archive.on('error', function(err) {
+ archive.on('error', function (err) {
throw new TypeError(
`export: An error occured during zipping the patterns: ${err}`
);
diff --git a/packages/cli/bin/ask.js b/packages/cli/bin/ask.js
index 55a337230..652fbda3b 100644
--- a/packages/cli/bin/ask.js
+++ b/packages/cli/bin/ask.js
@@ -12,8 +12,8 @@ const ask = inquirer.prompt;
* @param {object} options - Options passed in from CLI
* @param {boolean} options.force - Flag whether to force install in existing project directory. May overwrite stuff.
*/
-const init = options =>
- wrapsAsync(function*() {
+const init = (options) =>
+ wrapsAsync(function* () {
/**
* @property {string} project_root="./" - Path to the project root directory
* @property {string|Symbol} edition - The name of the edition npm package or a Symbol for no install
diff --git a/packages/cli/bin/build.js b/packages/cli/bin/build.js
index 51108a33d..383be9b59 100644
--- a/packages/cli/bin/build.js
+++ b/packages/cli/bin/build.js
@@ -19,6 +19,10 @@ function build(config, options) {
// Initiate Pattern Lab core with the config
const patternLab = pl(config);
+ if (options && options.watch) {
+ config.watch = options.watch;
+ }
+
/**
* Check whether a flag was passed for build
* 1. Build only patterns
@@ -31,7 +35,7 @@ function build(config, options) {
} else {
// 2
debug(`build: Building your project now into ${config.paths.public.root}`);
- return patternLab.build(config.cleanPublic);
+ return patternLab.build(config);
}
}
diff --git a/packages/cli/bin/cli-actions/build.js b/packages/cli/bin/cli-actions/build.js
index c6a34434a..b9a752665 100644
--- a/packages/cli/bin/cli-actions/build.js
+++ b/packages/cli/bin/cli-actions/build.js
@@ -3,10 +3,10 @@ const buildPatterns = require('../build');
const resolveConfig = require('../resolve-config');
const { error, info, wrapAsync } = require('../utils');
-const build = options =>
- wrapAsync(function*() {
+const build = (options) =>
+ wrapAsync(function* () {
try {
- const config = yield resolveConfig(options.parent.config);
+ const config = yield resolveConfig(options.config);
yield buildPatterns(config, options);
info(`build: Yay, your Pattern Lab project was successfully built ☺`);
} catch (err) {
diff --git a/packages/cli/bin/cli-actions/disable.js b/packages/cli/bin/cli-actions/disable.js
index ebf90ef60..35a460dc7 100644
--- a/packages/cli/bin/cli-actions/disable.js
+++ b/packages/cli/bin/cli-actions/disable.js
@@ -10,9 +10,12 @@ const writeJsonAsync = require('../utils').writeJsonAsync;
* @desc Handles deactivation of starterkits/plugins
* @param {object} options
*/
-const enable = options =>
- wrapAsync(function*() {
- const { parent: { config: configPath }, plugins } = options;
+const enable = (options) =>
+ wrapAsync(function* () {
+ const {
+ parent: { config: configPath },
+ plugins,
+ } = options;
const config = yield resolveConfig(configPath);
const spinner = ora(`⊙ patternlab → Disable …`).start();
@@ -21,7 +24,7 @@ const enable = options =>
spinner.succeed(
`⊙ patternlab → Disable following plugins: ${plugins.join(', ')}`
);
- plugins.map(plugin => {
+ plugins.map((plugin) => {
if (_.has(config, `plugins[${plugin}]`)) {
_.set(config, `plugins[${plugin}]['enabled']`, false);
spinner.succeed(
@@ -32,7 +35,7 @@ const enable = options =>
}
});
}
- yield writeJsonAsync(options.parent.config, config);
+ yield writeJsonAsync(options.config, config);
spinner.succeed(`⊙ patternlab → Updated config`);
});
diff --git a/packages/cli/bin/cli-actions/enable.js b/packages/cli/bin/cli-actions/enable.js
index d7095f25f..f5a3c67fb 100644
--- a/packages/cli/bin/cli-actions/enable.js
+++ b/packages/cli/bin/cli-actions/enable.js
@@ -10,9 +10,12 @@ const writeJsonAsync = require('../utils').writeJsonAsync;
* @desc Handles activation of starterkits/plugins
* @param {object} options
*/
-const enable = options =>
- wrapAsync(function*() {
- const { parent: { config: configPath }, plugins } = options;
+const enable = (options) =>
+ wrapAsync(function* () {
+ const {
+ parent: { config: configPath },
+ plugins,
+ } = options;
const config = yield resolveConfig(configPath);
const spinner = ora(`⊙ patternlab → Enable …`).start();
@@ -21,7 +24,7 @@ const enable = options =>
spinner.succeed(
`⊙ patternlab → Enable following plugins: ${plugins.join(', ')}`
);
- plugins.map(plugin => {
+ plugins.map((plugin) => {
if (_.has(config, `plugins[${plugin}]`)) {
_.set(config, `plugins[${plugin}]['enabled']`, true);
spinner.succeed(`⊙ patternlab → Enabled following plugin: ${plugin}`);
@@ -30,7 +33,7 @@ const enable = options =>
}
});
}
- yield writeJsonAsync(options.parent.config, config);
+ yield writeJsonAsync(options.config, config);
spinner.succeed(`⊙ patternlab → Updated config`);
});
diff --git a/packages/cli/bin/cli-actions/export.js b/packages/cli/bin/cli-actions/export.js
index 5f4f4ebc7..bfe674770 100644
--- a/packages/cli/bin/cli-actions/export.js
+++ b/packages/cli/bin/cli-actions/export.js
@@ -3,9 +3,9 @@ const archive = require('../archive');
const resolveConfig = require('../resolve-config');
const wrapAsync = require('../utils').wrapAsync;
-const _export = options =>
- wrapAsync(function*() {
- const config = yield resolveConfig(options.parent.config);
+const _export = (options) =>
+ wrapAsync(function* () {
+ const config = yield resolveConfig(options.config);
archive(config);
});
diff --git a/packages/cli/bin/cli-actions/help.js b/packages/cli/bin/cli-actions/help.js
index 6448e7749..e3ff72c85 100644
--- a/packages/cli/bin/cli-actions/help.js
+++ b/packages/cli/bin/cli-actions/help.js
@@ -3,8 +3,8 @@ module.exports = () => {
/* eslint-disable */
console.log(`
Examples:
- $ patternlab init # Initialize a Pattern Lab project.');
- $ patternlab # Builds Pattern Lab from the current dir');
- $ patternlab --config # Pattern Lab from a config in a specified directory');`);
+ $ patternlab init # Initialize a Pattern Lab project
+ $ patternlab # Builds Pattern Lab from the current dir
+ $ patternlab --config # Pattern Lab from a config in a specified directory`);
/* eslint-enable */
};
diff --git a/packages/cli/bin/cli-actions/init.js b/packages/cli/bin/cli-actions/init.js
index b8c743188..ff4decc91 100644
--- a/packages/cli/bin/cli-actions/init.js
+++ b/packages/cli/bin/cli-actions/init.js
@@ -13,8 +13,11 @@ const writeJsonAsync = require('../utils').writeJsonAsync;
const defaultPatternlabConfig = patternlab.getDefaultConfig();
-const init = options =>
- wrapAsync(function*() {
+// https://github.com/TehShrike/deepmerge#overwrite-array
+const overwriteMerge = (destinationArray, sourceArray) => sourceArray;
+
+const init = (options) =>
+ wrapAsync(function* () {
const sourceDir = 'source';
const publicDir = 'public';
const exportDir = 'pattern_exports';
@@ -43,6 +46,7 @@ const init = options =>
); // 1
yield scaffold(projectDir, sourceDir, publicDir, exportDir); // 2
+ process.env.projectDir = path.join(process.cwd(), projectDir);
if (edition) {
spinner.text = `⊙ patternlab → Installing edition: ${edition}`;
@@ -52,7 +56,9 @@ const init = options =>
projectDir
); // 3.1
if (newConf) {
- patternlabConfig = merge(patternlabConfig, newConf); // 3.2
+ patternlabConfig = merge(patternlabConfig, newConf, {
+ arrayMerge: overwriteMerge,
+ }); // 3.2
}
spinner.succeed(`⊙ patternlab → Installed edition: ${edition}`);
}
@@ -65,7 +71,9 @@ const init = options =>
);
spinner.succeed(`⊙ patternlab → Installed starterkit: ${starterkit}`);
if (starterkitConfig) {
- patternlabConfig = merge(patternlabConfig, starterkitConfig);
+ patternlabConfig = merge(patternlabConfig, starterkitConfig, {
+ arrayMerge: overwriteMerge,
+ });
}
} // 4
yield writeJsonAsync(
diff --git a/packages/cli/bin/cli-actions/install.js b/packages/cli/bin/cli-actions/install.js
index 28aa8a445..a00fca97f 100644
--- a/packages/cli/bin/cli-actions/install.js
+++ b/packages/cli/bin/cli-actions/install.js
@@ -11,9 +11,9 @@ const writeJsonAsync = require('../utils').writeJsonAsync;
* @desc Handles async install and activation of starterkits/plugins
* @param {object} options
*/
-const install = options =>
- wrapAsync(function*() {
- const config = yield resolveConfig(options.parent.config);
+const install = (options) =>
+ wrapAsync(function* () {
+ const config = yield resolveConfig(options.config);
const spinner = ora(
`⊙ patternlab → Installing additional resources …`
@@ -21,8 +21,8 @@ const install = options =>
if (options.starterkits && Array.isArray(options.starterkits)) {
const starterkits = yield Promise.all(
- options.starterkits.map(starterkit =>
- wrapAsync(function*() {
+ options.starterkits.map((starterkit) =>
+ wrapAsync(function* () {
spinner.text = `⊙ patternlab → Installing starterkit: ${starterkit}`;
return yield installStarterkit(
{
@@ -42,8 +42,8 @@ const install = options =>
}
if (options.plugins && Array.isArray(options.plugins)) {
const plugins = yield Promise.all(
- options.plugins.map(plugin =>
- wrapAsync(function*() {
+ options.plugins.map((plugin) =>
+ wrapAsync(function* () {
return yield installPlugin(
{
name: plugin,
@@ -58,7 +58,7 @@ const install = options =>
`⊙ patternlab → Installed following plugins: ${plugins.join(', ')}`
);
}
- yield writeJsonAsync(options.parent.config, config);
+ yield writeJsonAsync(options.config, config);
spinner.succeed(`⊙ patternlab → Updated config`);
});
diff --git a/packages/cli/bin/cli-actions/serve.js b/packages/cli/bin/cli-actions/serve.js
index 6e2cc8fd2..40576a761 100644
--- a/packages/cli/bin/cli-actions/serve.js
+++ b/packages/cli/bin/cli-actions/serve.js
@@ -3,9 +3,9 @@ const resolveConfig = require('../resolve-config');
const servePatterns = require('../serve');
const wrapAsync = require('../utils').wrapAsync;
-const serve = options =>
- wrapAsync(function*() {
- const config = yield resolveConfig(options.parent.config);
+const serve = (options) =>
+ wrapAsync(function* () {
+ const config = yield resolveConfig(options.config);
servePatterns(config, options);
});
diff --git a/packages/cli/bin/inquiries/edition.js b/packages/cli/bin/inquiries/edition.js
index 08cc2b068..fca4958f2 100644
--- a/packages/cli/bin/inquiries/edition.js
+++ b/packages/cli/bin/inquiries/edition.js
@@ -12,23 +12,15 @@ const editionSetup = [
{
type: 'list',
name: 'edition',
- message: 'Which edition do you want to use (defaults to edition-node)?',
+ message: 'What templating language do you want to use with Pattern Lab?',
choices: [
{
- name: 'edition-twig (php engine)',
- value: '@pattern-lab/edition-twig',
- },
- {
- name: 'edition-node',
+ name: 'Handlebars',
value: '@pattern-lab/edition-node',
},
{
- name: 'edition-node-grunt',
- value: '@pattern-lab/edition-node-grunt',
- },
- {
- name: 'edition-node-gulp',
- value: '@pattern-lab/edition-node-gulp',
+ name: 'Twig (PHP)',
+ value: '@pattern-lab/edition-twig',
},
new inquirer.Separator(),
{
@@ -36,9 +28,9 @@ const editionSetup = [
value: false,
},
],
- default: function() {
+ default: function () {
return {
- name: 'edition-node',
+ name: 'Handlebars',
value: '@pattern-lab/edition-node',
};
},
diff --git a/packages/cli/bin/inquiries/starterkit.js b/packages/cli/bin/inquiries/starterkit.js
index 9c4e5ca7b..c158c2189 100644
--- a/packages/cli/bin/inquiries/starterkit.js
+++ b/packages/cli/bin/inquiries/starterkit.js
@@ -7,48 +7,20 @@ const starterkitSetup = [
{
type: 'list',
name: 'starterkit',
- message: 'Which starterkit do you want to use?',
+ message: 'What initial patterns do you want included in your project?',
choices: [
{
- name: 'starterkit-mustache-demo',
- value: '@pattern-lab/starterkit-mustache-demo',
+ name: 'Handlebars base patterns (some basic patterns to get started with)',
+ value: '@pattern-lab/starterkit-handlebars-vanilla',
},
{
- name: 'starterkit-mustache-bootstrap',
- value: 'starterkit-mustache-bootstrap',
+ name: 'Handlebars demo patterns (full demo website and patterns)',
+ value: '@pattern-lab/starterkit-handlebars-demo',
},
{
- name: 'starterkit-mustache-foundation',
- value: 'starterkit-mustache-foundation',
- },
- // {
- // name: 'starterkit-twig-base',
- // value: 'starterkit-twig-base',
- // },
- {
- name: 'starterkit-twig-demo',
+ name: 'Twig (PHP) demo patterns (full demo website and patterns)',
value: '@pattern-lab/starterkit-twig-demo',
},
- {
- name: 'starterkit-mustache-materialdesign',
- value: 'starterkit-mustache-materialdesign',
- },
- // {
- // name: 'starterkit-twig-drupal-demo',
- // value: 'starterkit-twig-drupal-demo',
- // },
- // {
- // name: 'starterkit-twig-drupal-minimal',
- // value: 'starterkit-twig-drupal-minimal',
- // },
- {
- name: 'starterkit-mustache-webdesignday',
- value: 'starterkit-mustache-webdesignday',
- },
- {
- name: 'starterkit-mustache-base',
- value: '@pattern-lab/starterkit-mustache-base',
- },
new inquirer.Separator(),
{
name: 'Custom starterkit',
@@ -56,13 +28,13 @@ const starterkitSetup = [
},
new inquirer.Separator(),
{
- name: 'None',
+ name: 'Blank project (no patterns)',
value: false,
},
],
default: {
- name: 'starterkit-mustache-base',
- value: 'starterkit-mustache-base',
+ name: 'Handlebars demo patterns (full demo website and patterns)',
+ value: '@pattern-lab/starterkit-handlebars-demo',
},
},
{
diff --git a/packages/cli/bin/install-edition.js b/packages/cli/bin/install-edition.js
index 5e63efd28..7d39dfdd0 100644
--- a/packages/cli/bin/install-edition.js
+++ b/packages/cli/bin/install-edition.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-param-reassign */
'use strict';
const path = require('path');
@@ -10,11 +11,18 @@ const {
writeJsonAsync,
getJSONKey,
} = require('./utils');
+const {
+ resolveFileInPackage,
+ resolveDirInPackage,
+} = require('@pattern-lab/core/src/lib/resolver');
+
+// https://github.com/TehShrike/deepmerge#overwrite-array
+const overwriteMerge = (destinationArray, sourceArray) => sourceArray;
const installEdition = (edition, config, projectDir) => {
const pkg = require(path.resolve(projectDir, 'package.json'));
- return wrapAsync(function*() {
+ return wrapAsync(function* () {
/**
* 1. Trigger edition install
* 2. Copy over the mandatory edition files to sourceDir
@@ -27,7 +35,7 @@ const installEdition = (edition, config, projectDir) => {
const sourceDir = config.paths.source.root;
yield checkAndInstallPackage(edition); // 1
yield copyAsync(
- path.resolve('./node_modules', edition, 'source', '_meta'),
+ resolveDirInPackage(edition, 'source', '_meta'),
path.resolve(sourceDir, '_meta')
); // 2
pkg.dependencies = Object.assign(
@@ -35,29 +43,44 @@ const installEdition = (edition, config, projectDir) => {
pkg.dependencies || {},
yield getJSONKey(edition, 'dependencies')
); // 3
- switch (edition) { // 4
+ switch (
+ edition // 4
+ ) {
// 4.1
case '@pattern-lab/edition-node-gulp': {
yield copyAsync(
- path.resolve('./node_modules', edition, 'gulpfile.js'),
+ resolveFileInPackage(edition, 'gulpfile.js'),
path.resolve(sourceDir, '../', 'gulpfile.js')
);
break;
}
// 4.2
case '@pattern-lab/edition-node': {
+ const editionConfigPath = resolveFileInPackage(
+ edition,
+ 'patternlab-config.json'
+ );
+
+ const editionConfig = require(editionConfigPath);
+
pkg.scripts = Object.assign(
{},
pkg.scripts || {},
yield getJSONKey(edition, 'scripts')
);
+
+ yield copyAsync(
+ resolveFileInPackage(edition, 'helpers', 'test.js'),
+ path.resolve(sourceDir, '../', 'helpers/test.js')
+ );
+
+ config = merge(config, editionConfig, { arrayMerge: overwriteMerge });
break;
}
// 4.3
case '@pattern-lab/edition-twig': {
- const editionPath = path.resolve('./node_modules', edition);
- const editionConfigPath = path.resolve(
- editionPath,
+ const editionConfigPath = resolveFileInPackage(
+ edition,
'patternlab-config.json'
);
const editionConfig = require(editionConfigPath);
@@ -69,11 +92,11 @@ const installEdition = (edition, config, projectDir) => {
);
yield copyAsync(
- path.resolve(editionPath, 'alter-twig.php'),
+ resolveFileInPackage(edition, 'alter-twig.php'),
path.resolve(sourceDir, '../', 'alter-twig.php')
);
- config = merge(config, editionConfig);
+ config = merge(config, editionConfig, { arrayMerge: overwriteMerge });
break;
}
}
diff --git a/packages/cli/bin/install-plugin.js b/packages/cli/bin/install-plugin.js
index 42ea84c63..f152076b0 100644
--- a/packages/cli/bin/install-plugin.js
+++ b/packages/cli/bin/install-plugin.js
@@ -1,14 +1,12 @@
'use strict';
-const path = require('path');
-
const _ = require('lodash');
-const checkAndInstallPackage = require('./utils').checkAndInstallPackage;
-const wrapAsync = require('./utils').wrapAsync;
+const { checkAndInstallPackage, wrapAsync } = require('./utils');
+const { resolveFileInPackage } = require('@pattern-lab/core/src/lib/resolver');
const installPlugin = (plugin, config) =>
- wrapAsync(function*() {
+ wrapAsync(function* () {
const name = plugin.name || plugin;
yield checkAndInstallPackage(name);
// Put the installed plugin in the patternlab-config.json
@@ -16,13 +14,11 @@ const installPlugin = (plugin, config) =>
_.set(config, `plugins[${name}]['initialized']`, false);
// Get the options from the plugin, if any
- const pluginPathConfig = path.resolve(
- path.join(process.cwd(), 'node_modules', name, 'config.json')
- );
+ const pluginPathConfig = resolveFileInPackage(name, 'config.json');
try {
const pluginConfigJSON = require(pluginPathConfig);
if (!_.has(config.plugins[name].options)) {
- _.set(config, `plugins[${name}]['options]`, pluginConfigJSON);
+ _.set(config, `plugins[${name}][options]`, pluginConfigJSON);
}
} catch (ex) {
//a config.json file is not required at this time
diff --git a/packages/cli/bin/install-starterkit.js b/packages/cli/bin/install-starterkit.js
index f9b5f6135..016548737 100644
--- a/packages/cli/bin/install-starterkit.js
+++ b/packages/cli/bin/install-starterkit.js
@@ -7,17 +7,25 @@ const {
checkAndInstallPackage,
readJsonAsync,
} = require('./utils');
+const {
+ resolvePackageFolder,
+ resolveDirInPackage,
+} = require('@pattern-lab/core/src/lib/resolver');
const installStarterkit = (starterkit, config) =>
- wrapAsync(function*() {
+ wrapAsync(function* () {
const sourceDir = config.paths.source.root;
const name = starterkit.value || starterkit;
- const url = name.startsWith('@pattern-lab/') ? name : `pattern-lab/${name}`;
- yield checkAndInstallPackage(name, url);
- const kitPath = path.resolve('./node_modules', name);
- yield copyAsync(path.resolve(kitPath, 'dist'), path.resolve(sourceDir));
+ yield checkAndInstallPackage(name);
+ yield copyAsync(
+ resolveDirInPackage(name, 'dist'),
+ path.resolve(process.env.projectDir || '', sourceDir)
+ );
let kitConfig;
- const kitConfigPath = path.resolve(kitPath, 'patternlab-config.json');
+ const kitConfigPath = path.join(
+ resolvePackageFolder(name),
+ 'patternlab-config.json'
+ );
if (fs.existsSync(kitConfigPath)) {
kitConfig = yield readJsonAsync(kitConfigPath);
}
diff --git a/packages/cli/bin/patternlab.js b/packages/cli/bin/patternlab.js
index 0e7eeed22..a645f3259 100755
--- a/packages/cli/bin/patternlab.js
+++ b/packages/cli/bin/patternlab.js
@@ -1,6 +1,8 @@
#!/usr/bin/env node
+/* eslint-disable no-unused-vars */
'use strict';
-const cli = require('commander');
+const { Command } = require('commander');
+const cli = new Command();
const path = require('path');
const build = require('./cli-actions/build');
const disable = require('./cli-actions/disable');
@@ -15,12 +17,11 @@ const { error, log } = require('./utils');
const pkg = require('../package.json');
// Register info and error logging
-log.on('patternlab.error', err => console.log(err)); // eslint-disable-line
-log.on('patternlab.info', msg => console.log(msg)); // eslint-disable-line
+log.on('patternlab.error', (err) => console.log(err)); // eslint-disable-line
+log.on('patternlab.info', (msg) => console.log(msg)); // eslint-disable-line
// Conditionally register verbose logging
-const verboseLogs = verbose =>
- log.on('patternlab.debug', msg => console.log(msg)); // eslint-disable-line
+const verboseLogs = () => log.on('patternlab.debug', (msg) => console.log(msg)); // eslint-disable-line
// Conditionally unregister all logging
const silenceLogs = () => {
@@ -30,7 +31,7 @@ const silenceLogs = () => {
};
// Split strings into an array
-const list = val => val.split(',');
+const list = (val) => val.split(',');
/**
* Hook up cli version, usage and options
@@ -38,15 +39,7 @@ const list = val => val.split(',');
cli
.version(version(pkg), '-V, --version')
.usage(' [options]')
- .arguments(' [options]')
- .option(
- '-c, --config ',
- 'Specify config file. Default looks up the project dir',
- val => val.trim(),
- path.resolve(process.cwd(), 'patternlab-config.json')
- )
- .option('-v, --verbose', 'Show verbose console logs', verboseLogs)
- .option('--silent', 'Turn off console logs', silenceLogs);
+ .arguments(' [options]');
/**
* build
@@ -57,7 +50,7 @@ cli
.alias('compile')
.description('Build Pattern Lab. Optionally (re-)build only the patterns')
.option('-p, --patterns-only', 'Whether to only build patterns')
- .option('--no-watch', 'Start watching for changes')
+ .option('--watch', 'Start watching for changes')
.action(build);
/**
@@ -134,6 +127,20 @@ cli
.option('--no-watch', 'Start watching for changes')
.action(serve);
+// Common options can be added manually after setting up program and subcommands.
+// If the options are unsorted in the help, these will appear last.
+cli.commands.forEach((command) => {
+ command
+ .option(
+ '-c, --config ',
+ 'Specify config file. Default looks up the project dir',
+ (val) => val.trim(),
+ path.resolve(process.cwd(), 'patternlab-config.json')
+ )
+ .option('-v, --verbose', 'Show verbose console logs', verboseLogs)
+ .option('--silent', 'Turn off console logs', silenceLogs);
+});
+
// Show additional help
cli.on('--help', help);
diff --git a/packages/cli/bin/resolve-config.js b/packages/cli/bin/resolve-config.js
index f34c5e083..f81ed6aba 100644
--- a/packages/cli/bin/resolve-config.js
+++ b/packages/cli/bin/resolve-config.js
@@ -1,5 +1,5 @@
'use strict';
-const exists = require('path-exists');
+const fs = require('fs-extra');
const path = require('path');
const error = require('./utils').error;
const readJsonAsync = require('./utils').readJsonAsync;
@@ -12,14 +12,14 @@ const wrapAsync = require('./utils').wrapAsync;
* @return {object|boolean} Returns the config object or false otherwise.
*/
function resolveConfig(configPath) {
- return wrapAsync(function*() {
+ return wrapAsync(function* () {
if (typeof configPath !== 'string') {
error(
'resolveConfig: If configPath is set, it is expected to be of type string.'
);
return false;
}
- if (!exists.sync(configPath)) {
+ if (!fs.existsSync(configPath)) {
error(`resolveConfig: configPath ${configPath} does not exists`);
return false;
}
diff --git a/packages/cli/bin/scaffold.js b/packages/cli/bin/scaffold.js
index f817ac50d..ac2b4378b 100644
--- a/packages/cli/bin/scaffold.js
+++ b/packages/cli/bin/scaffold.js
@@ -1,7 +1,7 @@
'use strict';
const path = require('path');
const execa = require('execa');
-const fs = require('fs');
+const fs = require('fs-extra');
const wrapAsync = require('./utils').wrapAsync;
const mkdirsAsync = require('./utils').mkdirsAsync;
@@ -15,9 +15,13 @@ const mkdirsAsync = require('./utils').mkdirsAsync;
* @return {void}
*/
const scaffold = (projectDir, sourceDir, publicDir, exportDir) =>
- wrapAsync(function*() {
- if (!fs.existsSync(path.resolve(projectDir, 'package.json'))) {
- execa.sync('npm', ['init', '-y']);
+ wrapAsync(function* () {
+ const projectPath = path.join(process.cwd(), projectDir);
+ if (!fs.existsSync(path.join(projectPath, 'package.json'))) {
+ fs.ensureDirSync(projectPath);
+ execa.sync('npm', ['init', '-y'], {
+ cwd: projectPath,
+ });
}
/**
* Create mandatory files structure
diff --git a/packages/cli/bin/utils.js b/packages/cli/bin/utils.js
index aae408bbb..dbf6e3aa8 100644
--- a/packages/cli/bin/utils.js
+++ b/packages/cli/bin/utils.js
@@ -6,6 +6,10 @@ const path = require('path');
const chalk = require('chalk');
const EventEmitter = require('events').EventEmitter;
const hasYarn = require('has-yarn');
+const {
+ resolvePackageFolder,
+ resolveFileInPackage,
+} = require('@pattern-lab/core/src/lib/resolver');
/**
* @name log
@@ -62,7 +66,7 @@ const error = log.error.bind(log);
* @desc Wraps an generator function to yield out promisified stuff
* @param {function} fn - Takes a generator function
*/
-const wrapAsync = fn =>
+const wrapAsync = (fn) =>
new Promise((resolve, reject) => {
const generator = fn();
/* eslint-disable */
@@ -80,9 +84,7 @@ const wrapAsync = fn =>
if (res.done) {
return resolve(v);
}
- Promise.resolve(v)
- .then(spwn)
- .catch(spwn);
+ Promise.resolve(v).then(spwn).catch(spwn);
})();
/* eslint-enable */
});
@@ -96,10 +98,8 @@ const wrapAsync = fn =>
*/
const asyncGlob = (pattern, opts) =>
new Promise((resolve, reject) =>
- glob(
- pattern,
- opts,
- (err, matches) => (err !== null ? reject(err) : resolve(matches))
+ glob(pattern, opts, (err, matches) =>
+ err !== null ? reject(err) : resolve(matches)
)
);
@@ -112,13 +112,13 @@ const asyncGlob = (pattern, opts) =>
* @return {Promise}
*/
const copyWithPattern = (cwd, pattern, dest) =>
- wrapAsync(function*() {
+ wrapAsync(function* () {
const files = yield asyncGlob(pattern, { cwd: cwd });
if (files.length === 0) {
debug('copy: Nothing to copy');
}
// Copy concurrently
- const promises = files.map(file =>
+ const promises = files.map((file) =>
fs.copy(path.join(cwd, file), path.join(dest, file))
);
return yield Promise.all(promises);
@@ -126,18 +126,21 @@ const copyWithPattern = (cwd, pattern, dest) =>
/**
* @func fetchPackage
- * @desc Fetches and saves packages from npm into node_modules and adds a reference in the package.json under dependencies
+ * @desc Fetches packages from an npm package registry and adds a reference in the package.json under dependencies
* @param {string} packageName - The package name
- * @param {string} [url] - A URL which will be used to fetch the package from
*/
-const fetchPackage = (packageName, url) =>
- wrapAsync(function*() {
+const fetchPackage = (packageName) =>
+ wrapAsync(function* () {
const useYarn = hasYarn();
const pm = useYarn ? 'yarn' : 'npm';
const installCmd = useYarn ? 'add' : 'install';
try {
- if (packageName || url) {
- const cmd = yield spawn(pm, [installCmd, url || packageName]);
+ if (packageName) {
+ const opts = {};
+ if (process.env.projectDir) {
+ opts.cwd = process.env.projectDir;
+ }
+ const cmd = yield spawn(pm, [installCmd, packageName], opts);
error(cmd.stderr);
}
} catch (err) {
@@ -152,19 +155,18 @@ const fetchPackage = (packageName, url) =>
* @func checkAndInstallPackage
* Checks whether a package for a given packageName is installed locally. If package cannot be found, fetch and install it
* @param {string} packageName - The package name
- * @param {string} [url] - A URL which will be used to fetch the package from
* @return {boolean}
*/
-const checkAndInstallPackage = (packageName, url) =>
- wrapAsync(function*() {
+const checkAndInstallPackage = (packageName) =>
+ wrapAsync(function* () {
try {
- require.resolve(packageName);
+ resolvePackageFolder(packageName);
return true;
} catch (err) {
debug(
`checkAndInstallPackage: ${packageName} not installed. Fetching it now …`
);
- yield fetchPackage(packageName, url);
+ yield fetchPackage(packageName);
return false;
}
});
@@ -182,7 +184,7 @@ const noop = () => {};
* @param {object} data
*/
const writeJsonAsync = (filePath, data) =>
- wrapAsync(function*() {
+ wrapAsync(function* () {
yield fs.outputJSON(filePath, data, { spaces: 2 });
});
@@ -194,10 +196,10 @@ const writeJsonAsync = (filePath, data) =>
* @param {object} fileName - the filePath of the JSON
*/
const getJSONKey = (packageName, key, fileName = 'package.json') =>
- wrapAsync(function*() {
+ wrapAsync(function* () {
yield checkAndInstallPackage(packageName);
const jsonData = yield fs.readJson(
- path.resolve('node_modules', packageName, fileName)
+ resolveFileInPackage(packageName, fileName)
);
return jsonData[key];
});
diff --git a/packages/cli/license b/packages/cli/license
index ec350935b..e4746ea6b 100644
--- a/packages/cli/license
+++ b/packages/cli/license
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2016 Raphael Okon
+Copyright Patternlab contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/packages/cli/package.json b/packages/cli/package.json
index 2ea9f8808..ddfe4da2e 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -1,37 +1,35 @@
{
"name": "@pattern-lab/cli",
"description": "Command-line interface (CLI) for the @pattern-lab/core.",
- "version": "0.0.3-alpha.0",
+ "version": "6.1.0",
"bin": {
"patternlab": "bin/patternlab.js"
},
"author": {
- "name": "Raphael Okon"
+ "name": "Patternlab contributors"
},
"dependencies": {
- "@pattern-lab/core": "^3.0.1-alpha.0",
- "@pattern-lab/live-server": "^1.3.3-beta.1",
- "archiver": "2.1.1",
- "chalk": "2.4.1",
- "commander": "2.15.1",
- "deepmerge": "^2.1.1",
- "execa": "0.10.0",
- "fs-extra": "6.0.1",
- "glob": "7.1.2",
- "has-yarn": "1.0.0",
- "inquirer": "5.1.0",
- "lodash": "4.17.10",
- "ora": "2.1.0",
- "path-exists": "3.0.0",
- "sanitize-filename": "1.6.1"
+ "@pattern-lab/core": "^6.1.0",
+ "archiver": "5.3.0",
+ "chalk": "4.1.0",
+ "commander": "9.4.1",
+ "deepmerge": "^4.2.2",
+ "execa": "5.0.0",
+ "fs-extra": "10.0.0",
+ "glob": "7.1.6",
+ "has-yarn": "2.1.0",
+ "inquirer": "8.0.0",
+ "lodash": "4.17.21",
+ "ora": "5.4.0"
},
"devDependencies": {
+ "dos2unix-cli": "^1.0.1",
"eslint": "4.18.2",
"eslint-config-prettier": "2.9.0",
"eslint-plugin-prettier": "2.6.0",
- "prettier": "1.11.1",
- "proxyquire": "2.0.1",
- "tap": "11.1.1"
+ "prettier": "2.8.1",
+ "proxyquire": "2.1.3",
+ "tap": "14.11.0"
},
"files": [
"bin"
@@ -44,15 +42,17 @@
],
"scripts": {
"lint": "eslint ./{bin,test}",
- "test:separate": "tap './test/*.test.js' --reporter spec --timeout=120"
+ "test:separate": "tap './test/*.test.js' --reporter spec --timeout=120",
+ "prepublish": "npx dos2unix-cli bin/patternlab.js"
},
"repository": "https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli",
"bugs": "https://github.com/pattern-lab/patternlab-node/issues",
"license": "MIT",
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/cli/readme.md b/packages/cli/readme.md
index e5a9ae95e..b415e63dd 100644
--- a/packages/cli/readme.md
+++ b/packages/cli/readme.md
@@ -2,7 +2,8 @@
> Command-line interface (CLI) for the patternlab-node core.
-[](https://travis-ci.org/pattern-lab/patternlab-node)
+[](https://github.com/pattern-lab/patternlab-node/actions/workflows/continuous-integration.yml)
+[](https://github.com/pattern-lab/patternlab-node/actions/workflows/codeql-analysis.yml)
## Installation
@@ -93,8 +94,8 @@ Passing no options starts the init in interactive mode
Options:
-h, --help output usage information
-p, --project-dir Specify a project directory. Default: ./
- -e, --edition Specify an edition to install. Default: edition-node
- -k, --starterkit Specify a starterkit to install. Default: starterkit-mustache-base
+ -e, --edition Specify an edition to install. Default: @pattern-lab/edition-node
+ -k, --starterkit Specify a starterkit to install. Default: @pattern-lab/starterkit-handlebars-demo
```
### Serve Pattern Lab
@@ -139,4 +140,4 @@ Installs Pattern Lab related modules like starterkits or plugins
$ patternlab build --config # Builds Pattern Lab from different project directory
```
## License
-MIT © [Raphael Okon](https://github.com/raphaelokon)
+MIT © [Patternlab contributors](https://github.com/pattern-lab/patternlab-node/blob/master/CODEOWNERS)
diff --git a/packages/cli/test/build.test.js b/packages/cli/test/build.test.js
index 6a56cb6fe..8ee4770f4 100644
--- a/packages/cli/test/build.test.js
+++ b/packages/cli/test/build.test.js
@@ -10,7 +10,7 @@ const build = proxyquire('../bin/build', {
});
const opts = { patternsOnly: true };
-tap.test('Build ->', t => {
+tap.test('Build ->', (t) => {
t.throws(
() => {
build();
diff --git a/packages/cli/test/cli-build.test.js b/packages/cli/test/cli-build.test.js
index d6712deae..644d56429 100644
--- a/packages/cli/test/cli-build.test.js
+++ b/packages/cli/test/cli-build.test.js
@@ -1,4 +1,4 @@
-const exists = require('path-exists');
+const fs = require('fs-extra');
const getUniqueProjectPath = require('./utils/getUniqueProjectPath');
const path = require('path');
const spawnCmd = require('./utils/spawnCmd');
@@ -7,8 +7,8 @@ const wrapAsync = require('../bin/utils').wrapAsync;
const projectRoot = getUniqueProjectPath();
-tap.test('Init and build ->', t =>
- wrapAsync(function*() {
+tap.test('Init and build ->', (t) =>
+ wrapAsync(function* () {
yield spawnCmd([
'init',
'--verbose',
@@ -17,7 +17,7 @@ tap.test('Init and build ->', t =>
'--edition',
'@pattern-lab/edition-node',
'--starterkit',
- '@pattern-lab/starterkit-mustache-demo',
+ '@pattern-lab/starterkit-handlebars-demo',
]);
yield spawnCmd([
'build',
@@ -25,23 +25,23 @@ tap.test('Init and build ->', t =>
`${projectRoot}/patternlab-config.json`,
]);
t.ok(
- exists.sync(path.resolve(projectRoot, 'public')),
+ fs.existsSync(path.resolve(projectRoot, 'public')),
'should build all files into public dir'
);
t.ok(
- exists.sync(path.resolve(projectRoot, 'public', 'annotations')),
+ fs.existsSync(path.resolve(projectRoot, 'public', 'annotations')),
'with an annotations dir'
);
t.ok(
- exists.sync(path.resolve(projectRoot, 'public', 'css')),
+ fs.existsSync(path.resolve(projectRoot, 'public', 'css')),
'with a css dir'
);
t.ok(
- exists.sync(path.resolve(projectRoot, 'public', 'images')),
+ fs.existsSync(path.resolve(projectRoot, 'public', 'images')),
'with a images dir'
);
t.ok(
- exists.sync(path.resolve(projectRoot, 'public', 'styleguide')),
+ fs.existsSync(path.resolve(projectRoot, 'public', 'styleguide')),
'with a styleguide dir'
);
t.end();
diff --git a/packages/cli/test/cli-disable.test.js b/packages/cli/test/cli-disable.test.js
index 64715b882..dfe2f2925 100644
--- a/packages/cli/test/cli-disable.test.js
+++ b/packages/cli/test/cli-disable.test.js
@@ -6,8 +6,8 @@ const wrapAsync = require('../bin/utils').wrapAsync;
const projectRoot = getUniqueProjectPath();
-tap.test('Disable ->', t =>
- wrapAsync(function*() {
+tap.test('Disable ->', (t) =>
+ wrapAsync(function* () {
yield spawnCmd([
'init',
'--verbose',
@@ -16,7 +16,7 @@ tap.test('Disable ->', t =>
'--edition',
'@pattern-lab/edition-node',
'--starterkit',
- '@pattern-lab/starterkit-mustache-base',
+ '@pattern-lab/starterkit-handlebars-vanilla',
]);
yield spawnCmd([
'install',
diff --git a/packages/cli/test/cli-enable.test.js b/packages/cli/test/cli-enable.test.js
index 62b7d837a..8ea48d7ef 100644
--- a/packages/cli/test/cli-enable.test.js
+++ b/packages/cli/test/cli-enable.test.js
@@ -6,8 +6,8 @@ const wrapAsync = require('../bin/utils').wrapAsync;
const projectRoot = getUniqueProjectPath();
-tap.test('Enable ->', t =>
- wrapAsync(function*() {
+tap.test('Enable ->', (t) =>
+ wrapAsync(function* () {
yield spawnCmd([
'init',
'--verbose',
@@ -16,7 +16,7 @@ tap.test('Enable ->', t =>
'--edition',
'@pattern-lab/edition-node',
'--starterkit',
- '@pattern-lab/starterkit-mustache-base',
+ '@pattern-lab/starterkit-handlebars-vanilla',
]);
yield spawnCmd([
'install',
diff --git a/packages/cli/test/cli-export.test.js b/packages/cli/test/cli-export.test.js
index 63e82ba06..e0caa8e7d 100644
--- a/packages/cli/test/cli-export.test.js
+++ b/packages/cli/test/cli-export.test.js
@@ -1,4 +1,4 @@
-const exists = require('path-exists');
+const fs = require('fs-extra');
const getUniqueProjectPath = require('./utils/getUniqueProjectPath');
const path = require('path');
const spawnCmd = require('./utils/spawnCmd');
@@ -7,8 +7,8 @@ const wrapAsync = require('../bin/utils').wrapAsync;
const projectRoot = getUniqueProjectPath();
-tap.test('Init and export ->', t =>
- wrapAsync(function*() {
+tap.test('Init and export ->', (t) =>
+ wrapAsync(function* () {
yield spawnCmd([
'init',
'--verbose',
@@ -17,7 +17,7 @@ tap.test('Init and export ->', t =>
'--edition',
'@pattern-lab/edition-node',
'--starterkit',
- '@pattern-lab/starterkit-mustache-base',
+ '@pattern-lab/starterkit-handlebars-vanilla',
]);
yield spawnCmd([
'export',
@@ -25,7 +25,9 @@ tap.test('Init and export ->', t =>
`${projectRoot}/patternlab-config.json`,
]);
t.ok(
- exists.sync(path.resolve(projectRoot, 'pattern_exports', 'patterns.zip')),
+ fs.existsSync(
+ path.resolve(projectRoot, 'pattern_exports', 'patterns.zip')
+ ),
' should create patterns.zip'
);
t.end();
diff --git a/packages/cli/test/cli-init.test.js b/packages/cli/test/cli-init.test.js
index a80c031ff..34ad1d190 100644
--- a/packages/cli/test/cli-init.test.js
+++ b/packages/cli/test/cli-init.test.js
@@ -1,4 +1,4 @@
-const exists = require('path-exists');
+const fs = require('fs-extra');
const getUniqueProjectPath = require('./utils/getUniqueProjectPath');
const path = require('path');
const spawnCmd = require('./utils/spawnCmd');
@@ -7,8 +7,8 @@ const wrapAsync = require('../bin/utils').wrapAsync;
const projectRoot = getUniqueProjectPath();
-tap.test('Init ->', t =>
- wrapAsync(function*() {
+tap.test('Init ->', (t) =>
+ wrapAsync(function* () {
yield spawnCmd([
'init',
'--verbose',
@@ -17,20 +17,26 @@ tap.test('Init ->', t =>
'--edition',
'@pattern-lab/edition-node',
'--starterkit',
- '@pattern-lab/starterkit-mustache-base',
+ '@pattern-lab/starterkit-handlebars-vanilla',
]);
t.ok(
- exists.sync(path.resolve(projectRoot)),
+ fs.existsSync(path.resolve(projectRoot)),
'should initialize a Pattern Lab project'
);
- t.ok(exists.sync(path.resolve(projectRoot, 'source')), 'with a source dir');
- t.ok(exists.sync(path.resolve(projectRoot, 'public')), 'with a public dir');
t.ok(
- exists.sync(path.resolve(projectRoot, 'pattern_exports')),
+ fs.existsSync(path.resolve(projectRoot, 'source')),
+ 'with a source dir'
+ );
+ t.ok(
+ fs.existsSync(path.resolve(projectRoot, 'public')),
+ 'with a public dir'
+ );
+ t.ok(
+ fs.existsSync(path.resolve(projectRoot, 'pattern_exports')),
'with a pattern_exports dir'
);
t.ok(
- exists.sync(path.resolve(projectRoot, 'patternlab-config.json')),
+ fs.existsSync(path.resolve(projectRoot, 'patternlab-config.json')),
'with a pattern_exports dir'
);
t.end();
diff --git a/packages/cli/test/export.test.js b/packages/cli/test/export.test.js
index 169b60771..e9b600b24 100644
--- a/packages/cli/test/export.test.js
+++ b/packages/cli/test/export.test.js
@@ -2,10 +2,10 @@ const exportPatterns = require('../bin/cli-actions/export');
const tap = require('tap');
const wrapAsync = require('../bin/utils').wrapAsync;
-tap.test('Export ->', t => {
+tap.test('Export ->', (t) => {
t.plan(2);
- t.test('with options empty', tt =>
- wrapAsync(function*() {
+ t.test('with options empty', (tt) =>
+ wrapAsync(function* () {
try {
yield exportPatterns();
} catch (err) {
@@ -14,8 +14,8 @@ tap.test('Export ->', t => {
}
})
);
- t.test('with options not an object', tt =>
- wrapAsync(function*() {
+ t.test('with options not an object', (tt) =>
+ wrapAsync(function* () {
try {
yield exportPatterns(123);
} catch (err) {
diff --git a/packages/cli/test/fixtures/patternlab-config.json b/packages/cli/test/fixtures/patternlab-config.json
index 6102f522f..615be9273 100644
--- a/packages/cli/test/fixtures/patternlab-config.json
+++ b/packages/cli/test/fixtures/patternlab-config.json
@@ -46,8 +46,8 @@
"node_modules/@pattern-lab/uikit-workshop/views/partials/general-footer.mustache",
"patternSection":
"node_modules/@pattern-lab/uikit-workshop/views/partials/patternSection.mustache",
- "patternSectionSubtype":
- "node_modules/@pattern-lab/uikit-workshop/views/partials/patternSectionSubtype.mustache",
+ "patternSectionSubgroup":
+ "node_modules/@pattern-lab/uikit-workshop/views/partials/patternSectionSubgroup.mustache",
"viewall":
"node_modules/@pattern-lab/uikit-workshop/views/viewall.mustache"
},
@@ -68,10 +68,12 @@
"css": "./test/fixtures/public/css"
}
},
- "patternExtension": "mustache",
+ "patternExtension": "hbs",
"patternStateCascade": ["inprogress", "inreview", "complete"],
"patternExportDirectory": "./pattern_exports/",
"patternExportPatternPartials": [],
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
"serverOptions": {
"wait": 1000
},
@@ -81,5 +83,15 @@
"color": "dark",
"density": "compact",
"layout": "horizontal"
- }
+ },
+ "engines": {
+ "handlebars": {
+ "package": "@pattern-lab/engine-handlebars",
+ "fileExtensions": [
+ "handlebars",
+ "hbs"
+ ],
+ "extend": "helpers/*.js"
+ }
+ }
}
diff --git a/packages/cli/test/install-plugin.test.js b/packages/cli/test/install-plugin.test.js
index 269953007..c941d95d1 100644
--- a/packages/cli/test/install-plugin.test.js
+++ b/packages/cli/test/install-plugin.test.js
@@ -14,8 +14,8 @@ const minimalConfig = {
},
};
-tap.test('Install plugin-tab ->', t =>
- wrapAsync(function*() {
+tap.test('Install plugin-tab ->', (t) =>
+ wrapAsync(function* () {
yield installPlugin('@pattern-lab/plugin-tab', minimalConfig);
const pkg = yield moduleExist('@pattern-lab/plugin-tab');
t.ok(pkg, 'module should exist after install');
diff --git a/packages/cli/test/install-starterkit.test.js b/packages/cli/test/install-starterkit.test.js
index 0cda685c9..97a7599c1 100644
--- a/packages/cli/test/install-starterkit.test.js
+++ b/packages/cli/test/install-starterkit.test.js
@@ -14,64 +14,34 @@ const minimalConfig = {
},
};
-tap.test('Install starterkit-mustache-demo ->', t =>
- wrapAsync(function*() {
+tap.test('Install @pattern-lab/starterkit-handlebars-vanilla ->', (t) =>
+ wrapAsync(function* () {
yield installStarterkit(
- '@pattern-lab/starterkit-mustache-demo',
+ '@pattern-lab/starterkit-handlebars-vanilla',
minimalConfig
);
- const pkg = yield moduleExist('@pattern-lab/starterkit-mustache-demo');
+ const pkg = yield moduleExist('@pattern-lab/starterkit-handlebars-vanilla');
t.ok(pkg, 'module should exist after install');
t.end();
})
);
-tap.test('Install starterkit-mustache-base ->', t =>
- wrapAsync(function*() {
+tap.test('Install @pattern-lab/starterkit-handlebars-demo ->', (t) =>
+ wrapAsync(function* () {
yield installStarterkit(
- '@pattern-lab/starterkit-mustache-base',
+ '@pattern-lab/starterkit-handlebars-demo',
minimalConfig
);
- const pkg = yield moduleExist('@pattern-lab/starterkit-mustache-base');
+ const pkg = yield moduleExist('@pattern-lab/starterkit-handlebars-demo');
t.ok(pkg, 'module should exist after install');
t.end();
})
);
-tap.test('Install starterkit-mustache-bootstrap ->', t =>
- wrapAsync(function*() {
- yield installStarterkit('starterkit-mustache-bootstrap', minimalConfig);
- const pkg = yield moduleExist('starterkit-mustache-bootstrap');
- t.ok(pkg, 'module should exist after install');
- t.end();
- })
-);
-
-tap.test('Install starterkit-mustache-foundation ->', t =>
- wrapAsync(function*() {
- yield installStarterkit('starterkit-mustache-foundation', minimalConfig);
- const pkg = yield moduleExist('starterkit-mustache-foundation');
- t.ok(pkg, 'module should exist after install');
- t.end();
- })
-);
-
-tap.test('Install starterkit-mustache-acidtest ->', t =>
- wrapAsync(function*() {
- yield installStarterkit('starterkit-mustache-acidtest', minimalConfig);
- const pkg = yield moduleExist('starterkit-mustache-acidtest');
- t.ok(pkg, 'module should exist after install');
- t.end();
- })
-);
-
-tap.test('Install starterkit-mustache-materialdesign ->', t =>
- wrapAsync(function*() {
- yield installStarterkit(
- 'starterkit-mustache-materialdesign',
- minimalConfig
- );
- const pkg = yield moduleExist('starterkit-mustache-materialdesign');
+tap.test('Install @pattern-lab/starterkit-twig-demo ->', (t) =>
+ wrapAsync(function* () {
+ yield installStarterkit('@pattern-lab/starterkit-twig-demo', minimalConfig);
+ const pkg = yield moduleExist('@pattern-lab/starterkit-twig-demo');
t.ok(pkg, 'module should exist after install');
t.end();
})
diff --git a/packages/cli/test/mocks/liverserver.mock.js b/packages/cli/test/mocks/liverserver.mock.js
index 754fd5fc1..868f34fd5 100644
--- a/packages/cli/test/mocks/liverserver.mock.js
+++ b/packages/cli/test/mocks/liverserver.mock.js
@@ -1,12 +1,12 @@
function liveServerMock() {
return {
- reload: function() {
+ reload: function () {
return true;
},
- refreshCSS: function() {
+ refreshCSS: function () {
return true;
},
- start: function() {
+ start: function () {
return true;
},
};
diff --git a/packages/cli/test/mocks/patternlab.mock.js b/packages/cli/test/mocks/patternlab.mock.js
index 7186ca734..718767245 100644
--- a/packages/cli/test/mocks/patternlab.mock.js
+++ b/packages/cli/test/mocks/patternlab.mock.js
@@ -1,18 +1,18 @@
function patternLabMock() {
return {
- build: function() {
+ build: function () {
return true;
},
- help: function() {
+ help: function () {
return true;
},
- patternsonly: function() {
+ patternsonly: function () {
return true;
},
- liststarterkits: function() {
+ liststarterkits: function () {
return true;
},
- loadstarterkit: function() {
+ loadstarterkit: function () {
return true;
},
};
diff --git a/packages/cli/test/replace_config_paths.test.js b/packages/cli/test/replace_config_paths.test.js
index 6a98385ac..11d5bd84d 100644
--- a/packages/cli/test/replace_config_paths.test.js
+++ b/packages/cli/test/replace_config_paths.test.js
@@ -3,7 +3,7 @@ const tap = require('tap');
const replaceConfigPaths = require('../bin/replace-config');
const config = patternlab.getDefaultConfig();
-tap.test('replaceConfigPaths ->', t => {
+tap.test('replaceConfigPaths ->', (t) => {
const newConfig = replaceConfigPaths(
config,
'projectDir',
diff --git a/packages/cli/test/resolve_config.test.js b/packages/cli/test/resolve_config.test.js
index 36c250d9a..87feb8231 100644
--- a/packages/cli/test/resolve_config.test.js
+++ b/packages/cli/test/resolve_config.test.js
@@ -2,8 +2,8 @@ const tap = require('tap');
const wrapAsync = require('../bin/utils').wrapAsync;
const resolveConfig = require('../bin/resolve-config');
-tap.test('resolveConfig ->', t =>
- wrapAsync(function*() {
+tap.test('resolveConfig ->', (t) =>
+ wrapAsync(function* () {
const config = yield resolveConfig(
'./test/fixtures/patternlab-config.json'
);
diff --git a/packages/cli/test/scaffold.test.js b/packages/cli/test/scaffold.test.js
index c63d2365d..f1f3037d5 100644
--- a/packages/cli/test/scaffold.test.js
+++ b/packages/cli/test/scaffold.test.js
@@ -1,6 +1,6 @@
const tap = require('tap');
const path = require('path');
-const exists = require('path-exists');
+const fs = require('fs-extra');
const scaffold = require('../bin/scaffold');
const getUniqueProjectPath = require('./utils/getUniqueProjectPath');
const wrapAsync = require('../bin/utils').wrapAsync;
@@ -10,20 +10,20 @@ const sourceDir = 'source';
const publicDir = 'public';
const exportDir = 'patterns_export';
-tap.test('Scaffold ->', t =>
- wrapAsync(function*() {
+tap.test('Scaffold ->', (t) =>
+ wrapAsync(function* () {
yield scaffold(projectDir, sourceDir, publicDir, exportDir);
- t.ok(exists.sync(path.resolve(projectDir)), 'should create project dir');
+ t.ok(fs.existsSync(path.resolve(projectDir)), 'should create project dir');
t.ok(
- exists.sync(path.resolve(projectDir, sourceDir)),
+ fs.existsSync(path.resolve(projectDir, sourceDir)),
'should create source dir'
);
t.ok(
- exists.sync(path.resolve(projectDir, publicDir)),
+ fs.existsSync(path.resolve(projectDir, publicDir)),
'should create public dir'
);
t.ok(
- exists.sync(path.resolve(projectDir, exportDir)),
+ fs.existsSync(path.resolve(projectDir, exportDir)),
'should create export dir'
);
t.end();
diff --git a/packages/cli/test/serve.test.js b/packages/cli/test/serve.test.js
index c322cc41d..0d733cde0 100644
--- a/packages/cli/test/serve.test.js
+++ b/packages/cli/test/serve.test.js
@@ -10,8 +10,8 @@ const preview = proxyquire('../bin/serve', {
'@pattern-lab/core': patternLabMock,
});
-tap.test('Serve ->', t =>
- wrapAsync(function*() {
+tap.test('Serve ->', (t) =>
+ wrapAsync(function* () {
const config = yield resolveConfig(
'./test/fixtures/patternlab-config.json'
);
diff --git a/packages/cli/test/utils/spawnCmd.js b/packages/cli/test/utils/spawnCmd.js
index 4d0623515..f02cb91d4 100644
--- a/packages/cli/test/utils/spawnCmd.js
+++ b/packages/cli/test/utils/spawnCmd.js
@@ -4,8 +4,8 @@ const wrapAsync = require('../../bin/utils').wrapAsync;
const cli = path.resolve(__dirname, '../../bin/patternlab.js');
const spawnCmd = (args, endFn) =>
- wrapAsync(function*() {
- const fn = endFn || function() {};
+ wrapAsync(function* () {
+ const fn = endFn || function () {};
yield spawn('node', [cli].concat(args));
fn();
});
diff --git a/packages/core/.eslintrc.js b/packages/core/.eslintrc.js
new file mode 100644
index 000000000..5a2cc7f1e
--- /dev/null
+++ b/packages/core/.eslintrc.js
@@ -0,0 +1,3 @@
+module.exports = {
+ extends: ['../../.eslintrc.js'],
+};
diff --git a/packages/core/.npmignore b/packages/core/.npmignore
new file mode 100644
index 000000000..c1e1ac97f
--- /dev/null
+++ b/packages/core/.npmignore
@@ -0,0 +1,2 @@
+test
+.nyc_output
diff --git a/packages/core/.nvmrc b/packages/core/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/core/.nvmrc
+++ b/packages/core/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md
index 9da413dfa..1dbed1bf9 100644
--- a/packages/core/CHANGELOG.md
+++ b/packages/core/CHANGELOG.md
@@ -3,6 +3,373 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+
+### Bug Fixes
+
+* **twig engine:** startup and running problems ([#1478](https://github.com/pattern-lab/patternlab-node/issues/1478)) ([e5a1904](https://github.com/pattern-lab/patternlab-node/commit/e5a19049f083315939406677b1c0480f4b420569))
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+
+### Features
+
+* integrate @hadl/patternlab-plugin-pattern-wrap into core ([#1433](https://github.com/pattern-lab/patternlab-node/issues/1433)) ([414e038](https://github.com/pattern-lab/patternlab-node/commit/414e0383732b4bc4682981000908d1e0d1292703)), closes [#1432](https://github.com/pattern-lab/patternlab-node/issues/1432) [#1432](https://github.com/pattern-lab/patternlab-node/issues/1432)
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+
+### Bug Fixes
+
+* code scanning alert ([#1442](https://github.com/pattern-lab/patternlab-node/issues/1442)) ([749a3e7](https://github.com/pattern-lab/patternlab-node/commit/749a3e722249846c522e3f7de6e73b5afa8531b1))
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+
+### Bug Fixes
+
+* transformed asset types is ignored ([#1426](https://github.com/pattern-lab/patternlab-node/issues/1426)) ([8cbe189](https://github.com/pattern-lab/patternlab-node/commit/8cbe189d45afaa753ce6de41bdd9de1596e074f3)), closes [#1339](https://github.com/pattern-lab/patternlab-node/issues/1339)
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+
+### Bug Fixes
+
+* **core:** Subgroup cannot be hidden ([#1368](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1368)) ([3ce13ab](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/3ce13abffaab2810194003aeca88be671fedd38f))
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+
+### Bug Fixes
+
+* **node16:** prevent warning on installation process ([#1352](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1352)) ([d58e4c6](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/d58e4c6f2979f5e0bba9a14e17e0dbc4afc64f75))
+
+
+### Features
+
+* added https description to the docs ([#1355](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1355)) ([4118f74](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/4118f740810842b16cf86b9ee28bda2a623aa9c7))
+
+
+### Reverts
+
+* Revert "refactor: optimized engines directory retrieval (#1359)" (#1363) ([a275d36](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/a275d36c50c3846fc51c78baf6e11dba5309f5dc)), closes [#1359](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1359) [#1363](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1363)
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+
+### Features
+
+* **documentation:** added (sub)groups documentation again [#1262](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1262) ([#1334](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1334)) ([9fac269](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/9fac2699d2f6c64c4544e8e4d8e18c1a1ce7e49f))
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+
+### Bug Fixes
+
+* **core:** ReadDocumentation throw error on older node versions ([#1295](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1295)) ([399d0e1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/399d0e118ab77a414a926b078da9abbcb5347969))
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+
+### Bug Fixes
+
+* enable partial build via option ([8aaa533](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/8aaa53398563ade14123c481bf509f9ee0c768f5))
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+
+### Bug Fixes
+
+* enable partial build via option ([8aaa533](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/8aaa53398563ade14123c481bf509f9ee0c768f5))
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1192) ([cae9420](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/cae94208c52e4068430e048e729f4ff97847715a))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+
+### Bug Fixes
+
+* **core:** do not warn about uikit-polyfills ([6bb68e7](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/6bb68e763769969546542bf7aaf6d1f4235c6622))
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+
+### Bug Fixes
+
+* add a new method to check if PL is currently compiling + add new method to get the config PL is using ([26e886c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/26e886c93db5d135c91de648724f7278c4d5b3e9))
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+
+### Bug Fixes
+
+* **core:** re-add cleanPublic fix ([c100bbc](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/c100bbca3f339e9132acb9c482e98c1c8a66b8b5))
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+
+### Features
+
+* **config:** add new default pattern export options ([a7487a0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/a7487a0681cb11e6f3c5c8eaefd62e5648ad5ea3))
+* **core:** fix pattern export all conflicts ([b210d82](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/b210d820ba8ac0b64c82c7ff0f18c9f8a900fce2))
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* add eslint fixes ([00d7bbe](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/00d7bbe319ea77a6ee8cc9cd0348856feaaf13ad))
+* correct typo in build logging ([96d989f](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/96d989f8869630ba9f59705bfca66755f20e35ab))
+* updates to address eslint / prettier issues ([d945acc](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/d945acc13b8e4e36f3815b017fbc12266c323d1f))
+* updates to fix eslint / prettier issues; update packages/core to reuse root .eslintrc.js file ([5b7a057](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/5b7a057d46ccd16b5832af1441030c7b76f237a8))
+* **1049:** Treat folders like patterns only if they're subfolders of pattern groupings ([4eb79ab](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/4eb79ab48b335a35b2e5ed3b7053974b8e8bb6b6))
+* **core:** allow plugin resolution to follow normal algorithm ([3f6b83b](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/3f6b83be080c88aec1d8b73bececb76f0f57a79d))
+* **core:** find plugins from config only and with simpler args ([fe7351c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/fe7351cba346425512cbb2ef3a1b7728ab06ae60))
+* **plugin:** correct spelling error and function locations ([d4abd88](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/d4abd88cb017550002407241b5045a2ad1adb1dc))
+
+
+### Features
+
+* **core:** invoke registered plugin hooks ([a54d775](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/a54d7753b6939fe6a58da543f4fb34f64dd8901a))
+* **plugin-tab, core:** initial plugin hook exploration ([2f3d39a](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/2f3d39ac6b125ad4c6b872e27ee224ce2ea33a12))
+
+
+### BREAKING CHANGES
+
+* **core:** plugins now use async functions instead of events
+
+
+
+
+
+
+## [3.0.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/@pattern-lab/core@3.0.1...@pattern-lab/core@3.0.2) (2019-08-23)
+
+
+### Bug Fixes
+
+* add eslint fixes ([00d7bbe](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/00d7bbe))
+* correct typo in build logging ([96d989f](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/96d989f))
+* updates to address eslint / prettier issues ([d945acc](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/d945acc))
+* updates to fix eslint / prettier issues; update packages/core to reuse root .eslintrc.js file ([5b7a057](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/commit/5b7a057))
+
+
+
+
+
+
+## [3.0.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/@pattern-lab/core@3.0.1-alpha.0...@pattern-lab/core@3.0.1) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/core
+
+
+
+
+
# [3.0.0-beta.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core/compare/@pattern-lab/core@3.0.0-beta.0...@pattern-lab/core@3.0.0-beta.2) (2019-02-09)
diff --git a/packages/core/LICENSE b/packages/core/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/core/LICENSE
+++ b/packages/core/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/core/README.md b/packages/core/README.md
index f6a81c7bd..1cc57aaf0 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -1,6 +1,7 @@

-[](https://travis-ci.org/pattern-lab/patternlab-node)
+[](https://github.com/pattern-lab/patternlab-node/actions/workflows/continuous-integration.yml)
+[](https://github.com/pattern-lab/patternlab-node/actions/workflows/codeql-analysis.yml)


[](https://coveralls.io/github/pattern-lab/patternlab-node?branch=master)
@@ -10,7 +11,7 @@
# Pattern Lab Node Core
-This is the core API and orchestrator of the [Pattern Lab ecosystem](http://patternlab.io/docs/advanced-ecosystem-overview.html).
+This is the core API and orchestrator of the [Pattern Lab ecosystem](https://patternlab.io/docs/overview-of-pattern-lab's-ecosystem/).
## Installation
@@ -35,9 +36,9 @@ For users wanting a more pre-packaged experience several editions are available.
## Ecosystem
-
+
-Core, and Editions, are part of the [Pattern Lab Ecosystem](http://patternlab.io/docs/advanced-ecosystem-overview.html). With this architecture, we encourage people to write and maintain their own Editions, Starterkits, and even PatternEngines.
+Core, and Editions, are part of the [Pattern Lab Ecosystem](https://patternlab.io/docs/overview-of-pattern-lab's-ecosystem/). With this architecture, we encourage people to write and maintain their own Editions, Starterkits, and even PatternEngines.
## Usage
@@ -59,7 +60,7 @@ patternlab.serve({
});
```
-* Read more about [configuration](http://patternlab.io/docs/advanced-config-options.html#node) via `patternlab-config.json`.
+* Read more about [configuration](https://patternlab.io/docs/editing-the-configuration-options/) via `patternlab-config.json`.
* Read more about the rest of [Public API](./docs), and already implemented for you within [Editions](#editions).
@@ -102,9 +103,7 @@ Please read the [contribution guidelines](https://github.com/pattern-lab/pattern
## Core Team
-* [@bmuenzenmeyer](https://github.com/bmuenzenmeyer) - Lead Maintainer
* [@geoffp](https://github.com/geoffp) - Core Contributor
-* [@raphaelokon](https://github.com/raphaelokon) - CLI Contributor
* [@tburny](https://github.com/tburny) - Core Contributor
## Community
@@ -113,7 +112,7 @@ The Pattern Lab Node team uses [our gitter.im channel, pattern-lab/node](https:/
There is also a dedicated Pattern Lab channel on the [design system slack](http://designsystems.herokuapp.com) run by [@jina](https://twitter.com/jina).
-Ask or answer Pattern Lab questions on Stack Overflow: http://stackoverflow.com/questions/tagged/patternlab.io
+Ask or answer Pattern Lab questions on Stack Overflow: https://stackoverflow.com/questions/tagged/patternlab.io
## License
diff --git a/packages/core/docs/README.md b/packages/core/docs/README.md
index 7317083f6..34c17b12b 100644
--- a/packages/core/docs/README.md
+++ b/packages/core/docs/README.md
@@ -19,13 +19,13 @@ const patternlab = require('@pattern-lab/core')(config);
Build thoughtful, pattern-driven user interfaces using atomic design principles.
Many of these functions are exposed to users within [Editions](https://github.com/pattern-lab/patternlab-node#editions), but [direct consumption](https://github.com/pattern-lab/patternlab-node#direct-consumption) is also encouraged.
-**Kind**: global namespace
+**Kind**: global namespace
**See**
- [patternlab.io](patternlab.io) for more documentation.
- [https://github.com/pattern-lab/patternlab-node](https://github.com/pattern-lab/patternlab-node) for code, issues, and releases
-**License**: MIT
+**License**: MIT
* [`patternlab`](#patternlab) : object
* _instance_
@@ -33,7 +33,6 @@ Many of these functions are exposed to users within [Editions](https://github.co
* [`.build`](#patternlab+build) ⇒ Promise
* [`.getDefaultConfig`](#patternlab+getDefaultConfig) ⇒ object
* [`.getSupportedTemplateExtensions`](#patternlab+getSupportedTemplateExtensions) ⇒ Array.<string>
- * [`.installplugin`](#patternlab+installplugin) ⇒ void
* [`.liststarterkits`](#patternlab+liststarterkits) ⇒ Promise
* [`.loadstarterkit`](#patternlab+loadstarterkit) ⇒ void
* [`.patternsonly`](#patternlab+patternsonly) ⇒ Promise
@@ -51,17 +50,17 @@ Many of these functions are exposed to users within [Editions](https://github.co
### `patternlab.version` ⇒ string
Returns current version
-**Kind**: instance property of [patternlab](#patternlab)
-**Returns**: string - current patternlab-node version as defined in `package.json`, as string
+**Kind**: instance property of [patternlab](#patternlab)
+**Returns**: string - current patternlab-node version as defined in `package.json`, as string
### `patternlab.build` ⇒ Promise
Builds patterns, copies assets, and constructs user interface
-**Kind**: instance property of [patternlab](#patternlab)
-**Returns**: Promise - a promise fulfilled when build is complete
-**Emits**: event:PATTERNLAB_BUILD_START, event:PATTERNLAB_BUILD_END
-**See**: [all events](./events.md)
+**Kind**: instance property of [patternlab](#patternlab)
+**Returns**: Promise - a promise fulfilled when build is complete
+**Emits**: event:PATTERNLAB_BUILD_START, event:PATTERNLAB_BUILD_END
+**See**: [all events](./events.md)
| Param | Type | Default | Description |
| --- | --- | --- | --- |
@@ -75,39 +74,29 @@ Builds patterns, copies assets, and constructs user interface
### `patternlab.getDefaultConfig` ⇒ object
Returns the standardized default config used to run Pattern Lab. This method can be called statically or after instantiation.
-**Kind**: instance property of [patternlab](#patternlab)
-**Returns**: object - Returns the object representation of the `patternlab-config.json`
+**Kind**: instance property of [patternlab](#patternlab)
+**Returns**: object - Returns the object representation of the `patternlab-config.json`
### `patternlab.getSupportedTemplateExtensions` ⇒ Array.<string>
Returns all file extensions supported by installed PatternEngines
-**Kind**: instance property of [patternlab](#patternlab)
-**Returns**: Array.<string> - all supported file extensions
-
-
-### `patternlab.installplugin` ⇒ void
-Installs plugin already available via `node_modules/`
-
-**Kind**: instance property of [patternlab](#patternlab)
-
-| Param | Type | Description |
-| --- | --- | --- |
-| pluginName | string | name of plugin |
+**Kind**: instance property of [patternlab](#patternlab)
+**Returns**: Array.<string> - all supported file extensions
### `patternlab.liststarterkits` ⇒ Promise
Fetches starterkit repositories from pattern-lab github org that contain 'starterkit' in their name
-**Kind**: instance property of [patternlab](#patternlab)
-**Returns**: Promise - Returns an Array<{name,url}> for the starterkit repos
+**Kind**: instance property of [patternlab](#patternlab)
+**Returns**: Promise - Returns an Array<{name,url}> for the starterkit repos
### `patternlab.loadstarterkit` ⇒ void
Loads starterkit already available via `node_modules/`
-**Kind**: instance property of [patternlab](#patternlab)
+**Kind**: instance property of [patternlab](#patternlab)
| Param | Type | Description |
| --- | --- | --- |
@@ -119,8 +108,8 @@ Loads starterkit already available via `node_modules/`
### `patternlab.patternsonly` ⇒ Promise
Builds patterns only, leaving existing user interface files intact
-**Kind**: instance property of [patternlab](#patternlab)
-**Returns**: Promise - a promise fulfilled when build is complete
+**Kind**: instance property of [patternlab](#patternlab)
+**Returns**: Promise - a promise fulfilled when build is complete
| Param | Type | Default | Description |
| --- | --- | --- | --- |
@@ -133,21 +122,21 @@ Builds patterns only, leaving existing user interface files intact
### `patternlab.getDefaultConfig` ⇒ object
Static method that returns the standardized default config used to run Pattern Lab. This method can be called statically or after instantiation.
-**Kind**: static property of [patternlab](#patternlab)
-**Returns**: object - Returns the object representation of the `patternlab-config.json`
+**Kind**: static property of [patternlab](#patternlab)
+**Returns**: object - Returns the object representation of the `patternlab-config.json`
### `patternlab.getVersion` ⇒ string
Static method that returns current version
-**Kind**: static property of [patternlab](#patternlab)
-**Returns**: string - current @pattern-lab/core version as defined in `package.json`
+**Kind**: static property of [patternlab](#patternlab)
+**Returns**: string - current @pattern-lab/core version as defined in `package.json`
### `patternlab.server` : object
Server module
-**Kind**: static property of [patternlab](#patternlab)
+**Kind**: static property of [patternlab](#patternlab)
* [`.server`](#patternlab.server) : object
* [`.serve(options)`](#patternlab.server.serve) ⇒ Promise
@@ -159,8 +148,8 @@ Server module
#### `server.serve(options)` ⇒ Promise
Build patterns, copies assets, and constructs user interface. Watches configured `source/` directories, and serves all output locally
-**Kind**: static method of [server](#patternlab.server)
-**Returns**: Promise - a promise fulfilled when build is complete
+**Kind**: static method of [server](#patternlab.server)
+**Returns**: Promise - a promise fulfilled when build is complete
| Param | Type | Default | Description |
| --- | --- | --- | --- |
@@ -174,19 +163,19 @@ Build patterns, copies assets, and constructs user interface. Watches configured
#### `server.reload()` ⇒ Promise
Reloads any active live-server instances
-**Kind**: static method of [server](#patternlab.server)
-**Returns**: Promise - a promise fulfilled when operation is complete
+**Kind**: static method of [server](#patternlab.server)
+**Returns**: Promise - a promise fulfilled when operation is complete
#### `server.refreshCSS()` ⇒ Promise
Reloads CSS on any active live-server instances
-**Kind**: static method of [server](#patternlab.server)
-**Returns**: Promise - a promise fulfilled when operation is complete
+**Kind**: static method of [server](#patternlab.server)
+**Returns**: Promise - a promise fulfilled when operation is complete
### `patternlab.events` : EventEmitter
-**Kind**: static property of [patternlab](#patternlab)
+**Kind**: static property of [patternlab](#patternlab)
**See**
- [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
@@ -195,4 +184,4 @@ Reloads CSS on any active live-server instances
* * *
-[Pattern Lab](http://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
+[Pattern Lab](https://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
diff --git a/packages/core/docs/events.md b/packages/core/docs/events.md
index 2df8191d1..62dda5ff2 100644
--- a/packages/core/docs/events.md
+++ b/packages/core/docs/events.md
@@ -61,7 +61,7 @@ Emitted after patterns are iterated over to gather data about them. Right before
#### `EVENTS~PATTERNLAB_BUILD_GLOBAL_DATA_END`
-Emitted after global `data.json` and `listitems.json` are read, and the supporting Pattern Lab templates are loaded into memory (header, footer, patternSection, patternSectionSubType, viewall). Right before patterns are iterated over to gather data about them.
+Emitted after global `data.json` and `listitems.json` are read, and the supporting Pattern Lab templates are loaded into memory (header, footer, patternSection, patternSectionSubgroup, viewall). Right before patterns are iterated over to gather data about them.
**Kind**: inner property of [EVENTS](#exp_module_Events--EVENTS)
**Properties**
@@ -77,7 +77,7 @@ Emitted after global `data.json` and `listitems.json` are read, and the supporti
Emitted before all data is merged prior to a Pattern's render. Global `data.json` is merged with any pattern `.json`. Global `listitems.json` is merged with any pattern `.listitems.json`.
**Kind**: inner property of [EVENTS](#exp_module_Events--EVENTS)
-**See**: [Pattern](https://github.com/pattern-lab/patternlab-node/blob/master/src/lib/object_factory.js#L16)
+**See**: [Pattern](https://github.com/pattern-lab/patternlab-node/blob/master/packages/core/src/lib/object_factory.js#L16)
**Properties**
| Name | Type | Description |
@@ -92,7 +92,7 @@ Emitted before all data is merged prior to a Pattern's render. Global `data.json
Emitted before a pattern's template, HTML, and encoded HTML files are written to their output location
**Kind**: inner property of [EVENTS](#exp_module_Events--EVENTS)
-**See**: [Pattern](https://github.com/pattern-lab/patternlab-node/blob/master/src/lib/object_factory.js#L16)
+**See**: [Pattern](https://github.com/pattern-lab/patternlab-node/blob/master/packages/core/src/lib/object_factory.js#L16)
**Properties**
| Name | Type | Description |
@@ -107,7 +107,7 @@ Emitted before a pattern's template, HTML, and encoded HTML files are written to
Emitted after a pattern's template, HTML, and encoded HTML files are written to their output location
**Kind**: inner property of [EVENTS](#exp_module_Events--EVENTS)
-**See**: [Pattern](https://github.com/pattern-lab/patternlab-node/blob/master/src/lib/object_factory.js#L16)
+**See**: [Pattern](https://github.com/pattern-lab/patternlab-node/blob/master/packages/core/src/lib/object_factory.js#L16)
**Properties**
| Name | Type | Description |
@@ -156,4 +156,4 @@ Invoked when a pattern changes.
---
-[Pattern Lab](http://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
+[Pattern Lab](https://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
diff --git a/packages/core/package.json b/packages/core/package.json
index 38ea422ac..74b3555ed 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,36 +1,39 @@
{
"name": "@pattern-lab/core",
"description": "Create atomic design systems with Pattern Lab. This is the core API and orchestrator of the ecosystem.",
- "version": "3.0.1-alpha.0",
+ "version": "6.1.0",
"main": "./src/index.js",
"dependencies": {
- "@pattern-lab/engine-mustache": "^2.0.1-alpha.0",
- "@pattern-lab/live-server": "^1.3.3-beta.1",
- "chalk": "1.1.3",
- "chokidar": "1.7.0",
+ "@pattern-lab/engine-handlebars": "^6.1.0",
+ "@pattern-lab/engine-mustache": "^6.1.0",
+ "@pattern-lab/live-server": "^6.1.0",
+ "chalk": "4.1.0",
+ "chokidar": "3.5.1",
"dive": "0.5.0",
- "fs-extra": "5.0.0",
- "glob": "7.0.0",
- "graphlib": "2.1.1",
- "js-beautify": "1.6.3",
- "js-yaml": "3.6.1",
- "lodash": "4.17.5",
- "markdown-it": "6.0.1",
- "node-fetch": "1.6.0",
- "recursive-copy": "2.0.8",
- "update-notifier": "2.2.0"
+ "fs-extra": "10.0.0",
+ "glob": "7.1.6",
+ "graphlib": "2.1.8",
+ "js-beautify": "1.13.5",
+ "js-yaml": "4.1.0",
+ "lodash": "4.17.21",
+ "markdown-it": "12.3.2",
+ "node-fetch": "2.6.7",
+ "recursive-copy": "2.0.13",
+ "update-notifier": "5.1.0"
},
"devDependencies": {
- "eslint": "4.18.2",
- "eslint-config-prettier": "2.9.0",
- "eslint-plugin-prettier": "2.6.0",
- "husky": "0.14.3",
- "jsdoc-to-markdown": "3.0.0",
- "prettier": "1.11.1",
- "pretty-quick": "1.2.2",
+ "@babel/core": "^7.13.14",
+ "@babel/plugin-proposal-decorators": "^7.13.5",
+ "@babel/plugin-syntax-jsx": "^7.12.13",
+ "babel-eslint": "^10.0.2",
+ "eslint": "^6.1.0",
+ "eslint-config-prettier": "^6.0.0",
+ "eslint-plugin-prettier": "^3.1.0",
+ "jsdoc-to-markdown": "6.0.1",
+ "prettier": "^2.8.1",
"rewire": "2.5.2",
- "standard-version": "4.3.0",
- "tap": "11.1.1"
+ "standard-version": "9.1.1",
+ "tap": "14.11.0"
},
"keywords": [
"Pattern Lab",
@@ -49,9 +52,6 @@
{
"name": "Geoff Pursell"
},
- {
- "name": "Raphael Okon"
- },
{
"name": "tburny"
}
@@ -59,15 +59,16 @@
"license": "MIT",
"scripts": {
"docs": "node ./scripts/docs.js",
- "lint": "eslint src/**/*.js",
+ "lint": "eslint -c ../../.eslintrc.js src/**/*.js",
"pretest": "npm run lint",
"release": "standard-version",
"test": "tap test/*_tests.js --reporter spec --coverage"
},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/core/patternlab-config.json b/packages/core/patternlab-config.json
index 80669ea5f..d3022f24b 100644
--- a/packages/core/patternlab-config.json
+++ b/packages/core/patternlab-config.json
@@ -46,8 +46,8 @@
"views/partials/general-footer.mustache",
"patternSection":
"views/partials/patternSection.mustache",
- "patternSectionSubtype":
- "views/partials/patternSectionSubtype.mustache",
+ "patternSectionSubgroup":
+ "views/partials/patternSectionSubgroup.mustache",
"viewall":
"views/viewall.mustache"
},
@@ -70,8 +70,13 @@
},
"patternExtension": "mustache",
"patternStateCascade": ["inprogress", "inreview", "complete"],
- "patternExportDirectory": "./pattern_exports/",
+ "patternExportAll": false,
+ "patternExportDirectory": "pattern_exports",
"patternExportPatternPartials": [],
+ "patternExportPreserveDirectoryStructure": true,
+ "patternExportRaw": false,
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
"serverOptions": {
"wait": 1000
},
@@ -83,13 +88,26 @@
"density": "compact",
"layout": "horizontal"
},
+ "engines": {
+ "handlebars": {
+ "package": "@pattern-lab/engine-handlebars",
+ "fileExtensions": [
+ "handlebars",
+ "hbs"
+ ],
+ "extend": "helpers/*.js"
+ }
+ },
"uikits": [
{
"name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
"outputDir": "",
"enabled": true,
"excludedPatternStates": [],
"excludedTags": []
}
- ]
+ ],
+ "patternWrapClassesEnable": false,
+ "patternWrapClassesKey": []
}
diff --git a/packages/core/scripts/api.handlebars b/packages/core/scripts/api.handlebars
index 8959ef5cf..db5192088 100644
--- a/packages/core/scripts/api.handlebars
+++ b/packages/core/scripts/api.handlebars
@@ -17,4 +17,4 @@ const patternlab = require('@pattern-lab/core')(config);
* * *
-[Pattern Lab](http://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
+[Pattern Lab](https://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
diff --git a/packages/core/scripts/docs.js b/packages/core/scripts/docs.js
index 8b0907aca..92d16092c 100644
--- a/packages/core/scripts/docs.js
+++ b/packages/core/scripts/docs.js
@@ -18,7 +18,7 @@ doc
'name-format': 'backticks',
template: fs.readFileSync('./scripts/api.handlebars', 'utf8'),
})
- .then(x => {
+ .then((x) => {
fs.outputFile(path.resolve(process.cwd(), './docs/README.md'), x);
});
@@ -29,6 +29,6 @@ doc
'name-format': 'backticks',
template: fs.readFileSync('./scripts/events.handlebars', 'utf8'),
})
- .then(x => {
+ .then((x) => {
fs.outputFile(path.resolve(process.cwd(), './docs/events.md'), x);
});
diff --git a/packages/core/scripts/events.handlebars b/packages/core/scripts/events.handlebars
index 667e8c9bf..7dcec0dc8 100644
--- a/packages/core/scripts/events.handlebars
+++ b/packages/core/scripts/events.handlebars
@@ -16,4 +16,4 @@ Learn more about [Creating Plugins](https://github.com/pattern-lab/patternlab-no
* * *
-[Pattern Lab](http://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
+[Pattern Lab](https://patternlab.io) Node is [MIT Licensed](https://github.com/pattern-lab/patternlab-node/blob/master/LICENSE)
diff --git a/packages/core/src/index.js b/packages/core/src/index.js
index 653a9f731..1d46b5788 100644
--- a/packages/core/src/index.js
+++ b/packages/core/src/index.js
@@ -10,14 +10,11 @@
'use strict';
-const path = require('path');
-
const updateNotifier = require('update-notifier');
const packageInfo = require('../package.json');
const events = require('./lib/events');
const pe = require('./lib/pattern_exporter');
-const pm = require('./lib/plugin_manager');
const defaultConfig = require('../patternlab-config.json');
@@ -43,7 +40,7 @@ updateNotifier({
* @static
* @return {object} Returns the object representation of the `patternlab-config.json`
*/
-const getDefaultConfig = function() {
+const getDefaultConfig = function () {
return defaultConfig;
};
@@ -55,11 +52,11 @@ const getDefaultConfig = function() {
* @static
* @returns {string} current @pattern-lab/core version as defined in `package.json`
*/
-const getVersion = function() {
+const getVersion = function () {
return packageInfo.version;
};
-const patternlab_module = function(config) {
+const patternlab_module = function (config) {
const PatternLabClass = require('./lib/patternlab');
const patternlab = new PatternLabClass(config);
const server = serverModule(patternlab);
@@ -73,10 +70,34 @@ const patternlab_module = function(config) {
* @instance
* @returns {string} current patternlab-node version as defined in `package.json`, as string
*/
- version: function() {
+ version: function () {
return patternlab.getVersion();
},
+ /**
+ * Returns the current pattern lab configuration being used
+ *
+ * @memberof patternlab
+ * @name getConfig
+ * @instance
+ * @returns {object} the current patternlab-node config (defaults + customizations)
+ */
+ getConfig() {
+ return config;
+ },
+
+ /**
+ * Returns if Pattern Lab is busy compiling or not
+ *
+ * @memberof patternlab
+ * @name isBusy
+ * @instance
+ * @returns {boolean} if pattern lab is currently busy compiling
+ */
+ isBusy: function () {
+ return patternlab.isBusy;
+ },
+
/**
* Builds patterns, copies assets, and constructs user interface
*
@@ -92,7 +113,7 @@ const patternlab_module = function(config) {
* @see {@link ./events.md|all events}
* @returns {Promise} a promise fulfilled when build is complete
*/
- build: function(options) {
+ build: async function (options) {
// process.on('unhandledRejection', (reason, p) => {
// console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
// // application specific logging, throwing an error, or other logic here
@@ -109,53 +130,51 @@ const patternlab_module = function(config) {
}
patternlab.isBusy = true;
- return buildPatterns(options.cleanPublic, patternlab, options.data).then(
- () => {
- return new ui_builder().buildFrontend(patternlab).then(() => {
- copier()
- .copyAndWatch(patternlab.config.paths, patternlab, options)
- .then(() => {
- patternlab.isBusy = false;
- // only wire up this listener and the one inside serve.js
- // figure out how to detect if serve was called. we should not assume it was
- if (
- patternlab.serverReady //check for server presence
- ? this.events.listenerCount(
- events.PATTERNLAB_PATTERN_CHANGE
- ) === 1 //if the server is started, it has already setup one listener
- : !this.events.listenerCount(
- events.PATTERNLAB_PATTERN_CHANGE
- ) // else, check for the presnce of none
- ) {
- this.events.on(events.PATTERNLAB_PATTERN_CHANGE, () => {
- if (!patternlab.isBusy) {
- return this.build(options).then(() => {
- patternlab.isBusy = false;
- });
- }
- return Promise.resolve();
- });
- }
+ return await buildPatterns(
+ options.cleanPublic,
+ patternlab,
+ options.data
+ ).then(() => {
+ return new ui_builder().buildFrontend(patternlab).then(() => {
+ copier()
+ .copyAndWatch(patternlab.config.paths, patternlab, options)
+ .then(() => {
+ patternlab.isBusy = false;
+ // only wire up this listener and the one inside serve.js
+ // figure out how to detect if serve was called. we should not assume it was
+ if (
+ patternlab.serverReady //check for server presence
+ ? this.events.listenerCount(
+ events.PATTERNLAB_PATTERN_CHANGE
+ ) === 1 //if the server is started, it has already setup one listener
+ : !this.events.listenerCount(events.PATTERNLAB_PATTERN_CHANGE) // else, check for the presnce of none
+ ) {
+ this.events.on(events.PATTERNLAB_PATTERN_CHANGE, () => {
+ if (!patternlab.isBusy) {
+ return this.build(options).then(() => {
+ patternlab.isBusy = false;
+ });
+ }
+ return Promise.resolve();
+ });
+ }
- if (
- !this.events.listenerCount(events.PATTERNLAB_GLOBAL_CHANGE)
- ) {
- this.events.on(events.PATTERNLAB_GLOBAL_CHANGE, () => {
- if (!patternlab.isBusy) {
- return this.build(
- Object.assign({}, options, { cleanPublic: true }) // rebuild everything
- );
- }
- return Promise.resolve();
- });
- }
- })
- .then(() => {
- this.events.emit(events.PATTERNLAB_BUILD_END, patternlab);
- });
- });
- }
- );
+ if (!this.events.listenerCount(events.PATTERNLAB_GLOBAL_CHANGE)) {
+ this.events.on(events.PATTERNLAB_GLOBAL_CHANGE, () => {
+ if (!patternlab.isBusy) {
+ return this.build(
+ Object.assign({}, options, { cleanPublic: true }) // rebuild everything
+ );
+ }
+ return Promise.resolve();
+ });
+ }
+ })
+ .then(() => {
+ this.events.emit(events.PATTERNLAB_BUILD_END, patternlab);
+ });
+ });
+ });
},
/**
@@ -166,7 +185,7 @@ const patternlab_module = function(config) {
* @instance
* @return {object} Returns the object representation of the `patternlab-config.json`
*/
- getDefaultConfig: function() {
+ getDefaultConfig: function () {
return getDefaultConfig();
},
@@ -178,27 +197,10 @@ const patternlab_module = function(config) {
* @instance
* @returns {Array} all supported file extensions
*/
- getSupportedTemplateExtensions: function() {
+ getSupportedTemplateExtensions: function () {
return patternlab.getSupportedTemplateExtensions();
},
- /**
- * Installs plugin already available via `node_modules/`
- *
- * @memberof patternlab
- * @name installplugin
- * @instance
- * @param {string} pluginName name of plugin
- * @returns {void}
- */
- installplugin: function(pluginName) {
- //get the config
- const configPath = path.resolve(process.cwd(), 'patternlab-config.json');
- const plugin_manager = new pm(config, configPath);
-
- plugin_manager.install_plugin(pluginName);
- },
-
/**
* Fetches starterkit repositories from pattern-lab github org that contain 'starterkit' in their name
*
@@ -207,12 +209,12 @@ const patternlab_module = function(config) {
* @instance
* @returns {Promise} Returns an Array<{name,url}> for the starterkit repos
*/
- liststarterkits: function() {
+ liststarterkits: function () {
return patternlab.listStarterkits();
},
/**
- * Loads starterkit already available via `node_modules/`
+ * Loads starterkit already available as a package dependency
*
* @memberof patternlab
* @name loadstarterkit
@@ -221,7 +223,7 @@ const patternlab_module = function(config) {
* @param {boolean} clean whether or not to delete contents of source/ before load
* @returns {void}
*/
- loadstarterkit: function(starterkitName, clean) {
+ loadstarterkit: function (starterkitName, clean) {
patternlab.loadStarterKit(starterkitName, clean);
},
@@ -236,7 +238,7 @@ const patternlab_module = function(config) {
* @param {bool} [options.watch=true] whether or not Pattern Lab should watch configured `source/` directories for changes to rebuild
* @returns {Promise} a promise fulfilled when build is complete
*/
- patternsonly: function(options) {
+ patternsonly: async function (options) {
if (patternlab && patternlab.isBusy) {
logger.info(
'Pattern Lab is busy building a previous run - returning early.'
@@ -244,11 +246,13 @@ const patternlab_module = function(config) {
return Promise.resolve();
}
patternlab.isBusy = true;
- return buildPatterns(options.cleanPublic, patternlab, options.data).then(
- () => {
- patternlab.isBusy = false;
- }
- );
+ return await buildPatterns(
+ options.cleanPublic,
+ patternlab,
+ options.data
+ ).then(() => {
+ patternlab.isBusy = false;
+ });
},
/**
@@ -269,11 +273,11 @@ const patternlab_module = function(config) {
* @param {bool} [options.watch=true] whether or not Pattern Lab should watch configured `source/` directories for changes to rebuild
* @returns {Promise} a promise fulfilled when build is complete
*/
- serve: options => {
+ serve: (options) => {
return _api
.build(options)
.then(() => server.serve())
- .catch(e =>
+ .catch((e) =>
logger.error(`error inside core index.js server serve: ${e}`)
);
},
diff --git a/packages/core/src/lib/addPattern.js b/packages/core/src/lib/addPattern.js
index af6886466..0534c5dfd 100644
--- a/packages/core/src/lib/addPattern.js
+++ b/packages/core/src/lib/addPattern.js
@@ -1,10 +1,8 @@
'use strict';
-const _ = require('lodash');
-
const logger = require('./log');
-module.exports = function(pattern, patternlab) {
+module.exports = function (pattern, patternlab) {
//add the link to the global object
if (!patternlab.data.link) {
patternlab.data.link = {};
diff --git a/packages/core/src/lib/annotation_exporter.js b/packages/core/src/lib/annotationExporter.js
similarity index 65%
rename from packages/core/src/lib/annotation_exporter.js
rename to packages/core/src/lib/annotationExporter.js
index 8fb22470d..ffd16eb15 100644
--- a/packages/core/src/lib/annotation_exporter.js
+++ b/packages/core/src/lib/annotationExporter.js
@@ -6,43 +6,47 @@ const _ = require('lodash');
const mp = require('./markdown_parser');
const logger = require('./log');
-const annotations_exporter = function(pl) {
+const annotationExporter = function (pl) {
const paths = pl.config.paths;
- let oldAnnotations;
/**
* Parses JS annotations.
* @returns array of comments that used to be wrapped in raw JS
*/
- function parseAnnotationsJS() {
+ function parseAnnotationsJSON() {
+ const jsonPath = path.resolve(paths.source.annotations, 'annotations.json');
+ let annotations;
+
//attempt to read the file
try {
- oldAnnotations = fs.readFileSync(
- path.resolve(paths.source.annotations, 'annotations.js'),
- 'utf8'
- );
+ if (fs.pathExistsSync(jsonPath)) {
+ //read the new file
+ annotations = fs.readFileSync(jsonPath, 'utf8');
+ } else {
+ //read the old file
+ const jsPath = path.resolve(paths.source.annotations, 'annotations.js');
+
+ annotations = fs
+ .readFileSync(jsPath, 'utf8')
+ .replace(/^\s*var comments ?= ?/, '')
+ .replace(/};\s*$/, '}');
+
+ logger.info(
+ `Please convert ${jsPath} to JSON and rename it annotations.json.`
+ );
+ }
} catch (ex) {
logger.debug(
- `annotations.js file missing from ${
- paths.source.annotations
- }. This may be expected if you do not use annotations or are using markdown.`
+ `annotations.json file missing from ${paths.source.annotations}. This may be expected if you do not use annotations or are using markdown.`
);
return [];
}
- //parse as JSON by removing the old wrapping js syntax. comments and the trailing semi-colon
- oldAnnotations = oldAnnotations.replace('var comments = ', '');
- oldAnnotations = oldAnnotations.replace('};', '}');
-
try {
- const oldAnnotationsJSON = JSON.parse(oldAnnotations);
- return oldAnnotationsJSON.comments;
+ const annotationsJSON = JSON.parse(annotations);
+ return annotationsJSON.comments;
} catch (ex) {
- logger.error(
- `There was an error parsing JSON for ${
- paths.source.annotations
- }annotations.js`
- );
+ logger.error(`There was an error parsing JSON for ${jsonPath}`);
return [];
}
}
@@ -72,7 +76,7 @@ const annotations_exporter = function(pl) {
//let annotations = annotations;
const markdown_parser = parser;
- return function(filePath) {
+ return function (filePath) {
const annotationsMD = fs.readFileSync(path.resolve(filePath), 'utf8');
//take the annotation snippets and split them on our custom delimiter
@@ -108,22 +112,22 @@ const annotations_exporter = function(pl) {
* @returns array of annotations
*/
function gatherAnnotations() {
- const annotationsJS = parseAnnotationsJS();
+ const annotationsJS = parseAnnotationsJSON();
const annotationsMD = parseAnnotationsMD();
return _.unionBy(annotationsJS, annotationsMD, 'el');
}
return {
- gather: function() {
+ gather: function () {
return gatherAnnotations();
},
- gatherJS: function() {
- return parseAnnotationsJS();
+ gatherJSON: function () {
+ return parseAnnotationsJSON();
},
- gatherMD: function() {
+ gatherMD: function () {
return parseAnnotationsMD();
},
};
};
-module.exports = annotations_exporter;
+module.exports = annotationExporter;
diff --git a/packages/core/src/lib/buildFooter.js b/packages/core/src/lib/buildFooter.js
index 5a3eb6217..c70cfe249 100644
--- a/packages/core/src/lib/buildFooter.js
+++ b/packages/core/src/lib/buildFooter.js
@@ -10,10 +10,10 @@ let render = require('./render'); //eslint-disable-line prefer-const
/**
* Builds footer HTML from the general footer and user-defined footer
* @param patternlab - global data store
- * @param patternPartial - the partial key to build this for, either viewall-patternPartial or a viewall-patternType-all
+ * @param patternPartial - the partial key to build this for, either viewall-patternPartial or a viewall-patternGroup-all
* @returns A promise which resolves with the HTML
*/
-module.exports = function(patternlab, patternPartial, uikit) {
+module.exports = function (patternlab, patternPartial, uikit) {
//first render the general footer
return render(Pattern.createEmpty({ extendedTemplate: uikit.footer }), {
patternData: JSON.stringify({
@@ -21,7 +21,7 @@ module.exports = function(patternlab, patternPartial, uikit) {
}),
cacheBuster: patternlab.cacheBuster,
})
- .then(footerPartial => {
+ .then((footerPartial) => {
let allFooterData;
try {
allFooterData = jsonCopy(
@@ -29,14 +29,14 @@ module.exports = function(patternlab, patternPartial, uikit) {
'config.paths.source.data plus patterns data'
);
} catch (err) {
- logger.warning('There was an error parsing JSON for patternlab.data');
- logger.warning(err);
+ logger.error('There was an error parsing JSON for patternlab.data');
+ logger.error(err);
}
allFooterData.patternLabFoot = footerPartial;
return render(patternlab.userFoot, allFooterData);
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('Error building buildFooterHTML');
});
diff --git a/packages/core/src/lib/buildListItems.js b/packages/core/src/lib/buildListItems.js
index af9ba783d..7eb214f12 100644
--- a/packages/core/src/lib/buildListItems.js
+++ b/packages/core/src/lib/buildListItems.js
@@ -26,7 +26,7 @@ const items = [
'twenty',
];
-module.exports = function(container) {
+module.exports = function (container) {
//combine all list items into one structure
const list = [];
for (const item in container.listitems) {
diff --git a/packages/core/src/lib/buildPatterns.js b/packages/core/src/lib/buildPatterns.js
index 51dcea8b3..476a373c6 100644
--- a/packages/core/src/lib/buildPatterns.js
+++ b/packages/core/src/lib/buildPatterns.js
@@ -14,6 +14,8 @@ const CompileState = require('./object_factory').CompileState;
const processMetaPattern = require('./processMetaPattern');
const pe = require('./pattern_exporter');
const lh = require('./lineage_hunter');
+const pm = require('./plugin_manager');
+const pluginManager = new pm();
const markModifiedPatterns = require('./markModifiedPatterns');
const parseAllLinks = require('./parseAllLinks');
const render = require('./render');
@@ -24,8 +26,12 @@ let pattern_exporter = new pe(); // eslint-disable-line
const lineage_hunter = new lh();
-module.exports = (deletePatternDir, patternlab, additionalData) => {
- patternlab.events.emit(events.PATTERNLAB_BUILD_START, patternlab);
+module.exports = async (deletePatternDir, patternlab, additionalData) => {
+ await pluginManager.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_BUILD_START,
+ patternlab
+ );
const paths = patternlab.config.paths;
@@ -34,7 +40,7 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
//
const graph = (patternlab.graph = loadPatternGraph(
patternlab,
- deletePatternDir
+ patternlab.config.cleanPublic
));
const graphNeedsUpgrade = !PatternGraph.checkVersion(graph);
if (graphNeedsUpgrade) {
@@ -49,7 +55,9 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
// Flags
patternlab.incrementalBuildsEnabled = !(
- deletePatternDir || graphNeedsUpgrade
+ patternlab.config.cleanPublic ||
+ graphNeedsUpgrade ||
+ deletePatternDir
);
//
@@ -63,8 +71,9 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
return patternlab
.processAllPatternsIterative(paths.source.patterns)
- .then(() => {
- patternlab.events.emit(
+ .then(async () => {
+ await pluginManager.raiseEvent(
+ patternlab,
events.PATTERNLAB_PATTERN_ITERATION_END,
patternlab
);
@@ -85,12 +94,12 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
//perhaps we can check for a convention like [uikitname]_00-head.mustache, and if found, add them to patternlab.uikits[uikitname].userFoot
//then, if present, use those during compose()
const headPatternPromise = processMetaPattern(
- `_00-head.${patternlab.config.patternExtension}`,
+ `_head.${patternlab.config.patternExtension}`,
'userHead',
patternlab
);
const footPatternPromise = processMetaPattern(
- `_01-foot.${patternlab.config.patternExtension}`,
+ `_foot.${patternlab.config.patternExtension}`,
'userFoot',
patternlab
);
@@ -110,7 +119,7 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
cacheBuster: patternlab.cacheBuster,
}
)
- .then(results => {
+ .then((results) => {
patternlab.data.patternLabHead = results;
// If deletePatternDir == true or graph needs to be updated
@@ -124,7 +133,7 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
if (patternlab.incrementalBuildsEnabled) {
// When the graph was loaded from file, some patterns might have been moved/deleted between runs
// so the graph data become out of sync
- patternlab.graph.sync().forEach(n => {
+ patternlab.graph.sync().forEach((n) => {
logger.info('[Deleted/Moved] ' + n);
});
@@ -140,11 +149,11 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
}
}
//render all patterns last, so lineageR works
- const allPatternsPromise = patternsToBuild.map(pattern =>
- compose(pattern, patternlab)
+ const allPatternsPromise = patternsToBuild.map(
+ async (pattern) => await compose(pattern, patternlab)
);
//copy non-pattern files like JavaScript
- const allJS = patternsToBuild.map(pattern => {
+ const allJS = patternsToBuild.map((pattern) => {
const { name, patternPartial, subdir } = pattern;
const {
source: { patterns: sourceDir },
@@ -152,7 +161,7 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
} = patternlab.config.paths;
const src = path.join(sourceDir, subdir);
const dest = path.join(publicDir, name);
- return map(patternlab.uikits, uikit => {
+ return map(patternlab.uikits, (uikit) => {
return copy(
src,
path.resolve(process.cwd(), uikit.outputDir, dest),
@@ -190,27 +199,27 @@ module.exports = (deletePatternDir, patternlab, additionalData) => {
//export patterns if necessary
pattern_exporter.export_patterns(patternlab);
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('Error rendering patterns');
});
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('Error rendering pattern lab header');
});
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('Error processing meta patterns');
});
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('Error processing patterns recursively');
});
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('Error in buildPatterns()');
});
diff --git a/packages/core/src/lib/changes_hunter.js b/packages/core/src/lib/changes_hunter.js
index 038be8b41..ee4a4d52c 100644
--- a/packages/core/src/lib/changes_hunter.js
+++ b/packages/core/src/lib/changes_hunter.js
@@ -12,7 +12,7 @@ let fs = require('fs-extra'); //eslint-disable-line prefer-const
* For detecting changed patterns.
* @constructor
*/
-const ChangesHunter = function() {};
+const ChangesHunter = function () {};
ChangesHunter.prototype = {
/**
@@ -25,7 +25,7 @@ ChangesHunter.prototype = {
*
* @see {@link CompileState}
*/
- checkBuildState: function(pattern, patternlab) {
+ checkBuildState: function (pattern, patternlab) {
//write the compiled template to the public patterns directory
const renderedTemplatePath =
patternlab.config.paths.public.patterns +
@@ -40,12 +40,12 @@ ChangesHunter.prototype = {
pattern.compileState = CompileState.NEEDS_REBUILD;
}
- _.each(patternlab.uikits, uikit => {
+ _.each(patternlab.uikits, (uikit) => {
try {
// renderedTemplatePath required to display a single element
// Markup only is required for "View All" pages. It will get loaded later on.
// If any of these is missing, mark pattern for recompile
- [renderedTemplatePath, markupOnlyPath].forEach(renderedFile => {
+ [renderedTemplatePath, markupOnlyPath].forEach((renderedFile) => {
// Prevent error message if file does not exist
fs.accessSync(
path.join(process.cwd(), uikit.outputDir, renderedFile),
@@ -94,7 +94,7 @@ ChangesHunter.prototype = {
* @param {Pattern} currentPattern
* @param {string} file
*/
- checkLastModified: function(currentPattern, file) {
+ checkLastModified: function (currentPattern, file) {
if (file && fs.pathExistsSync(file)) {
try {
const stat = fs.statSync(file);
@@ -110,7 +110,7 @@ ChangesHunter.prototype = {
}
},
- needsRebuild: function(lastModified, p) {
+ needsRebuild: function (lastModified, p) {
if (p.compileState !== CompileState.CLEAN || !p.lastModified) {
return true;
}
diff --git a/packages/core/src/lib/cleanBuildDirectory.js b/packages/core/src/lib/cleanBuildDirectory.js
index 11d78c01e..0cfc300e0 100644
--- a/packages/core/src/lib/cleanBuildDirectory.js
+++ b/packages/core/src/lib/cleanBuildDirectory.js
@@ -15,12 +15,12 @@ module.exports = (incrementalBuildsEnabled, patternlab) => {
return Promise.resolve();
} else {
return Promise.all(
- _.map(patternlab.uikits, uikit => {
+ _.map(patternlab.uikits, (uikit) => {
return fs.emptyDir(
path.join(process.cwd(), uikit.outputDir, paths.public.patterns)
);
})
- ).catch(reason => {
+ ).catch((reason) => {
logger.error(reason);
});
}
diff --git a/packages/core/src/lib/compose.js b/packages/core/src/lib/compose.js
index 86b2f8f91..c3494e123 100644
--- a/packages/core/src/lib/compose.js
+++ b/packages/core/src/lib/compose.js
@@ -8,11 +8,15 @@ const logger = require('./log');
const parseLink = require('./parseLink');
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;
const CompileState = require('./object_factory').CompileState;
-module.exports = function(pattern, patternlab) {
+module.exports = async function (pattern, patternlab) {
// Pattern does not need to be built and recompiled more than once
if (!pattern.isPattern || pattern.compileState === CompileState.CLEAN) {
return Promise.resolve(false);
@@ -30,14 +34,15 @@ module.exports = function(pattern, patternlab) {
pattern.patternLineageEExists =
pattern.patternLineageExists || pattern.patternLineageRExists;
- patternlab.events.emit(
+ await pluginManager.raiseEvent(
+ patternlab,
events.PATTERNLAB_PATTERN_BEFORE_DATA_MERGE,
patternlab,
pattern
);
return Promise.all(
- _.map(patternlab.uikits, uikit => {
+ _.map(patternlab.uikits, (uikit) => {
// exclude pattern from uikit rendering
if (uikitExcludePattern(pattern, uikit)) {
return Promise.resolve();
@@ -53,8 +58,14 @@ module.exports = function(pattern, patternlab) {
'listitems.json + any pattern listitems.json'
);
- allData = _.merge({}, patternlab.data, pattern.jsonFileData);
- allData = _.merge({}, allData, allListItems);
+ allData = dataMerger(
+ patternlab.data,
+ pattern.jsonFileData,
+ patternlab.config
+ );
+ // _.merge({}, patternlab.data, pattern.jsonFileData);
+ allData = dataMerger(allData, allListItems, patternlab.config);
+ // _.merge({}, allData, allListItems);
allData.cacheBuster = patternlab.cacheBuster;
allData.patternPartial = pattern.patternPartial;
@@ -113,13 +124,13 @@ module.exports = function(pattern, patternlab) {
pattern.patternLineageExists || pattern.patternLineageRExists,
patternDesc: pattern.patternDescExists ? pattern.patternDesc : '',
patternBreadcrumb:
- pattern.patternGroup === pattern.patternSubGroup
+ pattern.patternGroup === pattern.patternSubgroup
? {
- patternType: pattern.patternGroup,
+ patternGroup: pattern.patternGroup,
}
: {
- patternType: pattern.patternGroup,
- patternSubtype: pattern.patternSubGroup,
+ patternGroup: pattern.patternGroup,
+ patternSubgroup: pattern.patternSubgroup,
},
patternExtension: pattern.fileExtension.substr(1), //remove the dot because styleguide asset default adds it for us
patternName: pattern.patternName,
@@ -144,11 +155,12 @@ module.exports = function(pattern, patternlab) {
patternPartialPromise,
footerPartialPromise,
])
- .then(intermediateResults => {
+ .then((intermediateResults) => {
// retrieve results of promises
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;
@@ -158,46 +170,50 @@ module.exports = function(pattern, patternlab) {
'config.paths.source.data global data'
);
} catch (err) {
- logger.info(
+ logger.error(
'There was an error parsing JSON for ' + pattern.relPath
);
- logger.info(err);
+ logger.error(err);
}
allFooterData = _.merge(allFooterData, pattern.jsonFileData);
+ allFooterData.cacheBuster = patternlab.cacheBuster;
allFooterData.patternLabFoot = footerPartial;
- return render(patternlab.userFoot, allFooterData).then(footerHTML => {
- ///////////////
- // WRITE FILES
- ///////////////
-
- patternlab.events.emit(
- events.PATTERNLAB_PATTERN_WRITE_BEGIN,
- patternlab,
- pattern
- );
-
- //write the compiled template to the public patterns directory
- patternlab.writePatternFiles(
- headHTML,
- pattern,
- footerHTML,
- uikit.outputDir
- );
-
- patternlab.events.emit(
- events.PATTERNLAB_PATTERN_WRITE_END,
- patternlab,
- pattern
- );
-
- // Allows serializing the compile state
- patternlab.graph.node(pattern).compileState = pattern.compileState =
- CompileState.CLEAN;
- logger.info('Built pattern: ' + pattern.patternPartial);
- });
+ return render(patternlab.userFoot, allFooterData).then(
+ async (footerHTML) => {
+ ///////////////
+ // WRITE FILES
+ ///////////////
+ await pluginManager.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_PATTERN_WRITE_BEGIN,
+ patternlab,
+ pattern
+ );
+
+ //write the compiled template to the public patterns directory
+ patternlab.writePatternFiles(
+ headHTML,
+ pattern,
+ footerHTML,
+ uikit.outputDir
+ );
+
+ await pluginManager.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_PATTERN_WRITE_END,
+ patternlab,
+ pattern
+ );
+
+ // Allows serializing the compile state
+ patternlab.graph.node(pattern).compileState =
+ pattern.compileState = CompileState.CLEAN;
+ logger.info('Built pattern: ' + pattern.patternPartial);
+ }
+ );
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
});
})
diff --git a/packages/core/src/lib/copier.js b/packages/core/src/lib/copier.js
index 441ffdf5b..ba1c22788 100644
--- a/packages/core/src/lib/copier.js
+++ b/packages/core/src/lib/copier.js
@@ -8,7 +8,7 @@ const watchAssets = require('./watchAssets');
const watchPatternLabFiles = require('./watchPatternLabFiles');
const copier = () => {
- const transform_paths = directories => {
+ const transform_paths = (directories) => {
//create array with all source keys minus our blacklist
const dirs = {};
const blackList = [
@@ -55,6 +55,14 @@ const copier = () => {
debug: patternlab.config.logLevel === 'debug',
};
+ // Adding assets to filter for in case of transformedAssetTypes defined; adapted regex from https://stackoverflow.com/a/6745455
+ if (patternlab.config.transformedAssetTypes) {
+ copyOptions.filter = new RegExp(
+ `.*(? {
} else {
//just copy
copyPromises.push(
- _.map(patternlab.uikits, uikit => {
+ _.map(patternlab.uikits, (uikit) => {
copyFile(
dir.source,
path.join(basePath, uikit.outputDir, dir.public),
@@ -79,7 +87,7 @@ const copier = () => {
// copy the styleguide
copyPromises.push(
- _.map(patternlab.uikits, uikit => {
+ _.map(patternlab.uikits, (uikit) => {
copyFile(
path.join(uikit.modulePath, assetDirectories.source.styleguide),
path.join(basePath, uikit.outputDir, assetDirectories.public.root),
@@ -90,9 +98,9 @@ const copier = () => {
// copy the favicon
copyPromises.push(
- _.map(patternlab.uikits, uikit => {
+ _.map(patternlab.uikits, (uikit) => {
copyFile(
- `${assetDirectories.source.root}/favicon.ico`,
+ `${assetDirectories.source.root}favicon.ico`,
path.join(
basePath,
uikit.outputDir,
@@ -116,7 +124,7 @@ const copier = () => {
copyAndWatch: (assetDirectories, patternlab, options) => {
return copyAndWatch(assetDirectories, patternlab, options);
},
- transformConfigPaths: paths => {
+ transformConfigPaths: (paths) => {
return transform_paths(paths);
},
};
diff --git a/packages/core/src/lib/copyFile.js b/packages/core/src/lib/copyFile.js
index ce1bc056a..c8202afe1 100644
--- a/packages/core/src/lib/copyFile.js
+++ b/packages/core/src/lib/copyFile.js
@@ -7,10 +7,10 @@ let copy = require('recursive-copy'); // eslint-disable-line prefer-const
const copyFile = (p, dest, options) => {
return copy(p, dest, options)
- .on(copy.events.ERROR, function(error, copyOperation) {
+ .on(copy.events.ERROR, function (error, copyOperation) {
logger.error('Unable to copy ' + copyOperation.dest);
})
- .on(copy.events.COPY_FILE_ERROR, error => {
+ .on(copy.events.COPY_FILE_ERROR, (error) => {
logger.error(error);
})
.on(copy.events.COPY_FILE_COMPLETE, () => {
diff --git a/packages/core/src/lib/dataMerger.js b/packages/core/src/lib/dataMerger.js
new file mode 100644
index 000000000..08544c320
--- /dev/null
+++ b/packages/core/src/lib/dataMerger.js
@@ -0,0 +1,36 @@
+const _ = require('lodash');
+
+/**
+ * Merges two objects depending on the configuration and will either merge
+ * arrays and only replaces items on the index or replace the entire
+ * collection of the different parameters
+ *
+ * @param {*} dataObject the object that contains the main data
+ * @param {*} dataToMergeWithObject the object that should be merged with the original data
+ * @param {*} patternlabConfig the patternlab configuration object
+ */
+module.exports = function (
+ dataObject,
+ dataToMergeWithObject,
+ patternlabConfig
+) {
+ return _.mergeWith(
+ {},
+ dataObject,
+ dataToMergeWithObject,
+ (objValue, srcValue) => {
+ if (
+ _.isArray(objValue) &&
+ // If the parameter is not available after updating pattern lab but
+ // not the patternlab-config it should not override arrays.
+ patternlabConfig.hasOwnProperty('patternMergeVariantArrays') &&
+ !patternlabConfig.patternMergeVariantArrays
+ ) {
+ return srcValue;
+ }
+ // Lodash will only check for "undefined" and eslint needs a consistent
+ // return so do not remove
+ return undefined;
+ }
+ );
+};
diff --git a/packages/core/src/lib/data_loader.js b/packages/core/src/lib/data_loader.js
index f1ac874c2..573edd04e 100644
--- a/packages/core/src/lib/data_loader.js
+++ b/packages/core/src/lib/data_loader.js
@@ -21,9 +21,7 @@ function loadFile(dataFilePath, fsDep) {
if (dataFile && fsDep.existsSync(path.resolve(dataFile))) {
try {
- return yaml.safeLoad(
- fsDep.readFileSync(path.resolve(dataFile), 'utf8')
- );
+ return yaml.load(fsDep.readFileSync(path.resolve(dataFile), 'utf8'));
} catch (err) {
throw new Error(`Error loading file: ${dataFile} - ${err.message}`);
}
@@ -53,9 +51,9 @@ function loadDataFromFolder(dataFilesPath, excludeFileNames, fsDep) {
const dataFiles = glob.sync(dataFilesFullPath, globOptions);
let mergeObject = {};
- dataFiles.forEach(function(filePath) {
+ dataFiles.forEach(function (filePath) {
try {
- const jsonData = yaml.safeLoad(
+ const jsonData = yaml.load(
fsDep.readFileSync(path.resolve(filePath), 'utf8')
);
mergeObject = _.merge(mergeObject, jsonData);
diff --git a/packages/core/src/lib/decompose.js b/packages/core/src/lib/decompose.js
index e541708b5..4c35cd694 100644
--- a/packages/core/src/lib/decompose.js
+++ b/packages/core/src/lib/decompose.js
@@ -16,7 +16,7 @@ const list_item_hunter = new lih();
* @param patternlab - global data store
* @param ignoreLineage - whether or not to hunt for lineage for this pattern
*/
-module.exports = function(pattern, patternlab, ignoreLineage) {
+module.exports = function (pattern, patternlab, ignoreLineage) {
//set the extendedTemplate to operate on later if we find partials to replace
if (!pattern.extendedTemplate) {
pattern.extendedTemplate = pattern.template;
@@ -51,7 +51,7 @@ module.exports = function(pattern, patternlab, ignoreLineage) {
expandPartialPromise,
lineagePromise,
addPromise,
- ]).catch(reason => {
+ ]).catch((reason) => {
logger.error(reason);
});
};
diff --git a/packages/core/src/lib/events.js b/packages/core/src/lib/events.js
index b1653b3c8..9eda9005f 100644
--- a/packages/core/src/lib/events.js
+++ b/packages/core/src/lib/events.js
@@ -30,7 +30,7 @@ const EVENTS = Object.freeze({
PATTERNLAB_PATTERN_ITERATION_END: 'patternlab-pattern-iteration-end',
/**
- * @desc Emitted after global `data.json` and `listitems.json` are read, and the supporting Pattern Lab templates are loaded into memory (header, footer, patternSection, patternSectionSubType, viewall). Right before patterns are iterated over to gather data about them.
+ * @desc Emitted after global `data.json` and `listitems.json` are read, and the supporting Pattern Lab templates are loaded into memory (header, footer, patternSection, patternSectionSubgroup, viewall). Right before patterns are iterated over to gather data about them.
* @property {object} patternlab - global data store
*/
PATTERNLAB_BUILD_GLOBAL_DATA_END: 'patternlab-build-global-data-end',
@@ -39,7 +39,7 @@ const EVENTS = Object.freeze({
* @desc Emitted before all data is merged prior to a Pattern's render. Global `data.json` is merged with any pattern `.json`. Global `listitems.json` is merged with any pattern `.listitems.json`.
* @property {object} patternlab - global data store
* @property {Pattern} pattern - current pattern
- * @see {@link https://github.com/pattern-lab/patternlab-node/blob/master/src/lib/object_factory.js#L16|Pattern}
+ * @see {@link https://github.com/pattern-lab/patternlab-node/blob/master/packages/core/src/lib/object_factory.js#L16|Pattern}
*/
PATTERNLAB_PATTERN_BEFORE_DATA_MERGE: 'patternlab-pattern-before-data-merge',
@@ -47,7 +47,7 @@ const EVENTS = Object.freeze({
* @desc Emitted before a pattern's template, HTML, and encoded HTML files are written to their output location
* @property {object} patternlab - global data store
* @property {Pattern} pattern - current pattern
- * @see {@link https://github.com/pattern-lab/patternlab-node/blob/master/src/lib/object_factory.js#L16|Pattern}
+ * @see {@link https://github.com/pattern-lab/patternlab-node/blob/master/packages/core/src/lib/object_factory.js#L16|Pattern}
*/
PATTERNLAB_PATTERN_WRITE_BEGIN: 'patternlab-pattern-write-begin',
@@ -55,7 +55,7 @@ const EVENTS = Object.freeze({
* @desc Emitted after a pattern's template, HTML, and encoded HTML files are written to their output location
* @property {object} patternlab - global data store
* @property {Pattern} pattern - current pattern
- * @see {@link https://github.com/pattern-lab/patternlab-node/blob/master/src/lib/object_factory.js#L16|Pattern}
+ * @see {@link https://github.com/pattern-lab/patternlab-node/blob/master/packages/core/src/lib/object_factory.js#L16|Pattern}
*/
PATTERNLAB_PATTERN_WRITE_END: 'patternlab-pattern-write-end',
diff --git a/packages/core/src/lib/expandPartials.js b/packages/core/src/lib/expandPartials.js
index a42df2cbc..e4976fe8b 100644
--- a/packages/core/src/lib/expandPartials.js
+++ b/packages/core/src/lib/expandPartials.js
@@ -1,15 +1,11 @@
'use strict';
const logger = require('./log');
-const ph = require('./parameter_hunter');
-const smh = require('./style_modifier_hunter');
const jsonCopy = require('./json_copy');
const getPartial = require('./get');
-const parameter_hunter = new ph();
-const style_modifier_hunter = new smh();
-
-module.exports = function(currentPattern, patternlab) {
+// TODO: remove when removing mustache
+module.exports = function (currentPattern, patternlab) {
const processRecursive = require('./processRecursive');
//find how many partials there may be for the given pattern
@@ -20,75 +16,51 @@ module.exports = function(currentPattern, patternlab) {
// results
if (
currentPattern.engine.expandPartials &&
- (foundPatternPartials !== null && foundPatternPartials.length > 0)
+ foundPatternPartials !== null &&
+ foundPatternPartials.length > 0
) {
logger.debug(`found partials for ${currentPattern.patternPartial}`);
- // determine if the template contains any pattern parameters. if so they
- // must be immediately consumed
- return parameter_hunter
- .find_parameters(currentPattern, patternlab)
- .then(() => {
- //do something with the regular old partials
- foundPatternPartials.forEach(foundPartial => {
- const partial = currentPattern.findPartial(foundPartial);
- const partialPattern = getPartial(partial, patternlab);
-
- //recurse through nested partials to fill out this extended template.
- return processRecursive(partialPattern.relPath, patternlab)
- .then(() => {
- //eslint-disable-line no-loop-func
+ //do something with the regular old partials
+ foundPatternPartials.forEach((foundPartial) => {
+ const partial = currentPattern.findPartial(foundPartial);
+ const partialPattern = getPartial(partial, patternlab);
- //complete assembly of extended template
- //create a copy of the partial so as to not pollute it after the getPartial call.
- const cleanPartialPattern = jsonCopy(
- partialPattern,
- `partial pattern ${partial}`
- );
+ //recurse through nested partials to fill out this extended template.
+ return processRecursive(partialPattern.relPath, patternlab)
+ .then(() => {
+ //eslint-disable-line no-loop-func
- //if partial has style modifier data, replace the styleModifier value
- if (
- currentPattern.stylePartials &&
- currentPattern.stylePartials.length > 0
- ) {
- style_modifier_hunter.consume_style_modifier(
- cleanPartialPattern,
- foundPartial,
- patternlab
- );
- }
+ //complete assembly of extended template
+ //create a copy of the partial so as to not pollute it after the getPartial call.
+ const cleanPartialPattern = jsonCopy(
+ partialPattern,
+ `partial pattern ${partial}`
+ );
- //this is what we came here for
- logger.debug(
- `within ${
- currentPattern.patternPartial
- }, replacing extendedTemplate partial ${foundPartial} with ${
- cleanPartialPattern.patternPartial
- }'s extendedTemplate`
- );
+ //this is what we came here for
+ logger.debug(
+ `within ${currentPattern.patternPartial}, replacing extendedTemplate partial ${foundPartial} with ${cleanPartialPattern.patternPartial}'s extendedTemplate`
+ );
- currentPattern.extendedTemplate = currentPattern.extendedTemplate.replace(
- foundPartial,
- cleanPartialPattern.extendedTemplate
- );
+ currentPattern.extendedTemplate =
+ currentPattern.extendedTemplate.replace(
+ foundPartial,
+ cleanPartialPattern.extendedTemplate
+ );
- // update the extendedTemplate in the partials object in case this
- // pattern is consumed later
- patternlab.partials[currentPattern.patternPartial] =
- currentPattern.extendedTemplate;
+ // update the extendedTemplate in the partials object in case this
+ // pattern is consumed later
+ patternlab.partials[currentPattern.patternPartial] =
+ currentPattern.extendedTemplate;
- return Promise.resolve();
- })
- .catch(reason => {
- console.log(reason);
- logger.error(reason);
- });
+ return Promise.resolve();
+ })
+ .catch((reason) => {
+ console.log(reason);
+ logger.error(reason);
});
- })
- .catch(reason => {
- console.log(reason);
- logger.error(reason);
- });
+ });
}
return Promise.resolve();
};
diff --git a/packages/core/src/lib/exportData.js b/packages/core/src/lib/exportData.js
index 51b166a08..aeef0a845 100644
--- a/packages/core/src/lib/exportData.js
+++ b/packages/core/src/lib/exportData.js
@@ -1,10 +1,9 @@
'use strict';
-const eol = require('os').EOL;
const path = require('path');
-const _ = require('lodash');
+const eol = require('os').EOL;
-const ae = require('./annotation_exporter');
+const ae = require('./annotationExporter');
let fs = require('fs-extra'); //eslint-disable-line prefer-const
@@ -12,8 +11,8 @@ let fs = require('fs-extra'); //eslint-disable-line prefer-const
* Write out our pattern information for use by the front end
* @param patternlab - global data store
*/
-module.exports = function(patternlab) {
- const annotation_exporter = new ae(patternlab);
+module.exports = function (patternlab, uikit) {
+ const annotationExporter = new ae(patternlab);
const paths = patternlab.config.paths;
@@ -32,8 +31,8 @@ module.exports = function(patternlab) {
//navItems
output +=
- 'var navItems = {"patternTypes": ' +
- JSON.stringify(patternlab.patternTypes) +
+ 'var navItems = {"patternGroups": ' +
+ JSON.stringify(patternlab.patternGroups) +
', "ishControlsHide": ' +
JSON.stringify(patternlab.config.ishControlsHide) +
'};' +
@@ -68,34 +67,41 @@ module.exports = function(patternlab) {
eol;
//annotations
- const annotationsJSON = annotation_exporter.gather();
+ const annotationsJSON = annotationExporter.gather();
const annotations =
'var comments = { "comments" : ' + JSON.stringify(annotationsJSON) + '};';
- _.each(patternlab.uikits, uikit => {
- fs.outputFileSync(
- path.resolve(
- path.join(
- process.cwd(),
- uikit.outputDir,
- paths.public.annotations,
- 'annotations.js'
- )
- ),
- annotations
- );
- });
+ fs.outputFileSync(
+ path.resolve(
+ path.join(
+ process.cwd(),
+ uikit.outputDir,
+ paths.public.annotations,
+ 'annotations.js'
+ )
+ ),
+ annotations
+ );
+
+ // add module.export to the Nodejs-specific file generated.
+ const exportedOutput =
+ output +
+ 'module.exports = { config, ishControls, navItems, patternPaths, viewAllPaths, plugins, defaultShowPatternInfo, defaultPattern };';
//write all output to patternlab-data
-
- _.each(patternlab.uikits, uikit => {
- fs.outputFileSync(
- path.resolve(
- path.join(process.cwd(), uikit.outputDir, paths.public.data),
- 'patternlab-data.js'
- ),
- output
- );
- });
+ fs.outputFileSync(
+ path.resolve(
+ path.join(process.cwd(), uikit.outputDir, paths.public.data),
+ 'patternlab-data.js'
+ ),
+ output
+ );
+ fs.outputFileSync(
+ path.resolve(
+ path.join(process.cwd(), uikit.outputDir, paths.public.data),
+ 'patternlab-data.cjs.js'
+ ),
+ exportedOutput
+ );
return output;
};
diff --git a/packages/core/src/lib/findModules.js b/packages/core/src/lib/findModules.js
index 246612ec8..f54f80d4f 100644
--- a/packages/core/src/lib/findModules.js
+++ b/packages/core/src/lib/findModules.js
@@ -6,7 +6,7 @@ const isScopedPackage = require('./isScopedPackage');
let fs = require('fs-extra'); // eslint-disable-line
-const isDir = fPath => {
+const isDir = (fPath) => {
const stats = fs.lstatSync(fPath);
return stats.isDirectory() || stats.isSymbolicLink();
};
@@ -27,7 +27,7 @@ module.exports = (dir, filter) => {
*/
const dirList = fs
.readdirSync(fPath)
- .filter(p => isDir(path.join(fPath, p)));
+ .filter((p) => isDir(path.join(fPath, p)));
/**
* @name m
@@ -35,7 +35,7 @@ module.exports = (dir, filter) => {
* @type {Array}
*/
const m = foundModules.concat(
- dirList.filter(filter).map(mod => {
+ dirList.filter(filter).map((mod) => {
return {
name: filter(mod),
modulePath: path.join(fPath, mod),
@@ -52,7 +52,7 @@ module.exports = (dir, filter) => {
...m,
...dirList
.filter(isScopedPackage) // 2
- .map(scope => findModules(path.join(fPath, scope), m)) // 3
+ .map((scope) => findModules(path.join(fPath, scope), m)) // 3
);
};
diff --git a/packages/core/src/lib/get.js b/packages/core/src/lib/get.js
index 2feccc135..2f180a77f 100644
--- a/packages/core/src/lib/get.js
+++ b/packages/core/src/lib/get.js
@@ -2,7 +2,7 @@
const logger = require('./log');
-module.exports = function(partialName, patternlab, reportWarning = true) {
+module.exports = function (partialName, patternlab, reportWarning = true) {
//look for exact partial matches
for (let i = 0; i < patternlab.patterns.length; i++) {
if (patternlab.patterns[i].patternPartial === partialName) {
@@ -35,7 +35,7 @@ module.exports = function(partialName, patternlab, reportWarning = true) {
}
if (reportWarning) {
logger.warning(
- `Could not find pattern referenced with partial syntax ${partialName}.
+ `Could not find pattern referenced with partial syntax "${partialName}" from "${patternlab.config.paths.source.patterns}".
This can occur when a pattern was renamed, moved, or no longer exists but it still referenced within a different template or within data as a link.`
);
}
diff --git a/packages/core/src/lib/isScopedPackage.js b/packages/core/src/lib/isScopedPackage.js
index cffd1d811..53b607ad7 100644
--- a/packages/core/src/lib/isScopedPackage.js
+++ b/packages/core/src/lib/isScopedPackage.js
@@ -10,7 +10,7 @@ const scopeMatch = /^@(.*)$/;
* @param {string} filePath - The pathname to check
* @return {Boolean} - Returns a bool when found, false othersie
*/
-module.exports = filePath => {
+module.exports = (filePath) => {
const baseName = path.basename(filePath);
return scopeMatch.test(baseName);
};
diff --git a/packages/core/src/lib/lineage_hunter.js b/packages/core/src/lib/lineage_hunter.js
index 0b844fcc9..3a90a0f65 100644
--- a/packages/core/src/lib/lineage_hunter.js
+++ b/packages/core/src/lib/lineage_hunter.js
@@ -2,7 +2,7 @@
const getPartial = require('./get');
const logger = require('./log');
-const lineage_hunter = function() {
+const lineage_hunter = function () {
function findlineage(pattern, patternlab) {
// As we are adding edges from pattern to ancestor patterns, ensure it is known to the graph
patternlab.graph.add(pattern);
@@ -10,7 +10,7 @@ const lineage_hunter = function() {
//find the {{> template-name }} within patterns
const matches = pattern.findPartials();
if (matches !== null) {
- matches.forEach(function(match) {
+ matches.forEach(function (match) {
//get the ancestorPattern
const ancestorPattern = getPartial(
pattern.findPartial(match),
@@ -131,13 +131,7 @@ const lineage_hunter = function() {
? '<>'
: lineageRPattern.patternState;
logger.info(
- `Found a lower common denominator pattern state: ${
- pattern.patternState
- } on ${
- pattern.patternPartial
- }. Setting reverse lineage pattern ${
- lineageRPattern.patternPartial
- } from ${oldState}`
+ `Found a lower common denominator pattern state: ${pattern.patternState} on ${pattern.patternPartial}. Setting reverse lineage pattern ${lineageRPattern.patternPartial} from ${oldState}`
);
lineageRPattern.patternState = pattern.patternState;
@@ -164,10 +158,10 @@ const lineage_hunter = function() {
}
return {
- find_lineage: function(pattern, patternlab) {
+ find_lineage: function (pattern, patternlab) {
findlineage(pattern, patternlab);
},
- cascade_pattern_states: function(patternlab) {
+ cascade_pattern_states: function (patternlab) {
cascadePatternStates(patternlab);
},
};
diff --git a/packages/core/src/lib/list_item_hunter.js b/packages/core/src/lib/list_item_hunter.js
index 167c8e55c..7d6346161 100644
--- a/packages/core/src/lib/list_item_hunter.js
+++ b/packages/core/src/lib/list_item_hunter.js
@@ -1,6 +1,6 @@
'use strict';
-const list_item_hunter = function() {
+const list_item_hunter = function () {
const logger = require('./log');
function processListItemPartials(pattern) {
@@ -11,9 +11,7 @@ const list_item_hunter = function() {
return matches.reduce((previousMatchPromise, liMatchStart) => {
return previousMatchPromise.then(() => {
logger.debug(
- `found listItem of size ${liMatchStart} inside ${
- pattern.patternPartial
- }`
+ `found listItem of size ${liMatchStart} inside ${pattern.patternPartial}`
);
//we found a listitem match
@@ -41,7 +39,7 @@ const list_item_hunter = function() {
}
return {
- process_list_item_partials: function(pattern) {
+ process_list_item_partials: function (pattern) {
return processListItemPartials(pattern);
},
};
diff --git a/packages/core/src/lib/loadPattern.js b/packages/core/src/lib/loadPattern.js
index 6eae3843e..b5990fecf 100644
--- a/packages/core/src/lib/loadPattern.js
+++ b/packages/core/src/lib/loadPattern.js
@@ -3,7 +3,6 @@
const path = require('path');
const Pattern = require('./object_factory').Pattern;
-const mp = require('./markdown_parser');
const logger = require('./log');
const patternEngines = require('./pattern_engines');
const ch = require('./changes_hunter');
@@ -12,7 +11,6 @@ const addPattern = require('./addPattern');
const buildListItems = require('./buildListItems');
const readDocumentation = require('./readDocumentation');
-const markdown_parser = new mp();
const changes_hunter = new ch();
const dataLoader = new da();
@@ -21,15 +19,28 @@ let fs = require('fs-extra'); //eslint-disable-line prefer-const
// loads a pattern from disk, creates a Pattern object from it and
// all its associated files, and records it in patternlab.patterns[]
-module.exports = function(relPath, patternlab) {
+module.exports = function (relPath, patternlab) {
+ const fileObject = path.parse(relPath);
+
+ //extract some information
+ const filename = fileObject.base;
+ const ext = fileObject.ext;
+ const patternsPath = patternlab.config.paths.source.patterns;
+
+ // skip non-pattern files
+ if (!patternEngines.isPatternFile(filename, patternlab)) {
+ return null;
+ }
+
+ // Determine patterns nested too deep and show a warning
const relativeDepth = (relPath.match(/\w(?=\\)|\w(?=\/)/g) || []).length;
- if (relativeDepth > 2) {
+ if (relativeDepth > 3) {
logger.warning('');
logger.warning('Warning:');
logger.warning(
'A pattern file: ' +
relPath +
- ' was found greater than 2 levels deep from ' +
+ ' was found greater than 3 levels deep from ' +
patternlab.config.paths.source.patterns +
'.'
);
@@ -37,69 +48,22 @@ module.exports = function(relPath, patternlab) {
"It's strongly suggested to not deviate from the following structure under _patterns/"
);
logger.warning(
- '[patternType]/[patternSubtype]/[patternName].[patternExtension]'
+ '[patternGroup]/[patternSubgroup]/[patternName].[patternExtension]'
+ );
+ logger.warning('or');
+ logger.warning(
+ '[patternGroup]/[patternSubgroup]/[patternName]/[patternName].[patternExtension]'
);
logger.warning('');
logger.warning(
'While Pattern Lab may still function, assets may 404 and frontend links may break. Consider yourself warned. '
);
logger.warning(
- 'Read More: http://patternlab.io/docs/pattern-organization.html'
+ 'Read More: https://patternlab.io/docs/overview-of-patterns/'
);
logger.warning('');
}
- //check if the found file is a top-level markdown file
- const fileObject = path.parse(relPath);
- if (fileObject.ext === '.md') {
- try {
- const proposedDirectory = path.resolve(
- patternlab.config.paths.source.patterns,
- fileObject.dir,
- fileObject.name
- );
- const proposedDirectoryStats = fs.statSync(proposedDirectory);
- if (proposedDirectoryStats.isDirectory()) {
- const subTypeMarkdownFileContents = fs.readFileSync(
- proposedDirectory + '.md',
- 'utf8'
- );
- const subTypeMarkdown = markdown_parser.parse(
- subTypeMarkdownFileContents
- );
- const subTypePattern = new Pattern(relPath, null, patternlab);
- subTypePattern.patternSectionSubtype = true;
- subTypePattern.patternDesc = subTypeMarkdown
- ? subTypeMarkdown.markdown
- : '';
- subTypePattern.flatPatternPath =
- subTypePattern.flatPatternPath + '-' + subTypePattern.fileName;
- subTypePattern.isPattern = false;
- subTypePattern.engine = null;
- patternlab.subtypePatterns[
- subTypePattern.patternPartial
- ] = subTypePattern;
-
- return subTypePattern;
- }
- } catch (err) {
- // no file exists, meaning it's a pattern markdown file
- if (err.code !== 'ENOENT') {
- logger.warning(err);
- }
- }
- }
-
- //extract some information
- const filename = fileObject.base;
- const ext = fileObject.ext;
- const patternsPath = patternlab.config.paths.source.patterns;
-
- // skip non-pattern files
- if (!patternEngines.isPatternFile(filename, patternlab)) {
- return null;
- }
-
//make a new Pattern Object
const currentPattern = new Pattern(relPath, null, patternlab);
@@ -130,10 +94,10 @@ module.exports = function(relPath, patternlab) {
);
}
} catch (err) {
- logger.warning(
+ logger.error(
`There was an error parsing sibling JSON for ${currentPattern.relPath}`
);
- logger.warning(err);
+ logger.error(err);
}
//look for a listitems.json file for this template
@@ -148,20 +112,16 @@ module.exports = function(relPath, patternlab) {
if (listItemsData) {
logger.debug(
- `found pattern-specific listitems data for ${
- currentPattern.patternPartial
- }`
+ `found pattern-specific listitems data for ${currentPattern.patternPartial}`
);
currentPattern.listitems = listItemsData;
buildListItems(currentPattern);
}
} catch (err) {
- logger.warning(
- `There was an error parsing sibling listitem JSON for ${
- currentPattern.relPath
- }`
+ logger.error(
+ `There was an error parsing sibling listitem JSON for ${currentPattern.relPath}`
);
- logger.warning(err);
+ logger.error(err);
}
//look for a markdown file for this template
@@ -172,11 +132,9 @@ module.exports = function(relPath, patternlab) {
currentPattern.template = fs.readFileSync(templatePath, 'utf8');
- //find any stylemodifiers that may be in the current pattern
- currentPattern.stylePartials = currentPattern.findPartialsWithStyleModifiers();
-
//find any pattern parameters that may be in the current pattern
- currentPattern.parameteredPartials = currentPattern.findPartialsWithPatternParameters();
+ currentPattern.parameteredPartials =
+ currentPattern.findPartialsWithPatternParameters();
[
templatePath,
@@ -186,7 +144,7 @@ module.exports = function(relPath, patternlab) {
`${listJsonFileName}.json`,
`${listJsonFileName}.yml`,
`${listJsonFileName}.yaml`,
- ].forEach(file => {
+ ].forEach((file) => {
changes_hunter.checkLastModified(currentPattern, file);
});
diff --git a/packages/core/src/lib/loaduikits.js b/packages/core/src/lib/loaduikits.js
index 1f97564a2..79de4556f 100644
--- a/packages/core/src/lib/loaduikits.js
+++ b/packages/core/src/lib/loaduikits.js
@@ -5,92 +5,110 @@ const _ = require('lodash');
const logger = require('./log');
-let findModules = require('./findModules'); //eslint-disable-line prefer-const
-let fs = require('fs-extra'); // eslint-disable-line
-
-const uiKitMatcher = /^uikit-(.*)$/;
-const nodeModulesPath = path.join(process.cwd(), 'node_modules');
-
-/**
- * Given a path: return the uikit name if the path points to a valid uikit
- * module directory, or false if it doesn't.
- * @param filePath
- * @returns UIKit name if exists or FALSE
- */
-const isUIKitModule = filePath => {
- const baseName = path.basename(filePath);
- const engineMatch = baseName.match(uiKitMatcher);
+const { resolvePackageFolder } = require('./resolver');
- if (engineMatch) {
- return engineMatch[1];
- }
- return false;
-};
+let fs = require('fs-extra'); // eslint-disable-line
-const readModuleFile = (kit, subPath) => {
+const readModuleFile = (uikitLocation, subPath) => {
return fs.readFileSync(
- path.resolve(path.join(kit.modulePath, subPath)),
+ path.resolve(path.join(uikitLocation, subPath)),
'utf8'
);
};
/**
* Loads uikits, connecting configuration and installed modules
- * [1] Looks in node_modules for uikits.
- * [2] Only continue if uikit is enabled in patternlab-config.json
- * [3] Reads files from uikit that apply to every template
+ * [1] Lists the enabled uikits from patternlab-config.json
+ * [2] Try to resolve the location of the uikit in the package dependencies
+ * [3] Warn when the uikit couldn't be loaded
+ * [4] Reads files from uikit that apply to every template
* @param {object} patternlab
*/
-module.exports = patternlab => {
+module.exports = (patternlab) => {
const paths = patternlab.config.paths;
- const uikits = findModules(nodeModulesPath, isUIKitModule); // [1]
-
- uikits.forEach(kit => {
- const configEntry = _.find(_.filter(patternlab.config.uikits, 'enabled'), {
- name: `uikit-${kit.name}`,
- }); // [2]
-
- if (!configEntry) {
- logger.warning(
- `Could not find uikit with name uikit-${
- kit.name
- } defined within patternlab-config.json, or it is not enabled.`
- );
- return;
+ const uikitConfigs = _.filter(patternlab.config.uikits, 'enabled'); // [1]
+ uikitConfigs.forEach((uikitConfig) => {
+ let uikitLocation = null;
+ if ('package' in uikitConfig) {
+ try {
+ uikitLocation = resolvePackageFolder(uikitConfig.package);
+ } catch (ex) {
+ logger.warning(
+ `Could not find uikit with package name ${uikitConfig.package}. Did you add it to the 'dependencies' section in your 'package.json' file?`
+ );
+ return;
+ }
+ } else {
+ // For backwards compatibility, name to package calculation is:
+ // 1. name -> name
+ // 2. name -> uikit-name
+ // 3. name -> @pattern-lab/name
+ // 4. name -> @pattern-lab/uikit-name
+ for (const packageName of [
+ uikitConfig.name,
+ `uikit-${uikitConfig.name}`,
+ `@pattern-lab/${uikitConfig.name}`,
+ `@pattern-lab/uikit-${uikitConfig.name}`,
+ ]) {
+ try {
+ uikitLocation = resolvePackageFolder(packageName); // [2]
+ } catch (ex) {
+ // Ignore
+ }
+ if (uikitLocation != null) {
+ uikitConfig.package = packageName;
+ logger.info(`Found uikit package ${packageName}`);
+ break;
+ }
+ }
+ if (uikitLocation == null) {
+ logger.warning(
+ `Could not find uikit with package name ${uikitConfig.name}, uikit-${uikitConfig.name}, @pattern-lab/${uikitConfig.name} or @pattern-lab/uikit-${uikitConfig.name} defined within patternlab-config.json in the package dependencies.`
+ );
+ return;
+ } else {
+ logger.warning(
+ `Please update the configuration of UIKit ${uikitConfig.name} with property 'package: ${uikitConfig.package}' in patternlab-config.json. Lookup by 'name' is deprecated and will be removed in the future.`
+ );
+ } // [3]
}
try {
- patternlab.uikits[`uikit-${kit.name}`] = {
- name: `uikit-${kit.name}`,
- modulePath: kit.modulePath,
+ patternlab.uikits[uikitConfig.name] = {
+ name: uikitConfig.name,
+ package: uikitConfig.package,
+ modulePath: uikitLocation,
enabled: true,
- outputDir: configEntry.outputDir,
- excludedPatternStates: configEntry.excludedPatternStates,
- excludedTags: configEntry.excludedTags,
+ outputDir: uikitConfig.outputDir,
+ excludedPatternStates: uikitConfig.excludedPatternStates,
+ excludedTags: uikitConfig.excludedTags,
header: readModuleFile(
- kit,
+ uikitLocation,
paths.source.patternlabFiles['general-header']
),
footer: readModuleFile(
- kit,
+ uikitLocation,
paths.source.patternlabFiles['general-footer']
),
patternSection: readModuleFile(
- kit,
+ uikitLocation,
paths.source.patternlabFiles.patternSection
),
- patternSectionSubType: readModuleFile(
- kit,
- paths.source.patternlabFiles.patternSectionSubtype
+ patternSectionSubgroup: readModuleFile(
+ uikitLocation,
+ paths.source.patternlabFiles.patternSectionSubgroup
+ ),
+ viewAll: readModuleFile(
+ uikitLocation,
+ paths.source.patternlabFiles.viewall
),
- viewAll: readModuleFile(kit, paths.source.patternlabFiles.viewall),
- }; // [3]
+ }; // [4]
} catch (ex) {
logger.error(ex);
logger.error(
'\nERROR: missing an essential file from ' +
- kit.modulePath +
+ uikitLocation +
paths.source.patternlabFiles +
". Pattern Lab won't work without this file.\n"
);
diff --git a/packages/core/src/lib/log.js b/packages/core/src/lib/log.js
index 87a7cd587..f55ff4aa1 100644
--- a/packages/core/src/lib/log.js
+++ b/packages/core/src/lib/log.js
@@ -63,8 +63,8 @@ const error = log.error.bind(log);
* @param {string} - a message to report
* @returns {function} - a callback to be passed to a Promise's .catch()
*/
-const reportError = function(message) {
- return function(err) {
+const reportError = function (message) {
+ return function (err) {
console.log(message);
console.log(err);
};
diff --git a/packages/core/src/lib/markModifiedPatterns.js b/packages/core/src/lib/markModifiedPatterns.js
index 00ed51de1..6eede313e 100644
--- a/packages/core/src/lib/markModifiedPatterns.js
+++ b/packages/core/src/lib/markModifiedPatterns.js
@@ -17,7 +17,7 @@ let fs = require('fs-extra'); //eslint-disable-line prefer-const
* @param lastModified
* @param patternlab
*/
-module.exports = function(lastModified, patternlab) {
+module.exports = function (lastModified, patternlab) {
/**
* If the given array exists, apply a function to each of its elements
* @param {Array} array
@@ -28,15 +28,13 @@ module.exports = function(lastModified, patternlab) {
array.forEach(func);
}
};
- const modifiedOrNot = _.groupBy(
- patternlab.patterns,
- p =>
- changes_hunter.needsRebuild(lastModified, p) ? 'modified' : 'notModified'
+ const modifiedOrNot = _.groupBy(patternlab.patterns, (p) =>
+ changes_hunter.needsRebuild(lastModified, p) ? 'modified' : 'notModified'
);
// For all unmodified patterns load their rendered template output
- forEachExisting(modifiedOrNot.notModified, cleanPattern => {
- _.each(patternlab.uikits, uikit => {
+ forEachExisting(modifiedOrNot.notModified, (cleanPattern) => {
+ _.each(patternlab.uikits, (uikit) => {
const xp = path.join(
process.cwd(),
uikit.outputDir,
@@ -52,7 +50,7 @@ module.exports = function(lastModified, patternlab) {
// For all patterns that were modified, schedule them for rebuild
forEachExisting(
modifiedOrNot.modified,
- p => (p.compileState = CompileState.NEEDS_REBUILD)
+ (p) => (p.compileState = CompileState.NEEDS_REBUILD)
);
return modifiedOrNot;
};
diff --git a/packages/core/src/lib/markdown_parser.js b/packages/core/src/lib/markdown_parser.js
index c940a5f67..f2c0e7b42 100644
--- a/packages/core/src/lib/markdown_parser.js
+++ b/packages/core/src/lib/markdown_parser.js
@@ -3,7 +3,7 @@ const md = require('markdown-it')();
const yaml = require('js-yaml');
const logger = require('./log');
-const markdown_parser = function() {
+const markdown_parser = function () {
/**
* Converts a markdown block with frontmatter (each is optional, technically) to a well-formed object.
* @param block - the ".md" file, which can contain frontmatter or not, or only frontmatter.
@@ -13,8 +13,9 @@ const markdown_parser = function() {
let returnObject = {};
try {
- //for each block process the yaml frontmatter and markdown
- const frontmatterRE = /---\r?\n{1}([\s\S]*)---\r?\n{1}([\s\S]*)+/gm;
+ // for each block process the yaml frontmatter and markdown
+ // even if the pattern only has pattern data without further documentation
+ const frontmatterRE = /---\r?\n{1}([\s\S]*)^---([\s\S]*)+/gm;
const chunks = frontmatterRE.exec(block);
if (chunks) {
@@ -22,7 +23,7 @@ const markdown_parser = function() {
if (chunks && chunks[1]) {
//parse the yaml if we got it
const frontmatter = chunks[1];
- returnObject = yaml.safeLoad(frontmatter);
+ returnObject = yaml.load(frontmatter);
}
if (chunks[2]) {
@@ -46,7 +47,7 @@ const markdown_parser = function() {
}
return {
- parse: function(block) {
+ parse: function (block) {
return parseMarkdownBlock(block);
},
};
diff --git a/packages/core/src/lib/object_factory.js b/packages/core/src/lib/object_factory.js
index 0c3ffe5d2..318b4cd25 100644
--- a/packages/core/src/lib/object_factory.js
+++ b/packages/core/src/lib/object_factory.js
@@ -1,82 +1,129 @@
'use strict';
-const patternEngines = require('./pattern_engines');
+
+const _ = require('lodash');
const path = require('path');
-const extend = require('util')._extend;
+const logger = require('./log');
+const patternEngines = require('./pattern_engines');
-// patternPrefixMatcher is intended to match the leading maybe-underscore,
+// prefixMatcher is intended to match the leading maybe-underscore,
// zero or more digits, and maybe-dash at the beginning of a pattern file name we can hack them
// off and get at the good part.
-const patternPrefixMatcher = /^_?(\d+-)?/;
+const prefixMatcher = /^_?(\d+-)?/;
+const prefixMatcherDeprecationCheckOrder = /^(\d+-).+/;
+const prefixMatcherDeprecationCheckHidden = /^_.+/;
-// Pattern properties
/**
- * Pattern constructor
- * @constructor
+ * Pattern constructor / Pattern properties
+ *
+ * Before changing functionalities of the pattern object please read the following pull requests
+ * to get more details about the behavior of the folder structure
+ * https://patternlab.io/docs/overview-of-patterns/#heading-deeper-nesting
+ * https://github.com/pattern-lab/patternlab-node/pull/992
+ * https://github.com/pattern-lab/patternlab-node/pull/1016
+ * https://github.com/pattern-lab/patternlab-node/pull/1143
+ *
+ * @param {string} relPath relative directory
+ * @param {Object} jsonFileData The JSON used to render values in the pattern.
+ * @param {Patternlab} patternlab The actual pattern lab instance
+ * @param {boolean} isPromoteToFlatPatternRun specifies if the pattern needs to be removed from its deep nesting folder
*/
-const Pattern = function(relPath, data, patternlab) {
+const Pattern = function (
+ relPath,
+ jsonFileData,
+ patternlab,
+ isPromoteToFlatPatternRun
+) {
+ this.relPath = path.normalize(relPath); // 'atoms/global/colors.mustache'
+
/**
* We expect relPath to be the path of the pattern template, relative to the
* root of the pattern tree. Parse out the path parts and save the useful ones.
- * @param {relPath} relative directory
- * @param {data} The JSON used to render values in the pattern.
- * @param {patternlab} rendered html files for the pattern
*/
- const pathObj = path.parse(path.normalize(relPath));
- this.relPath = path.normalize(relPath); // '00-atoms/00-global/00-colors.mustache'
- this.fileName = pathObj.name; // '00-colors'
- this.subdir = pathObj.dir; // '00-atoms/00-global'
+ const pathObj = path.parse(this.relPath);
+
+ const info = this.getPatternInfo(
+ pathObj,
+ patternlab,
+ isPromoteToFlatPatternRun ||
+ (patternlab &&
+ patternlab.config &&
+ patternlab.config.allPatternsAreDeeplyNested)
+ );
+
+ this.fileName = pathObj.name; // 'colors'
+ this.subdir = pathObj.dir; // 'atoms/global'
this.fileExtension = pathObj.ext; // '.mustache'
- // this is the unique name, subDir + fileName (sans extension)
- this.name =
- this.subdir.replace(path.sep, '-') + '-' + this.fileName.replace('~', '-'); // '00-atoms-00-global-00-colors'
+ // TODO: Remove if block when dropping ordering by prefix and keep else code
+ // (When we drop the info about the old ordering is deprecated)
+ if (
+ (prefixMatcherDeprecationCheckOrder.test(this.getDirLevel(0, info)) ||
+ prefixMatcherDeprecationCheckOrder.test(this.getDirLevel(1, info)) ||
+ prefixMatcherDeprecationCheckOrder.test(this.fileName)) &&
+ patternlab &&
+ patternlab.config &&
+ !patternlab.config.disableDeprecationWarningForOrderPatterns
+ ) {
+ logger.warning(
+ `${info.shortNotation}-${this.fileName} "Pattern", "Group" and "Subgroup" ordering by number prefix (##-) will be deprecated in the future.\n See https://patternlab.io/docs/reorganizing-patterns/`
+ );
+ }
+
+ if (
+ (prefixMatcherDeprecationCheckHidden.test(this.getDirLevel(0, info)) ||
+ prefixMatcherDeprecationCheckHidden.test(this.getDirLevel(1, info)) ||
+ prefixMatcherDeprecationCheckHidden.test(this.fileName)) &&
+ !info.isMetaPattern &&
+ patternlab &&
+ patternlab.config &&
+ !patternlab.config.disableDeprecationWarningForHiddenPatterns
+ ) {
+ logger.warning(
+ `${info.shortNotation}/${this.fileName} "Pattern", "Group" and "Subgroup" hiding by underscore prefix (_*) will be deprecated in the future.\n See https://patternlab.io/docs/hiding-patterns-in-the-navigation/`
+ );
+ }
+
+ // TODO: Remove if when dropping ordering by prefix and keep else code
+ if (info.patternHasOwnDir) {
+ // Since there is still the requirement of having the numbers provided for sorting
+ // this will be required to keep the folder prefix and the variant name
+ // /00-atoms/00-global/00-colors/colors~variant.hbs
+ // -> 00-atoms-00-global-00-colors-variant
+ this.name = `${info.shortNotation}-${path.parse(pathObj.dir).base}${
+ this.fileName.indexOf('~') !== -1 ? '-' + this.fileName.split('~')[1] : ''
+ }`;
+ } else {
+ // this is the unique name, subDir + fileName (sans extension)
+ this.name = `${info.shortNotation}-${this.fileName.replace('~', '-')}`;
+ }
// the JSON used to render values in the pattern
- this.jsonFileData = data || {};
+ this.jsonFileData = jsonFileData || {};
- // strip leading "00-" from the file name and flip tildes to dashes
+ // flip tildes to dashes
this.patternBaseName = this.fileName
- .replace(patternPrefixMatcher, '')
+ .replace(prefixMatcher, '')
.replace('~', '-'); // 'colors'
- // Fancy name. No idea how this works. 'Colors'
- this.patternName = this.patternBaseName
- .split('-')
- .reduce(function(val, working) {
- return (
- val.charAt(0).toUpperCase() +
- val.slice(1) +
- ' ' +
- working.charAt(0).toUpperCase() +
- working.slice(1)
- );
- }, '')
- .trim(); //this is the display name for the ui. strip numeric + hyphen prefixes
+ // Fancy name - Uppercase letters of pattern name partials.
+ // global-colors -> 'Global Colors'
+ // this is the display name for the ui. strip numeric + hyphen prefixes
+ this.patternName = _.startCase(this.patternBaseName);
// the top-level pattern group this pattern belongs to. 'atoms'
- this.patternGroup = this.subdir
- .split(path.sep)[0]
- .replace(patternPrefixMatcher, '');
-
- //00-atoms if needed
- this.patternType = this.subdir.split(path.sep)[0];
+ this.patternGroup = this.getDirLevel(0, info).replace(prefixMatcher, '');
// the sub-group this pattern belongs to.
- this.patternSubGroup = path
- .basename(this.subdir)
- .replace(patternPrefixMatcher, ''); // 'global'
-
- //00-colors if needed
- this.patternSubType = path.basename(this.subdir);
+ this.patternSubgroup = this.getDirLevel(1, info).replace(prefixMatcher, ''); // 'global'
// the joined pattern group and subgroup directory
- this.flatPatternPath = this.subdir.replace(/[\/\\]/g, '-'); // '00-atoms-00-global'
+ this.flatPatternPath = info.shortNotation; // 'atoms-global'
- // calculated path from the root of the public directory to the generated
+ // Calculated path from the root of the public directory to the generated
// (rendered!) html file for this pattern, to be shown in the iframe
- this.patternLink = this.patternSectionSubtype
- ? `$${this.name}/index.html`
- : patternlab ? this.getPatternLink(patternlab, 'rendered') : null;
+ this.patternLink = patternlab
+ ? this.getPatternLink(patternlab, 'rendered')
+ : null;
// The canonical "key" by which this pattern is known. This is the callable
// name of the pattern. UPDATE: this.key is now known as this.patternPartial
@@ -84,11 +131,24 @@ const Pattern = function(relPath, data, patternlab) {
// Let's calculate the verbose name ahead of time! We don't use path.sep here
// on purpose. This isn't a file name!
- this.verbosePartial =
- this.subdir.split(path.sep).join('/') + '/' + this.fileName;
+ this.verbosePartial = `${info.shortNotation}/${this.fileName}`;
+
+ /**
+ * Definition of flat pattern:
+ * The flat pattern is a high level pattern which is attached directly to
+ * the main root folder or to a root directory.
+ * --- This ---
+ * root
+ * flatPattern
+ * --- OR That ---
+ * root
+ * molecules
+ * flatPattern
+ */
+ this.isFlatPattern =
+ this.patternGroup === this.patternSubgroup || !this.patternSubgroup;
this.isPattern = true;
- this.isFlatPattern = this.patternGroup === this.patternSubGroup;
this.patternState = '';
this.template = '';
this.patternPartialCode = '';
@@ -97,17 +157,39 @@ const Pattern = function(relPath, data, patternlab) {
this.lineageR = [];
this.lineageRIndex = [];
this.isPseudoPattern = false;
- this.order = Number.MAX_SAFE_INTEGER;
+ this.order = 0;
+ this.variantOrder = 0;
this.engine = patternEngines.getEngineForPattern(this);
+ // TODO: Remove the following when ordering by file prefix gets obsolete
+ this.patternGroupData = this.patternGroupData || {};
+ if (!this.patternGroupData.order && info.patternGroupOrder) {
+ this.patternGroupData.order = info.patternGroupOrder;
+ }
+
+ // TODO: Remove the following when ordering by file prefix gets obsolete
+ this.patternSubgroupData = this.patternSubgroupData || {};
+ if (!this.patternSubgroupData.order && info.patternSubgroupOrder) {
+ this.patternGroupData.order = info.patternSubgroupOrder;
+ }
+
+ // TODO: Remove the following when ordering by file prefix gets obsolete
+ if (prefixMatcherDeprecationCheckOrder.test(this.fileName)) {
+ if (this.fileName.indexOf('~') === -1) {
+ this.order = this.setPatternOrderDataForInfo(this.fileName);
+ } else {
+ this.variantOrder = this.setPatternOrderDataForInfo(this.fileName);
+ }
+ }
+
/**
* Determines if this pattern needs to be recompiled.
*
- * @ee {@link CompileState}*/
+ * @see {@link CompileState}*/
this.compileState = null;
/**
- * Timestamp in milliseconds when the pattern template or auxilary file (e.g. json) were modified.
+ * Timestamp in milliseconds when the pattern template or auxiliary file (e.g. json) were modified.
* If multiple files are affected, this is the timestamp of the most recent change.
*
* @see {@link pattern}
@@ -119,7 +201,7 @@ const Pattern = function(relPath, data, patternlab) {
Pattern.prototype = {
// render function - acts as a proxy for the PatternEngine's
- render: function(data, partials) {
+ render: function (data, partials) {
if (!this.extendedTemplate) {
this.extendedTemplate = this.template;
}
@@ -131,26 +213,33 @@ Pattern.prototype = {
partials
);
return promise
- .then(results => {
+ .then((results) => {
return results;
})
- .catch(reason => {
+ .catch((reason) => {
return Promise.reject(reason);
});
}
return Promise.reject('where is the engine?');
},
- registerPartial: function() {
+ registerPartial: function () {
if (this.engine && typeof this.engine.registerPartial === 'function') {
this.engine.registerPartial(this);
}
},
- // calculated path from the root of the public directory to the generated html
- // file for this pattern.
- // Should look something like '00-atoms-00-global-00-colors/00-atoms-00-global-00-colors.html'
- getPatternLink: function(patternlab, suffixType, customfileExtension) {
+ /**
+ * calculated path from the root of the public directory to the generated html
+ * file for this pattern.
+ *
+ * Should look something like 'atoms-global-colors/atoms-global-colors.html'
+ *
+ * @param {Patternlab} patternlab Current patternlab instance
+ * @param {string} suffixType File suffix
+ * @param {string} customFileExtension Custom extension
+ */
+ getPatternLink: function (patternlab, suffixType, customFileExtension) {
// if no suffixType is provided, we default to rendered
const suffixConfig = patternlab.config.outputFileSuffixes;
const suffix = suffixType
@@ -162,59 +251,188 @@ Pattern.prototype = {
}
if (suffixType === 'custom') {
- return this.name + path.sep + this.name + customfileExtension;
+ return this.name + path.sep + this.name + customFileExtension;
}
return this.name + path.sep + this.name + suffix + '.html';
},
- // the finders all delegate to the PatternEngine, which also encapsulates all
- // appropriate regexes
- findPartials: function() {
+ /**
+ * The finders all delegate to the PatternEngine, which also
+ * encapsulates all appropriate regex's
+ */
+ findPartials: function () {
return this.engine.findPartials(this);
},
- findPartialsWithStyleModifiers: function() {
- return this.engine.findPartialsWithStyleModifiers(this);
- },
-
- findPartialsWithPatternParameters: function() {
+ findPartialsWithPatternParameters: function () {
return this.engine.findPartialsWithPatternParameters(this);
},
- findListItems: function() {
+ findListItems: function () {
return this.engine.findListItems(this);
},
- findPartial: function(partialString) {
+ findPartial: function (partialString) {
return this.engine.findPartial(partialString);
},
+
+ /**
+ * Get a directory on a specific level of the pattern path
+ *
+ * @param {Number} level Level of folder to get
+ * @param {Object} pInfo general information about the pattern
+ */
+ getDirLevel: function (level, pInfo) {
+ const items = this.subdir.split(path.sep);
+ pInfo && pInfo.patternHasOwnDir && items.pop();
+
+ if (items[level]) {
+ return items[level];
+ } else if (level >= 1) {
+ return '';
+ } else {
+ // I'm not quite sure about that but its better than empty node
+ // TODO: verify
+ return 'root';
+ }
+ },
+
+ /**
+ * Reset the information that the pattern has it's own directory,
+ * so that this pattern will not be handled as flat pattern if it
+ * is located on a top level folder.
+ *
+ * @param {Patternlab} patternlab Current patternlab instance
+ */
+ promoteFromDirectoryToFlatPattern: function (patternlab) {
+ const p = new Pattern(this.relPath, this.jsonFileData, patternlab, true);
+ // Only reset the specific fields, not everything
+ Object.assign(this, {
+ name: p.name,
+ patternLink: p.patternLink,
+ patternGroup: p.patternGroup,
+ patternSubgroup: p.patternSubgroup,
+ isFlatPattern: p.isFlatPattern,
+ flatPatternPath: p.flatPatternPath,
+ patternPartial: p.patternPartial,
+ verbosePartial: p.verbosePartial,
+ });
+ },
+
+ /**
+ * Retrieves the number prefix, which later is used for sorting.
+ * (Can be removed when sorting by number prefix becomes obsolete)
+ * @param {*} pathStr the path that needs to be checked for number prefixes
+ * @returns the order number or 0 when no prefix is available
+ */
+ setPatternOrderDataForInfo: (pathStr) => {
+ const match = pathStr.match(prefixMatcherDeprecationCheckOrder);
+ return match && match.length >= 1
+ ? pathStr.match(prefixMatcherDeprecationCheckOrder)[1].replace('-', '')
+ : 0;
+ },
+
+ /**
+ * The "info" object contains information about pattern structure if it is
+ * a nested pattern or if it just a sub folder structure. It's just used for
+ * internal purposes. Remember every pattern information based on "this.*"
+ * will be used by other functions
+ *
+ * @param pathObj path.parse() object containing useful path information
+ */
+ getPatternInfo: (pathObj, patternlab, isPromoteToFlatPatternRun) => {
+ const info = {
+ // colors(.mustache) is deeply nested in atoms-/global/colors
+ patternlab: patternlab,
+ patternHasOwnDir: isPromoteToFlatPatternRun
+ ? path.basename(pathObj.dir).replace(prefixMatcher, '') ===
+ pathObj.name.replace(prefixMatcher, '') ||
+ path.basename(pathObj.dir).replace(prefixMatcher, '') ===
+ pathObj.name.split('~')[0].replace(prefixMatcher, '')
+ : false,
+ };
+
+ info.dir = info.patternHasOwnDir ? pathObj.dir.split(path.sep).pop() : '';
+ info.dirLevel = pathObj.dir.split(path.sep).filter((s) => !!s).length;
+
+ // Only relevant for deprecation check and message
+ if (path.parse(pathObj.dir).base === '_meta') {
+ info.isMetaPattern = true;
+ }
+
+ if (info.dirLevel === 0 || (info.dirLevel === 1 && info.patternHasOwnDir)) {
+ // -> ./
+ info.shortNotation = 'root';
+ } else if (info.dirLevel === 2 && info.patternHasOwnDir) {
+ // -> ./folder
+ info.shortNotation = path.dirname(pathObj.dir).replace(prefixMatcher, '');
+ info.patternGroupOrder = Pattern.prototype.setPatternOrderDataForInfo(
+ path.dirname(pathObj.dir)
+ );
+ } else {
+ // -> ./folder/folder
+ info.shortNotation = pathObj.dir
+ .split(/\/|\\/, 2)
+ .map((o, i) => {
+ if (i === 0) {
+ // TODO: Remove when prefix gets deprecated
+ info.patternGroupOrder =
+ Pattern.prototype.setPatternOrderDataForInfo(o);
+ }
+
+ if (i === 1) {
+ // TODO: Remove when prefix gets deprecated
+ info.patternSubgroupOrder =
+ Pattern.prototype.setPatternOrderDataForInfo(o);
+ }
+
+ return o.replace(prefixMatcher, '');
+ })
+ .join('-')
+ .replace(new RegExp(`-${info.dir}$`), '');
+ info.verbosePartial = pathObj.dir
+ .split(/\/|\\/, 2)
+ .map((o) => o.replace(prefixMatcher, ''))
+ .join('/')
+ .replace(new RegExp(`-${info.dir}$`), '');
+ }
+
+ return info;
+ },
};
// Pattern static methods
-// factory: creates an empty Pattern for miscellaneous internal use, such as
-// by list_item_hunter
-Pattern.createEmpty = function(customProps, patternlab) {
+/**
+ * factory: creates an empty Pattern for miscellaneous internal use, such as
+ * by list_item_hunter
+ *
+ * @param {Object} customProps Properties to apply to new pattern
+ * @param {Patternlab} patternlab Current patternlab instance
+ */
+Pattern.createEmpty = function (customProps, patternlab) {
let relPath = '';
if (customProps) {
if (customProps.relPath) {
relPath = customProps.relPath;
} else if (customProps.subdir && customProps.filename) {
- relPath = customProps.subdir + path.sep + customProps.filename;
+ relPath = path.join(customProps.subdir, customProps.filename);
}
}
const pattern = new Pattern(relPath, null, patternlab);
- return extend(pattern, customProps);
+ return Object.assign(pattern, customProps);
};
-// factory: creates an Pattern object on-demand from a hash; the hash accepts
-// parameters that replace the positional parameters that the Pattern
-// constructor takes.
-Pattern.create = function(relPath, data, customProps, patternlab) {
+/**
+ * factory: creates a Pattern object on-demand from a hash; the hash accepts
+ * parameters that replace the positional parameters that the Pattern
+ * constructor takes.
+ */
+Pattern.create = function (relPath, data, customProps, patternlab) {
const newPattern = new Pattern(relPath || '', data || null, patternlab);
- return extend(newPattern, customProps);
+ return Object.assign(newPattern, customProps);
};
const CompileState = {
diff --git a/packages/core/src/lib/parameter_hunter.js b/packages/core/src/lib/parameter_hunter.js
deleted file mode 100644
index eeec121dc..000000000
--- a/packages/core/src/lib/parameter_hunter.js
+++ /dev/null
@@ -1,351 +0,0 @@
-'use strict';
-
-const smh = require('./style_modifier_hunter');
-const style_modifier_hunter = new smh();
-
-const getPartial = require('./get');
-const logger = require('./log');
-const parseLink = require('./parseLink');
-const jsonCopy = require('./json_copy');
-const replaceParameter = require('./replaceParameter');
-
-const parameter_hunter = function() {
- /**
- * This function is really to accommodate the lax JSON-like syntax allowed by
- * Pattern Lab PHP for parameter submissions to partials. Unfortunately, no
- * easily searchable library was discovered for this. What we had to do was
- * write a custom script to crawl through the parameter string, and wrap the
- * keys and values in double-quotes as necessary.
- * The steps on a high-level are as follows:
- * * Further escape all escaped quotes and colons. Use the string
- * representation of their unicodes for this. This has the added bonus
- * of being interpreted correctly by JSON.parse() without further
- * modification. This will be useful later in the function.
- * * Once escaped quotes are out of the way, we know the remaining quotes
- * are either key/value wrappers or wrapped within those wrappers. We know
- * that remaining commas and colons are either delimiters, or wrapped
- * within quotes to not be recognized as such.
- * * A do-while loop crawls paramString to write keys to a keys array and
- * values to a values array.
- * * Start by parsing the first key. Determine the type of wrapping quote,
- * if any.
- * * By knowing the open wrapper, we know that the next quote of that kind
- * (if the key is wrapped in quotes), HAS to be the close wrapper.
- * Similarly, if the key is unwrapped, we know the next colon HAS to be
- * the delimiter between key and value.
- * * Save the key to the keys array.
- * * Next, search for a value. It will either be the next block wrapped in
- * quotes, or a string of alphanumerics, decimal points, or minus signs.
- * * Save the value to the values array.
- * * The do-while loop truncates the paramString value while parsing. Its
- * condition for completion is when the paramString is whittled down to an
- * empty string.
- * * After the keys and values arrays are built, a for loop iterates through
- * them to build the final paramStringWellFormed string.
- * * No quote substitution had been done prior to this loop. In this loop,
- * all keys are ensured to be wrapped in double-quotes. String values are
- * also ensured to be wrapped in double-quotes.
- * * Unescape escaped unicodes except for double-quotes. Everything beside
- * double-quotes will be wrapped in double-quotes without need for escape.
- * * Return paramStringWellFormed.
- *
- * @param {string} pString
- * @returns {string} paramStringWellFormed
- */
- function paramToJson(pString) {
- let colonPos = -1;
- const keys = [];
- let paramString = pString; // to not reassign param
- let paramStringWellFormed;
- let quotePos = -1;
- let regex;
- const values = [];
- let wrapper;
-
- // attempt to parse the data in case it is already well formed JSON
- try {
- paramStringWellFormed = JSON.stringify(JSON.parse(pString));
- return paramStringWellFormed;
- } catch (err) {
- logger.debug(
- `Not valid JSON found for passed pattern parameter ${pString} will attempt to parse manually...`
- );
- }
-
- //replace all escaped double-quotes with escaped unicode
- paramString = paramString.replace(/\\"/g, '\\u0022');
-
- //replace all escaped single-quotes with escaped unicode
- paramString = paramString.replace(/\\'/g, '\\u0027');
-
- //replace all escaped colons with escaped unicode
- paramString = paramString.replace(/\\:/g, '\\u0058');
-
- //with escaped chars out of the way, crawl through paramString looking for
- //keys and values
- do {
- //check if searching for a key
- if (paramString[0] === '{' || paramString[0] === ',') {
- paramString = paramString.substring(1, paramString.length).trim();
-
- //search for end quote if wrapped in quotes. else search for colon.
- //everything up to that position will be saved in the keys array.
- switch (paramString[0]) {
- //need to search for end quote pos in case the quotes wrap a colon
- case '"':
- case "'":
- wrapper = paramString[0];
- quotePos = paramString.indexOf(wrapper, 1);
- break;
-
- default:
- colonPos = paramString.indexOf(':');
- }
-
- if (quotePos > -1) {
- keys.push(paramString.substring(0, quotePos + 1).trim());
-
- //truncate the beginning from paramString and look for a value
- paramString = paramString
- .substring(quotePos + 1, paramString.length)
- .trim();
-
- //unset quotePos
- quotePos = -1;
- } else if (colonPos > -1) {
- keys.push(paramString.substring(0, colonPos).trim());
-
- //truncate the beginning from paramString and look for a value
- paramString = paramString.substring(colonPos, paramString.length);
-
- //unset colonPos
- colonPos = -1;
-
- //if there are no more colons, and we're looking for a key, there is
- //probably a problem. stop any further processing.
- } else {
- paramString = '';
- break;
- }
- }
-
- //now, search for a value
- if (paramString[0] === ':') {
- paramString = paramString.substring(1, paramString.length).trim();
-
- //the only reason we're using regexes here, instead of indexOf(), is
- //because we don't know if the next delimiter is going to be a comma or
- //a closing curly brace. since it's not much of a performance hit to
- //use regexes as sparingly as here, and it's much more concise and
- //readable, we'll use a regex for match() and replace() instead of
- //performing conditional logic with indexOf().
- switch (paramString[0]) {
- //since a quote of same type as its wrappers would be escaped, and we
- //escaped those even further with their unicodes, it is safe to look
- //for wrapper pairs and conclude that their contents are values
- case '"':
- regex = /^"(.|\s)*?"/;
- break;
- case "'":
- regex = /^'(.|\s)*?'/;
- break;
-
- //if there is no value wrapper, regex for alphanumerics, decimal
- //points, and minus signs for exponential notation.
- default:
- regex = /^[\w\-\.]*/;
- }
- values.push(paramString.match(regex)[0].trim());
-
- //truncate the beginning from paramString and continue either
- //looking for a key, or returning
- paramString = paramString.replace(regex, '').trim();
-
- //exit do while if the final char is '}'
- if (paramString === '}') {
- paramString = '';
- break;
- }
-
- //if there are no more colons, and we're looking for a value, there is
- //probably a problem. stop any further processing.
- } else {
- paramString = '';
- break;
- }
- } while (paramString);
-
- //build paramStringWellFormed string for JSON parsing
- paramStringWellFormed = '{';
- for (let i = 0; i < keys.length; i++) {
- //keys
- //replace single-quote wrappers with double-quotes
- if (keys[i][0] === "'" && keys[i][keys[i].length - 1] === "'") {
- paramStringWellFormed += '"';
-
- //any enclosed double-quotes must be escaped
- paramStringWellFormed += keys[i]
- .substring(1, keys[i].length - 1)
- .replace(/"/g, '\\"');
- paramStringWellFormed += '"';
- } else {
- //open wrap with double-quotes if no wrapper
- if (keys[i][0] !== '"' && keys[i][0] !== "'") {
- paramStringWellFormed += '"';
-
- //this is to clean up vestiges from Pattern Lab PHP's escaping scheme.
- //F.Y.I. Pattern Lab PHP would allow special characters like question
- //marks in parameter keys so long as the key was unwrapped and the
- //special character escaped with a backslash. In Node, we need to wrap
- //those keys and unescape those characters.
- keys[i] = keys[i].replace(/\\/g, '');
- }
-
- paramStringWellFormed += keys[i];
-
- //close wrap with double-quotes if no wrapper
- if (
- keys[i][keys[i].length - 1] !== '"' &&
- keys[i][keys[i].length - 1] !== "'"
- ) {
- paramStringWellFormed += '"';
- }
- }
-
- //colon delimiter.
- paramStringWellFormed += ':';
-
- //values
- //replace single-quote wrappers with double-quotes
- if (values[i][0] === "'" && values[i][values[i].length - 1] === "'") {
- paramStringWellFormed += '"';
-
- //any enclosed double-quotes must be escaped
- paramStringWellFormed += values[i]
- .substring(1, values[i].length - 1)
- .replace(/"/g, '\\"');
- paramStringWellFormed += '"';
-
- //for everything else, just add the value however it's wrapped
- } else {
- paramStringWellFormed += values[i];
- }
-
- //comma delimiter
- if (i < keys.length - 1) {
- paramStringWellFormed += ',';
- }
- }
- paramStringWellFormed += '}';
-
- //unescape escaped unicode except for double-quotes
- paramStringWellFormed = paramStringWellFormed.replace(/\\u0027/g, "'");
- paramStringWellFormed = paramStringWellFormed.replace(/\\u0058/g, ':');
-
- return paramStringWellFormed;
- }
-
- //compile this partial immeadiately, essentially consuming it.
- function findparameters(pattern, patternlab) {
- if (pattern.parameteredPartials && pattern.parameteredPartials.length > 0) {
- logger.debug(`processing patternParameters for ${pattern.partialName}`);
-
- return pattern.parameteredPartials.reduce((previousPromise, pMatch) => {
- return previousPromise
- .then(() => {
- logger.debug(`processing patternParameter ${pMatch}`);
-
- //find the partial's name and retrieve it
- const partialName = pMatch.match(/([\w\-\.\/~]+)/g)[0];
- const partialPattern = jsonCopy(
- getPartial(
- partialName,
- patternlab,
- `partial pattern ${partialName}`
- )
- );
-
- //if we retrieved a pattern we should make sure that its extendedTemplate is reset. looks to fix #190
- if (!partialPattern.extendedTemplate) {
- partialPattern.extendedTemplate = partialPattern.template;
- }
-
- if (!pattern.extendedTemplate) {
- pattern.extendedTemplate = pattern.template;
- }
-
- logger.debug(`retrieved pattern ${partialName}`);
-
- //strip out the additional data, convert string to JSON.
- const leftParen = pMatch.indexOf('(');
- const rightParen = pMatch.lastIndexOf(')');
- const paramString =
- '{' + pMatch.substring(leftParen + 1, rightParen) + '}';
- const paramStringWellFormed = paramToJson(paramString);
-
- let paramData = {};
-
- try {
- paramData = JSON.parse(paramStringWellFormed);
- } catch (err) {
- logger.warning(
- `There was an error parsing JSON for ${pattern.relPath}`
- );
- logger.warning(err);
- }
-
- // resolve any pattern links that might be present
- paramData = parseLink(
- patternlab,
- paramData,
- pattern.patternPartial
- );
-
- // for each property in paramData
- for (const prop in paramData) {
- if (paramData.hasOwnProperty(prop)) {
- // find it within partialPattern.extendedTemplate and replace its value
- partialPattern.extendedTemplate = replaceParameter(
- partialPattern.extendedTemplate,
- prop,
- paramData[prop]
- );
- }
- }
-
- //if partial has style modifier data, replace the styleModifier value
- if (pattern.stylePartials && pattern.stylePartials.length > 0) {
- style_modifier_hunter.consume_style_modifier(
- partialPattern,
- pMatch,
- patternlab
- );
- }
-
- // set pattern.extendedTemplate pMatch with replacedPartial
- pattern.extendedTemplate = pattern.extendedTemplate.replace(
- pMatch,
- partialPattern.extendedTemplate
- );
-
- //todo: this no longer needs to be a promise
- return Promise.resolve();
- })
- .catch(reason => {
- console.log(reason);
- logger.error(reason);
- });
- }, Promise.resolve());
- }
- logger.debug(`pattern has no partials ${pattern.patternPartial}`);
- return Promise.resolve();
- }
-
- return {
- find_parameters: function(pattern, patternlab) {
- return findparameters(pattern, patternlab);
- },
- };
-};
-
-module.exports = parameter_hunter;
diff --git a/packages/core/src/lib/parseAllLinks.js b/packages/core/src/lib/parseAllLinks.js
index 894ad6f83..e69383bd7 100644
--- a/packages/core/src/lib/parseAllLinks.js
+++ b/packages/core/src/lib/parseAllLinks.js
@@ -4,7 +4,7 @@ const parseLink = require('./parseLink');
//look for pattern links included in data files.
//these will be in the form of link.* WITHOUT {{}}, which would still be there from direct pattern inclusion
-module.exports = function(patternlab) {
+module.exports = function (patternlab) {
//look for link.* such as link.pages-blog as a value
patternlab.data = parseLink(patternlab, patternlab.data, 'data.json');
diff --git a/packages/core/src/lib/parseLink.js b/packages/core/src/lib/parseLink.js
index d3d0c455e..be8ac61b5 100644
--- a/packages/core/src/lib/parseLink.js
+++ b/packages/core/src/lib/parseLink.js
@@ -5,9 +5,9 @@ const path = require('path');
const logger = require('./log');
const getPartial = require('./get');
-module.exports = function(patternlab, obj, key) {
+module.exports = function (patternlab, obj, key) {
//check for 'link.patternPartial'
- const linkRE = /(?:'|")(link\.[A-z0-9-_]+)(?:'|")/g;
+ const linkRE = /(?:'|")(link\.[\w-]+)(?:'|")/g;
//stringify the passed in object
let dataObjAsString;
@@ -20,45 +20,72 @@ module.exports = function(patternlab, obj, key) {
const linkMatches = dataObjAsString.match(linkRE);
if (linkMatches) {
- for (let i = 0; i < linkMatches.length; i++) {
- const dataLink = linkMatches[i];
+ linkMatches.forEach((dataLink) => {
if (dataLink && dataLink.split('.').length >= 2) {
//get the partial the link refers to
- const linkPatternPartial = dataLink
- .split('.')[1]
- .replace('"', '')
- .replace("'", '');
- const pattern = getPartial(linkPatternPartial, patternlab);
- if (pattern !== undefined) {
- //get the full built link and replace it
- let fullLink = patternlab.data.link[linkPatternPartial];
- if (fullLink) {
- fullLink = path.normalize(fullLink).replace(/\\/g, '/');
+ const linkPatternPartial = dataLink.split('.')[1].replace(/'|"/g, '');
+ const rawLink = `link.${linkPatternPartial}`;
+ let replacement = null;
- logger.debug(
- `expanded data link from ${dataLink} to ${fullLink} inside ${key}`
- );
+ if (linkPatternPartial.match(/viewall\-.+\-all/)) {
+ // Reverse engineer viewall-group-all link (if there is a pattern with that
+ // group there will be a view all page for that group)
+ const partial = linkPatternPartial
+ .replace('viewall-', '')
+ .replace('-all', '');
+ const pattern = patternlab.patterns.find(
+ (p) => p.patternGroup === partial
+ );
- //also make sure our global replace didn't mess up a protocol
- fullLink = fullLink.replace(/:\//g, '://');
- dataObjAsString = dataObjAsString.replace(
- 'link.' + linkPatternPartial,
- fullLink
- );
+ if (pattern) {
+ replacement = `/patterns/${partial}/index.html`;
}
+ } else if (linkPatternPartial.match(/viewall\-.+/)) {
+ // Reverse engineer viewall-group-subgroup link (if there is a pattern with that
+ // group and subgroup there will be a view all page for that group)
+ const partial = linkPatternPartial.replace('viewall-', '');
+ const pattern = patternlab.patterns.find(
+ (p) => `${p.patternGroup}-${p.patternSubgroup}` === partial
+ );
+
+ if (pattern) {
+ replacement = `/patterns/${pattern.flatPatternPath}/index.html`;
+ }
+ } else {
+ // Just search for the pattern partial
+ const pattern = getPartial(linkPatternPartial, patternlab);
+
+ if (pattern) {
+ // get the full built link and replace it
+ let fullLink = patternlab.data.link[linkPatternPartial];
+ if (fullLink) {
+ fullLink = path.normalize(fullLink).replace(/\\/g, '/');
+
+ logger.debug(
+ `expanded data link from ${dataLink} to ${fullLink} inside ${key}`
+ );
+
+ // also make sure our global replace didn't mess up a protocol
+ replacement = fullLink.replace(/:\//g, '://');
+ }
+ }
+ }
+
+ if (replacement) {
+ dataObjAsString = dataObjAsString.replace(rawLink, replacement);
} else {
logger.warning(`pattern not found for ${dataLink} inside ${key}`);
}
}
- }
+ });
}
let dataObj;
try {
dataObj = JSON.parse(dataObjAsString);
} catch (err) {
- logger.warning(`There was an error parsing JSON for ${key}`);
- logger.warning(err);
+ logger.error(`There was an error parsing JSON for ${key}`);
+ logger.error(err);
}
return dataObj;
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/src/lib/pattern_engines.js b/packages/core/src/lib/pattern_engines.js
index cde010125..71d4da883 100644
--- a/packages/core/src/lib/pattern_engines.js
+++ b/packages/core/src/lib/pattern_engines.js
@@ -9,6 +9,8 @@ const engineMatcher = /^engine-(.*)$/;
const logger = require('./log');
+const { resolvePackageFolder } = require('@pattern-lab/core/src/lib/resolver');
+
const enginesDirectories = [
{
displayName: 'the core',
@@ -18,6 +20,10 @@ const enginesDirectories = [
displayName: 'the edition or test directory',
path: path.join(process.cwd(), 'node_modules'),
},
+ {
+ displayName: 'the general node_modules directory',
+ path: path.resolve(resolvePackageFolder('@pattern-lab/core'), '..', '..'),
+ },
];
/**
@@ -56,6 +62,19 @@ function findEngineModulesInDirectory(dir) {
return foundEngines;
}
+function findEnginesInConfig(config) {
+ if ('engines' in config) {
+ return config.engines;
+ }
+ logger.warning(
+ "Scanning the 'node_modules' folder for pattern engines is deprecated and will be removed in v7."
+ );
+ logger.warning(
+ 'To configure your engines in patternlab-config.json, see https://patternlab.io/docs/editing-the-configuration-options/#heading-engines'
+ );
+ return null;
+}
+
//
// PatternEngines: the main export of this module
//
@@ -77,53 +96,109 @@ const PatternEngines = Object.create({
* @param patternLabConfig
* @memberof PatternEngines
*/
- loadAllEngines: function(patternLabConfig) {
+ loadAllEngines: function (patternLabConfig) {
const self = this;
- // Try to load engines! We scan for engines at each path specified above. This
- // function is kind of a big deal.
- enginesDirectories.forEach(function(engineDirectory) {
- const enginesInThisDir = findEngineModulesInDirectory(
- engineDirectory.path
- );
+ // Try to load engines! We load the engines configured in patternlab-config.json
+ const enginesInConfig = findEnginesInConfig(patternLabConfig);
- logger.debug(`Loading engines from ${engineDirectory.displayName}...`);
+ if (enginesInConfig) {
+ // Quick fix until we've removed @pattern-lab/engine-mustache, starting with https://github.com/pattern-lab/patternlab-node/issues/1239 & https://github.com/pattern-lab/patternlab-node/pull/1455
+ // @TODO: Remove after removing @pattern-lab/engine-mustache dependency
+ enginesInConfig.mustache = enginesInConfig.mustache || {};
+ enginesInConfig.mustache.package =
+ enginesInConfig.mustache.package || '@pattern-lab/engine-mustache';
+ enginesInConfig.mustache.extensions =
+ enginesInConfig.mustache.extensions || 'mustache';
- // find all engine-named things in this directory and try to load them,
- // unless it's already been loaded.
- enginesInThisDir.forEach(function(engineDiscovery) {
+ // Try loading each of the configured pattern engines
+ // eslint-disable-next-line guard-for-in
+ for (const name in enginesInConfig) {
+ const engineConfig = enginesInConfig[name];
let errorMessage;
const successMessage = 'good to go';
try {
// Give it a try! load 'er up. But not if we already have,
- // of course. Also pass the pattern lab config object into
+ // of course. Also pass the Pattern Lab config object into
// the engine's closure scope so it can know things about
// things.
- if (self[engineDiscovery.name]) {
+ if (self[name]) {
throw new Error('already loaded, skipping.');
}
- self[engineDiscovery.name] = require(engineDiscovery.modulePath);
- if (
- typeof self[engineDiscovery.name].usePatternLabConfig === 'function'
- ) {
- self[engineDiscovery.name].usePatternLabConfig(patternLabConfig);
- }
- if (typeof self[engineDiscovery.name].spawnMeta === 'function') {
- self[engineDiscovery.name].spawnMeta(patternLabConfig);
+ if ('package' in engineConfig) {
+ self[name] = require(engineConfig.package);
+ if (typeof self[name].usePatternLabConfig === 'function') {
+ self[name].usePatternLabConfig(patternLabConfig);
+ }
+ if (typeof self[name].spawnMeta === 'function') {
+ self[name].spawnMeta(patternLabConfig);
+ }
+ } else {
+ logger.warning(
+ `Engine ${name} not configured correctly. Please configure your engines in patternlab-config.json as documented in https://patternlab.io/docs/editing-the-configuration-options/#heading-engines`
+ );
}
} catch (err) {
errorMessage = err.message;
} finally {
// report on the status of the engine, one way or another!
logger.info(
- `Pattern Engine ${engineDiscovery.name}: ${
+ `Pattern Engine ${name} / package ${engineConfig.package}: ${
errorMessage ? errorMessage : successMessage
}`
);
}
+ }
+ } else {
+ // Try to load engines! We scan for engines at each path specified above. This
+ // function is kind of a big deal.
+ enginesDirectories.forEach(function (engineDirectory) {
+ const enginesInThisDir = findEngineModulesInDirectory(
+ engineDirectory.path
+ );
+
+ `Loading engines from ${engineDirectory.displayName}: ${engineDirectory.path} ...`;
+
+ // find all engine-named things in this directory and try to load them,
+ // unless it's already been loaded.
+ enginesInThisDir.forEach(function (engineDiscovery) {
+ let errorMessage;
+ const successMessage = 'good to go';
+
+ try {
+ // Give it a try! load 'er up. But not if we already have,
+ // of course. Also pass the Pattern Lab config object into
+ // the engine's closure scope so it can know things about
+ // things.
+ if (self[engineDiscovery.name]) {
+ throw new Error('already loaded, skipping.');
+ }
+ self[engineDiscovery.name] = require(engineDiscovery.modulePath);
+ if (
+ typeof self[engineDiscovery.name].usePatternLabConfig ===
+ 'function'
+ ) {
+ self[engineDiscovery.name].usePatternLabConfig(patternLabConfig);
+ }
+ if (typeof self[engineDiscovery.name].spawnMeta === 'function') {
+ self[engineDiscovery.name].spawnMeta(patternLabConfig);
+ }
+ } catch (err) {
+ errorMessage = err.message;
+ } finally {
+ // report on the status of the engine, one way or another!
+ logger.info(
+ `Pattern Engine ${
+ engineDiscovery.name
+ } by discovery (deprecated): ${
+ errorMessage ? errorMessage : successMessage
+ }`
+ );
+ }
+ });
});
- });
+ }
// Complain if for some reason we haven't loaded any engines.
if (Object.keys(self).length === 0) {
@@ -138,7 +213,7 @@ const PatternEngines = Object.create({
* @param pattern
* @returns engine name matching pattern
*/
- getEngineNameForPattern: function(pattern) {
+ getEngineNameForPattern: function (pattern) {
// avoid circular dependency by putting this in here. TODO: is this slow?
const of = require('./object_factory');
if (
@@ -175,7 +250,7 @@ const PatternEngines = Object.create({
* @param pattern
* @returns name of engine for pattern
*/
- getEngineForPattern: function(pattern) {
+ getEngineForPattern: function (pattern) {
if (pattern.isPseudoPattern) {
return this.getEngineForPattern(pattern.basePattern);
} else {
@@ -189,9 +264,9 @@ const PatternEngines = Object.create({
* @memberof PatternEngines
* @returns Array all supported file extensions
*/
- getSupportedFileExtensions: function() {
+ getSupportedFileExtensions: function () {
const engineNames = Object.keys(PatternEngines);
- const allEnginesExtensions = engineNames.map(engineName => {
+ const allEnginesExtensions = engineNames.map((engineName) => {
return PatternEngines[engineName].engineFileExtension;
});
return [].concat.apply([], allEnginesExtensions);
@@ -203,7 +278,7 @@ const PatternEngines = Object.create({
* @param fileExtension
* @returns Boolean
*/
- isFileExtensionSupported: function(fileExtension) {
+ isFileExtensionSupported: function (fileExtension) {
const supportedExtensions = PatternEngines.getSupportedFileExtensions();
return supportedExtensions.lastIndexOf(fileExtension) !== -1;
},
@@ -214,7 +289,7 @@ const PatternEngines = Object.create({
* @param filename
* @return boolean
*/
- isPseudoPatternJSON: function(filename) {
+ isPseudoPatternJSON: function (filename) {
const extension = path.extname(filename);
return extension === '.json' && filename.indexOf('~') > -1;
},
@@ -229,7 +304,7 @@ const PatternEngines = Object.create({
* @param filename
* @returns boolean
*/
- isPatternFile: function(filename) {
+ isPatternFile: function (filename) {
// skip hidden patterns/files without a second thought
const extension = path.extname(filename);
if (
@@ -240,7 +315,8 @@ const PatternEngines = Object.create({
}
// not a hidden pattern, let's dig deeper
- const supportedPatternFileExtensions = PatternEngines.getSupportedFileExtensions();
+ const supportedPatternFileExtensions =
+ PatternEngines.getSupportedFileExtensions();
return (
supportedPatternFileExtensions.lastIndexOf(extension) !== -1 ||
PatternEngines.isPseudoPatternJSON(filename)
diff --git a/packages/core/src/lib/pattern_exporter.js b/packages/core/src/lib/pattern_exporter.js
index 9bfc85ce3..221415bf8 100644
--- a/packages/core/src/lib/pattern_exporter.js
+++ b/packages/core/src/lib/pattern_exporter.js
@@ -1,8 +1,34 @@
'use strict';
const fs = require('fs-extra');
+const path = require('path');
-const pattern_exporter = function() {
+function exportSinglePattern(patternlab, pattern) {
+ const preserveDirStructure =
+ patternlab.config.patternExportPreserveDirectoryStructure;
+ let patternName = pattern.patternPartial;
+ let patternDir = patternlab.config.patternExportDirectory;
+ let patternCode = pattern.patternPartialCode;
+ let patternFileExtension = '.html';
+ if (preserveDirStructure) {
+ // Extract the first part of the pattern partial as the directory in which
+ // it should go.
+ patternDir = path.join(patternDir, pattern.patternPartial.split('-')[0]);
+ patternName = pattern.patternPartial.split('-').slice(1).join('-');
+ }
+
+ if (patternlab.config.patternExportRaw) {
+ patternCode = pattern.extendedTemplate;
+ patternFileExtension = `.${patternlab.config.patternExtension}`;
+ }
+
+ fs.outputFileSync(
+ path.join(patternDir, patternName) + patternFileExtension,
+ patternCode
+ );
+}
+
+const pattern_exporter = function () {
/**
* Exports all pattern's final HTML as defined in patternlab-config.json to desired location.
* Originally created to help facilitate easier consumption by jekyll.
@@ -13,25 +39,31 @@ const pattern_exporter = function() {
function exportPatterns(patternlab) {
//read the config export options
const exportPartials = patternlab.config.patternExportPatternPartials;
+ const exportAll = patternlab.config.patternExportAll;
+
+ if (exportAll) {
+ for (let i = 0; i < patternlab.patterns.length; i++) {
+ if (!patternlab.patterns[i].patternPartial.startsWith('-')) {
+ exportSinglePattern(patternlab, patternlab.patterns[i]);
+ }
+ }
+
+ return;
+ }
//find the chosen patterns to export
for (let i = 0; i < exportPartials.length; i++) {
for (let j = 0; j < patternlab.patterns.length; j++) {
if (exportPartials[i] === patternlab.patterns[j].patternPartial) {
//write matches to the desired location
- fs.outputFileSync(
- patternlab.config.patternExportDirectory +
- patternlab.patterns[j].patternPartial +
- '.html',
- patternlab.patterns[j].patternPartialCode
- );
+ exportSinglePattern(patternlab, patternlab.patterns[j]);
}
}
}
}
return {
- export_patterns: function(patternlab) {
+ export_patterns: function (patternlab) {
exportPatterns(patternlab);
},
};
diff --git a/packages/core/src/lib/pattern_graph.js b/packages/core/src/lib/pattern_graph.js
index 6ad17d012..a5320292d 100644
--- a/packages/core/src/lib/pattern_graph.js
+++ b/packages/core/src/lib/pattern_graph.js
@@ -35,7 +35,7 @@ const PATTERN_GRAPH_VERSION = 1;
* @see PatternGraph#fromJson
* @see #540
*/
-const PatternGraph = function(graph, timestamp, version) {
+const PatternGraph = function (graph, timestamp, version) {
this.graph =
graph ||
new Graph({
@@ -50,8 +50,8 @@ const PatternGraph = function(graph, timestamp, version) {
this.version = version || PATTERN_GRAPH_VERSION;
};
-// shorthand. Use relPath as it is always unique, even with subPatternType
-const nodeName = p => (p instanceof Pattern ? p.relPath : p);
+// shorthand. Use relPath as it is always unique, even with subPatternGroup
+const nodeName = (p) => (p instanceof Pattern ? p.relPath : p);
PatternGraph.prototype = {
/**
@@ -61,11 +61,11 @@ PatternGraph.prototype = {
*
* @see {@link https://github.com/pattern-lab/patternlab-node/issues/580|Issue #580}
*/
- sync: function() {
+ sync: function () {
// Remove any patterns that are in the graph data, but that haven't been discovered when
// walking all patterns iteratively
- const nodesToRemove = this.nodes().filter(n => !this.patterns.has(n));
- nodesToRemove.forEach(n => this.remove(n));
+ const nodesToRemove = this.nodes().filter((n) => !this.patterns.has(n));
+ nodesToRemove.forEach((n) => this.remove(n));
return nodesToRemove;
},
@@ -73,7 +73,7 @@ PatternGraph.prototype = {
* Creates an independent copy of the graph where nodes and edges can be modified without
* affecting the source.
*/
- clone: function() {
+ clone: function () {
const json = graphlib.json.write(this.graph);
const graph = graphlib.json.read(json);
return new PatternGraph(graph, this.timestamp, this.version);
@@ -85,7 +85,7 @@ PatternGraph.prototype = {
*
* @param {Pattern} pattern
*/
- add: function(pattern) {
+ add: function (pattern) {
const n = nodeName(pattern);
if (!this.patterns.has(n)) {
this.graph.setNode(n, {
@@ -96,7 +96,7 @@ PatternGraph.prototype = {
}
},
- remove: function(pattern) {
+ remove: function (pattern) {
const n = nodeName(pattern);
this.graph.removeNode(n);
this.patterns.remove(n);
@@ -106,8 +106,8 @@ PatternGraph.prototype = {
* Removes nodes from this graph for which the given predicate function returns false.
* @param {function} fn which takes a node name as argument
*/
- filter: function(fn) {
- this.graph.nodes().forEach(n => {
+ filter: function (fn) {
+ this.graph.nodes().forEach((n) => {
if (!fn(n)) {
this.remove(n);
}
@@ -123,7 +123,7 @@ PatternGraph.prototype = {
*
* @throws {Error} If the pattern is unknown
*/
- link: function(patternFrom, patternTo) {
+ link: function (patternFrom, patternTo) {
const nameFrom = nodeName(patternFrom);
const nameTo = nodeName(patternTo);
for (const name of [nameFrom, nameTo]) {
@@ -141,7 +141,7 @@ PatternGraph.prototype = {
*
* @return {boolean}
*/
- hasLink: function(patternFrom, patternTo) {
+ hasLink: function (patternFrom, patternTo) {
const nameFrom = nodeName(patternFrom);
const nameTo = nodeName(patternTo);
return this.graph.hasEdge(nameFrom, nameTo);
@@ -157,8 +157,8 @@ PatternGraph.prototype = {
* @return {Array} An Array of {@link Pattern}s in the order by which the changed patters must be
* compiled.
*/
- compileOrder: function() {
- const compileStateFilter = function(patterns, n) {
+ compileOrder: function () {
+ const compileStateFilter = function (patterns, n) {
const node = patterns.get(n);
return node.compileState !== CompileState.CLEAN;
};
@@ -173,10 +173,10 @@ PatternGraph.prototype = {
});
const nodes = this.graph.nodes();
- const changedNodes = nodes.filter(n =>
+ const changedNodes = nodes.filter((n) =>
compileStateFilter(this.patterns, n)
);
- this.nodes2patterns(changedNodes).forEach(pattern => {
+ this.nodes2patterns(changedNodes).forEach((pattern) => {
const patternNode = nodeName(pattern);
if (!compileGraph.hasNode(patternNode)) {
compileGraph.setNode(patternNode);
@@ -211,7 +211,7 @@ PatternGraph.prototype = {
* @param fn A function that takes the currently viewed pattern and node data. Allows synching data
* between patterns and node metadata.
*/
- applyReverse: function(pattern, fn) {
+ applyReverse: function (pattern, fn) {
for (const p of this.lineageR(pattern)) {
fn(p, pattern);
this.applyReverse(p, fn);
@@ -225,7 +225,7 @@ PatternGraph.prototype = {
*
* @return [null|Pattern]
*/
- node: function(pattern) {
+ node: function (pattern) {
return this.graph.node(nodeName(pattern));
},
@@ -234,8 +234,8 @@ PatternGraph.prototype = {
* @param nodes {Array}
* @return {Array} An Array of Patterns
*/
- nodes2patterns: function(nodes) {
- return nodes.map(n => this.patterns.get(n));
+ nodes2patterns: function (nodes) {
+ return nodes.map((n) => this.patterns.get(n));
},
// TODO cache result in a Map[String, Array]?
@@ -246,7 +246,7 @@ PatternGraph.prototype = {
* @param pattern
* @return {*|Array}
*/
- lineage: function(pattern) {
+ lineage: function (pattern) {
const nodes = this.graph.successors(nodeName(pattern));
return this.nodes2patterns(nodes);
},
@@ -256,7 +256,7 @@ PatternGraph.prototype = {
* @param {Pattern} pattern
* @return {*|Array}
*/
- lineageR: function(pattern) {
+ lineageR: function (pattern) {
const nodes = this.graph.predecessors(nodeName(pattern));
return this.nodes2patterns(nodes);
},
@@ -267,9 +267,9 @@ PatternGraph.prototype = {
*
* @see {@link PatternGraph.lineage(pattern)}
*/
- lineageIndex: function(pattern) {
+ lineageIndex: function (pattern) {
const lineage = this.lineage(pattern);
- return lineage.map(p => p.patternPartial);
+ return lineage.map((p) => p.patternPartial);
},
/**
@@ -280,16 +280,16 @@ PatternGraph.prototype = {
*
* @see {@link PatternGraph.lineageRIndex(pattern)}
*/
- lineageRIndex: function(pattern) {
+ lineageRIndex: function (pattern) {
const lineageR = this.lineageR(pattern);
- return lineageR.map(p => p.patternPartial);
+ return lineageR.map((p) => p.patternPartial);
},
/**
* Creates an object representing the graph and meta data.
* @returns {{timestamp: number, graph}}
*/
- toJson: function() {
+ toJson: function () {
return {
version: this.version,
timestamp: this.timestamp,
@@ -300,14 +300,14 @@ PatternGraph.prototype = {
/**
* @return {Array} An array of all node names.
*/
- nodes: function() {
+ nodes: function () {
return this.graph.nodes();
},
/**
* Updates the version to the most recent one
*/
- upgradeVersion: function() {
+ upgradeVersion: function () {
this.version = PATTERN_GRAPH_VERSION;
},
};
@@ -317,7 +317,7 @@ PatternGraph.prototype = {
* @param {int} [version=PATTERN_GRAPH_VERSION]
* @return {PatternGraph}
*/
-PatternGraph.empty = function(version) {
+PatternGraph.empty = function (version) {
return new PatternGraph(null, 0, version || PATTERN_GRAPH_VERSION);
};
@@ -326,7 +326,7 @@ PatternGraph.empty = function(version) {
* @param {PatternGraph|Object} graphOrJson
* @return {boolean}
*/
-PatternGraph.checkVersion = function(graphOrJson) {
+PatternGraph.checkVersion = function (graphOrJson) {
return graphOrJson.version === PATTERN_GRAPH_VERSION;
};
@@ -346,7 +346,7 @@ function VersionMismatch(oldVersion) {
* @param {object} o The JSON object to read from
* @return {PatternGraph}
*/
-PatternGraph.fromJson = function(o) {
+PatternGraph.fromJson = function (o) {
if (!PatternGraph.checkVersion(o)) {
throw new VersionMismatch(o.version);
}
@@ -360,7 +360,7 @@ PatternGraph.fromJson = function(o) {
* @param {string} [fileName='dependencyGraph.json'] Name of the graph file
* @return {string}
*/
-PatternGraph.resolveJsonGraphFile = function(
+PatternGraph.resolveJsonGraphFile = function (
filePath = process.cwd(),
fileName = 'dependencyGraph.json'
) {
@@ -377,7 +377,7 @@ PatternGraph.resolveJsonGraphFile = function(
* @see {@link PatternGraph.fromJson}
* @see {@link PatternGraph.resolveJsonGraphFile}
*/
-PatternGraph.loadFromFile = function(filePath, fileName) {
+PatternGraph.loadFromFile = function (filePath, fileName) {
const jsonGraphFile = this.resolveJsonGraphFile(filePath, fileName);
// File is fresh, so simply construct an empty graph in memory
@@ -399,7 +399,7 @@ PatternGraph.loadFromFile = function(filePath, fileName) {
*
* @see {@link PatternGraph.resolveJsonGraphFile}
*/
-PatternGraph.storeToFile = function(patternlab) {
+PatternGraph.storeToFile = function (patternlab) {
if (process.env.PATTERNLAB_ENV === 'CI') {
return;
}
@@ -413,7 +413,7 @@ PatternGraph.storeToFile = function(patternlab) {
* @param patternlab
@ @param {string} fileName Output filename
*/
-PatternGraph.exportToDot = function(patternlab, fileName) {
+PatternGraph.exportToDot = function (patternlab, fileName) {
const dotFile = this.resolveJsonGraphFile(undefined, fileName);
const g = PatternGraphDot.generate(patternlab.graph);
fs.outputFileSync(dotFile, g);
diff --git a/packages/core/src/lib/pattern_graph_dot.js b/packages/core/src/lib/pattern_graph_dot.js
index c2e865203..f4da40e18 100644
--- a/packages/core/src/lib/pattern_graph_dot.js
+++ b/packages/core/src/lib/pattern_graph_dot.js
@@ -23,7 +23,7 @@ function header() {
* @param name
* @return {string}
*/
-const niceKey = function(name) {
+const niceKey = function (name) {
return 'O' + name.replace('-', '');
};
@@ -84,7 +84,7 @@ const PatternGraphDot = {};
* @param patternGraph
* @return {string}
*/
-PatternGraphDot.generate = function(patternGraph) {
+PatternGraphDot.generate = function (patternGraph) {
const g = patternGraph.graph;
const patterns = patternGraph.patterns;
const buckets = new Map();
@@ -98,20 +98,20 @@ PatternGraphDot.generate = function(patternGraph) {
const colorMap = new Map();
let colIdx = 0;
for (const p of patterns.partials.values()) {
- if (p.isPseudoPattern || !p.patternType) {
+ if (p.isPseudoPattern || !p.patternGroup) {
continue;
}
- let bucket = buckets.get(p.patternType);
+ let bucket = buckets.get(p.patternGroup);
if (bucket) {
bucket.push(p);
} else {
bucket = [p];
- colorMap.set(p.patternType, colors[colIdx++]);
+ colorMap.set(p.patternGroup, colors[colIdx++]);
// Repeat if there are more categories
colIdx = colIdx % colors.length;
}
- buckets.set(p.patternType, bucket);
+ buckets.set(p.patternGroup, bucket);
}
let res = header();
@@ -131,11 +131,11 @@ PatternGraphDot.generate = function(patternGraph) {
foo: for (const edge of g.edges()) {
const fromTo = patternGraph.nodes2patterns([edge.v, edge.w]);
for (const pattern of fromTo) {
- if (pattern.isPseudoPattern || !pattern.patternType) {
+ if (pattern.isPseudoPattern || !pattern.patternGroup) {
continue foo;
}
}
- const thisColor = colorMap.get(fromTo[0].patternType);
+ const thisColor = colorMap.get(fromTo[0].patternGroup);
res.push(addEdge(fromTo[0], fromTo[1], thisColor));
}
diff --git a/packages/core/src/lib/pattern_registry.js b/packages/core/src/lib/pattern_registry.js
index 95145234c..041cb109e 100644
--- a/packages/core/src/lib/pattern_registry.js
+++ b/packages/core/src/lib/pattern_registry.js
@@ -4,7 +4,7 @@
* Allows lookups for patterns via a central registry.
* @constructor
*/
-const PatternRegistry = function() {
+const PatternRegistry = function () {
this.key2pattern = new Map();
/** For lookups by {@link Pattern#partialKey} */
@@ -12,15 +12,15 @@ const PatternRegistry = function() {
};
PatternRegistry.prototype = {
- allPatterns: function() {
+ allPatterns: function () {
return Array.from(this.key2pattern.values());
},
- has: function(name) {
+ has: function (name) {
return this.key2pattern.has(name);
},
- get: function(name) {
+ get: function (name) {
return this.key2pattern.get(name);
},
@@ -28,18 +28,18 @@ PatternRegistry.prototype = {
* Adds the given pattern to the registry. If a pattern with the same key exists, it is replaced.
* @param pattern {Pattern|*}
*/
- put: function(pattern) {
+ put: function (pattern) {
const name = PatternRegistry.partialName(pattern);
this.partials.set(name, pattern);
const key = PatternRegistry.patternKey(pattern);
this.key2pattern.set(key, pattern);
},
- remove: function(name) {
+ remove: function (name) {
this.key2pattern.delete(name);
},
- getPartial: function(partialName) {
+ getPartial: function (partialName) {
/*
Code in here has been moved from getPartial() to prepare for some refactoring.
There are a few advantages to this method:
@@ -83,7 +83,7 @@ PatternRegistry.prototype = {
},
};
-PatternRegistry.patternKey = function(pattern) {
+PatternRegistry.patternKey = function (pattern) {
return pattern.relPath;
};
@@ -93,7 +93,7 @@ PatternRegistry.patternKey = function(pattern) {
* @param pattern {Pattern}
* @return {string}
*/
-PatternRegistry.partialName = function(pattern) {
+PatternRegistry.partialName = function (pattern) {
return pattern.patternPartial;
};
diff --git a/packages/core/src/lib/patternlab.js b/packages/core/src/lib/patternlab.js
index 2b8cc3d43..405da4fc9 100644
--- a/packages/core/src/lib/patternlab.js
+++ b/packages/core/src/lib/patternlab.js
@@ -47,13 +47,14 @@ module.exports = class PatternLab {
// Load up engines please
this.engines = patternEngines;
this.engines.loadAllEngines(config);
+ this.isBusy = false;
//
// INITIALIZE EMPTY GLOBAL DATA STRUCTURES
//
this.data = {};
this.patterns = [];
- this.subtypePatterns = {};
+ this.subgroupPatterns = {};
this.partials = {};
// Cache the package.json in RAM
@@ -64,6 +65,9 @@ module.exports = class PatternLab {
// Make ye olde event emitter
this.events = new PatternLabEventEmitter();
+ this.hooks = {};
+ this.hooks[events.PATTERNLAB_PATTERN_WRITE_END] = [];
+
// Make a place for the pattern graph to sit
this.graph = null;
@@ -107,9 +111,7 @@ module.exports = class PatternLab {
if (typeof patternlab.config.paths.source.patternlabFiles === 'string') {
logger.warning('');
logger.warning(
- `Configuration key [paths.source.patternlabFiles] inside patternlab-config.json was found as the string '${
- patternlab.config.paths.source.patternlabFiles
- }'`
+ `Configuration key [paths.source.patternlabFiles] inside patternlab-config.json was found as the string '${patternlab.config.paths.source.patternlabFiles}'`
);
logger.warning(
'Since Pattern Lab Node Core 3.0.0 this key is an object. Suggest you update this key following this issue: https://github.com/pattern-lab/patternlab-node/issues/683.'
@@ -213,10 +215,10 @@ module.exports = class PatternLab {
}
writePatternFiles(headHTML, pattern, footerHTML, outputBasePath) {
- const nullFormatter = str => str;
- const defaultFormatter = codeString =>
+ const nullFormatter = (str) => str;
+ const defaultFormatter = (codeString) =>
cleanHtml(codeString, { indent_size: 2 });
- const makePath = type =>
+ const makePath = (type) =>
path.join(
this.config.paths.public.patterns,
pattern.getPatternLink(this, type)
@@ -256,7 +258,7 @@ module.exports = class PatternLab {
);
//write the compiled template to the public patterns directory
- outputFiles.forEach(outFile =>
+ outputFiles.forEach((outFile) =>
fs.outputFileSync(
path.join(process.cwd(), outputBasePath, outFile.path),
outFile.content
@@ -272,22 +274,22 @@ module.exports = class PatternLab {
*/
registerLogger(logLevel) {
if (logLevel === undefined) {
- logger.log.on('info', msg => console.info(msg));
- logger.log.on('warning', msg => console.info(msg));
- logger.log.on('error', msg => console.info(msg));
+ logger.log.on('info', (msg) => console.info(msg));
+ logger.log.on('warning', (msg) => console.info(msg));
+ logger.log.on('error', (msg) => console.info(msg));
} else {
if (logLevel === 'quiet') {
return;
}
switch (logLevel) {
case 'debug':
- logger.log.on('debug', msg => console.info(msg));
+ logger.log.on('debug', (msg) => console.info(msg));
case 'info':
- logger.log.on('info', msg => console.info(msg));
+ logger.log.on('info', (msg) => console.info(msg));
case 'warning':
- logger.log.on('warning', msg => console.info(msg));
+ logger.log.on('warning', (msg) => console.info(msg));
case 'error':
- logger.log.on('error', msg => console.info(msg));
+ logger.log.on('error', (msg) => console.info(msg));
}
}
}
@@ -305,7 +307,12 @@ module.exports = class PatternLab {
// dive once to perform iterative populating of patternlab object
processAllPatternsIterative(patterns_dir) {
const self = this;
- const promiseAllPatternFiles = new Promise(function(resolve) {
+
+ // before updating the patterns has to be reset, otherwise
+ // deleted pattern would still be present in the patterns array
+ this.patterns = [];
+
+ const promiseAllPatternFiles = new Promise(function (resolve) {
dive(
patterns_dir,
(err, file) => {
@@ -331,11 +338,11 @@ module.exports = class PatternLab {
});
return promiseAllPatternFiles.then(() => {
return Promise.all(
- this.patterns.map(pattern => {
+ this.patterns.map((pattern) => {
return processIterative(pattern, self);
})
).then(() => {
- // patterns sorted by name so the patterntype and patternsubtype is adhered to for menu building
+ // patterns sorted by name so the patternGroup and patternSubgroup is adhered to for menu building
this.patterns.sort((pattern1, pattern2) =>
pattern1.name.localeCompare(pattern2.name)
);
@@ -346,7 +353,7 @@ module.exports = class PatternLab {
processAllPatternsRecursive(patterns_dir) {
const self = this;
- const promiseAllPatternFiles = new Promise(function(resolve) {
+ const promiseAllPatternFiles = new Promise(function (resolve) {
dive(
patterns_dir,
(err, file) => {
diff --git a/packages/core/src/lib/plugin_manager.js b/packages/core/src/lib/plugin_manager.js
index a3a37ab58..f79307beb 100644
--- a/packages/core/src/lib/plugin_manager.js
+++ b/packages/core/src/lib/plugin_manager.js
@@ -1,65 +1,39 @@
'use strict';
-const plugin_manager = function() {
- const path = require('path');
- const findModules = require('./findModules');
-
- const _ = require('lodash');
-
+const plugin_manager = function () {
const logger = require('./log');
- const pluginMatcher = /^plugin-(.*)$/;
-
- /**
- * Loads a plugin
- *
- * @param modulePath {string} the path to the plugin
- * @return {object} the loaded plugin
- */
- function loadPlugin(modulePath) {
- return require(modulePath);
- }
-
- /**
- * Given a path: return the plugin name if the path points to a valid plugin
- * module directory, or false if it doesn't.
- * @param filePath
- * @returns Plugin name if exists or FALSE
- */
- function isPlugin(filePath) {
- const baseName = path.basename(filePath);
- const pluginMatch = baseName.match(pluginMatcher);
-
- if (pluginMatch) {
- return pluginMatch[1];
- }
- return false;
- }
-
/**
* Looks for installed plugins, loads them, and invokes them
* @param {object} patternlab
*/
function initializePlugins(patternlab) {
- const nodeModulesPath = path.join(process.cwd(), 'node_modules');
- const foundPlugins = findModules(nodeModulesPath, plugin_manager.is_plugin);
- foundPlugins.forEach(plugin => {
- logger.info(`Found plugin: plugin-${plugin.name}`);
+ const foundPlugins = Object.keys(patternlab.config.plugins || {});
+ foundPlugins.forEach((plugin) => {
+ logger.info(`Found plugin: ${plugin}`);
logger.info(`Attempting to load and initialize plugin.`);
- const pluginModule = plugin_manager.load_plugin(plugin.modulePath);
+ const pluginModule = require(plugin);
pluginModule(patternlab);
});
}
+ async function raiseEvent(patternlab, eventName, args) {
+ patternlab.events.emit(eventName, args);
+ await (async function () {
+ const hookHandlers = (patternlab.hooks[eventName] || []).map((h) =>
+ h(args)
+ );
+
+ await Promise.all(hookHandlers);
+ })();
+ }
+
return {
- intialize_plugins: patternlab => {
+ intialize_plugins: (patternlab) => {
initializePlugins(patternlab);
},
- load_plugin: modulePath => {
- return loadPlugin(modulePath);
- },
- is_plugin: filePath => {
- return isPlugin(filePath);
+ raiseEvent: async (patternlab, eventName, ...args) => {
+ await raiseEvent(patternlab, eventName, args);
},
};
};
diff --git a/packages/core/src/lib/processIterative.js b/packages/core/src/lib/processIterative.js
index 1c65c85ca..8f57f7dff 100644
--- a/packages/core/src/lib/processIterative.js
+++ b/packages/core/src/lib/processIterative.js
@@ -5,15 +5,12 @@ const pph = require('./pseudopattern_hunter');
// This is now solely for analysis; loading of the pattern file is
// above, in loadPatternIterative()
-module.exports = function(pattern, patternlab) {
+module.exports = function (pattern, patternlab) {
//look for a pseudo pattern by checking if there is a file
//containing same name, with ~ in it, ending in .json
return pph
.find_pseudopatterns(pattern, patternlab)
.then(() => {
- //find any stylemodifiers that may be in the current pattern
- pattern.stylePartials = pattern.findPartialsWithStyleModifiers();
-
//find any pattern parameters that may be in the current pattern
pattern.parameteredPartials = pattern.findPartialsWithPatternParameters();
return Promise.resolve(pattern);
diff --git a/packages/core/src/lib/processMetaPattern.js b/packages/core/src/lib/processMetaPattern.js
index 66ca99586..dea8fbe70 100644
--- a/packages/core/src/lib/processMetaPattern.js
+++ b/packages/core/src/lib/processMetaPattern.js
@@ -9,7 +9,7 @@ const logger = require('./log');
//this may be mocked in unit tests, so let it be overridden
let fs = require('fs-extra'); // eslint-disable-line
-module.exports = function(fileName, metaType, patternlab) {
+module.exports = function (fileName, metaType, patternlab) {
const metaPath = path.resolve(patternlab.config.paths.source.meta, fileName);
const metaPattern = new Pattern(metaPath, null, patternlab);
metaPattern.template = fs.readFileSync(metaPath, 'utf8');
@@ -19,11 +19,9 @@ module.exports = function(fileName, metaType, patternlab) {
.then(() => {
patternlab[metaType] = metaPattern;
})
- .catch(reason => {
+ .catch((reason) => {
logger.warning(
- `Could not find the user-editable template ${fileName}, currently configured to be at ${
- patternlab.config.paths.source.meta
- }. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.`
+ `Could not find the user-editable template ${fileName}, currently configured to be at ${patternlab.config.paths.source.meta}. Your configured path may be incorrect (check paths.source.meta in your config file), the file may have been deleted, or it may have been left in the wrong place during a migration or update.`
);
logger.warning(reason);
});
diff --git a/packages/core/src/lib/processRecursive.js b/packages/core/src/lib/processRecursive.js
index 97c4ac560..3c541c85c 100644
--- a/packages/core/src/lib/processRecursive.js
+++ b/packages/core/src/lib/processRecursive.js
@@ -4,7 +4,7 @@ const logger = require('./log');
const decompose = require('./decompose');
const getPartial = require('./get');
-module.exports = function(file, patternlab) {
+module.exports = function (file, patternlab) {
//find current pattern in patternlab object using file as a partial
const currentPattern = getPartial(file, patternlab, false);
@@ -19,7 +19,7 @@ module.exports = function(file, patternlab) {
}
//call our helper method to actually unravel the pattern with any partials
- return decompose(currentPattern, patternlab).catch(reason => {
+ return decompose(currentPattern, patternlab).catch((reason) => {
console.log(reason);
logger.error(reason);
});
diff --git a/packages/core/src/lib/pseudopattern_hunter.js b/packages/core/src/lib/pseudopattern_hunter.js
index c57379405..28d4f3e1a 100644
--- a/packages/core/src/lib/pseudopattern_hunter.js
+++ b/packages/core/src/lib/pseudopattern_hunter.js
@@ -13,10 +13,11 @@ const readDocumentation = require('./readDocumentation');
const lineage_hunter = new lh();
const changes_hunter = new ch();
const yaml = require('js-yaml');
+const dataMerger = require('./dataMerger');
-const pseudopattern_hunter = function() {};
+const pseudopattern_hunter = function () {};
-pseudopattern_hunter.prototype.find_pseudopatterns = function(
+pseudopattern_hunter.prototype.find_pseudopatterns = function (
currentPattern,
patternlab
) {
@@ -49,32 +50,27 @@ pseudopattern_hunter.prototype.find_pseudopatterns = function(
paths.source.patterns,
pseudoPatterns[i]
);
- variantFileData = yaml.safeLoad(
+ variantFileData = yaml.load(
fs.readFileSync(variantFileFullPath, 'utf8')
);
} catch (err) {
- logger.warning(
- `There was an error parsing pseudopattern JSON for ${
- currentPattern.relPath
- }`
+ logger.error(
+ `There was an error parsing pseudopattern JSON for ${currentPattern.relPath}`
);
- logger.warning(err);
+ logger.error(err);
}
//extend any existing data with variant data
- variantFileData = _.merge(
- {},
+ variantFileData = dataMerger(
currentPattern.jsonFileData,
- variantFileData
+ variantFileData,
+ patternlab.config
);
const variantName = pseudoPatterns[i]
.substring(pseudoPatterns[i].indexOf('~') + 1)
.split('.')[0];
- const variantExtension = pseudoPatterns[i]
- .split('.')
- .slice(-1)
- .pop();
+ const variantExtension = pseudoPatterns[i].split('.').slice(-1).pop();
const variantFilePath = path.join(
currentPattern.subdir,
currentPattern.fileName + '~' + variantName + '.' + variantExtension
@@ -90,7 +86,6 @@ pseudopattern_hunter.prototype.find_pseudopatterns = function(
extendedTemplate: currentPattern.extendedTemplate,
isPseudoPattern: true,
basePattern: currentPattern,
- stylePartials: currentPattern.stylePartials,
parameteredPartials: currentPattern.parameteredPartials,
// Only regular patterns are discovered during iterative walks
@@ -102,13 +97,15 @@ pseudopattern_hunter.prototype.find_pseudopatterns = function(
},
patternlab
);
+ patternVariant.order = _.clone(currentPattern.order);
+ patternVariant.hidden = _.clone(currentPattern.hidden);
changes_hunter.checkBuildState(patternVariant, patternlab);
patternlab.graph.add(patternVariant);
patternlab.graph.link(patternVariant, currentPattern);
//process the companion markdown file if it exists
- readDocumentation(patternVariant, patternlab);
+ readDocumentation(patternVariant, patternlab, true);
//find pattern lineage
lineage_hunter.find_lineage(patternVariant, patternlab);
diff --git a/packages/core/src/lib/readDocumentation.js b/packages/core/src/lib/readDocumentation.js
index d22c6fa88..1159a0347 100644
--- a/packages/core/src/lib/readDocumentation.js
+++ b/packages/core/src/lib/readDocumentation.js
@@ -1,7 +1,8 @@
'use strict';
-const path = require('path');
const _ = require('lodash');
+const path = require('path');
+const fs = require('fs-extra');
const ch = require('./changes_hunter');
const logger = require('./log');
@@ -10,14 +11,15 @@ const mp = require('./markdown_parser');
const changes_hunter = new ch();
const markdown_parser = new mp();
-let fs = require('fs-extra'); //eslint-disable-line prefer-const
+const FILE_EXTENSION = '.md';
+const GROUP_DOC_PREFIX = '_';
-module.exports = function(pattern, patternlab) {
+module.exports = function (pattern, patternlab, isVariant) {
try {
const markdownFileName = path.resolve(
patternlab.config.paths.source.patterns,
pattern.subdir,
- pattern.fileName + '.md'
+ pattern.fileName + FILE_EXTENSION
);
changes_hunter.checkLastModified(pattern, markdownFileName);
@@ -37,9 +39,9 @@ module.exports = function(pattern, patternlab) {
pattern.patternState = markdownObject.state;
}
if (markdownObject.order) {
- pattern.order = markdownObject.order;
+ pattern[isVariant ? 'variantOrder' : 'order'] = markdownObject.order;
}
- if (markdownObject.hidden) {
+ if (markdownObject.hasOwnProperty('hidden')) {
pattern.hidden = markdownObject.hidden;
}
if (markdownObject.excludeFromStyleguide) {
@@ -54,6 +56,14 @@ module.exports = function(pattern, patternlab) {
if (markdownObject.links) {
pattern.links = markdownObject.links;
}
+
+ if (
+ markdownObject.hasOwnProperty('deeplyNested') &&
+ markdownObject.deeplyNested
+ ) {
+ // Reset to pattern without own pattern-directory
+ pattern.promoteFromDirectoryToFlatPattern(patternlab);
+ }
} else {
logger.warning(`error processing markdown for ${pattern.patternPartial}`);
}
@@ -63,12 +73,83 @@ module.exports = function(pattern, patternlab) {
} catch (err) {
// do nothing when file not found
if (err.code !== 'ENOENT') {
- logger.warning(
- `'there was an error setting pattern keys after markdown parsing of the companion file for pattern ${
- pattern.patternPartial
- }`
+ logger.error(
+ `There was an error setting pattern keys after markdown parsing of the companion file for pattern ${pattern.patternPartial}${FILE_EXTENSION}`
+ );
+ logger.error(err);
+ }
+ }
+
+ // Read Documentation for Pattern-Group
+ // Use this approach, since pattern lab is a pattern driven software
+ if (pattern.patternGroup) {
+ const groupRelPath = pattern.relPath.split(path.sep);
+ try {
+ const markdownFileNameGroup = path.resolve(
+ patternlab.config.paths.source.patterns,
+ groupRelPath[0] || pattern.subdir,
+ GROUP_DOC_PREFIX + pattern.patternGroup + FILE_EXTENSION
+ );
+ const markdownFileContentsGroup = fs.readFileSync(
+ markdownFileNameGroup,
+ 'utf8'
+ );
+ const markdownObjectGroup = markdown_parser.parse(
+ markdownFileContentsGroup
+ );
+
+ if (!_.isEmpty(markdownObjectGroup)) {
+ pattern.patternGroupData = markdownObjectGroup;
+ }
+ } catch (err) {
+ // do nothing when file not found
+ if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
+ logger.warning(
+ `There was an error setting pattern group data after markdown parsing for ${path.join(
+ patternlab.config.paths.source.patterns,
+ groupRelPath[0] || pattern.subdir,
+ GROUP_DOC_PREFIX + pattern.patternGroup + FILE_EXTENSION
+ )}`
+ );
+ logger.warning(err);
+ }
+ }
+ }
+
+ // Read Documentation for Pattern-Subgroup
+ if (pattern.patternSubgroup) {
+ const subgroupRelPath = pattern.relPath.split(path.sep);
+ try {
+ const markdownFileNameSubgroup = path.resolve(
+ patternlab.config.paths.source.patterns,
+ subgroupRelPath[0],
+ subgroupRelPath[1],
+ GROUP_DOC_PREFIX + pattern.patternSubgroup + FILE_EXTENSION
);
- logger.warning(err);
+ const markdownFileContentsSubgroup = fs.readFileSync(
+ markdownFileNameSubgroup,
+ 'utf8'
+ );
+ const markdownObjectSubgroup = markdown_parser.parse(
+ markdownFileContentsSubgroup
+ );
+
+ if (!_.isEmpty(markdownObjectSubgroup)) {
+ pattern.patternSubgroupData = markdownObjectSubgroup;
+ }
+ } catch (err) {
+ // do nothing when file not found
+ if (err.code !== 'ENOENT' && err.code !== 'ENOTDIR') {
+ logger.warning(
+ `There was an error setting pattern subgroup data after markdown parsing for ${path.join(
+ patternlab.config.paths.source.patterns,
+ subgroupRelPath[0],
+ subgroupRelPath[1],
+ GROUP_DOC_PREFIX + pattern.patternSubgroup + FILE_EXTENSION
+ )}`
+ );
+ logger.warning(err);
+ }
}
}
};
diff --git a/packages/core/src/lib/render.js b/packages/core/src/lib/render.js
index 3ba1f2589..b73d5369f 100644
--- a/packages/core/src/lib/render.js
+++ b/packages/core/src/lib/render.js
@@ -2,7 +2,7 @@
const logger = require('./log');
-module.exports = function(pattern, data, partials) {
+module.exports = function (pattern, data, partials) {
logger.debug(
`render: ${
pattern.patternPartial !== '-.'
diff --git a/packages/core/src/lib/replaceParameter.js b/packages/core/src/lib/replaceParameter.js
index 7b0cd6734..b045b58b2 100644
--- a/packages/core/src/lib/replaceParameter.js
+++ b/packages/core/src/lib/replaceParameter.js
@@ -2,7 +2,7 @@
const logger = require('./log');
-module.exports = function(template, prop, data) {
+module.exports = function (template, prop, data) {
let t = template;
const valueRE = new RegExp(`{{{?\\s*[${prop}]+\\s*}?}}`);
diff --git a/packages/core/src/lib/resolver.js b/packages/core/src/lib/resolver.js
new file mode 100644
index 000000000..d70961413
--- /dev/null
+++ b/packages/core/src/lib/resolver.js
@@ -0,0 +1,53 @@
+'use strict';
+
+const path = require('path');
+
+/**
+ * @func resolvePackageLocations
+ * Resolves all possible package locations
+ */
+const resolvePackageLocations = () => {
+ let lookupPath = path.resolve(process.env.projectDir);
+ const paths = [lookupPath];
+ while (path.dirname(lookupPath) !== lookupPath) {
+ lookupPath = path.join(lookupPath, '../');
+ paths.push(lookupPath);
+ }
+ return paths;
+};
+
+/**
+ * @func resolveFileInPackage
+ * Resolves a file inside a package
+ */
+const resolveFileInPackage = (packageName, ...pathElements) => {
+ if (process.env.projectDir) {
+ return require.resolve(path.join(packageName, ...pathElements), {
+ paths: resolvePackageLocations(),
+ });
+ } else {
+ return require.resolve(path.join(packageName, ...pathElements));
+ }
+};
+
+/**
+ * @func resolvePackageFolder
+ * Resolves the location of a package on disc
+ */
+const resolvePackageFolder = (packageName) => {
+ return path.dirname(resolveFileInPackage(packageName, 'package.json'));
+};
+
+/**
+ * @func resolveDirInPackage
+ * Resolves a file inside a package
+ */
+const resolveDirInPackage = (packageName, ...pathElements) => {
+ return path.join(resolvePackageFolder(packageName), ...pathElements);
+};
+
+module.exports = {
+ resolveFileInPackage,
+ resolveDirInPackage,
+ resolvePackageFolder,
+};
diff --git a/packages/core/src/lib/server.js b/packages/core/src/lib/server.js
index 7b5a9cecd..58bef01a4 100644
--- a/packages/core/src/lib/server.js
+++ b/packages/core/src/lib/server.js
@@ -6,7 +6,7 @@ const liveServer = require('@pattern-lab/live-server');
const events = require('./events');
const logger = require('./log');
-const server = patternlab => {
+const server = (patternlab) => {
const _module = {
serve: () => {
let serverReady = false;
@@ -20,7 +20,7 @@ const server = patternlab => {
port: 3000,
};
- const servers = Object.keys(patternlab.uikits).map(kit => {
+ const servers = Object.keys(patternlab.uikits).map((kit) => {
const uikit = patternlab.uikits[kit];
defaults.root = path.resolve(
path.join(
@@ -36,6 +36,30 @@ const server = patternlab => {
patternlab.config.paths.public.root
)
);
+ defaults.assets = [
+ path.resolve(
+ path.join(
+ process.cwd(),
+ patternlab.config.paths.source.js,
+ '**',
+ '*.js' // prevent preprocessors like typescript from reloading
+ )
+ ),
+ path.resolve(
+ path.join(process.cwd(), patternlab.config.paths.source.images)
+ ),
+ path.resolve(
+ path.join(process.cwd(), patternlab.config.paths.source.fonts)
+ ),
+ path.resolve(
+ path.join(
+ process.cwd(),
+ patternlab.config.paths.source.css,
+ '**',
+ '*.css' // prevent preprocessors from reloading
+ )
+ ),
+ ];
// allow for overrides should they exist inside patternlab-config.json
const liveServerConfig = Object.assign(
@@ -63,9 +87,9 @@ const server = patternlab => {
setTimeout(() => {
try {
liveServer.start(liveServerConfig);
- resolveMsg = `Pattern Lab is being served from http://127.0.0.1:${
- liveServerConfig.port
- }`;
+ resolveMsg = `Pattern Lab is being served from ${
+ liveServerConfig.https ? 'https' : 'http'
+ }://127.0.0.1:${liveServerConfig.port}`;
logger.info(resolveMsg);
} catch (e) {
const err = `Pattern Lab serve failed to start: ${e}`;
@@ -82,7 +106,7 @@ const server = patternlab => {
return Promise.all(servers);
},
- reload: data => {
+ reload: (data) => {
const _data = data || {
file: '',
action: '',
diff --git a/packages/core/src/lib/starterkit_manager.js b/packages/core/src/lib/starterkit_manager.js
index c00b33bbe..737aadd9a 100644
--- a/packages/core/src/lib/starterkit_manager.js
+++ b/packages/core/src/lib/starterkit_manager.js
@@ -1,6 +1,6 @@
'use strict';
-const starterkit_manager = function(config) {
+const starterkit_manager = function (config) {
const path = require('path');
const fetch = require('node-fetch');
const fs = require('fs-extra');
@@ -29,7 +29,7 @@ const starterkit_manager = function(config) {
kitDirStats = fs.statSync(kitPath);
} catch (ex) {
logger.warning(
- `${starterkitName} not found, use npm to install it first.`
+ `${starterkitName} not found, use npm or another package manager to install it first.`
);
logger.warning(`${starterkitName} not loaded.`);
return;
@@ -38,16 +38,12 @@ const starterkit_manager = function(config) {
if (kitPathDirExists) {
if (clean) {
logger.info(
- `Deleting contents of ${
- paths.source.root
- } prior to starterkit load.`
+ `Deleting contents of ${paths.source.root} prior to starterkit load.`
);
fs.emptyDirSync(paths.source.root);
} else {
logger.info(
- `Overwriting contents of ${
- paths.source.root
- } during starterkit load.`
+ `Overwriting contents of ${paths.source.root} during starterkit load.`
);
}
@@ -82,7 +78,7 @@ const starterkit_manager = function(config) {
},
}
)
- .then(function(res) {
+ .then(function (res) {
const contentType = res.headers.get('content-type');
if (contentType && contentType.indexOf('application/json') === -1) {
throw new TypeError(
@@ -91,15 +87,15 @@ const starterkit_manager = function(config) {
}
return res.json();
})
- .then(function(json) {
+ .then(function (json) {
if (!json.items || !Array.isArray(json.items)) {
return false;
}
- return json.items.map(function(repo) {
+ return json.items.map(function (repo) {
return { name: repo.name, url: repo.html_url };
});
})
- .catch(function(err) {
+ .catch(function (err) {
logger.error(err);
return false;
});
@@ -115,27 +111,29 @@ const starterkit_manager = function(config) {
//TODO review for deletion or convert callers to use findModules()
function detectStarterKits() {
const node_modules_path = path.join(process.cwd(), 'node_modules');
- const npm_modules = fs.readdirSync(node_modules_path).filter(function(dir) {
- const module_path = path.join(process.cwd(), 'node_modules', dir);
- return (
- fs.statSync(module_path).isDirectory() &&
- dir.indexOf('starterkit-') === 0
- );
- });
+ const npm_modules = fs
+ .readdirSync(node_modules_path)
+ .filter(function (dir) {
+ const module_path = path.join(process.cwd(), 'node_modules', dir);
+ return (
+ fs.statSync(module_path).isDirectory() &&
+ dir.indexOf('starterkit-') === 0
+ );
+ });
return npm_modules;
}
return {
- load_starterkit: function(starterkitName, clean) {
+ load_starterkit: function (starterkitName, clean) {
loadStarterKit(starterkitName, clean);
},
- list_starterkits: function() {
+ list_starterkits: function () {
return listStarterkits();
},
- pack_starterkit: function() {
+ pack_starterkit: function () {
packStarterkit();
},
- detect_starterkits: function() {
+ detect_starterkits: function () {
return detectStarterKits();
},
};
diff --git a/packages/core/src/lib/style_modifier_hunter.js b/packages/core/src/lib/style_modifier_hunter.js
deleted file mode 100644
index 13a7ff2d1..000000000
--- a/packages/core/src/lib/style_modifier_hunter.js
+++ /dev/null
@@ -1,45 +0,0 @@
-'use strict';
-
-const logger = require('./log');
-
-const style_modifier_hunter = function() {
- /**
- * Modifies a patterns partial with any styleModifiers found on the supplied partial
- *
- * @param pattern {object} the pattern to extend
- * @param partial {string} partial containing styleModifiers
- * @param patternlab {object} the patternlab instance
- */
- function consumestylemodifier(pattern, partial, patternlab) {
- //extract the classname from the stylemodifier which comes in the format of :className
- let styleModifier = partial.match(/:([\w\-_|])+/g)
- ? partial.match(/:([\w\-_|])+/g)[0].slice(1)
- : null;
-
- if (styleModifier) {
- //replace the special character pipe | used to separate multiple classes with a space
- styleModifier = styleModifier.replace(/\|/g, ' ');
-
- logger.debug(
- `Found partial styleModifier within pattern ${pattern.patternPartial}`
- );
-
- //replace the stylemodifier placeholder with the class name
- pattern.extendedTemplate = pattern.extendedTemplate.replace(
- /{{[ ]?styleModifier[ ]?}}/i,
- styleModifier
- );
-
- //update the extendedTemplate in the partials object in case this pattern is consumed later
- patternlab.partials[pattern.patternPartial] = pattern.extendedTemplate;
- }
- }
-
- return {
- consume_style_modifier: function(pattern, partial, patternlab) {
- consumestylemodifier(pattern, partial, patternlab);
- },
- };
-};
-
-module.exports = style_modifier_hunter;
diff --git a/packages/core/src/lib/ui_builder.js b/packages/core/src/lib/ui_builder.js
index 96229e08c..8b3d7de3a 100644
--- a/packages/core/src/lib/ui_builder.js
+++ b/packages/core/src/lib/ui_builder.js
@@ -3,18 +3,17 @@
const path = require('path');
const _ = require('lodash');
-const of = require('./object_factory');
-const Pattern = of.Pattern;
+const Pattern = require('./object_factory').Pattern;
const logger = require('./log');
const uikitExcludePattern = require('./uikitExcludePattern');
-//these are mocked in unit tests, so let them be overridden
+// these are mocked in unit tests, so let them be overridden
let render = require('./render'); //eslint-disable-line prefer-const
let fs = require('fs-extra'); //eslint-disable-line prefer-const
let buildFooter = require('./buildFooter'); //eslint-disable-line prefer-const
let exportData = require('./exportData'); //eslint-disable-line prefer-const
-const ui_builder = function() {
+const ui_builder = function () {
/**
* Registers the pattern to the patternPaths object for the appropriate patternGroup and basename
* patternGroup + patternBaseName are what comprise the patternPartial (atoms-colors)
@@ -26,7 +25,7 @@ const ui_builder = function() {
patternlab.patternPaths[pattern.patternGroup] = {};
}
- //only add real patterns
+ // only add real patterns
if (pattern.isPattern && !pattern.isDocPattern) {
patternlab.patternPaths[pattern.patternGroup][pattern.patternBaseName] =
pattern.name;
@@ -34,7 +33,7 @@ const ui_builder = function() {
}
/**
- * Registers the pattern with the viewAllPaths object for the appropriate patternGroup and patternSubGroup
+ * Registers the pattern with the viewAllPaths object for the appropriate patternGroup and patternSubgroup
* @param patternlab - global data store
* @param pattern - the pattern to add
*/
@@ -44,20 +43,18 @@ const ui_builder = function() {
}
if (
- !patternlab.viewAllPaths[pattern.patternGroup][pattern.patternSubGroup]
+ !patternlab.viewAllPaths[pattern.patternGroup][pattern.patternSubgroup] &&
+ pattern.patternSubgroup
) {
+ // note these retain any number prefixes if present, because these paths match the filesystem
patternlab.viewAllPaths[pattern.patternGroup][
- pattern.patternSubGroup
- ] = {};
+ pattern.patternSubgroup
+ ] = `${pattern.patternGroup}-${pattern.patternSubgroup}`;
}
- //note these retain any number prefixes if present, because these paths match the filesystem
- patternlab.viewAllPaths[pattern.patternGroup][pattern.patternSubGroup] =
- pattern.patternType + '-' + pattern.patternSubType;
-
- //add all if it does not exist yet
+ // add all if it does not exist yet
if (!patternlab.viewAllPaths[pattern.patternGroup].all) {
- patternlab.viewAllPaths[pattern.patternGroup].all = pattern.patternType;
+ patternlab.viewAllPaths[pattern.patternGroup].all = pattern.patternGroup;
}
}
@@ -75,63 +72,57 @@ const ui_builder = function() {
isOmitted = uikitExcludePattern(pattern, uikit);
if (isOmitted) {
logger.info(
- `Omitting ${
- pattern.patternPartial
- } from styleguide patterns because its pattern state or tag is excluded within ${
- uikit.name
- }.`
+ `Omitting ${pattern.patternPartial} from styleguide patterns because its pattern state or tag is excluded within ${uikit.name}.`
);
return true;
}
- // skip underscore-prefixed files
- isOmitted = pattern.isPattern && pattern.fileName.charAt(0) === '_';
+ // skip marked as hidden patterns
+ isOmitted =
+ (pattern.isPattern && pattern.hidden) ||
+ // TODO: Remove next line when removing support & deprecation waring for underscore prefix hiding
+ (pattern.isPattern && pattern.fileName.charAt(0) === '_');
if (isOmitted) {
logger.info(
- `Omitting ${
- pattern.patternPartial
- } from styleguide patterns because it has an underscore suffix.`
+ `Omitting ${pattern.patternPartial} from styleguide patterns because it is marked as hidden within it's documentation.`
);
return true;
}
- //this is meant to be a homepage that is not present anywhere else
+ // this is meant to be a homepage that is not present anywhere else
isOmitted = pattern.patternPartial === patternlab.config.defaultPattern;
if (isOmitted) {
logger.info(
- `Omitting ${
- pattern.patternPartial
- } from styleguide patterns because it is defined as a defaultPattern.`
+ `Omitting ${pattern.patternPartial} from styleguide patterns because it is defined as a defaultPattern.`
);
patternlab.defaultPattern = pattern;
return true;
}
- //this pattern is contained with a directory prefixed with an underscore (a handy way to hide whole directories from the nav
+ // this pattern is contained with a directory documented as hidden (a handy way to hide whole directories from the nav
isOmitted =
+ (pattern.patternGroupData && pattern.patternGroupData.hidden) ||
+ (pattern.patternSubgroupData && pattern.patternSubgroupData.hidden) ||
+ // TODO: Remove next two lines when removing support & deprecation waring for underscore prefix hiding
pattern.relPath.charAt(0) === '_' ||
pattern.relPath.indexOf(path.sep + '_') > -1;
if (isOmitted) {
logger.info(
- `Omitting ${
- pattern.patternPartial
- } from styleguide patterns because its contained within an underscored directory.`
+ `Omitting ${pattern.patternPartial} from styleguide patterns because its contained within an hidden directory.`
);
return true;
}
- //this pattern is a head or foot pattern
+ // this pattern is a head or foot pattern
isOmitted = pattern.isMetaPattern;
if (isOmitted) {
logger.info(
- `Omitting ${
- pattern.patternPartial
- } from styleguide patterns because its a meta pattern.`
+ `Omitting ${pattern.patternPartial} from styleguide patterns because its a meta pattern.`
);
return true;
}
- //yay, let's include this on the front end
+ // yay, let's include this on the front end
return isOmitted;
}
@@ -139,203 +130,196 @@ const ui_builder = function() {
* For the given pattern, find or construct the view-all pattern block for the group
* @param pattern - the pattern to derive our documentation pattern from
* @param patternlab - global data store
- * @param isSubtypePattern - whether or not this is a subtypePattern or a typePattern (typePatterns not supported yet)
+ * @param isSubgroupPattern - whether or not this is a subgroupPattern or a typePattern (groupedPatterns not supported yet)
* @returns the found or created pattern object
*/
- function injectDocumentationBlock(pattern, patternlab, isSubtypePattern) {
- //first see if loadPattern processed one already
- let docPattern =
- patternlab.subtypePatterns[
- pattern.patternGroup +
- (isSubtypePattern ? '-' + pattern.patternSubGroup : '')
- ];
- if (docPattern) {
- docPattern.isDocPattern = true;
- docPattern.order = -Number.MAX_SAFE_INTEGER;
- return docPattern;
- }
-
- //if not, create one now
- docPattern = new Pattern.createEmpty(
+ function injectDocumentationBlock(pattern, patternlab, isSubgroupPattern) {
+ return new Pattern.createEmpty(
{
name: pattern.flatPatternPath,
- patternName: isSubtypePattern
- ? pattern.patternSubGroup
- : pattern.patternGroup,
- patternDesc: '',
- patternPartial:
- 'viewall-' +
- pattern.patternGroup +
- (isSubtypePattern ? '-' + pattern.patternSubGroup : ''),
- patternSectionSubtype: isSubtypePattern,
- patternLink: pattern.flatPatternPath + path.sep + 'index.html',
+ patternName: _.startCase(
+ isSubgroupPattern ? pattern.patternSubgroup : pattern.patternGroup
+ ),
+ patternDesc: isSubgroupPattern
+ ? pattern.patternSubgroupData.markdown
+ : pattern.patternGroupData.markdown,
+ patternPartial: `viewall-${pattern.patternGroup}-${
+ isSubgroupPattern ? pattern.patternSubgroup : 'all'
+ }`,
+ patternSectionSubgroup: true,
+ patternLink: path.join(
+ isSubgroupPattern ? pattern.flatPatternPath : pattern.patternGroup,
+ 'index.html'
+ ),
isPattern: false,
engine: null,
flatPatternPath: pattern.flatPatternPath,
isDocPattern: true,
- order: -Number.MAX_SAFE_INTEGER,
+ order: Number.MIN_SAFE_INTEGER,
},
patternlab
);
- return docPattern;
}
/**
- * Registers flat patterns with the patternTypes object
+ * Sorts the given patterns in the way they are ment to be sorted
+ * @param {array} patterns which should be sorted
+ * @returns a sorted array of patterns
+ */
+ function getSortedPatterns(patterns) {
+ return _.sortBy(patterns, ['order', 'variantOrder', 'name']);
+ }
+
+ /**
+ * Registers flat patterns with the patternGroups object
* This is a new menu group like atoms
* @param patternlab - global data store
* @param pattern - the pattern to register
*/
- function addPatternType(patternlab, pattern) {
- patternlab.patternTypes.push({
- patternTypeLC: pattern.patternGroup.toLowerCase(),
- patternTypeUC:
- pattern.patternGroup.charAt(0).toUpperCase() +
- pattern.patternGroup.slice(1),
- patternType: pattern.patternType,
- patternTypeDash: pattern.patternGroup, //todo verify
- patternTypeItems: [],
+ function addPatternGroup(patternlab, pattern) {
+ patternlab.patternGroups.push({
+ patternGroupLC: _.kebabCase(pattern.patternGroup),
+ patternGroupUC: _.startCase(pattern.patternGroup),
+ patternGroup: pattern.patternGroup,
+ patternGroupDash: pattern.patternGroup, //todo verify
+ patternGroupItems: [],
+ order:
+ pattern.patternGroupData && pattern.patternGroupData.order
+ ? Number(pattern.patternGroupData.order)
+ : 0,
});
+
+ patternlab.patternGroups = _.sortBy(
+ patternlab.patternGroups,
+ 'order',
+ 'patternGroup'
+ );
}
/**
- * Return the patternType object for the given pattern. Exits application if not found.
+ * Return the patternGroup object for the given pattern. Exits application if not found.
* @param patternlab - global data store
* @param pattern - the pattern to derive the pattern Type from
* @returns the found pattern type object
*/
- function getPatternType(patternlab, pattern) {
- const patternType = _.find(patternlab.patternTypes, [
- 'patternType',
- pattern.patternType,
+ function getPatternGroup(patternlab, pattern) {
+ const patternGroup = _.find(patternlab.patternGroups, [
+ 'patternGroup',
+ pattern.patternGroup,
]);
- if (!patternType) {
+ if (!patternGroup) {
logger.error(
- `Could not find patternType ${
- pattern.patternType
- }. This is a critical error.`
+ `Could not find patternGroup ${pattern.patternGroup}. This is a critical error.`
);
}
- return patternType;
+ return patternGroup;
}
/**
- * Return the patternSubType object for the given pattern. Exits application if not found.
+ * Return the patternSubgroup object for the given pattern. Exits application if not found.
* @param patternlab - global data store
- * @param pattern - the pattern to derive the pattern subType from
- * @returns the found patternSubType object
+ * @param pattern - the pattern to derive the pattern subgroup from
+ * @returns the found patternSubgroup object
*/
- function getPatternSubType(patternlab, pattern) {
- const patternType = getPatternType(patternlab, pattern);
- const patternSubType = _.find(patternType.patternTypeItems, [
- 'patternSubtype',
- pattern.patternSubType,
+ function getPatternSubgroup(patternlab, pattern) {
+ const patternGroup = getPatternGroup(patternlab, pattern);
+ const patternSubgroup = _.find(patternGroup.patternGroupItems, [
+ 'patternSubgroup',
+ pattern.patternSubgroup,
]);
- if (!patternSubType) {
+ if (!patternSubgroup) {
logger.error(
- `Could not find patternType ${pattern.patternType}-${
- pattern.patternType
- }. This is a critical error.`
+ `Could not find patternGroup ${pattern.patternGroup}-${pattern.patternGroup}. This is a critical error.`
);
}
- return patternSubType;
+ return patternSubgroup;
}
/**
- * Registers the pattern with the appropriate patternType.patternTypeItems object
+ * Registers the pattern with the appropriate patternGroup.patternGroupItems object
* This is a new menu group like atoms/global
* @param patternlab - global data store
* @param pattern - the pattern to register
*/
- function addPatternSubType(patternlab, pattern) {
- const newSubType = {
- patternSubtypeLC: pattern.patternSubGroup.toLowerCase(),
- patternSubtypeUC:
- pattern.patternSubGroup.charAt(0).toUpperCase() +
- pattern.patternSubGroup.slice(1),
- patternSubtype: pattern.patternSubType,
- patternSubtypeDash: pattern.patternSubGroup, //todo verify
- patternSubtypeItems: [],
- };
- const patternType = getPatternType(patternlab, pattern);
- const insertIndex = _.sortedIndexBy(
- patternType.patternTypeItems,
- newSubType,
- 'patternSubtype'
+ function addPatternSubgroup(patternlab, pattern) {
+ const patternGroup = getPatternGroup(patternlab, pattern);
+
+ patternGroup.patternGroupItems.push({
+ patternSubgroupLC: _.kebabCase(pattern.patternSubgroup),
+ patternSubgroupUC: _.startCase(pattern.patternSubgroup),
+ patternSubgroup: pattern.patternSubgroup,
+ patternSubgroupDash: pattern.patternSubgroup, //todo verify
+ patternSubgroupItems: [],
+ order:
+ pattern.patternSubgroupData && pattern.patternSubgroupData.order
+ ? Number(pattern.patternSubgroupData.order)
+ : 0,
+ });
+
+ patternGroup.patternGroupItems = _.sortBy(
+ patternGroup.patternGroupItems,
+ 'order',
+ 'patternSubgroup'
);
- patternType.patternTypeItems.splice(insertIndex, 0, newSubType);
}
/**
- * Creates a patternSubTypeItem object from a pattern
+ * Creates a patternSubgroupItem object from a pattern
* This is a menu item you click on
- * @param pattern - the pattern to derive the subtypeitem from
- * @returns {{patternPartial: string, patternName: (*|string), patternState: string, patternSrcPath: string, patternPath: string}}
+ * @param pattern - the pattern to derive the subgroupitem from
+ * @returns {{patternPartial: string, patternName: (*|string), patternState: string, patternPath: string}}
*/
- function createPatternSubTypeItem(pattern) {
- let patternPath = '';
- if (pattern.isFlatPattern) {
- patternPath =
- pattern.flatPatternPath +
- '-' +
- pattern.fileName +
- '/' +
- pattern.flatPatternPath +
- '-' +
- pattern.fileName +
- '.html';
- } else {
- patternPath =
- pattern.flatPatternPath + '/' + pattern.flatPatternPath + '.html';
- }
-
+ function createPatternSubgroupItem(pattern) {
return {
patternPartial: pattern.patternPartial,
patternName: pattern.patternName,
patternState: pattern.patternState,
- patternSrcPath: encodeURI(pattern.subdir + '/' + pattern.fileName),
- patternPath: patternPath,
- order: pattern.order,
+ patternPath: pattern.patternLink,
+ name: pattern.name,
+ isDocPattern: false,
+ order: Number(pattern.order) || 0, // Failsafe is someone entered a string
+ variantOrder: Number(pattern.variantOrder) || 0, // Failsafe is someone entered a string
};
}
/**
- * Registers the pattern with the appropriate patternType.patternSubType.patternSubtypeItems array
+ * Registers the pattern with the appropriate patternGroup.patternSubgroup.patternSubgroupItems array
* These are the actual menu items you click on
* @param patternlab - global data store
- * @param pattern - the pattern to derive the subtypeitem from
+ * @param pattern - the pattern to derive the subgroupitem from
* @param createViewAllVariant - whether or not to create the special view all item
*/
- function addPatternSubTypeItem(
+ function addPatternSubgroupItem(
patternlab,
pattern,
- createSubtypeViewAllVarient
+ createSubgroupViewAllVariant
) {
- let newSubTypeItem;
+ let newSubgroupItem;
- if (createSubtypeViewAllVarient) {
- newSubTypeItem = {
+ if (createSubgroupViewAllVariant) {
+ newSubgroupItem = {
patternPartial:
- 'viewall-' + pattern.patternGroup + '-' + pattern.patternSubGroup,
- patternName: 'View All',
+ 'viewall-' + pattern.patternGroup + '-' + pattern.patternSubgroup,
+ patternName: `View All`,
patternPath: encodeURI(pattern.flatPatternPath + '/index.html'),
- patternType: pattern.patternType,
- patternSubtype: pattern.patternSubtype,
- order: 0,
+ patternGroup: pattern.patternGroup,
+ patternSubgroup: pattern.patternSubgroup,
+ name: pattern.flatPatternPath,
+ isDocPattern: true,
+ order: Number.MAX_SAFE_INTEGER,
};
} else {
- newSubTypeItem = createPatternSubTypeItem(pattern);
+ newSubgroupItem = createPatternSubgroupItem(pattern);
}
- const patternSubType = getPatternSubType(patternlab, pattern);
- patternSubType.patternSubtypeItems.push(newSubTypeItem);
- patternSubType.patternSubtypeItems = _.sortBy(
- patternSubType.patternSubtypeItems,
- ['order', 'name']
+ const patternSubgroup = getPatternSubgroup(patternlab, pattern);
+ patternSubgroup.patternSubgroupItems.push(newSubgroupItem);
+ patternSubgroup.patternSubgroupItems = getSortedPatterns(
+ patternSubgroup.patternSubgroupItems
);
}
@@ -345,113 +329,42 @@ const ui_builder = function() {
* @param pattern - the pattern to add
*/
function addPatternItem(patternlab, pattern, isViewAllVariant) {
- const patternType = getPatternType(patternlab, pattern);
- if (!patternType) {
+ const patternGroup = getPatternGroup(patternlab, pattern);
+ if (!patternGroup) {
logger.error(
- `Could not find patternType ${
- pattern.patternType
- }. This is a critical error.`
+ `Could not find patternGroup ${pattern.patternGroup}. This is a critical error.`
);
}
- if (!patternType.patternItems) {
- patternType.patternItems = [];
- }
-
+ patternGroup.patternItems = patternGroup.patternItems || [];
if (isViewAllVariant) {
- if (!pattern.isFlatPattern) {
- //todo: it'd be nice if we could get this into createPatternSubTypeItem someday
- patternType.patternItems.push({
- patternPartial: 'viewall-' + pattern.patternGroup + '-all',
- patternName: 'View All',
- patternPath: encodeURI(pattern.patternType + '/index.html'),
- order: -Number.MAX_SAFE_INTEGER,
- });
- }
+ patternGroup.patternItems.push({
+ patternPartial: `viewall-${pattern.patternGroup}-all`,
+ patternName: `View all ${_.startCase(pattern.patternGroup)}`,
+ patternPath: encodeURI(pattern.patternGroup + '/index.html'),
+ name: pattern.patternGroup,
+ isDocPattern: true,
+ order: Number.MAX_SAFE_INTEGER, // Or pattern.groupData.order
+ });
} else {
- patternType.patternItems.push(createPatternSubTypeItem(pattern));
+ patternGroup.patternItems.push(createPatternSubgroupItem(pattern));
}
- patternType.patternItems = _.sortBy(patternType.patternItems, [
- 'order',
- 'name',
- ]);
- }
-
- // function getPatternItems(patternlab, patternType) {
- // var patternType = _.find(patternlab.patternTypes, ['patternTypeLC', patternType]);
- // if (patternType) {
- // return patternType.patternItems;
- // }
- // return [];
- // }
-
- /**
- * Sorts patterns based on order property found within pattern markdown, falling back on name.
- * @param patternsArray - patterns to sort
- * @returns sorted patterns
- */
- function sortPatterns(patternsArray) {
- return patternsArray.sort(function(a, b) {
- let aOrder = parseInt(a.order, 10);
- const bOrder = parseInt(b.order, 10);
-
- if (aOrder === NaN) {
- aOrder = Number.MAX_SAFE_INTEGER;
- }
-
- if (bOrder === NaN) {
- aOrder = Number.MAX_SAFE_INTEGER;
- }
-
- //alwasy return a docPattern first
- if (a.isDocPattern && !b.isDocPattern) {
- return -1;
- }
-
- if (!a.isDocPattern && b.isDocPattern) {
- return 1;
- }
-
- //use old alphabetical ordering if we have nothing else to use
- //pattern.order will be Number.MAX_SAFE_INTEGER if never defined by markdown, or markdown parsing fails
- if (
- aOrder === Number.MAX_SAFE_INTEGER &&
- bOrder === Number.MAX_SAFE_INTEGER
- ) {
- if (a.name > b.name) {
- return 1;
- }
- if (a.name < b.name) {
- return -1;
- }
- }
-
- //if we get this far, we can sort safely
- if (aOrder && bOrder) {
- if (aOrder > bOrder) {
- return 1;
- }
- if (aOrder < bOrder) {
- return -1;
- }
- }
- return 0;
- });
+ patternGroup.patternItems = getSortedPatterns(patternGroup.patternItems);
}
/**
* Returns an object representing how the front end styleguide and navigation is structured
* @param patternlab - global data store
* @param uikit - the current uikit being built
- * @returns ptterns grouped by type -> subtype like atoms -> global -> pattern, pattern, pattern
+ * @returns patterns grouped by type -> subgroup like atoms -> global -> pattern, pattern, pattern
*/
function groupPatterns(patternlab, uikit) {
const groupedPatterns = {
patternGroups: {},
};
- _.forEach(patternlab.patterns, function(pattern) {
- //ignore patterns we can omit from rendering directly
+ _.forEach(patternlab.patterns, function (pattern) {
+ // ignore patterns we can omit from rendering directly
pattern.omitFromStyleguide = isPatternExcluded(
pattern,
patternlab,
@@ -463,43 +376,45 @@ const ui_builder = function() {
if (!groupedPatterns.patternGroups[pattern.patternGroup]) {
groupedPatterns.patternGroups[pattern.patternGroup] = {};
- pattern.isSubtypePattern = false;
- addPatternType(patternlab, pattern);
-
- //todo: Pattern Type View All and Documentation
- //groupedPatterns.patternGroups[pattern.patternGroup]['viewall-' + pattern.patternGroup] = injectDocumentationBlock(pattern, patternlab, false);
- addPatternItem(patternlab, pattern, true);
+ pattern.isSubgroupPattern = false;
+ addPatternGroup(patternlab, pattern);
+ if (
+ !pattern.isFlatPattern ||
+ patternlab.config.renderFlatPatternsOnViewAllPages
+ ) {
+ addPatternItem(patternlab, pattern, true);
+ }
+ addToViewAllPaths(patternlab, pattern);
}
- //continue building navigation for nested patterns
- if (pattern.patternGroup !== pattern.patternSubGroup) {
+ // continue building navigation for nested patterns
+ if (!pattern.isFlatPattern) {
if (
!groupedPatterns.patternGroups[pattern.patternGroup][
- pattern.patternSubGroup
+ pattern.patternSubgroup
]
) {
- addPatternSubType(patternlab, pattern);
+ addPatternSubgroup(patternlab, pattern);
- pattern.isSubtypePattern = !pattern.isPattern;
+ pattern.isSubgroupPattern = !pattern.isPattern;
groupedPatterns.patternGroups[pattern.patternGroup][
- pattern.patternSubGroup
+ pattern.patternSubgroup
] = {};
groupedPatterns.patternGroups[pattern.patternGroup][
- pattern.patternSubGroup
- ][
- 'viewall-' + pattern.patternGroup + '-' + pattern.patternSubGroup
- ] = injectDocumentationBlock(pattern, patternlab, true);
+ pattern.patternSubgroup
+ ]['viewall-' + pattern.patternGroup + '-' + pattern.patternSubgroup] =
+ injectDocumentationBlock(pattern, patternlab, true);
addToViewAllPaths(patternlab, pattern);
- addPatternSubTypeItem(patternlab, pattern, true);
+ addPatternSubgroupItem(patternlab, pattern, true);
}
groupedPatterns.patternGroups[pattern.patternGroup][
- pattern.patternSubGroup
+ pattern.patternSubgroup
][pattern.patternBaseName] = pattern;
addToPatternPaths(patternlab, pattern);
- addPatternSubTypeItem(patternlab, pattern);
+ addPatternSubgroupItem(patternlab, pattern);
} else {
addPatternItem(patternlab, pattern);
addToPatternPaths(patternlab, pattern);
@@ -509,9 +424,27 @@ const ui_builder = function() {
return groupedPatterns;
}
+ /**
+ * Search all flat patterns of a specific pattern type
+ *
+ * @param {Patternlab} patternlab Current patternlab instance
+ * @param {string} patternGroup indicator which patterns to search for
+ */
+ function getFlatPatternItems(patternlab, patternGroup) {
+ const patterns = _.filter(
+ patternlab.patterns,
+ (pattern) =>
+ pattern.patternGroup === patternGroup && pattern.isFlatPattern
+ );
+ if (patterns) {
+ return getSortedPatterns(patterns);
+ }
+ return [];
+ }
+
/**
* Takes a set of patterns and builds a viewall HTML page for them
- * Used by the type and subtype viewall sets
+ * Used by the type and subgroup viewall sets
* @param patternlab - global data store
* @param patterns - the set of patterns to build the viewall page for
* @param patternPartial - a key used to identify the viewall page
@@ -519,24 +452,63 @@ const ui_builder = function() {
*/
function buildViewAllHTML(patternlab, patterns, patternPartial, uikit) {
return render(
- Pattern.createEmpty({ extendedTemplate: uikit.viewAll }),
+ Pattern.createEmpty({ extendedTemplate: uikit.viewAll }, patternlab),
{
- //data
+ // data
partials: patterns,
patternPartial: 'viewall-' + patternPartial,
cacheBuster: patternlab.cacheBuster,
},
{
- //templates
+ // templates
patternSection: uikit.patternSection,
- patternSectionSubtype: uikit.patternSectionSubType,
+ patternSectionSubgroup: uikit.patternSectionSubgroup,
}
- ).catch(reason => {
+ ).catch((reason) => {
console.log(reason);
logger.error('Error building buildViewAllHTML');
});
}
+ /**
+ * Sorts the pattern groups for the view all page as they are meant to be sorted.
+ * Therefore the function searches for the subgroup in the patternGroupItems and retrieves its sorting.
+ * @param patternGroup The pattern group object with it's subgroups
+ * @param patternGroupName the pattern group name e.g. atoms
+ * @param patternlab - global data store
+ * @returns a sorted list of pattern groups
+ */
+ function getSortedPatternSubgroups(
+ patternGroup,
+ patternGroupName,
+ patternlab
+ ) {
+ return _.sortBy(_.values(patternGroup), [
+ (pSubgroup) => {
+ const group = patternlab.patternGroups.find(
+ (g) => g.patternGroup === patternGroupName
+ );
+
+ if (group) {
+ const sg = group.patternGroupItems.find((item) => {
+ const firstPattern = _.first(
+ _.values(pSubgroup).filter((p) => p.patternBaseName !== '.')
+ );
+ return (
+ item &&
+ firstPattern &&
+ firstPattern.patternSubgroup === item.patternSubgroup
+ );
+ });
+
+ return sg ? sg.order : 0;
+ } else {
+ return 0;
+ }
+ },
+ ]);
+ }
+
/**
* Constructs viewall pages for each set of grouped patterns
* @param mainPageHeadHtml - the already built main page HTML
@@ -552,255 +524,302 @@ const ui_builder = function() {
) {
const paths = patternlab.config.paths;
let patterns = [];
- let writeViewAllFile = true;
-
- //loop through the grouped styleguide patterns, building at each level
- const allPatternTypePromises = _.map(
- styleguidePatterns.patternGroups,
- (patternGroup, patternType) => {
- let typePatterns = [];
- let styleguideTypePatterns = [];
- const styleGuideExcludes =
- patternlab.config.styleGuideExcludes ||
- patternlab.config.styleguideExcludes;
- const subTypePromises = _.map(
- _.values(patternGroup),
- (patternSubtypes, patternSubtype, originalPatternGroup) => {
+
+ // loop through the grouped styleguide patterns, building at each level
+ const allPatternGroupPromises = _.map(
+ patternlab.patternGroups,
+ (patternGroup) => {
+ const patternGroupName = patternGroup.patternGroup;
+ const group = styleguidePatterns.patternGroups[patternGroupName];
+ let groupedPatterns = [];
+ let styleguideGroupedPatterns = [];
+ const styleGuideExcludes = patternlab.config.styleGuideExcludes || [];
+
+ /**
+ * View all pages for subgroups
+ */
+ const subgroupPromises = _.map(
+ getSortedPatternSubgroups(group, patternGroupName, patternlab),
+ (patternSubgroups, patternSubgroup, originalPatternGroup) => {
let p;
- const samplePattern = _.find(patternSubtypes, st => {
- return !st.patternPartial.startsWith('viewall-');
- });
+ const samplePattern = _.find(
+ patternSubgroups,
+ (st) => !st.patternPartial.startsWith('viewall-')
+ );
const patternName = Object.keys(
- _.values(originalPatternGroup)[patternSubtype]
+ _.values(originalPatternGroup)[patternSubgroup]
)[1];
const patternPartial =
- patternType + '-' + samplePattern.patternSubType;
+ patternGroupName + '-' + samplePattern.patternSubgroup;
- //do not create a viewall page for flat patterns
- if (patternType === patternName) {
- writeViewAllFile = false;
+ // do not create a viewall page for flat patterns
+ if (patternGroupName === patternName) {
logger.debug(
- `skipping ${patternType} as flat patterns do not have view all pages`
+ `skipping ${patternGroupName} as flat patterns do not have view all pages`
);
return Promise.resolve();
}
- //render the footer needed for the viewall template
+ // render the footer needed for the viewall template
return buildFooter(patternlab, `viewall-${patternPartial}`, uikit)
- .then(footerHTML => {
- //render the viewall template by finding these smallest subtype-grouped patterns
- const subtypePatterns = sortPatterns(_.values(patternSubtypes));
+ .then((footerHTML) => {
+ // render the viewall template by finding these smallest subgroup-grouped patterns
+ const subgroupPatterns = getSortedPatterns(
+ _.values(patternSubgroups)
+ );
- //determine if we should write at this time by checking if these are flat patterns or grouped patterns
- p = _.find(subtypePatterns, function(pat) {
+ // determine if we should write at this time by checking if these are flat patterns or grouped patterns
+ p = _.find(subgroupPatterns, function (pat) {
return pat.isDocPattern;
});
- //determine if we should omit this subpatterntype completely from the viewall page
- const omitPatternType =
+ // determine if we should omit this subpatternGroup completely from the viewall page
+ const omitPatternGroup =
styleGuideExcludes &&
styleGuideExcludes.length &&
- _.some(styleGuideExcludes, function(exclude) {
- return exclude === patternType + '/' + patternName;
- });
- if (omitPatternType) {
+ _.some(
+ styleGuideExcludes,
+ (exclude) =>
+ exclude === `${patternGroupName}/${patternName}`
+ );
+ if (omitPatternGroup) {
logger.debug(
- `Omitting ${patternType}/${patternName} from building a viewall page because its patternSubGroup is specified in styleguideExcludes.`
+ `Omitting ${patternGroupName}/${patternName} from building a viewall page because its patternSubgroup is specified in styleguideExcludes.`
);
} else {
- styleguideTypePatterns = styleguideTypePatterns.concat(
- subtypePatterns
- );
+ styleguideGroupedPatterns =
+ styleguideGroupedPatterns.concat(subgroupPatterns);
}
- typePatterns = typePatterns.concat(subtypePatterns);
+ groupedPatterns = groupedPatterns.concat(subgroupPatterns);
- //render the viewall template for the subtype
+ // render the viewall template for the subgroup
return buildViewAllHTML(
patternlab,
- subtypePatterns,
+ subgroupPatterns,
patternPartial,
uikit
)
- .then(viewAllHTML => {
+ .then((viewAllHTML) => {
return fs.outputFile(
path.join(
process.cwd(),
uikit.outputDir,
- paths.public.patterns +
- p.flatPatternPath +
- '/index.html'
+ path.join(
+ `${paths.public.patterns}${p.flatPatternPath}`,
+ 'index.html'
+ )
),
mainPageHeadHtml + viewAllHTML + footerHTML
);
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('Error building ViewAllHTML');
});
})
- .then(() => {
- //do not create a viewall page for flat patterns
- if (!writeViewAllFile || !p) {
+ .catch((reason) => {
+ console.log(reason);
+ logger.error('Error building footer HTML');
+ });
+ }
+ );
+
+ /**
+ * View all pages for groups
+ */
+ return Promise.all(subgroupPromises)
+ .then(() => {
+ // render the footer needed for the viewall template
+ return buildFooter(
+ patternlab,
+ `viewall-${patternGroupName}-all`,
+ uikit
+ )
+ .then((footerHTML) => {
+ const sortedFlatPatterns = getFlatPatternItems(
+ patternlab,
+ patternGroupName
+ );
+
+ if (patternlab.config.renderFlatPatternsOnViewAllPages) {
+ // Check if this is a flat pattern group
+ groupedPatterns = sortedFlatPatterns.concat(groupedPatterns);
+ }
+
+ // get the appropriate patternGroup
+ const anyPatternOfType = _.find(
+ groupedPatterns,
+ function (pat) {
+ return pat.patternGroup && pat.patternGroup !== '';
+ }
+ );
+
+ if (!anyPatternOfType || !groupedPatterns.length) {
logger.debug(
- `skipping ${patternType} as flat patterns do not have view all pages`
+ `skipping ${patternGroupName} as flat patterns do not have view all pages`
);
- return Promise.resolve();
+ return Promise.resolve([]);
}
- //render the footer needed for the viewall template
- return buildFooter(
+ // render the viewall template for the type
+ return buildViewAllHTML(
patternlab,
- 'viewall-' + patternType + '-all',
+ groupedPatterns,
+ patternGroupName,
uikit
)
- .then(footerHTML => {
- //add any flat patterns
- //todo this isn't quite working yet
- //typePatterns = typePatterns.concat(getPatternItems(patternlab, patternType));
-
- //get the appropriate patternType
- const anyPatternOfType = _.find(typePatterns, function(
- pat
- ) {
- return pat.patternType && pat.patternType !== '';
- });
-
- if (!anyPatternOfType) {
+ .then((viewAllHTML) => {
+ fs.outputFileSync(
+ path.join(
+ process.cwd(),
+ uikit.outputDir,
+ path.join(
+ `${paths.public.patterns}${patternGroupName}`,
+ 'index.html'
+ )
+ ),
+ mainPageHeadHtml + viewAllHTML + footerHTML
+ );
+
+ // determine if we should omit this patternGroup completely from the viewall page
+ const omitPatternGroup =
+ styleGuideExcludes &&
+ styleGuideExcludes.length &&
+ _.some(styleGuideExcludes, function (exclude) {
+ return exclude === patternGroupName;
+ });
+ if (omitPatternGroup) {
logger.debug(
- `skipping ${patternType} as flat patterns do not have view all pages`
+ `Omitting ${patternGroupName} from building a viewall page because its patternGroup is specified in styleguideExcludes.`
);
- return Promise.resolve();
+ } else {
+ if (patternlab.config.renderFlatPatternsOnViewAllPages) {
+ patterns = sortedFlatPatterns;
+ patterns = patterns.concat(styleguideGroupedPatterns);
+ } else {
+ patterns = styleguideGroupedPatterns;
+ }
}
-
- //render the viewall template for the type
- return buildViewAllHTML(
- patternlab,
- typePatterns,
- patternType,
- uikit
- )
- .then(viewAllHTML => {
- fs.outputFileSync(
- path.join(
- process.cwd(),
- uikit.outputDir,
- paths.public.patterns +
- anyPatternOfType.patternType +
- '/index.html'
- ),
- mainPageHeadHtml + viewAllHTML + footerHTML
- );
-
- //determine if we should omit this patterntype completely from the viewall page
- const omitPatternType =
- styleGuideExcludes &&
- styleGuideExcludes.length &&
- _.some(styleGuideExcludes, function(exclude) {
- return exclude === patternType;
- });
- if (omitPatternType) {
- logger.debug(
- `Omitting ${patternType} from building a viewall page because its patternGroup is specified in styleguideExcludes.`
- );
- } else {
- patterns = patterns.concat(styleguideTypePatterns);
- }
- return Promise.resolve(patterns);
- })
- .catch(reason => {
- console.log(reason);
- logger.error('Error building ViewAllHTML');
- });
+ return Promise.resolve(patterns);
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
- logger.error('Error building footerHTML');
+ logger.error('Error building ViewAllHTML');
});
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
- logger.error('Error building footer HTML');
+ logger.error('Error building footerHTML');
});
- }
- );
-
- return Promise.all(subTypePromises).catch(reason => {
- console.log(reason);
- logger.error('Error during buildViewAllPages');
- });
+ })
+ .catch((reason) => {
+ console.log(reason);
+ logger.error('Error during buildViewAllPages');
+ });
}
);
- return Promise.all(allPatternTypePromises).catch(reason => {
- console.log(reason);
- logger.error('Error during buildViewAllPages');
- });
+ return Promise.all(allPatternGroupPromises)
+ .then((allPatterns) =>
+ Promise.resolve(_.filter(allPatterns, (p) => p.length))
+ )
+ .catch((reason) => {
+ console.log(reason);
+ logger.error('Error during buildViewAllPages');
+ });
}
/**
* Reset any global data we use between builds to guard against double adding things
+ *
+ * @param {Patternlab} patternlab Actual patternlab instance
*/
function resetUIBuilderState(patternlab) {
patternlab.patternPaths = {};
patternlab.viewAllPaths = {};
- patternlab.patternTypes = [];
+ patternlab.patternGroups = [];
+ }
+
+ /**
+ * Uniques all generated patterns and groups, also adds a group document pattern before
+ * each group. Used for generating view all page and all its pattern.
+ *
+ * @param {[Pattern[]]} allPatterns All generated patterns
+ * @param {Patternlab} patternlab Actual patternlab instance
+ */
+ function uniqueAllPatterns(allPatterns, patternlab) {
+ return _.uniq(
+ _.flatMapDeep(
+ _.map(allPatterns, (patterns) => [
+ injectDocumentationBlock(
+ _.find(patterns, (p) => !p.patternPartial.startsWith('viewall-')),
+ patternlab,
+ false
+ ),
+ ...patterns,
+ ]),
+ (pattern) => pattern
+ )
+ );
}
/**
* The main entry point for ui_builder
- * @param patternlab - global data store
+ * @param patternlabGlobal - global data store
* @returns {Promise} a promise fulfilled when build is complete
*/
- function buildFrontend(patternlab) {
- resetUIBuilderState(patternlab);
+ function buildFrontend(patternlabGlobal) {
+ const paths = patternlabGlobal.config.paths;
- const paths = patternlab.config.paths;
+ const uikitPromises = _.map(patternlabGlobal.uikits, (uikit) => {
+ //we need to make sure the patternlab object gets manipulated per uikit
+ const patternlab = Object.assign({}, patternlabGlobal);
- const uikitPromises = _.map(patternlab.uikits, uikit => {
+ resetUIBuilderState(patternlab);
//determine which patterns should be included in the front-end rendering
const styleguidePatterns = groupPatterns(patternlab, uikit);
- return new Promise(resolve => {
- //set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
+ return new Promise((resolve) => {
+ // set the pattern-specific header by compiling the general-header with data, and then adding it to the meta header
const headerPromise = render(
- Pattern.createEmpty({ extendedTemplate: uikit.header }),
+ Pattern.createEmpty({ extendedTemplate: uikit.header }, patternlab),
{
cacheBuster: patternlab.cacheBuster,
}
)
- .then(headerPartial => {
+ .then((headerPartial) => {
const headFootData = patternlab.data;
headFootData.patternLabHead = headerPartial;
headFootData.cacheBuster = patternlab.cacheBuster;
return render(patternlab.userHead, headFootData);
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('error during header render()');
});
- //set the pattern-specific footer by compiling the general-footer with data, and then adding it to the meta footer
+ // set the pattern-specific footer by compiling the general-footer with data, and then adding it to the meta footer
const footerPromise = render(
- Pattern.createEmpty({ extendedTemplate: uikit.footer }),
+ Pattern.createEmpty({ extendedTemplate: uikit.footer }, patternlab),
{
patternData: '{}',
cacheBuster: patternlab.cacheBuster,
}
)
- .then(footerPartial => {
+ .then((footerPartial) => {
const headFootData = patternlab.data;
headFootData.patternLabFoot = footerPartial;
return render(patternlab.userFoot, headFootData);
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('error during footer render()');
});
return Promise.all([headerPromise, footerPromise]).then(
- headFootPromiseResults => {
- //build the viewall pages
+ (headFootPromiseResults) => {
+ // build the viewall pages
return buildViewAllPages(
headFootPromiseResults[0],
@@ -808,34 +827,36 @@ const ui_builder = function() {
styleguidePatterns,
uikit
)
- .then(allPatterns => {
- //todo track down why we need to make this unique in the first place
- const uniquePatterns = _.uniq(
- _.flatMapDeep(allPatterns, pattern => {
- return pattern;
- })
+ .then((allPatterns) => {
+ // todo track down why we need to make this unique in the first place
+ const uniquePatterns = uniqueAllPatterns(
+ allPatterns,
+ patternlab
);
- //add the defaultPattern if we found one
+ // add the defaultPattern if we found one
if (patternlab.defaultPattern) {
uniquePatterns.push(patternlab.defaultPattern);
addToPatternPaths(patternlab, patternlab.defaultPattern);
}
- //build the main styleguide page
+ // build the main styleguide page
return render(
- Pattern.createEmpty({
- extendedTemplate: uikit.viewAll,
- }),
+ Pattern.createEmpty(
+ {
+ extendedTemplate: uikit.viewAll,
+ },
+ patternlab
+ ),
{
partials: uniquePatterns,
},
{
patternSection: uikit.patternSection,
- patternSectionSubtype: uikit.patternSectionSubType,
+ patternSectionSubgroup: uikit.patternSectionSubgroup,
}
)
- .then(styleguideHtml => {
+ .then((styleguideHtml) => {
fs.outputFileSync(
path.resolve(
path.join(
@@ -852,7 +873,7 @@ const ui_builder = function() {
logger.info('Built Pattern Lab front end');
- //move the index file from its asset location into public root
+ // move the index file from its asset location into public root
let patternlabSiteHtml;
try {
patternlabSiteHtml = fs.readFileSync(
@@ -867,9 +888,7 @@ const ui_builder = function() {
);
} catch (err) {
logger.error(
- `Could not load one or more styleguidekit assets from ${
- paths.source.styleguide
- }`
+ `Could not load one or more styleguidekit assets from ${paths.source.styleguide}`
);
}
fs.outputFileSync(
@@ -885,15 +904,15 @@ const ui_builder = function() {
);
//write out patternlab.data object to be read by the client
- exportData(patternlab);
+ exportData(patternlab, uikit);
resolve();
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('error during buildFrontend()');
});
})
- .catch(reason => {
+ .catch((reason) => {
console.log(reason);
logger.error('error during buildViewAllPages()');
});
@@ -905,31 +924,12 @@ const ui_builder = function() {
}
return {
- buildFrontend: function(patternlab) {
- return buildFrontend(patternlab);
- },
- isPatternExcluded: function(pattern, patternlab, uikit) {
- return isPatternExcluded(pattern, patternlab, uikit);
- },
- groupPatterns: function(patternlab, uikit) {
- return groupPatterns(patternlab, uikit);
- },
- resetUIBuilderState: function(patternlab) {
- resetUIBuilderState(patternlab);
- },
- buildViewAllPages: function(
- mainPageHeadHtml,
- patternlab,
- styleguidePatterns,
- uikit
- ) {
- return buildViewAllPages(
- mainPageHeadHtml,
- patternlab,
- styleguidePatterns,
- uikit
- );
- },
+ buildFrontend: buildFrontend,
+ isPatternExcluded: isPatternExcluded,
+ groupPatterns: groupPatterns,
+ resetUIBuilderState: resetUIBuilderState,
+ uniqueAllPatterns: uniqueAllPatterns,
+ buildViewAllPages: buildViewAllPages,
};
};
diff --git a/packages/core/src/lib/uikitExcludePattern.js b/packages/core/src/lib/uikitExcludePattern.js
index 61cddcb57..22aa3eece 100644
--- a/packages/core/src/lib/uikitExcludePattern.js
+++ b/packages/core/src/lib/uikitExcludePattern.js
@@ -1,7 +1,14 @@
'use strict';
+const _ = require('lodash');
+
const uikitExcludePattern = (pattern, uikit) => {
const state = pattern.patternState;
- return uikit.excludedPatternStates.includes(state);
+ const tags = _.isArray(pattern.tags) ? pattern.tags : [pattern.tags];
+
+ return (
+ _.includes(uikit.excludedPatternStates, state) ||
+ _.intersection(uikit.excludedTags, tags).length > 0
+ );
};
module.exports = uikitExcludePattern;
diff --git a/packages/core/src/lib/watchAssets.js b/packages/core/src/lib/watchAssets.js
index f087b8a28..6f07626e7 100644
--- a/packages/core/src/lib/watchAssets.js
+++ b/packages/core/src/lib/watchAssets.js
@@ -10,7 +10,7 @@ let copyFile = require('./copyFile'); // eslint-disable-line prefer-const
function onWatchTripped(patternlab, p, assetBase, basePath, dir, copyOptions) {
const subPath = p.replace(assetBase, '');
- _.each(patternlab.uikits, uikit => {
+ _.each(patternlab.uikits, (uikit) => {
const destination = path.resolve(
basePath,
uikit.outputDir,
@@ -57,10 +57,10 @@ const watchAssets = (
//watch for changes and copy
assetWatcher
- .on('add', p => {
+ .on('add', (p) => {
onWatchTripped(patternlab, p, assetBase, basePath, dir, copyOptions);
})
- .on('change', p => {
+ .on('change', (p) => {
onWatchTripped(patternlab, p, assetBase, basePath, dir, copyOptions);
});
diff --git a/packages/core/src/lib/watchPatternLabFiles.js b/packages/core/src/lib/watchPatternLabFiles.js
index 7a1c390c2..c2eb681ab 100644
--- a/packages/core/src/lib/watchPatternLabFiles.js
+++ b/packages/core/src/lib/watchPatternLabFiles.js
@@ -4,6 +4,8 @@ const path = require('path');
const logger = require('./log');
const events = require('./events');
+const pm = require('./plugin_manager');
+const pluginMananger = new pm();
let chokidar = require('chokidar'); // eslint-disable-line prefer-const
@@ -18,12 +20,12 @@ const watchPatternLabFiles = (
assetDirectories.source.data,
assetDirectories.source.meta,
];
- const globalPaths = globalSources.map(globalSource =>
- path.join(basePath, globalSource, '*')
+ const globalPaths = globalSources.map((globalSource) =>
+ path.join(path.resolve(basePath, globalSource), '*')
);
- _.each(globalPaths, globalPath => {
- logger.debug(`Pattern Lab is watching ${globalPath} for changes`);
+ _.each(globalPaths, (globalPath) => {
+ logger.debug(`Pattern Lab is watching ${globalPath} for changes!`);
if (patternlab.watchers[globalPath]) {
patternlab.watchers[globalPath].close();
@@ -41,20 +43,32 @@ const watchPatternLabFiles = (
//watch for changes and rebuild
globalWatcher
- .on('addDir', p => {
- patternlab.events.emit(events.PATTERNLAB_GLOBAL_CHANGE, {
- file: p,
- });
+ .on('addDir', async (p) => {
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_GLOBAL_CHANGE,
+ {
+ file: p,
+ }
+ );
})
- .on('add', p => {
- patternlab.events.emit(events.PATTERNLAB_GLOBAL_CHANGE, {
- file: p,
- });
+ .on('add', async (p) => {
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_GLOBAL_CHANGE,
+ {
+ file: p,
+ }
+ );
})
- .on('change', p => {
- patternlab.events.emit(events.PATTERNLAB_GLOBAL_CHANGE, {
- file: p,
- });
+ .on('change', async (p) => {
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_GLOBAL_CHANGE,
+ {
+ file: p,
+ }
+ );
});
patternlab.watchers[globalPath] = globalWatcher;
@@ -64,15 +78,16 @@ const watchPatternLabFiles = (
const baseFileExtensions = ['.json', '.yml', '.yaml', '.md'];
const patternWatches = baseFileExtensions
.concat(patternlab.engines.getSupportedFileExtensions())
- .map(dotExtension =>
+ .map((dotExtension) =>
path.join(
- basePath,
- assetDirectories.source.patterns,
+ path.resolve(basePath, assetDirectories.source.patterns),
`/**/*${dotExtension}`
)
);
- _.each(patternWatches, patternWatchPath => {
- logger.debug(`Pattern Lab is watching ${patternWatchPath} for changes`);
+ _.each(patternWatches, (patternWatchPath) => {
+ logger.debug(
+ `Pattern Lab is watching ${patternWatchPath} for changes - local!`
+ );
if (patternlab.watchers[patternWatchPath]) {
patternlab.watchers[patternWatchPath].close();
@@ -90,29 +105,62 @@ const watchPatternLabFiles = (
//watch for changes and rebuild
patternWatcher
- .on('addDir', p => {
- patternlab.events.emit(events.PATTERNLAB_PATTERN_CHANGE, {
- file: p,
- });
+ .on('addDir', async (p) => {
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_PATTERN_CHANGE,
+ {
+ file: p,
+ }
+ );
+ })
+ .on('add', async (p) => {
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_PATTERN_CHANGE,
+ {
+ file: p,
+ }
+ );
})
- .on('add', p => {
- patternlab.events.emit(events.PATTERNLAB_PATTERN_CHANGE, {
- file: p,
- });
+ .on('change', async (p) => {
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_PATTERN_CHANGE,
+ {
+ file: p,
+ }
+ );
})
- .on('change', p => {
- patternlab.events.emit(events.PATTERNLAB_PATTERN_CHANGE, {
- file: p,
- });
+ // the watcher does not react on unlink and unlinkDir
+ // events, so patterns are never removed
+ .on('unlink', async (p) => {
+ patternlab.graph.sync();
+ patternlab.graph.upgradeVersion();
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_PATTERN_CHANGE,
+ {
+ file: p,
+ }
+ );
+ })
+ .on('unlinkDir', async (p) => {
+ patternlab.graph.sync();
+ patternlab.graph.upgradeVersion();
+ await pluginMananger.raiseEvent(
+ patternlab,
+ events.PATTERNLAB_PATTERN_CHANGE,
+ {
+ file: p,
+ }
+ );
});
-
patternlab.watchers[patternWatchPath] = patternWatcher;
});
logger.info(
- `Pattern Lab is watching for changes to files under ${
- assetDirectories.source.root
- }`
+ `Pattern Lab is watching for changes to files under ${assetDirectories.source.root}`
);
return Promise.resolve();
};
diff --git a/packages/core/test/addPattern_tests.js b/packages/core/test/addPattern_tests.js
index 0957e43e0..cf495cccb 100644
--- a/packages/core/test/addPattern_tests.js
+++ b/packages/core/test/addPattern_tests.js
@@ -10,11 +10,11 @@ const patterns_dir = './test/files/_patterns';
tap.test(
'addPattern - adds pattern extended template to patternlab partial object',
- function(test) {
+ function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
- var pattern = new Pattern('00-test/01-bar.mustache');
+ var pattern = new Pattern('test/bar.mustache');
pattern.extendedTemplate = 'barExtended';
pattern.template = 'bar';
@@ -22,20 +22,20 @@ tap.test(
addPattern(pattern, patternlab);
//assert
- test.equals(patternlab.patterns.length, 1);
- test.equals(patternlab.partials['test-bar'] !== undefined, true);
- test.equals(patternlab.partials['test-bar'], 'barExtended');
+ test.equal(patternlab.patterns.length, 1);
+ test.equal(patternlab.partials['test-bar'] !== undefined, true);
+ test.equal(patternlab.partials['test-bar'], 'barExtended');
test.end();
}
);
tap.test(
'addPattern - adds pattern template to patternlab partial object if extendedtemplate does not exist yet',
- function(test) {
+ function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
- var pattern = new Pattern('00-test/01-bar.mustache');
+ var pattern = new Pattern('test/bar.mustache');
pattern.extendedTemplate = undefined;
pattern.template = 'bar';
@@ -43,9 +43,9 @@ tap.test(
addPattern(pattern, patternlab);
//assert
- test.equals(patternlab.patterns.length, 1);
- test.equals(patternlab.partials['test-bar'] !== undefined, true);
- test.equals(patternlab.partials['test-bar'], 'bar');
+ test.equal(patternlab.patterns.length, 1);
+ test.equal(patternlab.partials['test-bar'] !== undefined, true);
+ test.equal(patternlab.partials['test-bar'], 'bar');
test.end();
}
);
diff --git a/packages/core/test/annotation_exporter_tests.js b/packages/core/test/annotation_exporter_tests.js
index 68c7b2f48..9fe95a1f6 100644
--- a/packages/core/test/annotation_exporter_tests.js
+++ b/packages/core/test/annotation_exporter_tests.js
@@ -20,35 +20,35 @@ function createFakePatternLab(anPath, customProps) {
}
var patternlab = createFakePatternLab(anPath);
-var ae = require('../src/lib/annotation_exporter')(patternlab);
+var ae = require('../src/lib/annotationExporter')(patternlab);
-tap.test('converts old JS annotations into new format', function(test) {
+tap.test('converts old JS annotations into new format', function (test) {
//arrange
//act
- var annotations = ae.gatherJS();
+ var annotations = ae.gatherJSON();
//assert
- test.equals(annotations.length, 2);
- test.equals(annotations[1].el, '.logo');
- test.equals(annotations[1].title, 'Logo');
- test.equals(
+ test.equal(annotations.length, 2);
+ test.equal(annotations[1].el, '.logo');
+ test.equal(annotations[1].title, 'Logo');
+ test.equal(
annotations[1].comment,
- 'The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don\'t support SVG images.
Further reading: Optimizing Web Experiences for High Resolution Screens
'
+ 'The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don\'t support SVG images.Further reading: Optimizing Web Experiences for High Resolution Screens
'
);
test.end();
});
-tap.test('converts new markdown annotations into an array', function(test) {
+tap.test('converts new markdown annotations into an array', function (test) {
//arrange
//act
var annotations = ae.gatherMD();
//assert
- test.equals(annotations.length, 3);
- test.equals(annotations[1].el, '.logo');
- test.equals(annotations[1].title, 'Logo');
- test.equals(
+ test.equal(annotations.length, 3);
+ test.equal(annotations[1].el, '.logo');
+ test.equal(annotations[1].title, 'Logo');
+ test.equal(
annotations[1].comment.replace(/\r?\n|\r/gm, ''),
'The logo image is an SVG file.
'
);
@@ -56,17 +56,17 @@ tap.test('converts new markdown annotations into an array', function(test) {
test.end();
});
-tap.test('merges both annotation methods into one array', function(test) {
+tap.test('merges both annotation methods into one array', function (test) {
//arrange
//act
var annotations = ae.gather();
//assert
- test.equals(annotations.length, 3);
- test.equals(annotations[2].el, '#nav');
- test.equals(annotations[2].title, 'Navigation');
- test.equals(
+ test.equal(annotations.length, 3);
+ test.equal(annotations[2].el, '#nav');
+ test.equal(annotations[2].title, 'Navigation');
+ test.equal(
annotations[2].comment.replace(/\r?\n|\r/gm, ''),
'Navigation for adaptive web experiences can be tricky. Refer to these repsonsive patterns when evaluating solutions.
'
);
@@ -74,12 +74,12 @@ tap.test('merges both annotation methods into one array', function(test) {
test.end();
});
-tap.test('when there are 0 annotation files', function(test) {
+tap.test('when there are 0 annotation files', function (test) {
var emptyAnPath = './test/files/empty/';
var patternlab2 = createFakePatternLab(emptyAnPath);
- var ae2 = require('../src/lib/annotation_exporter')(patternlab2);
+ var ae2 = require('../src/lib/annotationExporter')(patternlab2);
var annotations = ae2.gather();
- test.equals(annotations.length, 0);
+ test.equal(annotations.length, 0);
test.end();
});
diff --git a/packages/core/test/buildListItems_tests.js b/packages/core/test/buildListItems_tests.js
index 757c8f1aa..720e4a604 100644
--- a/packages/core/test/buildListItems_tests.js
+++ b/packages/core/test/buildListItems_tests.js
@@ -7,7 +7,7 @@ const listItems = require('./files/_data/listitems.json');
const buildlistItems = rewire('../src/lib/buildListItems');
const _Mock = {
- shuffle: function(list) {
+ shuffle: function (list) {
return list;
},
};
@@ -19,9 +19,9 @@ buildlistItems.__set__({
tap.test(
'buildlistItems transforms container of listItems with one value',
- test => {
+ (test) => {
// do this to avoid the shuffling for now
- const container = Object.assign({}, { listitems: { '1': listItems['1'] } });
+ const container = Object.assign({}, { listitems: { 1: listItems['1'] } });
buildlistItems(container);
test.same(container.listitems, {
'listItems-one': [
@@ -38,7 +38,7 @@ tap.test(
tap.test(
'buildlistItems transforms container of listItems with three values',
- test => {
+ (test) => {
// do this to avoid the shuffling for now
const container = { listitems: listItems };
buildlistItems(container);
diff --git a/packages/core/test/changes_hunter_tests.js b/packages/core/test/changes_hunter_tests.js
index 68b6c054d..a9050af0a 100644
--- a/packages/core/test/changes_hunter_tests.js
+++ b/packages/core/test/changes_hunter_tests.js
@@ -6,7 +6,7 @@ const rewire = require('rewire');
const ch = rewire('../src/lib/changes_hunter');
const fsMock = {
- statSync: function() {
+ statSync: function () {
return {
mtime: {
getTime: () => {
@@ -27,41 +27,41 @@ ch.__set__({
const changes_hunter = new ch();
-tap.test('checkLastModified - sets lastModified to fileTime ', function(test) {
+tap.test('checkLastModified - sets lastModified to fileTime ', function (test) {
//arrange
const mockPattern = { lastModified: 0 };
//act
changes_hunter.checkLastModified(mockPattern, {});
//assert
- test.equals(mockPattern.lastModified, 100);
+ test.equal(mockPattern.lastModified, 100);
test.end();
});
tap.test(
'checkLastModified - does not alter pattern if file not found',
- function(test) {
+ function (test) {
//arrange
const mockPattern = { lastModified: 1010 };
//act
changes_hunter.checkLastModified(mockPattern, null);
//assert
- test.equals(mockPattern.lastModified, 1010);
+ test.equal(mockPattern.lastModified, 1010);
test.end();
}
);
tap.test(
'checkLastModified - uses pattern.lastModified if greater than file time',
- function(test) {
+ function (test) {
//arrange
const mockPattern = { lastModified: 101 };
//act
changes_hunter.checkLastModified(mockPattern, {});
//assert
- test.equals(mockPattern.lastModified, 101);
+ test.equal(mockPattern.lastModified, 101);
test.end();
}
);
diff --git a/packages/core/test/copier_tests.js b/packages/core/test/copier_tests.js
index 388300a01..b7e57af3d 100644
--- a/packages/core/test/copier_tests.js
+++ b/packages/core/test/copier_tests.js
@@ -52,7 +52,7 @@ function createFakePatternLab(customProps) {
tap.test(
'transformConfigPaths takes configuration.paths() and maps to a better key store',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({});
@@ -60,10 +60,10 @@ tap.test(
var result = copier.transformConfigPaths(patternlab.config.paths);
//assert
- test.equals(result.img.source, './test/img');
- test.equals(result.img.public, './test/output/img');
- test.equals(result.css.source, './test/css');
- test.equals(result.css.public, './test/output/css');
+ test.equal(result.img.source, './test/img');
+ test.equal(result.img.public, './test/output/img');
+ test.equal(result.css.source, './test/css');
+ test.equal(result.css.public, './test/output/css');
test.end();
}
);
diff --git a/packages/core/test/data_loader_tests.js b/packages/core/test/data_loader_tests.js
index 9eaa8864b..2eae23311 100644
--- a/packages/core/test/data_loader_tests.js
+++ b/packages/core/test/data_loader_tests.js
@@ -2,12 +2,12 @@
const tap = require('tap');
-tap.test('loadDataFromFile - Load ', function(test) {
+tap.test('loadDataFromFile - Load ', function (test) {
const fs = require('fs-extra'),
dataLoader = require('../src/lib/data_loader')(),
data_dir = `${__dirname}/files/_data/`;
let data = dataLoader.loadDataFromFile(data_dir + 'foo', fs);
- test.equals(data.foo, 'bar');
+ test.equal(data.foo, 'bar');
test.end();
});
diff --git a/packages/core/test/engine_handlebars_tests.js b/packages/core/test/engine_handlebars_tests.js
index d268c1c63..8e5d3c34e 100644
--- a/packages/core/test/engine_handlebars_tests.js
+++ b/packages/core/test/engine_handlebars_tests.js
@@ -24,7 +24,7 @@ engineLoader.loadAllEngines(config);
// don't run these tests unless handlebars is installed
if (!engineLoader.handlebars) {
- tap.test('Handlebars engine not installed, skipping tests.', function(test) {
+ tap.test('Handlebars engine not installed, skipping tests.', function (test) {
test.end();
});
return;
@@ -61,9 +61,9 @@ function testFindPartials(test, partialTests) {
// setup current pattern from what we would have during execution
// docs on partial syntax are here:
- // http://patternlab.io/docs/pattern-including.html
+ // https://patternlab.io/docs/including-patterns/
var currentPattern = Pattern.create(
- '01-molecules/00-testing/00-test-mol.hbs', // relative path now
+ 'molecules/testing/test-mol.hbs', // relative path now
null, // data
{
template: partialTests.join(),
@@ -74,27 +74,27 @@ function testFindPartials(test, partialTests) {
var results = currentPattern.findPartials();
// assert
- test.equals(results.length, partialTests.length);
- partialTests.forEach(function(testString, index) {
- test.equals(results[index], testString);
+ test.equal(results.length, partialTests.length);
+ partialTests.forEach(function (testString, index) {
+ test.equal(results[index], testString);
});
test.end();
}
-tap.test('hello world handlebars pattern renders', function(test) {
+tap.test('hello world handlebars pattern renders', function (test) {
test.plan(1);
- var patternPath = path.join('00-atoms', '00-global', '00-helloworld.hbs');
+ var patternPath = path.join('atoms', 'global', 'helloworld.hbs');
// do all the normal processing of the pattern
var patternlab = new fakePatternLab();
var helloWorldPattern = loadPattern(patternPath, patternlab);
- processIterative(helloWorldPattern, patternlab).then(helloWorldPattern => {
+ processIterative(helloWorldPattern, patternlab).then((helloWorldPattern) => {
processRecursive(patternPath, patternlab).then(() => {
- helloWorldPattern.render().then(results => {
- test.equals(results, 'Hello world!' + eol);
+ helloWorldPattern.render().then((results) => {
+ test.equal(results, 'Hello world!' + eol);
test.end();
});
});
@@ -103,16 +103,12 @@ tap.test('hello world handlebars pattern renders', function(test) {
tap.test(
'hello worlds handlebars pattern can see the atoms-helloworld partial and renders it twice',
- function(test) {
+ function (test) {
test.plan(1);
// pattern paths
- var pattern1Path = path.join('00-atoms', '00-global', '00-helloworld.hbs');
- var pattern2Path = path.join(
- '00-molecules',
- '00-global',
- '00-helloworlds.hbs'
- );
+ var pattern1Path = path.join('atoms', 'global', 'helloworld.hbs');
+ var pattern2Path = path.join('molecules', 'global', 'helloworlds.hbs');
// set up environment
var patternlab = new fakePatternLab(); // environment
@@ -128,8 +124,8 @@ tap.test(
processRecursive(pattern1Path, patternlab).then(() => {
processRecursive(pattern2Path, patternlab).then(() => {
// test
- pattern2.render().then(results => {
- test.equals(
+ pattern2.render().then((results) => {
+ test.equal(
results,
'Hello world!' + eol + ' and Hello world!' + eol + eol
);
@@ -141,15 +137,11 @@ tap.test(
}
);
-tap.test('handlebars partials can render JSON values', function(test) {
+tap.test('handlebars partials can render JSON values', function (test) {
test.plan(1);
// pattern paths
- var pattern1Path = path.join(
- '00-atoms',
- '00-global',
- '00-helloworld-withdata.hbs'
- );
+ var pattern1Path = path.join('atoms', 'global', 'helloworld-withdata.hbs');
// set up environment
var patternlab = new fakePatternLab(); // environment
@@ -160,8 +152,8 @@ tap.test('handlebars partials can render JSON values', function(test) {
processIterative(helloWorldWithData, patternlab).then(() => {
processRecursive(pattern1Path, patternlab).then(() => {
// test
- helloWorldWithData.render().then(results => {
- test.equals(
+ helloWorldWithData.render().then((results) => {
+ test.equal(
results,
'Hello world!' +
eol +
@@ -176,19 +168,15 @@ tap.test('handlebars partials can render JSON values', function(test) {
tap.test(
'handlebars partials use the JSON environment from the calling pattern and can accept passed parameters',
- function(test) {
+ function (test) {
test.plan(1);
// pattern paths
- var atomPath = path.join(
- '00-atoms',
- '00-global',
- '00-helloworld-withdata.hbs'
- );
+ var atomPath = path.join('atoms', 'global', 'helloworld-withdata.hbs');
var molPath = path.join(
- '00-molecules',
- '00-global',
- '00-call-atom-with-molecule-data.hbs'
+ 'molecules',
+ 'global',
+ 'call-atom-with-molecule-data.hbs'
);
// set up environment
@@ -204,9 +192,9 @@ tap.test(
processRecursive(atomPath, patternlab),
processRecursive(molPath, patternlab),
]).then(() => {
- mol.render().then(results => {
+ mol.render().then((results) => {
// test
- test.equals(
+ test.equal(
results,
'Call with default JSON environment: ' +
eol +
@@ -229,7 +217,7 @@ tap.test(
}
);
-tap.only('find_pattern_partials finds partials', function(test) {
+tap.only('find_pattern_partials finds partials', function (test) {
testFindPartials(test, [
'{{> molecules-comment-header}}',
'{{> molecules-comment-header}}',
@@ -239,20 +227,20 @@ tap.only('find_pattern_partials finds partials', function(test) {
]);
});
-tap.test('find_pattern_partials finds verbose partials', function(test) {
+tap.test('find_pattern_partials finds verbose partials', function (test) {
testFindPartials(test, [
- '{{> 01-molecules/06-components/03-comment-header.hbs }}',
- "{{> 01-molecules/06-components/02-single-comment.hbs(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}",
+ '{{> molecules/components/comment-header.hbs }}',
+ "{{> molecules/components/single-comment.hbs(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}",
'{{> molecules-single-comment:foo }}',
"{{>atoms-error(message: 'That's no moon...')}}",
"{{> atoms-error(message: 'That's no moon...') }}",
- '{{> 00-atoms/00-global/06-test }}',
+ '{{> atoms/global/test }}',
]);
});
tap.test(
'find_pattern_partials finds simple partials with parameters',
- function(test) {
+ function (test) {
testFindPartials(test, [
"{{> molecules-single-comment(description: 'A life isn't like a garden. Perfect moments can be had, but not preserved, except in memory.') }}",
'{{> molecules-single-comment(description:"A life is like a "garden". Perfect moments can be had, but not preserved, except in memory.") }}',
@@ -260,16 +248,9 @@ tap.test(
}
);
-tap.test(
- 'find_pattern_partials finds simple partials with style modifiers',
- function(test) {
- testFindPartials(test, ['{{> molecules-single-comment:foo }}']);
- }
-);
-
tap.test(
'find_pattern_partials finds partials with handlebars parameters',
- function(test) {
+ function (test) {
testFindPartials(test, [
'{{> atoms-title title="bravo" headingLevel="2" headingSize="bravo" position="left"}}',
'{{> atoms-title title="bravo"' +
@@ -289,15 +270,16 @@ tap.test(
}
);
-tap.test('find_pattern_partials finds handlebars block partials', function(
- test
-) {
- testFindPartials(test, ['{{#> myPartial }}']);
-});
+tap.test(
+ 'find_pattern_partials finds handlebars block partials',
+ function (test) {
+ testFindPartials(test, ['{{#> myPartial }}']);
+ }
+);
tap.only(
'hidden handlebars patterns can be called by their nice names',
- function(test) {
+ function (test) {
//arrange
const testPatternsPath = path.resolve(
__dirname,
@@ -306,15 +288,11 @@ tap.only(
);
const pl = util.fakePatternLab(testPatternsPath);
- var hiddenPatternPath = path.join(
- '00-atoms',
- '00-global',
- '_00-hidden.hbs'
- );
+ var hiddenPatternPath = path.join('atoms', 'global', '_hidden.hbs');
var testPatternPath = path.join(
- '00-molecules',
- '00-global',
- '00-hidden-pattern-tester.hbs'
+ 'molecules',
+ 'global',
+ 'hidden-pattern-tester.hbs'
);
var hiddenPattern = loadPattern(hiddenPatternPath, pl);
@@ -326,9 +304,9 @@ tap.only(
processRecursive(hiddenPatternPath, pl),
processRecursive(testPatternPath, pl),
]).then(() => {
- testPattern.render().then(results => {
+ testPattern.render().then((results) => {
//act
- test.equals(
+ test.equal(
util.sanitized(results),
util.sanitized("Here's the hidden atom: [I'm the hidden atom\n]\n")
);
@@ -340,14 +318,10 @@ tap.only(
tap.test(
'@partial-block template should render without throwing (@geoffp repo issue #3)',
- function(test) {
+ function (test) {
test.plan(1);
- var patternPath = path.join(
- '00-atoms',
- '00-global',
- '10-at-partial-block.hbs'
- );
+ var patternPath = path.join('atoms', 'global', 'at-partial-block.hbs');
// do all the normal processing of the pattern
var patternlab = new fakePatternLab();
@@ -355,7 +329,7 @@ tap.test(
processIterative(atPartialBlockPattern, patternlab).then(() => {
processRecursive(patternPath, patternlab).then(() => {
- atPartialBlockPattern.render().then(results => {
+ atPartialBlockPattern.render().then((results) => {
var expectedResults =
'{{> @partial-block }}' + eol + 'It worked!' + eol;
test.equal(results, expectedResults);
@@ -367,19 +341,15 @@ tap.test(
tap.test(
'A template calling a @partial-block template should render correctly',
- function(test) {
+ function (test) {
test.plan(1);
// pattern paths
- var pattern1Path = path.join(
- '00-atoms',
- '00-global',
- '10-at-partial-block.hbs'
- );
+ var pattern1Path = path.join('atoms', 'global', 'at-partial-block.hbs');
var pattern2Path = path.join(
- '00-molecules',
- '00-global',
- '10-call-at-partial-block.hbs'
+ 'molecules',
+ 'global',
+ 'call-at-partial-block.hbs'
);
// set up environment
@@ -395,10 +365,10 @@ tap.test(
processRecursive(pattern1Path, patternlab),
processRecursive(pattern2Path, patternlab),
]).then(() => {
- callAtPartialBlockPattern.render().then(results => {
+ callAtPartialBlockPattern.render().then((results) => {
// test
var expectedResults = 'Hello World!' + eol + 'It worked!' + eol;
- test.equals(results, expectedResults);
+ test.equal(results, expectedResults);
});
});
}
diff --git a/packages/core/test/engine_liquid_tests.js b/packages/core/test/engine_liquid_tests.js
index 9036dbca1..7aefb6e03 100644
--- a/packages/core/test/engine_liquid_tests.js
+++ b/packages/core/test/engine_liquid_tests.js
@@ -12,7 +12,7 @@ var eol = require('os').EOL;
// don't run these tests unless liquid is installed
var engineLoader = require('../src/lib/pattern_engines');
if (!engineLoader.liquid) {
- tap.test('Liquid engine not installed, skipping tests.', function(test) {
+ tap.test('Liquid engine not installed, skipping tests.', function (test) {
test.end();
});
return;
@@ -49,9 +49,9 @@ function testFindPartials(test, partialTests) {
// setup current pattern from what we would have during execution
// docs on partial syntax are here:
- // http://patternlab.io/docs/pattern-including.html
+ // https://patternlab.io/docs/including-patterns/
var currentPattern = Pattern.create(
- '01-molecules/00-testing/00-test-mol.liquid', // relative path now
+ 'molecules/testing/test-mol.liquid', // relative path now
null, // data
{
template: partialTests.join(),
@@ -62,18 +62,18 @@ function testFindPartials(test, partialTests) {
var results = currentPattern.findPartials();
// assert
- test.equals(results.length, partialTests.length);
- partialTests.forEach(function(testString, index) {
- test.equals(results[index], testString);
+ test.equal(results.length, partialTests.length);
+ partialTests.forEach(function (testString, index) {
+ test.equal(results[index], testString);
});
test.end();
}
-tap.test('button liquid pattern renders', function(test) {
+tap.test('button liquid pattern renders', function (test) {
test.plan(1);
- var patternPath = path.join('00-atoms', '00-general', '08-button.liquid');
+ var patternPath = path.join('atoms', 'general', 'button.liquid');
var expectedValue =
'\n\n\n\n\n\n';
+ '\n\n\n\n\n\n';
// set up environment
var patternlab = new fakePatternLab(); // environment
@@ -153,7 +145,7 @@ tap.test(
// test
// this pattern is too long - so just remove line endings on both sides and compare output
- test.equals(
+ test.equal(
mediaObjectPattern.render().replace(/\r?\n|\r/gm, ''),
expectedValue.replace(/\r?\n|\r/gm, '')
);
@@ -161,55 +153,57 @@ tap.test(
}
);
-tap.test('liquid partials can render JSON values', { skip: true }, function(
- test
-) {
- test.plan(1);
+tap.test(
+ 'liquid partials can render JSON values',
+ { skip: true },
+ function (test) {
+ test.plan(1);
- // pattern paths
- var pattern1Path = path.resolve(
- testPatternsPath,
- '00-atoms',
- '00-global',
- '00-helloworld-withdata.hbs'
- );
+ // pattern paths
+ var pattern1Path = path.resolve(
+ testPatternsPath,
+ 'atoms',
+ 'global',
+ 'helloworld-withdata.hbs'
+ );
- // set up environment
- var patternlab = new fakePatternLab(); // environment
+ // set up environment
+ var patternlab = new fakePatternLab(); // environment
- // do all the normal processing of the pattern
- var helloWorldWithData = assembler.process_pattern_iterative(
- pattern1Path,
- patternlab
- );
- assembler.process_pattern_recursive(pattern1Path, patternlab);
+ // do all the normal processing of the pattern
+ var helloWorldWithData = assembler.process_pattern_iterative(
+ pattern1Path,
+ patternlab
+ );
+ assembler.process_pattern_recursive(pattern1Path, patternlab);
- // test
- test.equals(
- helloWorldWithData.render(),
- 'Hello world!\nYeah, we got the subtitle from the JSON.\n'
- );
- test.end();
-});
+ // test
+ test.equal(
+ helloWorldWithData.render(),
+ 'Hello world!\nYeah, we got the subtitle from the JSON.\n'
+ );
+ test.end();
+ }
+);
tap.test(
'liquid partials use the JSON environment from the calling pattern and can accept passed parameters',
{ skip: true },
- function(test) {
+ function (test) {
test.plan(1);
// pattern paths
var atomPath = path.resolve(
testPatternsPath,
- '00-atoms',
- '00-global',
- '00-helloworld-withdata.hbs'
+ 'atoms',
+ 'global',
+ 'helloworld-withdata.hbs'
);
var molPath = path.resolve(
testPatternsPath,
- '00-molecules',
- '00-global',
- '00-call-atom-with-molecule-data.hbs'
+ 'molecules',
+ 'global',
+ 'call-atom-with-molecule-data.hbs'
);
// set up environment
@@ -222,7 +216,7 @@ tap.test(
assembler.process_pattern_recursive(molPath, patternlab);
// test
- test.equals(
+ test.equal(
mol.render(),
'Call with default JSON environment: \nThis is Hello world!\nfrom the default JSON.\n\n\nCall with passed parameter: \nHowever, this is Hello world!\nfrom a totally different blob.\n\n'
);
@@ -230,7 +224,7 @@ tap.test(
}
);
-tap.test('find_pattern_partials finds partials', function(test) {
+tap.test('find_pattern_partials finds partials', function (test) {
testFindPartials(test, [
'{% include "atoms-image" %}',
"{% include 'atoms-image' %}",
@@ -241,16 +235,16 @@ tap.test('find_pattern_partials finds partials', function(test) {
]);
});
-tap.test('find_pattern_partials finds verbose partials', function(test) {
+tap.test('find_pattern_partials finds verbose partials', function (test) {
testFindPartials(test, [
- "{% include '01-molecules/06-components/03-comment-header.liquid' %}",
- "{% include '00-atoms/00-global/06-test' %}",
+ "{% include 'molecules/components/comment-header.liquid' %}",
+ "{% include 'atoms/global/test' %}",
]);
});
tap.test(
'find_pattern_partials finds partials with liquid parameters',
- function(test) {
+ function (test) {
testFindPartials(test, [
"{% include 'molecules-template' with {'foo': 'bar'} %}",
"{% include 'molecules-template' with vars %}",
diff --git a/packages/core/test/engine_mustache_tests.js b/packages/core/test/engine_mustache_tests.js
index 8f0241d24..dd5e3fb19 100644
--- a/packages/core/test/engine_mustache_tests.js
+++ b/packages/core/test/engine_mustache_tests.js
@@ -13,7 +13,7 @@ var config = require('./util/patternlab-config.json');
var engineLoader = require('../src/lib/pattern_engines');
engineLoader.loadAllEngines(config);
if (!engineLoader.mustache) {
- tap.test('Mustache engine not installed, skipping tests.', function(test) {
+ tap.test('Mustache engine not installed, skipping tests.', function (test) {
test.end();
});
return;
@@ -50,9 +50,9 @@ function testFindPartials(test, partialTests) {
// setup current pattern from what we would have during execution
// docs on partial syntax are here:
- // http://patternlab.io/docs/pattern-including.html
+ // https://patternlab.io/docs/including-patterns/
var currentPattern = Pattern.create(
- '01-molecules/00-testing/00-test-mol.mustache', // relative path now
+ 'molecules/testing/test-mol.mustache', // relative path now
null, // data
{
template: partialTests.join(eol),
@@ -63,35 +63,9 @@ function testFindPartials(test, partialTests) {
var results = currentPattern.findPartials();
// assert
- test.equals(results.length, partialTests.length);
- partialTests.forEach(function(testString, index) {
- test.equals(results[index], testString);
- });
-
- test.end();
-}
-
-function testFindPartialsWithStyleModifiers(test, partialTests) {
- test.plan(partialTests.length + 1);
-
- // setup current pattern from what we would have during execution
- // docs on partial syntax are here:
- // http://patternlab.io/docs/pattern-including.html
- var currentPattern = Pattern.create(
- '01-molecules/00-testing/00-test-mol.mustache', // relative path now
- null, // data
- {
- template: partialTests.join(eol),
- }
- );
-
- // act
- var results = currentPattern.findPartialsWithStyleModifiers();
-
- // assert
- test.equals(results.length, partialTests.length);
- partialTests.forEach(function(testString, index) {
- test.equals(results[index], testString);
+ test.equal(results.length, partialTests.length);
+ partialTests.forEach(function (testString, index) {
+ test.equal(results[index], testString);
});
test.end();
@@ -102,9 +76,9 @@ function testFindPartialsWithPatternParameters(test, partialTests) {
// setup current pattern from what we would have during execution
// docs on partial syntax are here:
- // http://patternlab.io/docs/pattern-including.html
+ // https://patternlab.io/docs/including-patterns/
var currentPattern = Pattern.create(
- '01-molecules/00-testing/00-test-mol.mustache', // relative path now
+ 'molecules/testing/test-mol.mustache', // relative path now
null, // data
{
template: partialTests.join(eol),
@@ -115,21 +89,21 @@ function testFindPartialsWithPatternParameters(test, partialTests) {
var results = currentPattern.findPartialsWithPatternParameters();
// assert
- test.equals(results.length, partialTests.length);
- partialTests.forEach(function(testString, index) {
- test.equals(results[index], testString);
+ test.equal(results.length, partialTests.length);
+ partialTests.forEach(function (testString, index) {
+ test.equal(results[index], testString);
});
test.end();
}
-tap.test('find_pattern_partials finds one simple partial', function(test) {
+tap.test('find_pattern_partials finds one simple partial', function (test) {
testFindPartials(test, ['{{> molecules-comment-header}}']);
});
tap.test(
'find_pattern_partials finds simple partials under stressed circumstances',
- function(test) {
+ function (test) {
testFindPartials(test, [
'{{>molecules-comment-header}}',
'{{> ' + eol + ' molecules-comment-header' + eol + '}}',
@@ -138,86 +112,38 @@ tap.test(
}
);
-tap.test('find_pattern_partials finds one simple verbose partial', function(
- test
-) {
- testFindPartials(test, ['{{> 00-atoms/00-global/06-test }}']);
-});
-
-tap.test('find_pattern_partials finds partials with parameters', function(
- test
-) {
- testFindPartials(test, [
- '{{> molecules-single-comment(description: true) }}',
- '{{> molecules-single-comment(description: 42) }}',
- "{{> molecules-single-comment(description: '42') }}",
- '{{> molecules-single-comment(description: "42") }}',
- "{{> molecules-single-comment(description: 'test', anotherThing: 'retest') }}",
- '{{> molecules-single-comment(description: false, anotherThing: "retest") }}',
- '{{> molecules-single-comment(description:"A life is like a "garden". Perfect moments can be had, but not preserved, except in memory.") }}',
- ]);
-});
+tap.test(
+ 'find_pattern_partials finds one simple verbose partial',
+ function (test) {
+ testFindPartials(test, ['{{> atoms/global/test }}']);
+ }
+);
tap.test(
- 'find_pattern_partials finds simple partials with style modifiers',
- function(test) {
+ 'find_pattern_partials finds partials with parameters',
+ function (test) {
testFindPartials(test, [
- '{{> molecules-single-comment:foo }}',
- '{{> molecules-single-comment:foo|bar }}',
+ '{{> molecules-single-comment(description: true) }}',
+ '{{> molecules-single-comment(description: 42) }}',
+ "{{> molecules-single-comment(description: '42') }}",
+ '{{> molecules-single-comment(description: "42") }}',
+ "{{> molecules-single-comment(description: 'test', anotherThing: 'retest') }}",
+ '{{> molecules-single-comment(description: false, anotherThing: "retest") }}',
+ '{{> molecules-single-comment(description:"A life is like a "garden". Perfect moments can be had, but not preserved, except in memory.") }}',
]);
}
);
-tap.test('find_pattern_partials finds mixed partials', function(test) {
+tap.test('find_pattern_partials finds mixed partials', function (test) {
testFindPartials(test, [
'{{> molecules-single-comment:foo(description: "test", anotherThing: true) }}',
'{{> molecules-single-comment:foo|bar(description: true) }}',
]);
});
-tap.test(
- 'find_pattern_partials finds one simple partial with styleModifier',
- function(test) {
- testFindPartialsWithStyleModifiers(test, [
- '{{> molecules-comment-header:test}}',
- ]);
- }
-);
-
-tap.test(
- 'find_pattern_partials finds partial with many styleModifiers',
- function(test) {
- testFindPartialsWithStyleModifiers(test, [
- '{{> molecules-comment-header:test|test2|test3}}',
- ]);
- }
-);
-
-tap.test(
- 'find_pattern_partials finds partials with differing styleModifiers',
- function(test) {
- testFindPartialsWithStyleModifiers(test, [
- '{{> molecules-comment-header:test|test2|test3}}',
- '{{> molecules-comment-header:foo-1}}',
- '{{> molecules-comment-header:bar_1}}',
- ]);
- }
-);
-
-tap.test(
- 'find_pattern_partials finds partials with styleModifiers when parameters present',
- function(test) {
- testFindPartialsWithStyleModifiers(test, [
- '{{> molecules-comment-header:test|test2|test3(description: true)}}',
- "{{> molecules-comment-header:foo-1(description: 'foo')}}",
- "{{> molecules-comment-header:bar_1(descrition: 'bar', anotherThing: 10102010) }}",
- ]);
- }
-);
-
tap.test(
'find_pattern_partials_with_parameters finds one simple partial with parameters',
- function(test) {
+ function (test) {
testFindPartialsWithPatternParameters(test, [
"{{> molecules-comment-header(description: 'test')}}",
]);
@@ -226,7 +152,7 @@ tap.test(
tap.test(
'find_pattern_partials_with_parameters finds partials with parameters',
- function(test) {
+ function (test) {
testFindPartialsWithPatternParameters(test, [
'{{> molecules-single-comment(description: true) }}',
'{{> molecules-single-comment(description: 42) }}',
@@ -238,14 +164,3 @@ tap.test(
]);
}
);
-
-tap.test(
- 'find_pattern_partials finds partials with parameters when styleModifiers present',
- function(test) {
- testFindPartialsWithPatternParameters(test, [
- '{{> molecules-comment-header:test|test2|test3(description: true)}}',
- "{{> molecules-comment-header:foo-1(description: 'foo')}}",
- "{{> molecules-comment-header:bar_1(descrition: 'bar', anotherThing: 10102010) }}",
- ]);
- }
-);
diff --git a/packages/core/test/engine_react_tests.js b/packages/core/test/engine_react_tests.js
index 2d271bb9b..8e34d5338 100644
--- a/packages/core/test/engine_react_tests.js
+++ b/packages/core/test/engine_react_tests.js
@@ -15,33 +15,33 @@ engineLoader.loadAllEngines(config);
// don't run these tests unless the react engine is installed
if (!engineLoader.react) {
- tap.test('React engine not installed, skipping tests.', test => {
+ tap.test('React engine not installed, skipping tests.', (test) => {
test.end();
});
} else {
const fpl = testUtils.fakePatternLab(testPatternsPath);
- tap.test('Load the hello world pattern and verify contents', test => {
+ tap.test('Load the hello world pattern and verify contents', (test) => {
const patternPath = path.join(
testPatternsPath,
- '00-atoms/00-general/HelloWorld.jsx'
+ 'atoms/general/HelloWorld.jsx'
);
const patternContent = fs.readFileSync(patternPath, { encoding: 'utf8' });
const pattern = loadPattern(patternPath, fpl);
- test.equals(pattern.template, patternContent);
+ test.equal(pattern.template, patternContent);
test.end();
});
- tap.test('Load the hello world pattern and verify output', test => {
+ tap.test('Load the hello world pattern and verify output', (test) => {
const patternPath = path.join(
testPatternsPath,
- '00-atoms/00-general/HelloWorld.jsx'
+ 'atoms/general/HelloWorld.jsx'
);
const pattern = loadPattern(patternPath, fpl);
- return pattern.render().then(output => {
- test.equals(output, 'Hello world!
\n');
+ return pattern.render().then((output) => {
+ test.equal(output, 'Hello world!
\n');
});
});
}
diff --git a/packages/core/test/engine_twig_tests.js b/packages/core/test/engine_twig_tests.js
index 33a49bbe9..d631a4020 100644
--- a/packages/core/test/engine_twig_tests.js
+++ b/packages/core/test/engine_twig_tests.js
@@ -12,7 +12,7 @@ var eol = require('os').EOL;
// don't run these tests unless twig is installed
var engineLoader = require('../src/lib/pattern_engines');
if (!engineLoader.twig) {
- tap.test('Twig engine not installed, skipping tests.', function(test) {
+ tap.test('Twig engine not installed, skipping tests.', function (test) {
test.end();
});
return;
@@ -49,9 +49,9 @@ function testFindPartials(test, partialTests) {
// setup current pattern from what we would have during execution
// docs on partial syntax are here:
- // http://patternlab.io/docs/pattern-including.html
+ // https://patternlab.io/docs/including-patterns/
var currentPattern = Pattern.create(
- '01-molecules/00-testing/00-test-mol.twig', // relative path now
+ 'molecules/testing/test-mol.twig', // relative path now
null, // data
{
template: partialTests.join(),
@@ -62,18 +62,18 @@ function testFindPartials(test, partialTests) {
var results = currentPattern.findPartials();
// assert
- test.equals(results.length, partialTests.length);
- partialTests.forEach(function(testString, index) {
- test.equals(results[index], testString);
+ test.equal(results.length, partialTests.length);
+ partialTests.forEach(function (testString, index) {
+ test.equal(results[index], testString);
});
test.end();
}
-tap.test('button twig pattern renders', function(test) {
+tap.test('button twig pattern renders', function (test) {
test.plan(1);
- var patternPath = path.join('00-atoms', '00-general', '08-button.twig');
+ var patternPath = path.join('atoms', 'general', 'button.twig');
var expectedValue =
'\n\n\n\n\n\n';
+ '\n\n\n\n\n\n';
// set up environment
var patternlab = new fakePatternLab(); // environment
@@ -149,7 +145,7 @@ tap.test(
// test
// this pattern is too long - so just remove line endings on both sides and compare output
- test.equals(
+ test.equal(
mediaObjectPattern.render().replace(/\r?\n|\r/gm, ''),
expectedValue.replace(/\r?\n|\r/gm, '')
);
@@ -157,55 +153,57 @@ tap.test(
}
);
-tap.test('twig partials can render JSON values', { skip: true }, function(
- test
-) {
- test.plan(1);
+tap.test(
+ 'twig partials can render JSON values',
+ { skip: true },
+ function (test) {
+ test.plan(1);
- // pattern paths
- var pattern1Path = path.resolve(
- testPatternsPath,
- '00-atoms',
- '00-global',
- '00-helloworld-withdata.hbs'
- );
+ // pattern paths
+ var pattern1Path = path.resolve(
+ testPatternsPath,
+ 'atoms',
+ 'global',
+ 'helloworld-withdata.hbs'
+ );
- // set up environment
- var patternlab = new fakePatternLab(); // environment
+ // set up environment
+ var patternlab = new fakePatternLab(); // environment
- // do all the normal processing of the pattern
- var helloWorldWithData = assembler.process_pattern_iterative(
- pattern1Path,
- patternlab
- );
- assembler.process_pattern_recursive(pattern1Path, patternlab);
+ // do all the normal processing of the pattern
+ var helloWorldWithData = assembler.process_pattern_iterative(
+ pattern1Path,
+ patternlab
+ );
+ assembler.process_pattern_recursive(pattern1Path, patternlab);
- // test
- test.equals(
- helloWorldWithData.render(),
- 'Hello world!\nYeah, we got the subtitle from the JSON.\n'
- );
- test.end();
-});
+ // test
+ test.equal(
+ helloWorldWithData.render(),
+ 'Hello world!\nYeah, we got the subtitle from the JSON.\n'
+ );
+ test.end();
+ }
+);
tap.test(
'twig partials use the JSON environment from the calling pattern and can accept passed parameters',
{ skip: true },
- function(test) {
+ function (test) {
test.plan(1);
// pattern paths
var atomPath = path.resolve(
testPatternsPath,
- '00-atoms',
- '00-global',
- '00-helloworld-withdata.hbs'
+ 'atoms',
+ 'global',
+ 'helloworld-withdata.hbs'
);
var molPath = path.resolve(
testPatternsPath,
- '00-molecules',
- '00-global',
- '00-call-atom-with-molecule-data.hbs'
+ 'molecules',
+ 'global',
+ 'call-atom-with-molecule-data.hbs'
);
// set up environment
@@ -218,7 +216,7 @@ tap.test(
assembler.process_pattern_recursive(molPath, patternlab);
// test
- test.equals(
+ test.equal(
mol.render(),
'Call with default JSON environment: \nThis is Hello world!\nfrom the default JSON.\n\n\nCall with passed parameter: \nHowever, this is Hello world!\nfrom a totally different blob.\n\n'
);
@@ -226,7 +224,7 @@ tap.test(
}
);
-tap.test('find_pattern_partials finds partials', function(test) {
+tap.test('find_pattern_partials finds partials', function (test) {
testFindPartials(test, [
'{% include "atoms-image" %}',
"{% include 'atoms-image' %}",
@@ -237,20 +235,21 @@ tap.test('find_pattern_partials finds partials', function(test) {
]);
});
-tap.test('find_pattern_partials finds verbose partials', function(test) {
+tap.test('find_pattern_partials finds verbose partials', function (test) {
testFindPartials(test, [
- "{% include '01-molecules/06-components/03-comment-header.twig' %}",
- "{% include '00-atoms/00-global/06-test' %}",
+ "{% include 'molecules/components/comment-header.twig' %}",
+ "{% include 'atoms/global/test' %}",
]);
});
-tap.test('find_pattern_partials finds partials with twig parameters', function(
- test
-) {
- testFindPartials(test, [
- "{% include 'molecules-template' with {'foo': 'bar'} %}",
- "{% include 'molecules-template' with vars %}",
- "{% include 'molecules-template.twig' with {'foo': 'bar'} only %}",
- "{% include 'organisms-sidebar' ignore missing with {'foo': 'bar'} %}",
- ]);
-});
+tap.test(
+ 'find_pattern_partials finds partials with twig parameters',
+ function (test) {
+ testFindPartials(test, [
+ "{% include 'molecules-template' with {'foo': 'bar'} %}",
+ "{% include 'molecules-template' with vars %}",
+ "{% include 'molecules-template.twig' with {'foo': 'bar'} only %}",
+ "{% include 'organisms-sidebar' ignore missing with {'foo': 'bar'} %}",
+ ]);
+ }
+);
diff --git a/packages/core/test/engine_underscore_tests.js b/packages/core/test/engine_underscore_tests.js
index fbdbb5617..a944e830b 100644
--- a/packages/core/test/engine_underscore_tests.js
+++ b/packages/core/test/engine_underscore_tests.js
@@ -14,7 +14,7 @@ var eol = require('os').EOL;
// don't run tests unless underscore is installed
var engineLoader = require('../src/lib/pattern_engines');
if (!engineLoader.underscore) {
- tap.test('Underscore engine not installed, skipping tests', function(test) {
+ tap.test('Underscore engine not installed, skipping tests', function (test) {
test.end();
});
return;
@@ -45,14 +45,14 @@ function fakePatternLab() {
return fpl;
}
-tap.test('hello world underscore pattern renders', function(test) {
+tap.test('hello world underscore pattern renders', function (test) {
test.plan(1);
var patternPath = path.resolve(
testPatternsPath,
- '00-atoms',
- '00-global',
- '00-helloworld.html'
+ 'atoms',
+ 'global',
+ 'helloworld.html'
);
// do all the normal processing of the pattern
@@ -65,19 +65,19 @@ tap.test('hello world underscore pattern renders', function(test) {
.then(() => {
assembler.process_pattern_recursive(patternPath, patternlab);
- test.equals(helloWorldPattern.render(), 'Hello world!' + eol);
+ test.equal(helloWorldPattern.render(), 'Hello world!' + eol);
});
});
-tap.test('underscore partials can render JSON values', function(test) {
+tap.test('underscore partials can render JSON values', function (test) {
test.plan(1);
// pattern paths
var pattern1Path = path.resolve(
testPatternsPath,
- '00-atoms',
- '00-global',
- '00-helloworld-withdata.html'
+ 'atoms',
+ 'global',
+ 'helloworld-withdata.html'
);
// set up environment
@@ -91,7 +91,7 @@ tap.test('underscore partials can render JSON values', function(test) {
assembler.process_pattern_recursive(pattern1Path, patternlab);
// test
- test.equals(
+ test.equal(
helloWorldWithData.render(),
'Hello world!' + eol + 'Yeah, we got the subtitle from the JSON.' + eol
);
@@ -100,7 +100,7 @@ tap.test('underscore partials can render JSON values', function(test) {
tap.test(
'findPartial return the ID of the partial, given a whole partial call',
- function(test) {
+ function (test) {
var engineLoader = require('../src/lib/pattern_engines');
var underscoreEngine = engineLoader.underscore;
@@ -108,7 +108,7 @@ tap.test(
// do all the normal processing of the pattern
// test
- test.equals(
+ test.equal(
underscoreEngine.findPartial(
"<%= _.renderNamedPartial('molecules-details', obj) %>"
),
@@ -120,7 +120,7 @@ tap.test(
tap.test(
'hidden underscore patterns can be called by their nice names',
- function(test) {
+ function (test) {
const util = require('./util/test_utils.js');
//arrange
@@ -131,15 +131,11 @@ tap.test(
);
const pl = util.fakePatternLab(testPatternsPath);
- var hiddenPatternPath = path.join(
- '00-atoms',
- '00-global',
- '_00-hidden.html'
- );
+ var hiddenPatternPath = path.join('atoms', 'global', '_hidden.html');
var testPatternPath = path.join(
- '00-molecules',
- '00-global',
- '00-hidden-pattern-tester.html'
+ 'molecules',
+ 'global',
+ 'hidden-pattern-tester.html'
);
var hiddenPattern = loadPattern(hiddenPatternPath, pl);
@@ -153,7 +149,7 @@ tap.test(
pattern_assembler.process_pattern_recursive(testPatternPath, pl);
//act
- test.equals(
+ test.equal(
util.sanitized(testPattern.render()),
util.sanitized("Here's the hidden atom: [I'm the hidden atom\n]\n")
);
diff --git a/packages/core/test/exportData_tests.js b/packages/core/test/exportData_tests.js
index 93cd9573d..2443dde76 100644
--- a/packages/core/test/exportData_tests.js
+++ b/packages/core/test/exportData_tests.js
@@ -10,7 +10,7 @@ const util = require('./util/test_utils.js');
const testPatternsPath = path.resolve(__dirname, 'files', '_patterns');
const fsMock = {
- outputFileSync: function(path, content) {
+ outputFileSync: function (path, content) {
/* INTENTIONAL NOOP */
},
};
@@ -20,49 +20,78 @@ exportData.__set__({
fs: fsMock,
});
-const patternlab = util.fakePatternLab(testPatternsPath);
-const result = exportData(patternlab);
+const uikitFoo = {
+ name: 'uikit-foo',
+ enabled: true,
+ outputDir: 'foo',
+ excludedPatternStates: ['legacy'],
+ excludedTags: ['baz'],
+};
+
+tap.test('exportData exports config', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
-tap.test('exportData exports config', function(test) {
- test.equals(result.indexOf('config') > -1, true);
- test.equals(result.indexOf('paths') > -1, true);
- test.equals(result.indexOf('theme') > -1, true);
+ test.equal(result.indexOf('config') > -1, true);
+ test.equal(result.indexOf('paths') > -1, true);
+ test.equal(result.indexOf('theme') > -1, true);
test.end();
});
-tap.test('exportData exports ishControls', function(test) {
- test.equals(result.indexOf('ishControlsHide') > -1, true);
+tap.test('exportData exports ishControls', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
+
+ test.equal(result.indexOf('ishControlsHide') > -1, true);
test.end();
});
-tap.test('exportData exports navItems', function(test) {
- test.equals(result.indexOf('patternTypes') > -1, true);
+tap.test('exportData exports navItems', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
+
+ test.equal(result.indexOf('patternGroups') > -1, true);
test.end();
});
-tap.test('exportData exports patternPaths', function(test) {
- test.equals(result.indexOf('patternPaths') > -1, true);
+tap.test('exportData exports patternPaths', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
+
+ test.equal(result.indexOf('patternPaths') > -1, true);
test.end();
});
-tap.test('exportData exports viewAllPaths', function(test) {
- test.equals(result.indexOf('viewAllPaths') > -1, true);
+tap.test('exportData exports viewAllPaths', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
+
+ test.equal(result.indexOf('viewAllPaths') > -1, true);
test.end();
});
-tap.test('exportData exports plugins', function(test) {
- test.equals(result.indexOf('plugins') > -1, true);
+tap.test('exportData exports plugins', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
+
+ test.equal(result.indexOf('plugins') > -1, true);
test.end();
});
-tap.test('exportData exports defaultShowPatternInfo', function(test) {
- test.equals(result.indexOf('defaultShowPatternInfo') > -1, true);
- test.equals(result.indexOf('"defaultShowPatternInfo":false') > -1, true);
+tap.test('exportData exports defaultShowPatternInfo', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
+
+ test.equal(result.indexOf('defaultShowPatternInfo') > -1, true);
+ test.equal(result.indexOf('"defaultShowPatternInfo":false') > -1, true);
test.end();
});
-tap.test('exportData exports defaultPattern', function(test) {
- test.equals(result.indexOf('defaultPattern') > -1, true);
- test.equals(result.indexOf('"defaultPattern":"all"') > -1, true);
+tap.test('exportData exports defaultPattern', function (test) {
+ const patternlab = util.fakePatternLab(testPatternsPath);
+ const result = exportData(patternlab, uikitFoo);
+
+ test.equal(result.indexOf('defaultPattern') > -1, true);
+ test.equal(result.indexOf('"defaultPattern":"all"') > -1, true);
test.end();
});
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/00-helloworld-withdata.hbs b/packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/00-helloworld-withdata.hbs
deleted file mode 100644
index 3cfaf83c0..000000000
--- a/packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/00-helloworld-withdata.hbs
+++ /dev/null
@@ -1,2 +0,0 @@
-Hello world!
-{{ subtitle }}
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/_00-hidden.hbs b/packages/core/test/files/_handlebars-test-patterns/atoms/global/_hidden.hbs
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/_00-hidden.hbs
rename to packages/core/test/files/_handlebars-test-patterns/atoms/global/_hidden.hbs
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/10-at-partial-block.hbs b/packages/core/test/files/_handlebars-test-patterns/atoms/global/at-partial-block.hbs
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/10-at-partial-block.hbs
rename to packages/core/test/files/_handlebars-test-patterns/atoms/global/at-partial-block.hbs
diff --git a/packages/core/test/files/_handlebars-test-patterns/atoms/global/helloworld-withdata.hbs b/packages/core/test/files/_handlebars-test-patterns/atoms/global/helloworld-withdata.hbs
new file mode 100644
index 000000000..30c6ff45a
--- /dev/null
+++ b/packages/core/test/files/_handlebars-test-patterns/atoms/global/helloworld-withdata.hbs
@@ -0,0 +1,2 @@
+Hello world!
+{{subtitle}}
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/00-helloworld-withdata.json b/packages/core/test/files/_handlebars-test-patterns/atoms/global/helloworld-withdata.json
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/00-helloworld-withdata.json
rename to packages/core/test/files/_handlebars-test-patterns/atoms/global/helloworld-withdata.json
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/00-helloworld.hbs b/packages/core/test/files/_handlebars-test-patterns/atoms/global/helloworld.hbs
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-atoms/00-global/00-helloworld.hbs
rename to packages/core/test/files/_handlebars-test-patterns/atoms/global/helloworld.hbs
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/10-call-at-partial-block.hbs b/packages/core/test/files/_handlebars-test-patterns/molecules/global/call-at-partial-block.hbs
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/10-call-at-partial-block.hbs
rename to packages/core/test/files/_handlebars-test-patterns/molecules/global/call-at-partial-block.hbs
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.hbs b/packages/core/test/files/_handlebars-test-patterns/molecules/global/call-atom-with-molecule-data.hbs
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.hbs
rename to packages/core/test/files/_handlebars-test-patterns/molecules/global/call-atom-with-molecule-data.hbs
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.json b/packages/core/test/files/_handlebars-test-patterns/molecules/global/call-atom-with-molecule-data.json
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.json
rename to packages/core/test/files/_handlebars-test-patterns/molecules/global/call-atom-with-molecule-data.json
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-helloworlds.hbs b/packages/core/test/files/_handlebars-test-patterns/molecules/global/helloworlds.hbs
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-helloworlds.hbs
rename to packages/core/test/files/_handlebars-test-patterns/molecules/global/helloworlds.hbs
diff --git a/packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-hidden-pattern-tester.hbs b/packages/core/test/files/_handlebars-test-patterns/molecules/global/hidden-pattern-tester.hbs
similarity index 100%
rename from packages/core/test/files/_handlebars-test-patterns/00-molecules/00-global/00-hidden-pattern-tester.hbs
rename to packages/core/test/files/_handlebars-test-patterns/molecules/global/hidden-pattern-tester.hbs
diff --git a/packages/core/test/files/_liquid_test-patterns/00-atoms/00-general/09-image.liquid b/packages/core/test/files/_liquid_test-patterns/00-atoms/00-general/09-image.liquid
deleted file mode 100644
index 01c4af9f8..000000000
--- a/packages/core/test/files/_liquid_test-patterns/00-atoms/00-general/09-image.liquid
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/packages/core/test/files/_liquid_test-patterns/00-atoms/00-general/08-button.liquid b/packages/core/test/files/_liquid_test-patterns/atoms/general/button.liquid
similarity index 100%
rename from packages/core/test/files/_liquid_test-patterns/00-atoms/00-general/08-button.liquid
rename to packages/core/test/files/_liquid_test-patterns/atoms/general/button.liquid
diff --git a/packages/core/test/files/_liquid_test-patterns/atoms/general/image.liquid b/packages/core/test/files/_liquid_test-patterns/atoms/general/image.liquid
new file mode 100644
index 000000000..320401c8e
--- /dev/null
+++ b/packages/core/test/files/_liquid_test-patterns/atoms/general/image.liquid
@@ -0,0 +1,5 @@
+
diff --git a/packages/core/test/files/_liquid_test-patterns/00-molecules/00-general/00-media-object.liquid b/packages/core/test/files/_liquid_test-patterns/molecules/general/media-object.liquid
similarity index 100%
rename from packages/core/test/files/_liquid_test-patterns/00-molecules/00-general/00-media-object.liquid
rename to packages/core/test/files/_liquid_test-patterns/molecules/general/media-object.liquid
diff --git a/packages/core/test/files/_meta/_01-foot.hbs b/packages/core/test/files/_meta/_foot.hbs
similarity index 100%
rename from packages/core/test/files/_meta/_01-foot.hbs
rename to packages/core/test/files/_meta/_foot.hbs
diff --git a/packages/core/test/files/_meta/_01-foot.html b/packages/core/test/files/_meta/_foot.html
similarity index 100%
rename from packages/core/test/files/_meta/_01-foot.html
rename to packages/core/test/files/_meta/_foot.html
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_01-foot.hbs b/packages/core/test/files/_meta/_foot.mustache
similarity index 100%
rename from packages/development-edition-engine-handlebars/source/_meta/_01-foot.hbs
rename to packages/core/test/files/_meta/_foot.mustache
diff --git a/packages/core/test/files/_meta/_00-head.hbs b/packages/core/test/files/_meta/_head.hbs
similarity index 94%
rename from packages/core/test/files/_meta/_00-head.hbs
rename to packages/core/test/files/_meta/_head.hbs
index b1f5c1ce0..d2b1ea726 100644
--- a/packages/core/test/files/_meta/_00-head.hbs
+++ b/packages/core/test/files/_meta/_head.hbs
@@ -2,7 +2,7 @@
{{ title }}
-
+
diff --git a/packages/development-edition-engine-react/source/_meta/_00-head.hbs b/packages/core/test/files/_meta/_head.html
similarity index 55%
rename from packages/development-edition-engine-react/source/_meta/_00-head.hbs
rename to packages/core/test/files/_meta/_head.html
index cf826617a..56d9a2432 100644
--- a/packages/development-edition-engine-react/source/_meta/_00-head.hbs
+++ b/packages/core/test/files/_meta/_head.html
@@ -1,16 +1,23 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
diff --git a/packages/edition-node-gulp/source/_meta/_00-head.mustache b/packages/core/test/files/_meta/_head.mustache
similarity index 94%
rename from packages/edition-node-gulp/source/_meta/_00-head.mustache
rename to packages/core/test/files/_meta/_head.mustache
index 0001e7628..14a98f369 100644
--- a/packages/edition-node-gulp/source/_meta/_00-head.mustache
+++ b/packages/core/test/files/_meta/_head.mustache
@@ -2,7 +2,7 @@
{{ title }}
-
+
diff --git a/packages/core/test/files/_patterns/00-test/03-styled-atom.mustache b/packages/core/test/files/_patterns/00-test/03-styled-atom.mustache
deleted file mode 100644
index b736c06aa..000000000
--- a/packages/core/test/files/_patterns/00-test/03-styled-atom.mustache
+++ /dev/null
@@ -1,3 +0,0 @@
-
- {{message}}
-
diff --git a/packages/core/test/files/_patterns/00-test/nav.json b/packages/core/test/files/_patterns/00-test/nav.json
deleted file mode 100644
index 32a6c0952..000000000
--- a/packages/core/test/files/_patterns/00-test/nav.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "brad" : {
- "url" : "link.twitter-brad"
- },
- "dave" : {
- "url" : "link.twitter-dave"
- },
- "brian" : {
- "url" : "link.twitter-brian"
- }
-}
diff --git a/packages/core/test/files/_patterns/00-test/paramMiddle.mustache b/packages/core/test/files/_patterns/00-test/paramMiddle.mustache
deleted file mode 100644
index 31169fb7e..000000000
--- a/packages/core/test/files/_patterns/00-test/paramMiddle.mustache
+++ /dev/null
@@ -1,3 +0,0 @@
-
- {{> test-link }}
-
diff --git a/packages/core/test/files/_patterns/00-test/paramParent.mustache b/packages/core/test/files/_patterns/00-test/paramParent.mustache
deleted file mode 100644
index bf4e84562..000000000
--- a/packages/core/test/files/_patterns/00-test/paramParent.mustache
+++ /dev/null
@@ -1 +0,0 @@
-{{> test-paramMiddle(styleModifier: "foo") }}
diff --git a/packages/core/test/files/_patterns/00-test/sticky-comment-verbose.mustache b/packages/core/test/files/_patterns/00-test/sticky-comment-verbose.mustache
deleted file mode 100644
index 55b21011d..000000000
--- a/packages/core/test/files/_patterns/00-test/sticky-comment-verbose.mustache
+++ /dev/null
@@ -1 +0,0 @@
-{{> 00-test/comment(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}
diff --git a/packages/core/test/files/_patterns/orderTest/_orderTest.md b/packages/core/test/files/_patterns/orderTest/_orderTest.md
new file mode 100644
index 000000000..c71e03c11
--- /dev/null
+++ b/packages/core/test/files/_patterns/orderTest/_orderTest.md
@@ -0,0 +1,3 @@
+---
+order: 1
+---
\ No newline at end of file
diff --git a/packages/core/test/files/_meta/_00-head.mustache b/packages/core/test/files/_patterns/orderTest/a/a-test.mustache
similarity index 100%
rename from packages/core/test/files/_meta/_00-head.mustache
rename to packages/core/test/files/_patterns/orderTest/a/a-test.mustache
diff --git a/packages/core/test/files/_patterns/orderTest/b/_b.md b/packages/core/test/files/_patterns/orderTest/b/_b.md
new file mode 100644
index 000000000..7017cea54
--- /dev/null
+++ b/packages/core/test/files/_patterns/orderTest/b/_b.md
@@ -0,0 +1,3 @@
+---
+order: 2
+---
\ No newline at end of file
diff --git a/packages/core/test/files/_meta/_01-foot.mustache b/packages/core/test/files/_patterns/orderTest/b/b-test.mustache
similarity index 100%
rename from packages/core/test/files/_meta/_01-foot.mustache
rename to packages/core/test/files/_patterns/orderTest/b/b-test.mustache
diff --git a/packages/core/test/files/_patterns/orderTest/c/_c.md b/packages/core/test/files/_patterns/orderTest/c/_c.md
new file mode 100644
index 000000000..4c2122185
--- /dev/null
+++ b/packages/core/test/files/_patterns/orderTest/c/_c.md
@@ -0,0 +1,3 @@
+---
+order: -1
+---
\ No newline at end of file
diff --git a/packages/core/test/files/partials/patternSectionSubtype.mustache b/packages/core/test/files/_patterns/orderTest/c/c-test.mustache
similarity index 100%
rename from packages/core/test/files/partials/patternSectionSubtype.mustache
rename to packages/core/test/files/_patterns/orderTest/c/c-test.mustache
diff --git a/packages/core/test/files/_patterns/orderTest/c/subfolder/subfolder.mustache b/packages/core/test/files/_patterns/orderTest/c/subfolder/subfolder.mustache
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/core/test/files/_patterns/orderTest/orderTest.md b/packages/core/test/files/_patterns/orderTest/orderTest.md
new file mode 100644
index 000000000..c71e03c11
--- /dev/null
+++ b/packages/core/test/files/_patterns/orderTest/orderTest.md
@@ -0,0 +1,3 @@
+---
+order: 1
+---
\ No newline at end of file
diff --git a/packages/core/test/files/_patterns/00-test/_00-hidden-pattern.mustache b/packages/core/test/files/_patterns/test/_hidden-pattern.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/_00-hidden-pattern.mustache
rename to packages/core/test/files/_patterns/test/_hidden-pattern.mustache
diff --git a/packages/core/test/files/_patterns/00-test/_ignored-pattern.mustache b/packages/core/test/files/_patterns/test/_ignored-pattern.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/_ignored-pattern.mustache
rename to packages/core/test/files/_patterns/test/_ignored-pattern.mustache
diff --git a/packages/core/test/files/_patterns/00-test/539-a.mustache b/packages/core/test/files/_patterns/test/a.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/539-a.mustache
rename to packages/core/test/files/_patterns/test/a.mustache
diff --git a/packages/core/test/files/_patterns/00-test/12-another-styled-atom.mustache b/packages/core/test/files/_patterns/test/another-styled-atom.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/12-another-styled-atom.mustache
rename to packages/core/test/files/_patterns/test/another-styled-atom.mustache
diff --git a/packages/core/test/files/_patterns/00-test/539-b.mustache b/packages/core/test/files/_patterns/test/b.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/539-b.mustache
rename to packages/core/test/files/_patterns/test/b.mustache
diff --git a/packages/core/test/files/_patterns/00-test/01-bar.md b/packages/core/test/files/_patterns/test/bar.md
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/01-bar.md
rename to packages/core/test/files/_patterns/test/bar.md
diff --git a/packages/core/test/files/_patterns/00-test/01-bar.mustache b/packages/core/test/files/_patterns/test/bar.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/01-bar.mustache
rename to packages/core/test/files/_patterns/test/bar.mustache
diff --git a/packages/core/test/files/_patterns/00-test/02-baz.md b/packages/core/test/files/_patterns/test/baz.md
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/02-baz.md
rename to packages/core/test/files/_patterns/test/baz.md
diff --git a/packages/core/test/files/_patterns/00-test/02-baz.mustache b/packages/core/test/files/_patterns/test/baz.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/02-baz.mustache
rename to packages/core/test/files/_patterns/test/baz.mustache
diff --git a/packages/core/test/files/_patterns/00-test/11-bookend-listitem.mustache b/packages/core/test/files/_patterns/test/bookend-listitem.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/11-bookend-listitem.mustache
rename to packages/core/test/files/_patterns/test/bookend-listitem.mustache
diff --git a/packages/core/test/files/_patterns/00-test/08-bookend-params.mustache b/packages/core/test/files/_patterns/test/bookend-params.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/08-bookend-params.mustache
rename to packages/core/test/files/_patterns/test/bookend-params.mustache
diff --git a/packages/core/test/files/_patterns/00-test/09-bookend.mustache b/packages/core/test/files/_patterns/test/bookend.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/09-bookend.mustache
rename to packages/core/test/files/_patterns/test/bookend.mustache
diff --git a/packages/core/test/files/_patterns/00-test/539-c.mustache b/packages/core/test/files/_patterns/test/c.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/539-c.mustache
rename to packages/core/test/files/_patterns/test/c.mustache
diff --git a/packages/core/test/files/_patterns/00-test/comment-tag.mustache b/packages/core/test/files/_patterns/test/comment-tag.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/comment-tag.mustache
rename to packages/core/test/files/_patterns/test/comment-tag.mustache
diff --git a/packages/core/test/files/_patterns/00-test/comment.mustache b/packages/core/test/files/_patterns/test/comment.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/comment.mustache
rename to packages/core/test/files/_patterns/test/comment.mustache
diff --git a/packages/core/test/files/_patterns/00-test/00-foo.md b/packages/core/test/files/_patterns/test/foo.md
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/00-foo.md
rename to packages/core/test/files/_patterns/test/foo.md
diff --git a/packages/core/test/files/_patterns/00-test/00-foo.mustache b/packages/core/test/files/_patterns/test/foo.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/00-foo.mustache
rename to packages/core/test/files/_patterns/test/foo.mustache
diff --git a/packages/core/test/files/_patterns/00-test/04-group.mustache b/packages/core/test/files/_patterns/test/group.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/04-group.mustache
rename to packages/core/test/files/_patterns/test/group.mustache
diff --git a/packages/core/test/files/_patterns/00-test/05-group2.mustache b/packages/core/test/files/_patterns/test/group2.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/05-group2.mustache
rename to packages/core/test/files/_patterns/test/group2.mustache
diff --git a/packages/core/test/files/_patterns/00-test/15-hidden-pattern-tester.mustache b/packages/core/test/files/_patterns/test/hidden-pattern-tester.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/15-hidden-pattern-tester.mustache
rename to packages/core/test/files/_patterns/test/hidden-pattern-tester.mustache
diff --git a/packages/core/test/files/_patterns/00-test/14-inception.mustache b/packages/core/test/files/_patterns/test/inception.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/14-inception.mustache
rename to packages/core/test/files/_patterns/test/inception.mustache
diff --git a/packages/core/test/files/_patterns/00-test/link.mustache b/packages/core/test/files/_patterns/test/link.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/link.mustache
rename to packages/core/test/files/_patterns/test/link.mustache
diff --git a/packages/core/test/files/_patterns/00-test/linkInParameter.mustache b/packages/core/test/files/_patterns/test/linkInParameter.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/linkInParameter.mustache
rename to packages/core/test/files/_patterns/test/linkInParameter.mustache
diff --git a/packages/core/test/files/_patterns/00-test/685-list.mustache b/packages/core/test/files/_patterns/test/list.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/685-list.mustache
rename to packages/core/test/files/_patterns/test/list.mustache
diff --git a/packages/core/test/files/_patterns/00-test/listWithListItems.listitems.json b/packages/core/test/files/_patterns/test/listWithListItems.listitems.json
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/listWithListItems.listitems.json
rename to packages/core/test/files/_patterns/test/listWithListItems.listitems.json
diff --git a/packages/core/test/files/_patterns/00-test/listWithListItems.mustache b/packages/core/test/files/_patterns/test/listWithListItems.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/listWithListItems.mustache
rename to packages/core/test/files/_patterns/test/listWithListItems.mustache
diff --git a/packages/core/test/files/_patterns/00-test/listWithPartial.mustache b/packages/core/test/files/_patterns/test/listWithPartial.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/listWithPartial.mustache
rename to packages/core/test/files/_patterns/test/listWithPartial.mustache
diff --git a/packages/core/test/files/_patterns/00-test/13-listitem.mustache b/packages/core/test/files/_patterns/test/listitem.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/13-listitem.mustache
rename to packages/core/test/files/_patterns/test/listitem.mustache
diff --git a/packages/core/test/files/_patterns/00-test/mirror.mustache b/packages/core/test/files/_patterns/test/mirror.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/mirror.mustache
rename to packages/core/test/files/_patterns/test/mirror.mustache
diff --git a/packages/core/test/files/_patterns/00-test/07-mixed-params.mustache b/packages/core/test/files/_patterns/test/mixed-params.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/07-mixed-params.mustache
rename to packages/core/test/files/_patterns/test/mixed-params.mustache
diff --git a/packages/core/test/files/_patterns/00-test/06-mixed.mustache b/packages/core/test/files/_patterns/test/mixed.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/06-mixed.mustache
rename to packages/core/test/files/_patterns/test/mixed.mustache
diff --git a/packages/core/test/files/_patterns/00-test/10-multiple-classes-numeric.mustache b/packages/core/test/files/_patterns/test/multiple-classes-numeric.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/10-multiple-classes-numeric.mustache
rename to packages/core/test/files/_patterns/test/multiple-classes-numeric.mustache
diff --git a/packages/core/test/files/_patterns/test/nav.json b/packages/core/test/files/_patterns/test/nav.json
new file mode 100644
index 000000000..8d47a2491
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/nav.json
@@ -0,0 +1,29 @@
+{
+ "brad": {
+ "url": "link.twitter-brad"
+ },
+ "dave": {
+ "url": "link.twitter-dave"
+ },
+ "brian": {
+ "url": "link.twitter-brian"
+ },
+ "someone": {
+ "url": "link.twitter-someone"
+ },
+ "someone2": {
+ "url": "link.facebook-someone2"
+ },
+ "viewall-twitter": {
+ "url": "link.viewall-twitter-all"
+ },
+ "viewall-twitter-people": {
+ "url": "link.viewall-twitter-people"
+ },
+ "viewall-facebook": {
+ "url": "link.viewall-facebook-all"
+ },
+ "viewall-facebook-people": {
+ "url": "link.viewall-facebook-people"
+ }
+}
\ No newline at end of file
diff --git a/packages/core/test/files/_patterns/00-test/nav.mustache b/packages/core/test/files/_patterns/test/nav.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/nav.mustache
rename to packages/core/test/files/_patterns/test/nav.mustache
diff --git a/packages/core/test/files/_patterns/test/paramMiddle.mustache b/packages/core/test/files/_patterns/test/paramMiddle.mustache
new file mode 100644
index 000000000..b69912370
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/paramMiddle.mustache
@@ -0,0 +1,3 @@
+
+ {{> test-link }}
+
diff --git a/packages/core/test/files/_patterns/00-test/paramParent.json b/packages/core/test/files/_patterns/test/paramParent.json
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/paramParent.json
rename to packages/core/test/files/_patterns/test/paramParent.json
diff --git a/packages/core/test/files/_patterns/test/paramParent.mustache b/packages/core/test/files/_patterns/test/paramParent.mustache
new file mode 100644
index 000000000..5ae3cb466
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/paramParent.mustache
@@ -0,0 +1 @@
+{{> test-paramMiddle(additionalClasses: "foo") }}
diff --git a/packages/core/test/files/_patterns/00-test/parameterTags.mustache b/packages/core/test/files/_patterns/test/parameterTags.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/parameterTags.mustache
rename to packages/core/test/files/_patterns/test/parameterTags.mustache
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/files/_patterns/00-test/474-pseudomodifier.mustache b/packages/core/test/files/_patterns/test/pseudomodifier.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/474-pseudomodifier.mustache
rename to packages/core/test/files/_patterns/test/pseudomodifier.mustache
diff --git a/packages/core/test/files/_patterns/00-test/474-pseudomodifier~test.json b/packages/core/test/files/_patterns/test/pseudomodifier~test.json
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/474-pseudomodifier~test.json
rename to packages/core/test/files/_patterns/test/pseudomodifier~test.json
diff --git a/packages/core/test/files/_patterns/00-test/553-repeatedListItems.mustache b/packages/core/test/files/_patterns/test/repeatedListItems.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/553-repeatedListItems.mustache
rename to packages/core/test/files/_patterns/test/repeatedListItems.mustache
diff --git a/packages/core/test/files/_patterns/test/sticky-comment-verbose.mustache b/packages/core/test/files/_patterns/test/sticky-comment-verbose.mustache
new file mode 100644
index 000000000..168b757d9
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/sticky-comment-verbose.mustache
@@ -0,0 +1 @@
+{{> test/comment(description: 'A life is like a garden. Perfect moments can be had, but not preserved, except in memory.') }}
diff --git a/packages/core/test/files/_patterns/00-test/sticky-comment.mustache b/packages/core/test/files/_patterns/test/sticky-comment.mustache
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/sticky-comment.mustache
rename to packages/core/test/files/_patterns/test/sticky-comment.mustache
diff --git a/packages/core/test/files/_patterns/00-test/03-styled-atom.json b/packages/core/test/files/_patterns/test/styled-atom.json
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/03-styled-atom.json
rename to packages/core/test/files/_patterns/test/styled-atom.json
diff --git a/packages/core/test/files/_patterns/00-test/03-styled-atom.md b/packages/core/test/files/_patterns/test/styled-atom.md
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/03-styled-atom.md
rename to packages/core/test/files/_patterns/test/styled-atom.md
diff --git a/packages/core/test/files/_patterns/test/styled-atom.mustache b/packages/core/test/files/_patterns/test/styled-atom.mustache
new file mode 100644
index 000000000..e85d0fc26
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/styled-atom.mustache
@@ -0,0 +1,3 @@
+
+ {{message}}
+
diff --git a/packages/core/test/files/_patterns/00-test/03-styled-atom~alt.json b/packages/core/test/files/_patterns/test/styled-atom~alt.json
similarity index 100%
rename from packages/core/test/files/_patterns/00-test/03-styled-atom~alt.json
rename to packages/core/test/files/_patterns/test/styled-atom~alt.json
diff --git a/packages/core/test/files/_patterns/test/variant-test.json b/packages/core/test/files/_patterns/test/variant-test.json
new file mode 100644
index 000000000..9d371748a
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/variant-test.json
@@ -0,0 +1,9 @@
+{
+ "a": 1,
+ "b": [2, 3],
+ "c": {
+ "d": [4, 5],
+ "e": 8,
+ "f": {"a": ["a"], "b": ["b"], "c": ["c"]}
+ }
+}
\ No newline at end of file
diff --git a/packages/core/test/files/_patterns/test/variant-test.mustache b/packages/core/test/files/_patterns/test/variant-test.mustache
new file mode 100644
index 000000000..fe4dd1f58
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/variant-test.mustache
@@ -0,0 +1 @@
+{{a}}
\ No newline at end of file
diff --git a/packages/core/test/files/_patterns/test/variant-test~merge.json b/packages/core/test/files/_patterns/test/variant-test~merge.json
new file mode 100644
index 000000000..c60d0974c
--- /dev/null
+++ b/packages/core/test/files/_patterns/test/variant-test~merge.json
@@ -0,0 +1,8 @@
+{
+ "a": 2,
+ "b": [8],
+ "c": {
+ "d": [6, 7],
+ "f": {"b": ["x"]}
+ }
+}
\ No newline at end of file
diff --git a/packages/core/test/files/_react-test-patterns/00-atoms/00-general/HelloWorld.jsx b/packages/core/test/files/_react-test-patterns/atoms/general/HelloWorld.jsx
similarity index 100%
rename from packages/core/test/files/_react-test-patterns/00-atoms/00-general/HelloWorld.jsx
rename to packages/core/test/files/_react-test-patterns/atoms/general/HelloWorld.jsx
diff --git a/packages/core/test/files/_twig-test-patterns/00-atoms/00-general/09-image.twig b/packages/core/test/files/_twig-test-patterns/00-atoms/00-general/09-image.twig
deleted file mode 100644
index 01c4af9f8..000000000
--- a/packages/core/test/files/_twig-test-patterns/00-atoms/00-general/09-image.twig
+++ /dev/null
@@ -1,5 +0,0 @@
-
diff --git a/packages/core/test/files/_twig-test-patterns/00-atoms/00-general/08-button.twig b/packages/core/test/files/_twig-test-patterns/atoms/general/button.twig
similarity index 100%
rename from packages/core/test/files/_twig-test-patterns/00-atoms/00-general/08-button.twig
rename to packages/core/test/files/_twig-test-patterns/atoms/general/button.twig
diff --git a/packages/core/test/files/_twig-test-patterns/atoms/general/image.twig b/packages/core/test/files/_twig-test-patterns/atoms/general/image.twig
new file mode 100644
index 000000000..320401c8e
--- /dev/null
+++ b/packages/core/test/files/_twig-test-patterns/atoms/general/image.twig
@@ -0,0 +1,5 @@
+
diff --git a/packages/core/test/files/_twig-test-patterns/00-molecules/00-general/00-media-object.twig b/packages/core/test/files/_twig-test-patterns/molecules/general/media-object.twig
similarity index 100%
rename from packages/core/test/files/_twig-test-patterns/00-molecules/00-general/00-media-object.twig
rename to packages/core/test/files/_twig-test-patterns/molecules/general/media-object.twig
diff --git a/packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/00-helloworld-withdata.html b/packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/00-helloworld-withdata.html
deleted file mode 100644
index 32c1c7361..000000000
--- a/packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/00-helloworld-withdata.html
+++ /dev/null
@@ -1,2 +0,0 @@
-Hello world!
-<%= subtitle %>
diff --git a/packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-helloworlds.html b/packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-helloworlds.html
deleted file mode 100644
index a493205c3..000000000
--- a/packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-helloworlds.html
+++ /dev/null
@@ -1 +0,0 @@
-<%= _.template(_partials['atoms-helloworld'])(_data) %> and <%= _.template(_partials['atoms-helloworld'])(_data) %>
diff --git a/packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/_00-hidden.html b/packages/core/test/files/_underscore-test-patterns/atoms/global/_hidden.html
similarity index 100%
rename from packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/_00-hidden.html
rename to packages/core/test/files/_underscore-test-patterns/atoms/global/_hidden.html
diff --git a/packages/core/test/files/_underscore-test-patterns/atoms/global/helloworld-withdata.html b/packages/core/test/files/_underscore-test-patterns/atoms/global/helloworld-withdata.html
new file mode 100644
index 000000000..92e7cd0d0
--- /dev/null
+++ b/packages/core/test/files/_underscore-test-patterns/atoms/global/helloworld-withdata.html
@@ -0,0 +1 @@
+Hello world! <%= subtitle %>
diff --git a/packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/00-helloworld-withdata.json b/packages/core/test/files/_underscore-test-patterns/atoms/global/helloworld-withdata.json
similarity index 100%
rename from packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/00-helloworld-withdata.json
rename to packages/core/test/files/_underscore-test-patterns/atoms/global/helloworld-withdata.json
diff --git a/packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/00-helloworld.html b/packages/core/test/files/_underscore-test-patterns/atoms/global/helloworld.html
similarity index 100%
rename from packages/core/test/files/_underscore-test-patterns/00-atoms/00-global/00-helloworld.html
rename to packages/core/test/files/_underscore-test-patterns/atoms/global/helloworld.html
diff --git a/packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.html b/packages/core/test/files/_underscore-test-patterns/molecules/global/call-atom-with-molecule-data.html
similarity index 100%
rename from packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.html
rename to packages/core/test/files/_underscore-test-patterns/molecules/global/call-atom-with-molecule-data.html
diff --git a/packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.json b/packages/core/test/files/_underscore-test-patterns/molecules/global/call-atom-with-molecule-data.json
similarity index 100%
rename from packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-call-atom-with-molecule-data.json
rename to packages/core/test/files/_underscore-test-patterns/molecules/global/call-atom-with-molecule-data.json
diff --git a/packages/core/test/files/_underscore-test-patterns/molecules/global/helloworlds.html b/packages/core/test/files/_underscore-test-patterns/molecules/global/helloworlds.html
new file mode 100644
index 000000000..a7e774300
--- /dev/null
+++ b/packages/core/test/files/_underscore-test-patterns/molecules/global/helloworlds.html
@@ -0,0 +1,2 @@
+<%= _.template(_partials['atoms-helloworld'])(_data) %> and <%=
+_.template(_partials['atoms-helloworld'])(_data) %>
diff --git a/packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-hidden-pattern-tester.html b/packages/core/test/files/_underscore-test-patterns/molecules/global/hidden-pattern-tester.html
similarity index 100%
rename from packages/core/test/files/_underscore-test-patterns/00-molecules/00-global/00-hidden-pattern-tester.html
rename to packages/core/test/files/_underscore-test-patterns/molecules/global/hidden-pattern-tester.html
diff --git a/packages/core/test/files/annotations.js b/packages/core/test/files/annotations.js
index 6bc8c1432..66a3475c4 100644
--- a/packages/core/test/files/annotations.js
+++ b/packages/core/test/files/annotations.js
@@ -8,7 +8,7 @@ var comments = {
{
"el": ".logo",
"title": "Logo",
- "comment": "The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don't support SVG images.Further reading: Optimizing Web Experiences for High Resolution Screens
"
+ "comment": "The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don't support SVG images.Further reading: Optimizing Web Experiences for High Resolution Screens
"
}
]
};
diff --git a/packages/core/test/files/partials/patternSectionSubgroup.mustache b/packages/core/test/files/partials/patternSectionSubgroup.mustache
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/core/test/get_tests.js b/packages/core/test/get_tests.js
index 5e954182c..59be0fd20 100644
--- a/packages/core/test/get_tests.js
+++ b/packages/core/test/get_tests.js
@@ -7,29 +7,30 @@ const getPartial = require('../src/lib/get');
const patterns_dir = './test/files/_patterns';
-tap.test('getPartial - returns the fuzzy result when no others found', function(
- test
-) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
- patternlab.patterns = [];
+tap.test(
+ 'getPartial - returns the fuzzy result when no others found',
+ function (test) {
+ //arrange
+ const patternlab = util.fakePatternLab(patterns_dir);
+ patternlab.patterns = [];
- patternlab.patterns.push({
- patternPartial: 'character-han-solo',
- subdir: 'character',
- fileName: 'han-solo',
- verbosePartial: 'character/han-solo',
- });
+ patternlab.patterns.push({
+ patternPartial: 'character-han-solo',
+ subdir: 'character',
+ fileName: 'han-solo',
+ verbosePartial: 'character/han-solo',
+ });
- //act
- var result = getPartial('character-han', patternlab);
+ //act
+ var result = getPartial('character-han', patternlab);
- //assert
- test.equals(result, patternlab.patterns[0]);
- test.end();
-});
+ //assert
+ test.equal(result, patternlab.patterns[0]);
+ test.end();
+ }
+);
-tap.test('getPartial - returns the verbose result if found', function(test) {
+tap.test('getPartial - returns the verbose result if found', function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
patternlab.patterns = [];
@@ -53,11 +54,11 @@ tap.test('getPartial - returns the verbose result if found', function(test) {
var result = getPartial('molecules/primary-nav', patternlab);
//assert
- test.equals(result, patternlab.patterns[1]);
+ test.equal(result, patternlab.patterns[1]);
test.end();
});
-tap.test('getPartial - returns the exact key if found', function(test) {
+tap.test('getPartial - returns the exact key if found', function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
patternlab.patterns = [];
@@ -79,6 +80,6 @@ tap.test('getPartial - returns the exact key if found', function(test) {
var result = getPartial('molecules-primary-nav', patternlab);
//assert
- test.equals(result, patternlab.patterns[1]);
+ test.equal(result, patternlab.patterns[1]);
test.end();
});
diff --git a/packages/core/test/index_tests.js b/packages/core/test/index_tests.js
index d2e98895e..5cf82654e 100644
--- a/packages/core/test/index_tests.js
+++ b/packages/core/test/index_tests.js
@@ -15,33 +15,33 @@ process.env.PATTERNLAB_ENV = 'CI';
//set up a global mocks - we don't want to be writing/rendering any files right now
-const copierMock = function() {
+const copierMock = function () {
return {
- copyAndWatch: function() {
+ copyAndWatch: function () {
return Promise.resolve();
},
};
};
-const uiBuilderMock = function() {
+const uiBuilderMock = function () {
return {
- buildFrontend: function() {
+ buildFrontend: function () {
return Promise.resolve();
},
};
};
const fsMock = {
- outputFileSync: function(path, content) {
+ outputFileSync: function (path, content) {
/* INTENTIONAL NOOP */
},
- readJSONSync: function(path, encoding) {
+ readJSONSync: function (path, encoding) {
return fs.readJSONSync(path, encoding);
},
- emptyDir: function(path) {
+ emptyDir: function (path) {
return fs.emptyDir(path);
},
- readFileSync: function(path, encoding) {
+ readFileSync: function (path, encoding) {
return fs.readFileSync(path, encoding);
},
};
@@ -57,29 +57,29 @@ entry.__set__({
copier: copierMock,
});
-tap.test('version - should call patternlab.getVersion', test => {
+tap.test('version - should call patternlab.getVersion', (test) => {
//arrange
const pl = new entry(testConfig);
//act
//assert
- test.equals(pl.version(), packageInfo.version);
+ test.equal(pl.version(), packageInfo.version);
test.end();
});
tap.test(
'getDefaultConfig - static method should return the default config object',
- test => {
+ (test) => {
const requestedConfig = entry.getDefaultConfig();
test.type(requestedConfig, 'object');
- test.equals(requestedConfig, defaultConfig);
+ test.equal(requestedConfig, defaultConfig);
test.end();
}
);
tap.test(
'getDefaultConfig - instance method should return the default config object',
- test => {
+ (test) => {
//arrange
const pl = new entry(testConfig);
@@ -87,12 +87,12 @@ tap.test(
//assert
const requestedConfig = pl.getDefaultConfig();
test.type(requestedConfig, 'object');
- test.equals(requestedConfig, defaultConfig);
+ test.equal(requestedConfig, defaultConfig);
test.end();
}
);
-tap.test('patternsonly a promise', test => {
+tap.test('patternsonly a promise', (test) => {
//arrange
const revert = entry.__set__('buildPatterns', buildPatternsMock);
const pl = new entry(testConfig);
@@ -104,7 +104,7 @@ tap.test('patternsonly a promise', test => {
});
});
-tap.test('patternsonly calls buildPatterns', test => {
+tap.test('patternsonly calls buildPatterns', (test) => {
//arrange
const revert = entry.__set__(
'buildPatterns',
@@ -113,7 +113,7 @@ tap.test('patternsonly calls buildPatterns', test => {
test.ok(cleanPublic);
test.type(patternlab, 'object');
test.type(data, 'object');
- test.equals(data.foo, 'bar');
+ test.equal(data.foo, 'bar');
return Promise.resolve();
}
);
@@ -128,9 +128,9 @@ tap.test('patternsonly calls buildPatterns', test => {
});
});
-tap.test('serve calls serve', test => {
+tap.test('serve calls serve', (test) => {
//arrange
- const revert = entry.__set__('serverModule', patternlab => {
+ const revert = entry.__set__('serverModule', (patternlab) => {
return {
serve: () => {
test.ok(1);
@@ -149,7 +149,7 @@ tap.test('serve calls serve', test => {
});
});
-tap.test('buildPatterns suite', test => {
+tap.test('buildPatterns suite', (test) => {
//arrange
const patternExporterMock = {
@@ -158,19 +158,18 @@ tap.test('buildPatterns suite', test => {
the contents of the patterns look like. This, coupled with a mocking of fs and the ui_builder, allow us to focus
only on the order of events within build.
*/
- export_patterns: function(patternlab) {
+ export_patterns: function (patternlab) {
tap.test(
'replace data link even when pattern parameter present',
- function(test) {
+ function (test) {
var pattern = get('test-paramParent', patternlab);
- test.equals(
+ test.equal(
util.sanitized(pattern.extendedTemplate),
'',
'partial inclusion completes'
);
- test.equals(
- pattern.patternPartialCode.indexOf('00-test-00-foo.rendered.html') >
- -1,
+ test.equal(
+ pattern.patternPartialCode.indexOf('test-foo.rendered.html') > -1,
true,
'data link should be replaced properly'
);
@@ -180,9 +179,9 @@ tap.test('buildPatterns suite', test => {
tap.test(
'finds partials with their own parameters and renders them too',
- function(test) {
+ function (test) {
var pattern = get('test-c', patternlab);
- test.equals(
+ test.equal(
util.sanitized(pattern.patternPartialCode),
util.sanitized(`c
b
@@ -196,9 +195,9 @@ tap.test('buildPatterns suite', test => {
tap.test(
'finds and extends templates with mixed parameter and global data',
- function(test) {
+ function (test) {
var pattern = get('test-sticky-comment', patternlab);
- test.equals(
+ test.equal(
util.sanitized(pattern.patternPartialCode),
util.sanitized(
`Bar A life is like a garden. Perfect moments can be had, but not preserved, except in memory.
`
@@ -208,21 +207,21 @@ tap.test('buildPatterns suite', test => {
}
);
- tap.test('expands links inside parameters', function(test) {
+ tap.test('expands links inside parameters', function (test) {
var pattern = get('test-linkInParameter', patternlab);
- test.equals(
+ test.equal(
util.sanitized(pattern.patternPartialCode),
util.sanitized(
- `Cool Dude `
+ `Cool Dude `
)
);
test.end();
});
- tap.test('uses global listItem property', test => {
+ tap.test('uses global listItem property', (test) => {
var pattern = get('test-listWithPartial', patternlab);
let assertionCount = 0;
- ['dA', 'dB', 'dC'].forEach(d => {
+ ['dA', 'dB', 'dC'].forEach((d) => {
if (pattern.patternPartialCode.indexOf(d) > -1) {
assertionCount++;
}
@@ -233,7 +232,7 @@ tap.test('buildPatterns suite', test => {
tap.test(
'overwrites listItem property if that property is in local .listitem.json',
- test => {
+ (test) => {
var pattern = get('test-listWithListItems', patternlab);
test.ok(pattern.patternPartialCode.indexOf('tX') > -1);
test.ok(pattern.patternPartialCode.indexOf('tY') > -1);
@@ -245,7 +244,7 @@ tap.test('buildPatterns suite', test => {
tap.test(
'uses global listItem property after merging local .listitem.json',
- test => {
+ (test) => {
var pattern = get('test-listWithListItems', patternlab);
test.ok(pattern.patternPartialCode.indexOf('dA') > -1);
test.ok(pattern.patternPartialCode.indexOf('dB') > -1);
@@ -254,39 +253,11 @@ tap.test('buildPatterns suite', test => {
}
);
- tap.test(
- 'correctly ignores bookended partials without a style modifier when the same partial has a style modifier between',
- test => {
- var pattern = get('test-bookend-listitem', patternlab);
- test.equals(
- util.sanitized(pattern.extendedTemplate),
- util.sanitized(`
- {{#listItems-two}}
-
- {{message}}
-
-
-
- {{message}}
-
-
-
- {{message}}
-
-
- {{/listItems-two}}
-
- `)
- );
- test.end();
- }
- );
-
tap.test(
'listItems keys (`one` through `twelve`) can be used more than once per pattern',
- test => {
+ (test) => {
var pattern = get('test-repeatedListItems', patternlab);
- test.equals(
+ test.equal(
util.sanitized(pattern.patternPartialCode),
util.sanitized(`AAA BBB`)
);
@@ -299,7 +270,7 @@ tap.test('buildPatterns suite', test => {
// From issue #145 https://github.com/pattern-lab/patternlab-node/issues/145
// tap.test(' parses parameters containing html tags', function (test) {
// var pattern = get('test-parameterTags', patternlab);
- // test.equals(util.sanitized(pattern.patternPartialCode), util.sanitized(`Single-quoted
Double-quoted
With attributes
`));
+ // test.equal(util.sanitized(pattern.patternPartialCode), util.sanitized(`Single-quoted
Double-quoted
With attributes
`));
// test.end();
// });
@@ -314,7 +285,7 @@ tap.test('buildPatterns suite', test => {
testConfig.patternExportPatternPartials = ['test-paramParent'];
const pl = new entry(testConfig);
- test.equals(pl.events.eventNames().length, 0);
+ test.equal(pl.events.eventNames().length, 0);
//act
return pl
@@ -326,12 +297,12 @@ tap.test('buildPatterns suite', test => {
},
})
.then(() => {
- test.equals(
+ test.equal(
pl.events.eventNames().length,
2,
'should register two events'
);
- test.equals(pl.events.listenerCount(events.PATTERNLAB_PATTERN_CHANGE), 1);
- test.equals(pl.events.listenerCount(events.PATTERNLAB_GLOBAL_CHANGE), 1);
+ test.equal(pl.events.listenerCount(events.PATTERNLAB_PATTERN_CHANGE), 1);
+ test.equal(pl.events.listenerCount(events.PATTERNLAB_GLOBAL_CHANGE), 1);
});
});
diff --git a/packages/core/test/lineage_hunter_tests.js b/packages/core/test/lineage_hunter_tests.js
index b19157a28..31a40b764 100644
--- a/packages/core/test/lineage_hunter_tests.js
+++ b/packages/core/test/lineage_hunter_tests.js
@@ -22,7 +22,7 @@ const lineage_hunter = new lh();
// fake pattern creators
function createFakeEmptyErrorPattern() {
return new Pattern(
- '01-molecules/01-toast/00-error.mustache', // relative path now
+ 'molecules/toast/error.mustache', // relative path now
null // data
);
}
@@ -53,42 +53,41 @@ function createBasePatternLabObject() {
pl.patterns = [];
pl.partials = {};
pl.patternGroups = {};
- pl.subtypePatterns = {};
+ pl.subgroupPatterns = {};
return pl;
}
-tap.test('find_lineage - finds lineage', function(test) {
+tap.test('find_lineage - finds lineage', function (test) {
//setup current pattern from what we would have during execution
var currentPattern = new Pattern(
- '02-organisms/00-global/00-header.mustache', // relative path now
+ 'organisms/global/header.mustache', // relative path now
null // data
);
extend(currentPattern, {
template:
'\r\n\r\n\r\n',
patternPartialCode:
- '\r\n\r\n\r\n',
+ '\r\n\r\n\r\n',
});
var patternlab = {
graph: new PatternGraph(null, 0),
patterns: [
Pattern.createEmpty({
- name: '00-atoms-03-images-00-logo',
- subdir: '00-atoms\\03-images',
- filename: '00-logo.mustache',
+ name: 'atoms-images-logo',
+ subdir: 'atoms\\images',
+ filename: 'logo.mustache',
data: null,
template:
' ',
patternPartialCode:
' ',
patternBaseName: 'logo',
- patternLink:
- '00-atoms-03-images-00-logo/00-atoms-03-images-00-logo.html',
+ patternLink: 'atoms-images-logo/atoms-images-logo.html',
patternGroup: 'atoms',
- patternSubGroup: 'atoms\\03-images',
- flatPatternPath: '00-atoms\\03-images',
+ patternSubgroup: 'atoms\\images',
+ flatPatternPath: 'atoms\\images',
patternPartial: 'atoms-logo',
patternState: '',
lineage: [],
@@ -97,9 +96,9 @@ tap.test('find_lineage - finds lineage', function(test) {
lineageRIndex: [],
}),
Pattern.createEmpty({
- name: '01-molecules-05-navigation-00-primary-nav',
- subdir: '01-molecules\\05-navigation',
- filename: '00-primary-nav.mustache',
+ name: 'molecules-navigation-primary-nav',
+ subdir: 'molecules\\navigation',
+ filename: 'primary-nav.mustache',
data: null,
template:
'\r\n\t\r\n \r\n',
@@ -107,10 +106,10 @@ tap.test('find_lineage - finds lineage', function(test) {
'\r\n\t\r\n \r\n',
patternBaseName: 'primary-nav',
patternLink:
- '01-molecules-05-navigation-00-primary-nav/01-molecules-05-navigation-00-primary-nav.html',
+ 'molecules-navigation-primary-nav/molecules-navigation-primary-nav.html',
patternGroup: 'molecules',
- patternSubGroup: 'molecules\\05-navigation',
- flatPatternPath: '01-molecules\\05-navigation',
+ patternSubgroup: 'molecules\\navigation',
+ flatPatternPath: 'molecules\\navigation',
patternPartial: 'molecules-primary-nav',
patternState: '',
lineage: [],
@@ -119,20 +118,19 @@ tap.test('find_lineage - finds lineage', function(test) {
lineageRIndex: [],
}),
Pattern.createEmpty({
- name: '01-molecules-04-forms-00-search',
- subdir: '01-molecules\\04-forms',
- filename: '00-search.mustache',
+ name: 'molecules-forms-search',
+ subdir: 'molecules\\forms',
+ filename: 'search.mustache',
data: null,
template:
- '',
+ '',
patternPartialCode:
- '',
+ '',
patternBaseName: 'search',
- patternLink:
- '01-molecules-04-forms-00-search/01-molecules-04-forms-00-search.html',
+ patternLink: 'molecules-forms-search/molecules-forms-search.html',
patternGroup: 'molecules',
- patternSubGroup: 'molecules\\04-forms',
- flatPatternPath: '01-molecules\\04-forms',
+ patternSubgroup: 'molecules\\forms',
+ flatPatternPath: 'molecules\\forms',
patternPartial: 'molecules-search',
patternState: '',
lineage: [],
@@ -150,7 +148,7 @@ tap.test('find_lineage - finds lineage', function(test) {
},
};
// BAD: This "patches" the relative path which is unset when using "createEmpty"
- patternlab.patterns.forEach(p => (p.relPath = p.patternLink));
+ patternlab.patterns.forEach((p) => (p.relPath = p.patternLink));
lineage_hunter.find_lineage(currentPattern, patternlab);
@@ -158,10 +156,10 @@ tap.test('find_lineage - finds lineage', function(test) {
// Ensure compatibility
for (let i of [currentPattern.lineageIndex, graphLineageIndex]) {
- test.equals(i.length, 3);
- test.equals(i[0], 'atoms-logo');
- test.equals(i[1], 'molecules-primary-nav');
- test.equals(i[2], 'molecules-search');
+ test.equal(i.length, 3);
+ test.equal(i[0], 'atoms-logo');
+ test.equal(i[1], 'molecules-primary-nav');
+ test.equal(i[2], 'molecules-search');
}
test.end();
@@ -169,7 +167,7 @@ tap.test('find_lineage - finds lineage', function(test) {
tap.test(
'find_lineage - finds lineage with spaced pattern parameters',
- function(test) {
+ function (test) {
//setup current pattern from what we would have during execution
var currentPattern = createFakeEmptyErrorPattern();
extend(currentPattern, {
@@ -180,7 +178,7 @@ tap.test(
var patternlab = {
graph: new PatternGraph(null, 0),
patterns: [
- Pattern.create('00-atoms/05-alerts/00-error.mustache', null, {
+ Pattern.create('atoms/alerts/error.mustache', null, {
template: ' {{message}} ',
extendedTemplate: ' {{message}} ',
}),
@@ -196,10 +194,10 @@ tap.test(
lineage_hunter.find_lineage(currentPattern, patternlab);
- test.equals(currentPattern.lineageIndex.length, 1);
- test.equals(currentPattern.lineageIndex[0], 'atoms-error');
- test.equals(patternlab.patterns[0].lineageRIndex.length, 1);
- test.equals(
+ test.equal(currentPattern.lineageIndex.length, 1);
+ test.equal(currentPattern.lineageIndex[0], 'atoms-error');
+ test.equal(patternlab.patterns[0].lineageRIndex.length, 1);
+ test.equal(
patternlab.patterns[0].lineageR[0].lineagePattern,
'molecules-error'
);
@@ -214,14 +212,14 @@ tap.test(
);
var currentPatternLineageIndex = graph.lineageIndex(currentPattern);
- test.equals(currentPatternLineageIndex.length, 1);
- test.equals(currentPatternLineageIndex[0], 'atoms-error');
+ test.equal(currentPatternLineageIndex.length, 1);
+ test.equal(currentPatternLineageIndex[0], 'atoms-error');
var patternlabPattern0_lineageRIndex = graph.lineageRIndex(
patternlab.patterns[0]
);
- test.equals(patternlabPattern0_lineageRIndex.length, 1);
- test.equals(patternlabPattern0_lineageRIndex[0], 'molecules-error');
+ test.equal(patternlabPattern0_lineageRIndex.length, 1);
+ test.equal(patternlabPattern0_lineageRIndex[0], 'molecules-error');
test.end();
}
@@ -229,13 +227,13 @@ tap.test(
tap.test(
'cascade_pattern_states promotes a lower pattern state up to the consumer',
- function(test) {
+ function (test) {
//arrange
var pl = createBasePatternLabObject();
- var atomPattern = new of.Pattern('00-test/01-bar.mustache');
+ var atomPattern = new of.Pattern('test/bar.mustache');
atomPattern.template = fs.readFileSync(
- pl.config.paths.source.patterns + '00-test/01-bar.mustache',
+ pl.config.paths.source.patterns + 'test/bar.mustache',
'utf8'
);
atomPattern.extendedTemplate = atomPattern.template;
@@ -243,9 +241,9 @@ tap.test(
addPattern(atomPattern, pl);
- var consumerPattern = new of.Pattern('00-test/00-foo.mustache');
+ var consumerPattern = new of.Pattern('test/foo.mustache');
consumerPattern.template = fs.readFileSync(
- pl.config.paths.source.patterns + '00-test/00-foo.mustache',
+ pl.config.paths.source.patterns + 'test/foo.mustache',
'utf8'
);
consumerPattern.extendedTemplate = consumerPattern.template;
@@ -259,20 +257,20 @@ tap.test(
//assert
var consumerPatternReturned = getPartial('test-foo', pl);
- test.equals(consumerPatternReturned.patternState, 'inreview');
+ test.equal(consumerPatternReturned.patternState, 'inreview');
test.end();
}
);
tap.test(
'cascade_pattern_states promotes a lower pattern state up to the consumers lineage',
- function(test) {
+ function (test) {
//arrange
var pl = createBasePatternLabObject();
- var atomPattern = new of.Pattern('00-test/01-bar.mustache');
+ var atomPattern = new of.Pattern('test/bar.mustache');
atomPattern.template = fs.readFileSync(
- pl.config.paths.source.patterns + '00-test/01-bar.mustache',
+ pl.config.paths.source.patterns + 'test/bar.mustache',
'utf8'
);
atomPattern.extendedTemplate = atomPattern.template;
@@ -280,9 +278,9 @@ tap.test(
addPattern(atomPattern, pl);
- var consumerPattern = new of.Pattern('00-test/00-foo.mustache');
+ var consumerPattern = new of.Pattern('test/foo.mustache');
consumerPattern.template = fs.readFileSync(
- pl.config.paths.source.patterns + '00-test/00-foo.mustache',
+ pl.config.paths.source.patterns + 'test/foo.mustache',
'utf8'
);
consumerPattern.extendedTemplate = consumerPattern.template;
@@ -297,19 +295,19 @@ tap.test(
//assert
var consumerPatternReturned = getPartial('test-foo', pl);
const lineage = pl.graph.lineage(consumerPatternReturned);
- test.equals(lineage[0].lineageState, 'inreview');
+ test.equal(lineage[0].lineageState, 'inreview');
test.end();
}
);
tap.test(
'cascade_pattern_states sets the pattern state on any lineage patterns reverse lineage',
- function(test) {
+ function (test) {
//arrange
var pl = createBasePatternLabObject();
- var atomPattern = loadPattern('00-test/01-bar.mustache', pl);
- var consumerPattern = loadPattern('00-test/00-foo.mustache', pl);
+ var atomPattern = loadPattern('test/bar.mustache', pl);
+ var consumerPattern = loadPattern('test/foo.mustache', pl);
lineage_hunter.find_lineage(consumerPattern, pl);
@@ -319,7 +317,7 @@ tap.test(
//assert
var consumedPatternReturned = getPartial('test-bar', pl);
let lineageR = pl.graph.lineageR(consumedPatternReturned);
- test.equals(lineageR[0].lineageState, 'inreview');
+ test.equal(lineageR[0].lineageState, 'inreview');
test.end();
}
@@ -327,13 +325,13 @@ tap.test(
tap.test(
'cascade_pattern_states promotes lower pattern state when consumer does not have its own state',
- function(test) {
+ function (test) {
//arrange
var pl = createBasePatternLabObject();
- var atomPattern = new of.Pattern('00-test/01-bar.mustache');
+ var atomPattern = new of.Pattern('test/bar.mustache');
atomPattern.template = fs.readFileSync(
- path.resolve(pl.config.paths.source.patterns, '00-test/01-bar.mustache'),
+ path.resolve(pl.config.paths.source.patterns, 'test/bar.mustache'),
'utf8'
);
atomPattern.extendedTemplate = atomPattern.template;
@@ -341,9 +339,9 @@ tap.test(
addPattern(atomPattern, pl);
- var consumerPattern = new of.Pattern('00-test/00-foo.mustache');
+ var consumerPattern = new of.Pattern('test/foo.mustache');
consumerPattern.template = fs.readFileSync(
- path.resolve(pl.config.paths.source.patterns, '00-test/00-foo.mustache'),
+ path.resolve(pl.config.paths.source.patterns, 'test/foo.mustache'),
'utf8'
);
consumerPattern.extendedTemplate = consumerPattern.template;
@@ -356,16 +354,16 @@ tap.test(
//assert
var consumerPatternReturned = getPartial('test-foo', pl);
- test.equals(consumerPatternReturned.lineage.length, 1);
- test.equals(consumerPatternReturned.lineage[0].lineageState, 'inreview');
- test.equals(consumerPatternReturned.patternState, 'inreview');
+ test.equal(consumerPatternReturned.lineage.length, 1);
+ test.equal(consumerPatternReturned.lineage[0].lineageState, 'inreview');
+ test.equal(consumerPatternReturned.patternState, 'inreview');
test.end();
}
);
tap.test(
'find_lineage - finds lineage with unspaced pattern parameters',
- function(test) {
+ function (test) {
//setup current pattern from what we would have during execution
var currentPattern = createFakeEmptyErrorPattern();
extend(currentPattern, {
@@ -377,18 +375,17 @@ tap.test(
graph: PatternGraph.empty(),
patterns: [
Pattern.createEmpty({
- name: '01-atoms-05-alerts-00-error',
- subdir: '01-atoms\\05-alerts',
- filename: '00-error.mustache',
+ name: 'atoms-alerts-error',
+ subdir: 'atoms\\alerts',
+ filename: 'error.mustache',
data: null,
template: ' {{message}} ',
extendedTemplate: ' {{message}} ',
patternBaseName: 'error',
- patternLink:
- '01-atoms-05-alerts-00-error/01-atoms-05-alerts-00-error.html',
+ patternLink: 'atoms-alerts-error/atoms-alerts-error.html',
patternGroup: 'atoms',
- patternSubGroup: 'atoms\\05-alerts',
- flatPatternPath: '01-atoms\\05-alerts',
+ patternSubgroup: 'atoms\\alerts',
+ flatPatternPath: 'atoms\\alerts',
patternPartial: 'atoms-error',
patternState: '',
lineage: [],
@@ -408,228 +405,30 @@ tap.test(
lineage_hunter.find_lineage(currentPattern, patternlab);
- test.equals(currentPattern.lineageIndex.length, 1);
- test.equals(currentPattern.lineageIndex[0], 'atoms-error');
- test.equals(patternlab.patterns[0].lineageRIndex.length, 1);
- test.equals(
+ test.equal(currentPattern.lineageIndex.length, 1);
+ test.equal(currentPattern.lineageIndex[0], 'atoms-error');
+ test.equal(patternlab.patterns[0].lineageRIndex.length, 1);
+ test.equal(
patternlab.patterns[0].lineageR[0].lineagePattern,
'molecules-error'
);
- var currentPatternLineageIndex = patternlab.graph.lineageIndex(
- currentPattern
- );
- test.equals(currentPatternLineageIndex.length, 1);
- test.equals(currentPatternLineageIndex[0], 'atoms-error');
+ var currentPatternLineageIndex =
+ patternlab.graph.lineageIndex(currentPattern);
+ test.equal(currentPatternLineageIndex.length, 1);
+ test.equal(currentPatternLineageIndex[0], 'atoms-error');
var pattern0LineageRIndex = patternlab.graph.lineageRIndex(
patternlab.patterns[0]
);
- test.equals(pattern0LineageRIndex.length, 1);
- test.equals(pattern0LineageRIndex[0], 'molecules-error');
-
- test.end();
- }
-);
-
-tap.test('find_lineage - finds lineage with spaced styleModifier', function(
- test
-) {
- //setup current pattern from what we would have during execution
- var currentPattern = Pattern.createEmpty({
- name: '01-molecules-01-toast-00-error',
- subdir: '01-molecules\\01-toast',
- filename: '00-error.mustache',
- data: null,
- template: '{{> atoms-error:foo }}',
- extendedTemplate: '{{> atoms-error:foo }}',
- patternBaseName: 'error',
- patternLink:
- '01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html',
- patternGroup: 'molecules',
- patternSubGroup: 'molecules\\01-toast',
- flatPatternPath: '01-molecules\\01-toast',
- patternPartial: 'molecules-error',
- patternState: '',
- lineage: [],
- lineageIndex: [],
- lineageR: [],
- lineageRIndex: [],
- });
- var patternlab = {
- graph: new PatternGraph(null, 0),
- patterns: [
- Pattern.createEmpty({
- name: '01-atoms-05-alerts-00-error',
- subdir: '01-atoms\\05-alerts',
- filename: '00-error.mustache',
- data: null,
- template: ' {{message}} ',
- extendedTemplate: ' {{message}} ',
- patternBaseName: 'error',
- patternLink:
- '01-atoms-05-alerts-00-error/01-atoms-05-alerts-00-error.html',
- patternGroup: 'atoms',
- patternSubGroup: 'atoms\\05-alerts',
- flatPatternPath: '01-atoms\\05-alerts',
- patternPartial: 'atoms-error',
- patternState: '',
- lineage: [],
- lineageIndex: [],
- lineageR: [],
- lineageRIndex: [],
- }),
- ],
- config: {
- outputFileSuffixes: {
- rendered: '.rendered',
- rawTemplate: '',
- markupOnly: '.markup-only',
- },
- },
- };
-
- lineage_hunter.find_lineage(currentPattern, patternlab);
-
- test.equals(currentPattern.lineageIndex.length, 1);
- test.equals(currentPattern.lineageIndex[0], 'atoms-error');
-
- test.end();
-});
-
-tap.test('find_lineage - finds lineage with unspaced styleModifier', function(
- test
-) {
- //setup current pattern from what we would have during execution
- var currentPattern = Pattern.createEmpty({
- name: '01-molecules-01-toast-00-error',
- subdir: '01-molecules\\01-toast',
- filename: '00-error.mustache',
- data: null,
- template: '{{> atoms-error:foo }}',
- extendedTemplate: '{{>atoms-error:foo}}',
- patternBaseName: 'error',
- patternLink:
- '01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html',
- patternGroup: 'molecules',
- patternSubGroup: 'molecules\\01-toast',
- flatPatternPath: '01-molecules\\01-toast',
- patternPartial: 'molecules-error',
- patternState: '',
- lineage: [],
- lineageIndex: [],
- lineageR: [],
- lineageRIndex: [],
- });
- var patternlab = {
- graph: PatternGraph.empty(),
- patterns: [
- Pattern.createEmpty({
- name: '01-atoms-05-alerts-00-error',
- subdir: '01-atoms\\05-alerts',
- filename: '00-error.mustache',
- data: null,
- template: ' {{message}} ',
- extendedTemlpate: ' {{message}} ',
- patternBaseName: 'error',
- patternLink:
- '01-atoms-05-alerts-00-error/01-atoms-05-alerts-00-error.html',
- patternGroup: 'atoms',
- patternSubGroup: 'atoms\\05-alerts',
- flatPatternPath: '01-atoms\\05-alerts',
- patternPartial: 'atoms-error',
- patternState: '',
- lineage: [],
- lineageIndex: [],
- lineageR: [],
- lineageRIndex: [],
- }),
- ],
- config: {
- outputFileSuffixes: {
- rendered: '.rendered',
- rawTemplate: '',
- markupOnly: '.markup-only',
- },
- },
- };
-
- lineage_hunter.find_lineage(currentPattern, patternlab);
-
- test.equals(currentPattern.lineageIndex.length, 1);
- test.equals(currentPattern.lineageIndex[0], 'atoms-error');
-
- test.end();
-});
-
-tap.test(
- 'find_lineage - finds lineage with fuzzy partial with styleModifier',
- function(test) {
- //setup current pattern from what we would have during execution
- var currentPattern = Pattern.createEmpty({
- name: '01-molecules-01-toast-00-error',
- subdir: '01-molecules\\01-toast',
- filename: '00-error.mustache',
- data: null,
- template: '{{> atoms-e:foo }}',
- extendedTemplate: '{{>atoms-e:foo}}',
- patternBaseName: 'error',
- patternLink:
- '01-molecules-01-toast-00-error/01-molecules-01-toast-00-error.html',
- patternGroup: 'molecules',
- patternSubGroup: 'molecules\\01-toast',
- flatPatternPath: '01-molecules\\01-toast',
- patternPartial: 'molecules-error',
- patternState: '',
- lineage: [],
- lineageIndex: [],
- lineageR: [],
- lineageRIndex: [],
- });
- var patternlab = {
- graph: PatternGraph.empty(),
- patterns: [
- Pattern.createEmpty({
- name: '01-atoms-05-alerts-00-error',
- subdir: '01-atoms\\05-alerts',
- filename: '00-error.mustache',
- data: null,
- template: ' {{message}} ',
- extendedTemplate: ' {{message}} ',
- patternBaseName: 'error',
- patternLink:
- '01-atoms-05-alerts-00-error/01-atoms-05-alerts-00-error.html',
- patternGroup: 'atoms',
- patternSubGroup: 'atoms\\05-alerts',
- flatPatternPath: '01-atoms\\05-alerts',
- patternPartial: 'atoms-error',
- patternState: '',
- lineage: [],
- lineageIndex: [],
- lineageR: [],
- lineageRIndex: [],
- }),
- ],
- config: {
- outputFileSuffixes: {
- rendered: '.rendered',
- rawTemplate: '',
- markupOnly: '.markup-only',
- },
- },
- };
-
- var lineage_hunter = new lh();
- lineage_hunter.find_lineage(currentPattern, patternlab);
-
- test.equals(currentPattern.lineageIndex.length, 1);
- test.equals(currentPattern.lineageIndex[0], 'atoms-error');
+ test.equal(pattern0LineageRIndex.length, 1);
+ test.equal(pattern0LineageRIndex[0], 'molecules-error');
test.end();
}
);
-tap.test('find_lineage - does not apply lineage twice', function(test) {
+tap.test('find_lineage - does not apply lineage twice', function (test) {
//setup current pattern from what we would have during execution
var currentPattern = createFakeEmptyErrorPattern();
extend(currentPattern, {
@@ -640,18 +439,17 @@ tap.test('find_lineage - does not apply lineage twice', function(test) {
graph: PatternGraph.empty(),
patterns: [
Pattern.createEmpty({
- name: '01-atoms-05-alerts-00-error',
- subdir: '01-atoms\\05-alerts',
- filename: '00-error.mustache',
+ name: 'atoms-alerts-error',
+ subdir: 'atoms\\alerts',
+ filename: 'error.mustache',
data: null,
template: ' {{message}} ',
extendedTemplate: ' {{message}} ',
patternBaseName: 'error',
- patternLink:
- '01-atoms-05-alerts-00-error/01-atoms-05-alerts-00-error.html',
+ patternLink: 'atoms-alerts-error/atoms-alerts-error.html',
patternGroup: 'atoms',
- patternSubGroup: 'atoms\\05-alerts',
- flatPatternPath: '01-atoms\\05-alerts',
+ patternSubgroup: 'atoms\\alerts',
+ flatPatternPath: 'atoms\\alerts',
patternPartial: 'atoms-error',
patternState: '',
lineage: [],
@@ -673,10 +471,10 @@ tap.test('find_lineage - does not apply lineage twice', function(test) {
lineage_hunter.find_lineage(currentPattern, patternlab);
lineage_hunter.find_lineage(currentPattern, patternlab);
- test.equals(currentPattern.lineageIndex.length, 1);
- test.equals(currentPattern.lineageIndex[0], 'atoms-error');
- test.equals(patternlab.patterns[0].lineageRIndex.length, 1);
- test.equals(
+ test.equal(currentPattern.lineageIndex.length, 1);
+ test.equal(currentPattern.lineageIndex[0], 'atoms-error');
+ test.equal(patternlab.patterns[0].lineageRIndex.length, 1);
+ test.equal(
patternlab.patterns[0].lineageR[0].lineagePattern,
'molecules-error'
);
@@ -684,11 +482,11 @@ tap.test('find_lineage - does not apply lineage twice', function(test) {
var graph = patternlab.graph;
var currentPatternLineageIndex = graph.lineageIndex(currentPattern);
- test.equals(currentPatternLineageIndex.length, 1);
- test.equals(currentPatternLineageIndex[0], 'atoms-error');
+ test.equal(currentPatternLineageIndex.length, 1);
+ test.equal(currentPatternLineageIndex[0], 'atoms-error');
var patternZeroLineageR = graph.lineageR(patternlab.patterns[0]);
- test.equals(patternZeroLineageR.length, 1);
- test.equals(patternZeroLineageR[0].patternPartial, 'molecules-error');
+ test.equal(patternZeroLineageR.length, 1);
+ test.equal(patternZeroLineageR[0].patternPartial, 'molecules-error');
test.end();
});
diff --git a/packages/core/test/list_item_hunter_tests.js b/packages/core/test/list_item_hunter_tests.js
index 278de7dcc..5447f194f 100644
--- a/packages/core/test/list_item_hunter_tests.js
+++ b/packages/core/test/list_item_hunter_tests.js
@@ -16,10 +16,10 @@ engineLoader.loadAllEngines(config);
tap.test(
'process_list_item_partials converts partial to simpler format',
- test => {
+ (test) => {
//arrange
const pl = util.fakePatternLab(testPatternsPath);
- const listPath = path.join('00-test', '685-list.mustache');
+ const listPath = path.join('test', 'list.mustache');
const testPattern = loadPattern(listPath, pl);
//usually decompose does this
@@ -28,7 +28,7 @@ tap.test(
//act
list_item_hunter.process_list_item_partials(testPattern, pl).then(() => {
//assert
- test.equals(
+ test.equal(
util.sanitized(testPattern.extendedTemplate),
util.sanitized(`
{{#listItems-three}}
@@ -43,10 +43,10 @@ tap.test(
tap.test(
'process_list_item_partials converts partial with includes to simpler format',
- test => {
+ (test) => {
//arrange
const pl = util.fakePatternLab(testPatternsPath);
- const listPath = path.join('00-test', 'listWithPartial.mustache');
+ const listPath = path.join('test', 'listWithPartial.mustache');
const testPattern = loadPattern(listPath, pl);
//usually decompose does this
@@ -55,7 +55,7 @@ tap.test(
//act
list_item_hunter.process_list_item_partials(testPattern, pl).then(() => {
//assert
- test.equals(
+ test.equal(
util.sanitized(testPattern.extendedTemplate),
util.sanitized(`
{{#listItems-two}}
diff --git a/packages/core/test/loadPattern_tests.js b/packages/core/test/loadPattern_tests.js
index 2ebec760f..d2903a6c0 100644
--- a/packages/core/test/loadPattern_tests.js
+++ b/packages/core/test/loadPattern_tests.js
@@ -12,91 +12,99 @@ patternEngines.loadAllEngines(config);
const patterns_dir = `${__dirname}/files/_patterns`;
-tap.test('loadPattern - returns null if file is not a pattern', function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
- var patternPath = path.join('00-test', '03-styled-atom.json');
+tap.test(
+ 'loadPattern - returns null if file is not a pattern',
+ function (test) {
+ //arrange
+ const patternlab = util.fakePatternLab(patterns_dir);
+ var patternPath = path.join('test', 'styled-atom.json');
- //act
- var result = loadPattern(patternPath, patternlab);
+ //act
+ var result = loadPattern(patternPath, patternlab);
- //assert
- test.equals(result, null);
- test.end();
-});
+ //assert
+ test.equal(result, null);
+ test.end();
+ }
+);
-tap.test('loadPattern - loads pattern sibling json if found', function(test) {
+tap.test('loadPattern - loads pattern sibling json if found', function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
- var patternPath = path.join('00-test', '03-styled-atom.mustache');
+ var patternPath = path.join('test', 'styled-atom.mustache');
//act
var result = loadPattern(patternPath, patternlab);
//assert
- test.equals(result.jsonFileData.message, 'baseMessage');
+ test.equal(result.jsonFileData.message, 'baseMessage');
test.end();
});
tap.test(
'loadPattern - adds the pattern to the patternlab.partials object',
- function(test) {
+ function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
- var fooPatternPath = path.join('00-test', '01-bar.mustache');
+ var fooPatternPath = path.join('test', 'bar.mustache');
//act
var result = loadPattern(fooPatternPath, patternlab);
//assert
- test.equals(util.sanitized(patternlab.partials['test-bar']), 'bar');
+ test.equal(util.sanitized(patternlab.partials['test-bar']), 'bar');
test.end();
}
);
-tap.test('loadPattern - returns pattern with template populated', function(
- test
-) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
- var fooPatternPath = path.join('00-test', '01-bar.mustache');
-
- //act
- var result = loadPattern(fooPatternPath, patternlab);
-
- //assert
- test.equals(util.sanitized(result.template), util.sanitized('bar'));
- test.end();
-});
+tap.test(
+ 'loadPattern - returns pattern with template populated',
+ function (test) {
+ //arrange
+ const patternlab = util.fakePatternLab(patterns_dir);
+ var fooPatternPath = path.join('test', 'bar.mustache');
-tap.test('loadPattern - adds a markdown pattern if encountered', function(
- test
-) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
- var colorsMarkDownPath = path.join('patternType1', 'patternSubType1.md');
+ //act
+ var result = loadPattern(fooPatternPath, patternlab);
- //act
- var result = loadPattern(colorsMarkDownPath, patternlab);
+ //assert
+ test.equal(util.sanitized(result.template), util.sanitized('bar'));
+ test.end();
+ }
+);
- //assert
- const subTypePattern =
- patternlab.subtypePatterns['patternType1-patternSubType1'];
- test.equals(subTypePattern.patternSectionSubtype, true);
- test.equals(subTypePattern.isPattern, false);
- test.equals(subTypePattern.patternDesc, 'Colors
\n');
- test.equals(subTypePattern.engine, null);
- test.equals(subTypePattern.flatPatternPath, 'patternType1-patternSubType1');
- test.equals(result, subTypePattern);
- test.end();
-});
+// TODO: Fix doc pattern test when new logic in loadPattern is implemented
+// tap.test('loadPattern - adds a markdown pattern if encountered', function(
+// test
+// ) {
+// //arrange
+// const patternlab = util.fakePatternLab(patterns_dir);
+// var colorsMarkDownPath = path.join('patternGroup1', 'patternSubgroup1.md');
+
+// //act
+// var result = loadPattern(colorsMarkDownPath, patternlab);
+
+// //assert
+// const subgroupPattern =
+// patternlab.subgroupPatterns['patternGroup1-patternSubgroup1'];
+// test.equal(subgroupPattern.patternSectionSubgroup, true);
+// test.equal(subgroupPattern.isPattern, false);
+// test.equal(subgroupPattern.patternDesc, 'Colors
\n');
+// test.equal(subgroupPattern.engine, null);
+// test.equal(
+// subgroupPattern.flatPatternPath,
+// 'patternGroup1-patternSubgroup1'
+// );
+// test.equal(result, subgroupPattern);
+// test.end();
+// });
tap.test(
'loadPattern - does not load pseudopattern data on the base pattern',
- test => {
+ (test) => {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
- const basePatternPath = path.join('00-test', '474-pseudomodifier.mustache');
+ const basePatternPath = path.join('test', 'pseudomodifier.mustache');
//act
const result = loadPattern(basePatternPath, patternlab);
@@ -107,3 +115,65 @@ tap.test(
test.end();
}
);
+
+tap.test(
+ 'loadPattern - group and subgroup ordering will be taken from markdown files',
+ (test) => {
+ //arrange
+ const patternlab = util.fakePatternLab(patterns_dir);
+
+ const basePatternAPath = path.join('orderTest', 'a', 'a-test.mustache');
+ const basePatternBPath = path.join('orderTest', 'b', 'b-test.mustache');
+ const basePatternCPath = path.join(
+ 'orderTest',
+ 'c',
+ 'subfolder',
+ 'subfolder.mustache'
+ );
+
+ //act
+ const resultPatternA = loadPattern(basePatternAPath, patternlab);
+ const resultPatternB = loadPattern(basePatternBPath, patternlab);
+ const resultPatternC = loadPattern(basePatternCPath, patternlab);
+
+ //assert
+ console.log(resultPatternA.patternGroupData.order);
+ test.same(
+ resultPatternA.patternGroupData.order,
+ 1,
+ 'Pattern group should be loaded as 1'
+ );
+ console.log(resultPatternA.patternSubgroupData.order || 0);
+ test.same(
+ resultPatternA.patternSubgroupData.order || 0,
+ 0,
+ 'Pattern Subgroup not be availabe and default to 0'
+ );
+
+ console.log(resultPatternB.patternGroupData.order);
+ test.same(
+ resultPatternB.patternGroupData.order,
+ 1,
+ 'Pattern group should be loaded as 1'
+ );
+ console.log(resultPatternB.patternSubgroupData.order);
+ test.same(
+ resultPatternB.patternSubgroupData.order,
+ 2,
+ 'Pattern Subgroup should be loaded as 2'
+ );
+
+ test.same(
+ resultPatternC.patternGroupData.order,
+ 1,
+ 'Pattern group should be loaded as 1'
+ );
+ test.same(
+ resultPatternC.patternSubgroupData.order,
+ -1,
+ 'Pattern Subgroup should be loaded as -1'
+ );
+
+ test.end();
+ }
+);
diff --git a/packages/core/test/loaduitkits_tests.js b/packages/core/test/loaduitkits_tests.js
index c0fc9a4b1..a4cf2bd3b 100644
--- a/packages/core/test/loaduitkits_tests.js
+++ b/packages/core/test/loaduitkits_tests.js
@@ -1,116 +1,72 @@
'use strict';
const tap = require('tap');
+const path = require('path');
const rewire = require('rewire');
+const logger = require('../src/lib/log');
const loaduikits = rewire('../src/lib/loaduikits');
const testConfig = require('./util/patternlab-config.json');
-const findModulesMock = function() {
- return [
- {
- name: 'foo',
- modulePath: 'node_modules/@pattern-lab/uikit-foo',
- },
- {
- name: 'bar',
- modulePath: 'node_modules/@pattern-lab/uikit-bar',
- },
- {
- name: 'baz',
- modulePath: 'node_modules/@pattern-lab/uikit-baz',
- },
- ];
-};
+tap.test('loaduikits - does warn on missing package property', (test) => {
+ //arrange
+ const patternlab = {
+ config: testConfig,
+ uikits: {},
+ };
-const fsMock = {
- readFileSync: function(path, encoding) {
- return 'file';
- },
-};
+ patternlab.config.logLevel = 'warning';
+ logger.log.on('warning', (msg) => test.ok(msg.includes('package:')));
-loaduikits.__set__({
- findModules: findModulesMock,
- fs: fsMock,
+ //act
+ loaduikits(patternlab).then(() => {
+ logger.warning = () => {};
+ test.done();
+ });
});
-tap.test('loaduikits - maps fields correctly', function(test) {
+tap.test('loaduikits - maps fields correctly', function (test) {
//arrange
const patternlab = {
config: testConfig,
- uikits: [],
- };
-
- const uikitFoo = {
- name: 'uikit-foo',
- enabled: true,
- outputDir: 'foo',
- excludedPatternStates: ['legacy'],
- excludedTags: ['baz'],
+ uikits: {},
};
- patternlab.config.uikits = [uikitFoo];
-
//act
loaduikits(patternlab).then(() => {
//assert
- test.equals(patternlab.uikits['uikit-foo'].name, uikitFoo.name);
- test.equals(
- patternlab.uikits['uikit-foo'].modulePath,
- 'node_modules/@pattern-lab/uikit-foo'
- );
- test.ok(patternlab.uikits['uikit-foo'].enabled);
- test.equals(patternlab.uikits['uikit-foo'].outputDir, uikitFoo.outputDir);
- test.equals(
- patternlab.uikits['uikit-foo'].excludedPatternStates,
- uikitFoo.excludedPatternStates
+ test.equal(patternlab.uikits['uikit-workshop'].name, 'uikit-workshop');
+ test.equal(
+ patternlab.uikits['uikit-workshop'].package,
+ '@pattern-lab/uikit-workshop'
);
- test.equals(
- patternlab.uikits['uikit-foo'].excludedTags,
- uikitFoo.excludedTags
+ test.contains(
+ patternlab.uikits['uikit-workshop'].modulePath,
+ path.join('packages', 'uikit-workshop')
);
+ test.ok(patternlab.uikits['uikit-workshop'].enabled);
+ test.equal(patternlab.uikits['uikit-workshop'].outputDir, 'test/');
+ test.deepEquals(patternlab.uikits['uikit-workshop'].excludedPatternStates, [
+ 'legacy',
+ ]);
+ test.deepEquals(patternlab.uikits['uikit-workshop'].excludedTags, ['baz']);
test.end();
});
});
-tap.test('loaduikits - only adds files for enabled uikits', function(test) {
+tap.test('loaduikits - only adds files for enabled uikits', function (test) {
//arrange
const patternlab = {
config: testConfig,
- uikits: [],
+ uikits: {},
};
- patternlab.config.uikits = [
- {
- name: 'uikit-foo',
- enabled: true,
- outputDir: 'foo',
- excludedPatternStates: ['legacy'],
- excludedTags: ['baz'],
- },
- {
- name: 'uikit-bar',
- enabled: true,
- outputDir: 'bar',
- excludedPatternStates: ['development'],
- excludedTags: ['baz', 'foo'],
- },
- {
- name: 'uikit-baz',
- enabled: false,
- outputDir: 'baz',
- excludedPatternStates: [''],
- excludedTags: [],
- },
- ];
-
//act
loaduikits(patternlab).then(() => {
//assert
- test.ok(patternlab.uikits['uikit-foo']);
- test.ok(patternlab.uikits['uikit-bar']);
- test.notOk(patternlab.uikits['uikit-baz']);
+ test.ok(patternlab.uikits['uikit-workshop']);
+ test.notOk(patternlab.uikits['uikit-polyfills']);
test.end();
});
});
diff --git a/packages/core/test/markModifiedPatterns_tests.js b/packages/core/test/markModifiedPatterns_tests.js
index 173e0283f..18f06d646 100644
--- a/packages/core/test/markModifiedPatterns_tests.js
+++ b/packages/core/test/markModifiedPatterns_tests.js
@@ -13,7 +13,7 @@ const markModifiedPatterns = rewire('../src/lib/markModifiedPatterns');
const config = require('./util/patternlab-config.json');
const fsMock = {
- readFileSync: function(path, encoding, cb) {
+ readFileSync: function (path, encoding, cb) {
return '';
},
};
@@ -28,7 +28,7 @@ const public_dir = './test/public';
tap.only(
'markModifiedPatterns - finds patterns modified since a given date',
- function(test) {
+ function (test) {
//arrange
markModifiedPatterns.__set__('fs', fsMock);
@@ -40,7 +40,7 @@ tap.only(
markupOnly: '.markup-only',
};
- var pattern = new Pattern('00-test/01-bar.mustache');
+ var pattern = new Pattern('test/bar.mustache');
pattern.extendedTemplate = undefined;
pattern.template = 'bar';
@@ -75,7 +75,7 @@ tap.only(
tap.test(
'markModifiedPatterns - finds patterns when modification date is missing',
- function(test) {
+ function (test) {
//arrange
var patternlab = emptyPatternLab();
patternlab.partials = {};
@@ -83,7 +83,7 @@ tap.test(
patternlab.config = { logLevel: 'quiet' };
patternlab.config.outputFileSuffixes = { rendered: '' };
- var pattern = new Pattern('00-test/01-bar.mustache');
+ var pattern = new Pattern('test/bar.mustache');
pattern.extendedTemplate = undefined;
pattern.template = 'bar';
pattern.lastModified = undefined;
@@ -96,24 +96,25 @@ tap.test(
);
// This is the case when we want to force recompilation
-tap.test('markModifiedPatterns - finds patterns via compile state', function(
- test
-) {
- //arrange
- var patternlab = emptyPatternLab();
- patternlab.partials = {};
- patternlab.data = { link: {} };
- patternlab.config = { logLevel: 'quiet' };
- patternlab.config.outputFileSuffixes = { rendered: '' };
-
- var pattern = new Pattern('00-test/01-bar.mustache');
- pattern.extendedTemplate = undefined;
- pattern.template = 'bar';
- pattern.lastModified = 100000;
- pattern.compileState = CompileState.NEEDS_REBUILD;
- patternlab.patterns = [pattern];
-
- let p = markModifiedPatterns(1000, patternlab);
- test.same(p.modified.length, 1);
- test.end();
-});
+tap.test(
+ 'markModifiedPatterns - finds patterns via compile state',
+ function (test) {
+ //arrange
+ var patternlab = emptyPatternLab();
+ patternlab.partials = {};
+ patternlab.data = { link: {} };
+ patternlab.config = { logLevel: 'quiet' };
+ patternlab.config.outputFileSuffixes = { rendered: '' };
+
+ var pattern = new Pattern('test/bar.mustache');
+ pattern.extendedTemplate = undefined;
+ pattern.template = 'bar';
+ pattern.lastModified = 100000;
+ pattern.compileState = CompileState.NEEDS_REBUILD;
+ patternlab.patterns = [pattern];
+
+ let p = markModifiedPatterns(1000, patternlab);
+ test.same(p.modified.length, 1);
+ test.end();
+ }
+);
diff --git a/packages/core/test/markdown_parser_tests.js b/packages/core/test/markdown_parser_tests.js
index 3e25a5934..717f5b27f 100644
--- a/packages/core/test/markdown_parser_tests.js
+++ b/packages/core/test/markdown_parser_tests.js
@@ -9,10 +9,10 @@ var markdown_parser = new mp();
tap.test(
'parses pattern description block correctly when frontmatter not present',
- function(test) {
+ function (test) {
//arrange
var markdownFileName = path.resolve(
- `${__dirname}/files/_patterns/00-test/02-baz.md`
+ `${__dirname}/files/_patterns/test/baz.md`
);
var markdownFileContents = fs.readFileSync(markdownFileName, 'utf8');
@@ -20,17 +20,17 @@ tap.test(
var returnObject = markdown_parser.parse(markdownFileContents);
//assert
- test.equals(returnObject.markdown, 'Only baz \n');
+ test.equal(returnObject.markdown, 'Only baz \n');
test.end();
}
);
tap.test(
'parses pattern description block correctly when frontmatter present',
- function(test) {
+ function (test) {
//arrange
var markdownFileName = path.resolve(
- `${__dirname}/files/_patterns/00-test/01-bar.md`
+ `${__dirname}/files/_patterns/test/bar.md`
);
var markdownFileContents = fs.readFileSync(markdownFileName, 'utf8');
@@ -38,19 +38,19 @@ tap.test(
var returnObject = markdown_parser.parse(markdownFileContents);
//assert
- test.equals(
+ test.equal(
returnObject.markdown,
'A Simple Bit of Markup \nFoo cannot get simpler than bar, amiright?
\n'
);
- test.equals(returnObject.state, 'complete');
+ test.equal(returnObject.state, 'complete');
test.end();
}
);
-tap.test('parses frontmatter only when no markdown present', function(test) {
+tap.test('parses frontmatter only when no markdown present', function (test) {
//arrange
var markdownFileName = path.resolve(
- `${__dirname}/files/_patterns/00-test/03-styled-atom.md`
+ `${__dirname}/files/_patterns/test/styled-atom.md`
);
var markdownFileContents = fs.readFileSync(markdownFileName, 'utf8');
@@ -58,7 +58,7 @@ tap.test('parses frontmatter only when no markdown present', function(test) {
var returnObject = markdown_parser.parse(markdownFileContents);
//assert
- test.equals(returnObject.markdown, '');
- test.equals(returnObject.state, 'inprogress');
+ test.equal(returnObject.markdown, '');
+ test.equal(returnObject.state, 'inprogress');
test.end();
});
diff --git a/packages/core/test/object_factory_tests.js b/packages/core/test/object_factory_tests.js
index 463dce978..6684628df 100644
--- a/packages/core/test/object_factory_tests.js
+++ b/packages/core/test/object_factory_tests.js
@@ -30,121 +30,301 @@ var pl = fakePatternLab();
var engineLoader = require('../src/lib/pattern_engines');
engineLoader.loadAllEngines(config);
-tap.test('test Pattern initializes correctly', function(test) {
- var p = new Pattern('00-atoms/00-global/00-colors.mustache', { d: 123 });
- test.equals(
+tap.test('test Pattern initializes correctly', function (test) {
+ var p = new Pattern('atoms/global/colors.mustache', { d: 123 });
+ test.equal(
p.relPath,
- '00-atoms' + path.sep + '00-global' + path.sep + '00-colors.mustache'
+ 'atoms' + path.sep + 'global' + path.sep + 'colors.mustache'
);
- test.equals(p.name, '00-atoms-00-global-00-colors');
- test.equals(p.subdir, '00-atoms' + path.sep + '00-global');
- test.equals(p.fileName, '00-colors');
- test.equals(p.fileExtension, '.mustache');
- test.equals(p.jsonFileData.d, 123);
- test.equals(p.patternBaseName, 'colors');
- test.equals(p.patternName, 'Colors');
- test.equals(
+ test.equal(p.name, 'atoms-global-colors');
+ test.equal(p.subdir, 'atoms' + path.sep + 'global');
+ test.equal(p.fileName, 'colors');
+ test.equal(p.fileExtension, '.mustache');
+ test.equal(p.jsonFileData.d, 123);
+ test.equal(p.patternBaseName, 'colors');
+ test.equal(p.patternName, 'Colors');
+ test.equal(
p.getPatternLink(pl),
- '00-atoms-00-global-00-colors' +
- path.sep +
- '00-atoms-00-global-00-colors.rendered.html'
+ 'atoms-global-colors' + path.sep + 'atoms-global-colors.rendered.html'
);
- test.equals(p.patternGroup, 'atoms');
- test.equals(p.patternSubGroup, 'global');
- test.equals(p.flatPatternPath, '00-atoms-00-global');
- test.equals(p.patternPartial, 'atoms-colors');
- test.equals(p.template, '');
- test.equals(p.patternPartialCode, '');
- test.equals(p.lineage.length, 0);
- test.equals(p.lineageIndex.length, 0);
- test.equals(p.lineageR.length, 0);
- test.equals(p.lineageRIndex.length, 0);
- test.equals(p.patternState, '');
+ test.equal(p.patternGroup, 'atoms');
+ test.equal(p.patternSubgroup, 'global');
+ test.equal(p.flatPatternPath, 'atoms-global');
+ test.equal(p.patternPartial, 'atoms-colors');
+ test.equal(p.template, '');
+ test.equal(p.patternPartialCode, '');
+ test.equal(p.lineage.length, 0);
+ test.equal(p.lineageIndex.length, 0);
+ test.equal(p.lineageR.length, 0);
+ test.equal(p.lineageRIndex.length, 0);
+ test.equal(p.patternState, '');
test.end();
});
-tap.test('test Pattern with one-directory subdir works as expected', function(
- test
-) {
- var p = new Pattern('00-atoms/00-colors.mustache', { d: 123 });
- test.equals(p.relPath, '00-atoms' + path.sep + '00-colors.mustache');
- test.equals(p.name, '00-atoms-00-colors');
- test.equals(p.subdir, '00-atoms');
- test.equals(p.fileName, '00-colors');
- test.equals(p.fileExtension, '.mustache');
- test.equals(p.jsonFileData.d, 123);
- test.equals(p.patternBaseName, 'colors');
- test.equals(p.patternName, 'Colors');
- test.equals(
- p.getPatternLink(pl),
- '00-atoms-00-colors' + path.sep + '00-atoms-00-colors.rendered.html'
- );
- test.equals(p.patternGroup, 'atoms');
- test.equals(p.flatPatternPath, '00-atoms');
- test.equals(p.patternPartial, 'atoms-colors');
- test.equals(p.template, '');
- test.equals(p.lineage.length, 0);
- test.equals(p.lineageIndex.length, 0);
- test.equals(p.lineageR.length, 0);
- test.equals(p.lineageRIndex.length, 0);
- test.end();
-});
+tap.test(
+ 'test Pattern initializes correctly with pattern in sepatated directory',
+ function (test) {
+ var p = new Pattern('atoms/global/colors/colors.mustache', {
+ d: 123,
+ });
+ test.equal(
+ p.relPath,
+ 'atoms' +
+ path.sep +
+ 'global' +
+ path.sep +
+ 'colors' +
+ path.sep +
+ 'colors.mustache'
+ );
+ test.equal(p.name, 'atoms-global-colors');
+ test.equal(p.subdir, path.join('atoms', 'global', 'colors'));
+ test.equal(p.fileName, 'colors');
+ test.equal(p.fileExtension, '.mustache');
+ test.equal(p.jsonFileData.d, 123);
+ test.equal(p.patternBaseName, 'colors');
+ test.equal(p.patternName, 'Colors');
+ test.equal(
+ p.getPatternLink(pl),
+ 'atoms-global-colors' + path.sep + 'atoms-global-colors.rendered.html'
+ );
+ test.equal(p.patternGroup, 'atoms');
+ test.equal(p.patternSubgroup, 'global');
+ test.equal(p.flatPatternPath, 'atoms-global');
+ test.equal(p.patternPartial, 'atoms-colors');
+ test.equal(p.template, '');
+ test.equal(p.patternPartialCode, '');
+ test.equal(p.lineage.length, 0);
+ test.equal(p.lineageIndex.length, 0);
+ test.equal(p.lineageR.length, 0);
+ test.equal(p.lineageRIndex.length, 0);
+ test.equal(p.patternState, '');
+ test.end();
+ }
+);
+
+tap.test(
+ 'test Pattern name for variants correctly initialzed',
+ function (test) {
+ var p1 = new Pattern('atoms/global/colors/colors~variant.mustache', {
+ d: 123,
+ });
+ var p2 = new Pattern('atoms/global/colors/colors~variant-minus.json', {
+ d: 123,
+ });
+ test.equal(p1.name, 'atoms-global-colors-variant');
+ test.equal(p2.name, 'atoms-global-colors-variant-minus');
+ test.end();
+ }
+);
+
+tap.test(
+ 'test Pattern with one-directory subdir works as expected',
+ function (test) {
+ var p = new Pattern('atoms/colors.mustache', { d: 123 });
+ test.equal(p.relPath, 'atoms' + path.sep + 'colors.mustache');
+ test.equal(p.name, 'atoms-colors');
+ test.equal(p.subdir, 'atoms');
+ test.equal(p.fileName, 'colors');
+ test.equal(p.fileExtension, '.mustache');
+ test.equal(p.jsonFileData.d, 123);
+ test.equal(p.patternBaseName, 'colors');
+ test.equal(p.patternName, 'Colors');
+ test.equal(
+ p.getPatternLink(pl),
+ 'atoms-colors' + path.sep + 'atoms-colors.rendered.html'
+ );
+ test.equal(p.patternGroup, 'atoms');
+ test.equal(p.flatPatternPath, 'atoms');
+ test.equal(p.patternPartial, 'atoms-colors');
+ test.equal(p.template, '');
+ test.equal(p.lineage.length, 0);
+ test.equal(p.lineageIndex.length, 0);
+ test.equal(p.lineageR.length, 0);
+ test.equal(p.lineageRIndex.length, 0);
+ test.end();
+ }
+);
+
+tap.test(
+ 'test Pattern with own-directory gets resetted as expected',
+ function (test) {
+ var p = new Pattern('atoms/button/button.mustache', { d: 123 }, pl);
+ p.promoteFromDirectoryToFlatPattern(pl);
+
+ test.equal(p.relPath, path.join('atoms', 'button', 'button.mustache'));
+ test.equal(p.name, 'atoms-button');
+ test.equal(p.subdir, path.join('atoms', 'button'));
+ test.equal(p.fileName, 'button');
+ test.equal(p.fileExtension, '.mustache');
+ test.equal(p.jsonFileData.d, 123);
+ test.equal(p.patternBaseName, 'button');
+ test.equal(p.patternName, 'Button');
+ test.equal(
+ p.getPatternLink(pl),
+ path.join('atoms-button', 'atoms-button.rendered.html')
+ );
+ test.equal(p.patternGroup, 'atoms');
+ test.equal(p.flatPatternPath, 'atoms');
+ test.equal(p.patternPartial, 'atoms-button');
+ test.equal(p.template, '');
+ test.equal(p.lineage.length, 0);
+ test.equal(p.lineageIndex.length, 0);
+ test.equal(p.lineageR.length, 0);
+ test.equal(p.lineageRIndex.length, 0);
+ test.end();
+ }
+);
tap.test(
'test Pattern with no numbers in pattern group works as expected',
- function(test) {
+ function (test) {
var p = new Pattern('atoms/colors.mustache', { d: 123 });
- test.equals(p.relPath, 'atoms' + path.sep + 'colors.mustache');
- test.equals(p.name, 'atoms-colors');
- test.equals(p.subdir, 'atoms');
- test.equals(p.fileName, 'colors');
- test.equals(
+ test.equal(p.relPath, 'atoms' + path.sep + 'colors.mustache');
+ test.equal(p.name, 'atoms-colors');
+ test.equal(p.subdir, 'atoms');
+ test.equal(p.fileName, 'colors');
+ test.equal(
p.getPatternLink(pl),
'atoms-colors' + path.sep + 'atoms-colors.rendered.html'
);
- test.equals(p.patternGroup, 'atoms');
- test.equals(p.flatPatternPath, 'atoms');
- test.equals(p.patternPartial, 'atoms-colors');
+ test.equal(p.patternGroup, 'atoms');
+ test.equal(p.flatPatternPath, 'atoms');
+ test.equal(p.patternPartial, 'atoms-colors');
test.end();
}
);
-tap.test('test Pattern capitalizes patternDisplayName correctly', function(
- test
-) {
- var p = new Pattern('00-atoms/00-global/00-colors-alt.mustache', { d: 123 });
- test.equals(p.patternBaseName, 'colors-alt');
- test.equals(p.patternName, 'Colors Alt');
- test.end();
-});
+tap.test(
+ 'test Pattern capitalizes patternDisplayName correctly',
+ function (test) {
+ var p = new Pattern('atoms/global/colors-alt.mustache', { d: 123 });
+ test.equal(p.patternBaseName, 'colors-alt');
+ test.equal(p.patternName, 'Colors Alt');
+ test.end();
+ }
+);
-tap.test('The forms of Pattern.getPatternLink() work as expected', function(
- test
-) {
- var p = new Pattern('00-atoms/00-global/00-colors.hbs');
- test.equals(
- p.getPatternLink(pl),
- '00-atoms-00-global-00-colors' +
- path.sep +
- '00-atoms-00-global-00-colors.rendered.html'
- );
- test.equals(
- p.getPatternLink(pl, 'rendered'),
- '00-atoms-00-global-00-colors' +
- path.sep +
- '00-atoms-00-global-00-colors.rendered.html'
- );
- test.equals(
- p.getPatternLink(pl, 'rawTemplate'),
- '00-atoms-00-global-00-colors' +
- path.sep +
- '00-atoms-00-global-00-colors.hbs'
- );
- test.equals(
- p.getPatternLink(pl, 'markupOnly'),
- '00-atoms-00-global-00-colors' +
- path.sep +
- '00-atoms-00-global-00-colors.markup-only.html'
- );
- test.end();
-});
+tap.test(
+ 'test Pattern get dir level no separated pattern directory',
+ function (test) {
+ var p = new Pattern('atoms/global/colors-alt.mustache', { d: 123 });
+ console.log(p);
+ test.equal(p.getDirLevel(0, { patternHasOwnDir: false }), 'atoms');
+ test.equal(p.getDirLevel(1, { patternHasOwnDir: false }), 'global');
+ test.equal(p.getDirLevel(2, { patternHasOwnDir: false }), ''); // There is no third level
+ var p = new Pattern('atoms/colors-alt.mustache', { d: 123 });
+ test.equal(p.getDirLevel(0, { patternHasOwnDir: false }), 'atoms');
+ test.equal(p.getDirLevel(1, { patternHasOwnDir: false }), ''); // There is no second level
+ test.equal(p.getDirLevel(2, { patternHasOwnDir: false }), ''); // There is no third level
+ var p = new Pattern('colors-alt.mustache', { d: 123 });
+ test.equal(p.getDirLevel(0, { patternHasOwnDir: false }), 'root'); // No first level means root
+ test.equal(p.getDirLevel(1, { patternHasOwnDir: false }), ''); // There is no second level
+ test.equal(p.getDirLevel(2, { patternHasOwnDir: false }), ''); // There is no third leveL
+ test.end();
+ }
+);
+
+tap.test(
+ 'test Pattern get dir level with separated pattern directory',
+ function (test) {
+ var p = new Pattern('atoms/global/colors-alt/colors-alt.mustache', {
+ d: 123,
+ });
+ test.equal(p.getDirLevel(0, { patternHasOwnDir: true }), 'atoms');
+ test.equal(p.getDirLevel(1, { patternHasOwnDir: true }), 'global');
+ test.equal(p.getDirLevel(2, { patternHasOwnDir: true }), ''); // There is no third level
+
+ var p = new Pattern('atoms/colors-alt/colors-alt.mustache', {
+ d: 123,
+ });
+ test.equal(p.getDirLevel(0, { patternHasOwnDir: true }), 'atoms');
+ test.equal(p.getDirLevel(1, { patternHasOwnDir: true }), ''); // There is no second level
+ test.equal(p.getDirLevel(2, { patternHasOwnDir: true }), ''); // There is no third level
+
+ var p = new Pattern('colors-alt/colors-alt.mustache', { d: 123 });
+ test.equal(p.getDirLevel(0, { patternHasOwnDir: true }), 'root'); // No first level means root
+ test.equal(p.getDirLevel(1, { patternHasOwnDir: true }), ''); // There is no second level
+ test.equal(p.getDirLevel(2, { patternHasOwnDir: true }), ''); // There is no third leveL
+
+ var p = new Pattern('atoms/global/colors-alt/colors-alt~variant.mustache', {
+ d: 123,
+ });
+ test.equal(p.name, 'atoms-global-colors-alt-variant');
+ test.equal(p.flatPatternPath, 'atoms-global');
+ test.equal(p.patternBaseName, 'colors-alt-variant');
+
+ test.end();
+ }
+);
+
+tap.test(
+ 'test Patterns that are nested deeper without own directory',
+ function (test) {
+ var p = new Pattern('atoms/global/random-folder/colors-alt.mustache', {
+ d: 123,
+ });
+ test.equal(p.name, 'atoms-global-colors-alt');
+ test.equal(p.flatPatternPath, 'atoms-global');
+
+ var p = new Pattern(
+ 'atoms/global/random-folder/another-folder/colors-alt.mustache',
+ {
+ d: 123,
+ }
+ );
+ test.equal(p.name, 'atoms-global-colors-alt');
+ test.equal(p.flatPatternPath, 'atoms-global');
+
+ var p = new Pattern(
+ 'atoms/global/random-folder/another-folder/some-folder/colors-alt.mustache',
+ { d: 123 }
+ );
+ test.equal(p.name, 'atoms-global-colors-alt');
+ test.equal(p.flatPatternPath, 'atoms-global');
+
+ var p = new Pattern(
+ 'atoms/global/random-folder/another-folder/colors-alt/colors-alt.mustache',
+ { d: 123 }
+ );
+ test.equal(p.name, 'atoms-global-colors-alt');
+ test.equal(p.flatPatternPath, 'atoms-global');
+
+ var p = new Pattern(
+ 'atoms/global/random-folder/another-folder/some-folder/colors-alt~variant.mustache',
+ { d: 123 }
+ );
+ test.equal(p.name, 'atoms-global-colors-alt-variant');
+ test.equal(p.flatPatternPath, 'atoms-global');
+ test.equal(p.patternBaseName, 'colors-alt-variant');
+ test.end();
+ }
+);
+
+tap.test(
+ 'The forms of Pattern.getPatternLink() work as expected',
+ function (test) {
+ var p = new Pattern('atoms/global/colors.hbs');
+ test.equal(
+ p.getPatternLink(pl),
+ 'atoms-global-colors' + path.sep + 'atoms-global-colors.rendered.html'
+ );
+ test.equal(
+ p.getPatternLink(pl, 'rendered'),
+ 'atoms-global-colors' + path.sep + 'atoms-global-colors.rendered.html'
+ );
+ test.equal(
+ p.getPatternLink(pl, 'rawTemplate'),
+ 'atoms-global-colors' + path.sep + 'atoms-global-colors.hbs'
+ );
+ test.equal(
+ p.getPatternLink(pl, 'markupOnly'),
+ 'atoms-global-colors' + path.sep + 'atoms-global-colors.markup-only.html'
+ );
+ test.equal(
+ p.getPatternLink(pl, 'custom', '.custom-extension'),
+ 'atoms-global-colors' + path.sep + 'atoms-global-colors.custom-extension'
+ );
+ test.end();
+ }
+);
diff --git a/packages/core/test/parameter_hunter_tests.js b/packages/core/test/parameter_hunter_tests.js
deleted file mode 100644
index 3c3328648..000000000
--- a/packages/core/test/parameter_hunter_tests.js
+++ /dev/null
@@ -1,465 +0,0 @@
-'use strict';
-
-const path = require('path');
-const util = require('./util/test_utils.js');
-const tap = require('tap');
-
-const loadPattern = require('../src/lib/loadPattern');
-const ph = require('../src/lib/parameter_hunter');
-const processIterative = require('../src/lib/processIterative');
-
-const parameter_hunter = new ph();
-
-const config = require('./util/patternlab-config.json');
-const engineLoader = require('../src/lib/pattern_engines');
-engineLoader.loadAllEngines(config);
-
-const testPatternsPath = path.resolve(__dirname, 'files', '_patterns');
-
-tap.test('parameter hunter finds and extends templates', function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- parameter_hunter
- .find_parameters(testPattern, pl)
- .then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized(
- '{{foo}} A life is like a garden. Perfect moments can be had, but not preserved, except in memory.
'
- )
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
-});
-
-tap.test(
- 'parameter hunter finds and extends templates with verbose partials',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join(
- '00-test',
- 'sticky-comment-verbose.mustache'
- );
- var testPattern = loadPattern(testPatternPath, pl);
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- parameter_hunter
- .find_parameters(testPattern, pl)
- .then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized(
- '{{foo}} A life is like a garden. Perfect moments can be had, but not preserved, except in memory.
'
- )
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
-//previous tests were for unquoted parameter keys and single-quoted values.
-//test other quoting options.
-tap.test(
- 'parameter hunter parses parameters with unquoted keys and unquoted values',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template = '{{> test-comment(description: true) }}';
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('{{foo}} true
')
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with unquoted keys and double-quoted values',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template = '{{> test-comment(description: "true") }}';
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('{{foo}} true
')
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with single-quoted keys and unquoted values',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template = "{{> test-comment('description': true) }}";
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('{{foo}} true
')
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with single-quoted keys and single-quoted values wrapping internal escaped single-quotes',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template =
- "{{> test-comment('description': 'true not,\\'true\\'') }}";
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized(`{{foo}} true not,'true'
`)
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with single-quoted keys and double-quoted values wrapping internal single-quotes',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template =
- "{{> test-comment('description': \"true not:'true'\") }}";
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized(`{{foo}} true not:'true'
`)
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with double-unquoted keys and unquoted values',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template = '{{> test-comment("description": true) }}';
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('{{foo}} true
')
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with double-quoted keys and single-quoted values wrapping internal double-quotes',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template =
- '{{> test-comment("description": \'true not{"true"\') }}';
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('{{foo}} true not{"true"
')
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with double-quoted keys and double-quoted values wrapping internal escaped double-quotes',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template =
- '{{> test-comment("description": "true not}\\"true\\"") }}';
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('{{foo}} true not}"true"
')
- );
- test.end();
- });
- });
- }
-);
-
-tap.test(
- 'parameter hunter parses parameters with combination of quoting schemes for keys and values',
- function(test) {
- //arrange
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template =
- '{{> test-comment(description: true, \'foo\': false, "bar": false, \'single\': true, \'singlesingle\': \'true\', \'singledouble\': "true", "double": true, "doublesingle": \'true\', "doubledouble": "true") }}';
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('false true
')
- );
- test.end();
- });
- });
- }
-);
-
-//todo https://github.com/pattern-lab/patternlab-node/issues/673
-// tap.test('parameter hunter parses parameters with values containing a closing parenthesis', function (test) {
-// //arrange
-// const pl = util.fakePatternLab(testPatternsPath);
-
-// var commentPath = path.join('00-test', 'comment.mustache');
-// var commentPattern = loadPattern(commentPath, pl);
-
-// var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
-// var testPattern = loadPattern(testPatternPath, pl);
-
-// //override the file
-// testPattern.template = "{{> test-comment(description: 'Hello ) World') }}";
-// testPattern.extendedTemplate = testPattern.template;
-// testPattern.parameteredPartials[0] = testPattern.template;
-
-// var p1 = processIterative(commentPattern, pl);
-// var p2 = processIterative(testPattern, pl);
-
-// Promise.all([p1, p2]).then(() => {
-// //act
-// parameter_hunter.find_parameters(testPattern, pl).then(() => {
-// //assert
-// test.equals(util.sanitized(testPattern.extendedTemplate), util.sanitized('Hello ) World
'));
-// test.end();
-// });
-// });
-// });
-
-tap.test('parameter hunter skips malformed parameters', function(test) {
- const pl = util.fakePatternLab(testPatternsPath);
-
- var commentPath = path.join('00-test', 'comment.mustache');
- var commentPattern = loadPattern(commentPath, pl);
-
- var testPatternPath = path.join('00-test', 'sticky-comment.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
-
- //override the file
- testPattern.template =
- '{{> test-comment( missing-val: , : missing-key, : , , foo: "Hello World") }}';
- testPattern.extendedTemplate = testPattern.template;
- testPattern.parameteredPartials[0] = testPattern.template;
-
- var p1 = processIterative(commentPattern, pl);
- var p2 = processIterative(testPattern, pl);
-
- Promise.all([p1, p2]).then(() => {
- //act
- parameter_hunter.find_parameters(testPattern, pl).then(() => {
- //assert
- console.log(
- '\nPattern Lab should catch JSON.parse() errors and output useful debugging information...'
- );
- test.equals(
- util.sanitized(testPattern.extendedTemplate),
- util.sanitized('{{foo}} {{description}}
')
- );
- test.end();
- });
- });
-});
diff --git a/packages/core/test/parseAllLinks_tests.js b/packages/core/test/parseAllLinks_tests.js
index 271b3ee5b..7077bf454 100644
--- a/packages/core/test/parseAllLinks_tests.js
+++ b/packages/core/test/parseAllLinks_tests.js
@@ -17,20 +17,26 @@ const patterns_dir = './test/files/_patterns';
tap.test(
'parseDataLinks - replaces found link.* data for their expanded links',
- function(test) {
+ function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
patternlab.graph = PatternGraph.empty();
- patternlab.patterns = [
- Pattern.createEmpty({ patternPartial: 'twitter-brad' }, patternlab),
- Pattern.createEmpty({ patternPartial: 'twitter-dave' }, patternlab),
- Pattern.createEmpty({ patternPartial: 'twitter-brian' }, patternlab),
- ];
- patternlab.data.link = {};
+ addPattern(new Pattern('twitter/brad.hbs', {}, patternlab), patternlab);
+ addPattern(new Pattern('twitter/dave.hbs', {}, patternlab), patternlab);
+ addPattern(new Pattern('twitter/brian.hbs', {}, patternlab), patternlab);
+ addPattern(
+ new Pattern('twitter/people/someone.hbs', {}, patternlab),
+ patternlab
+ );
+ // Test with pattern prefix
+ addPattern(
+ new Pattern('facebook/people/someone2.hbs', {}, patternlab),
+ patternlab
+ );
// copies essential logic from loadPattern
- const navPattern = new Pattern('00-test/nav.mustache');
+ const navPattern = new Pattern('test/nav.mustache', {}, patternlab);
const patternData = dataLoader.loadDataFromFile(
path.resolve(
__dirname,
@@ -43,74 +49,138 @@ tap.test(
navPattern.jsonFileData = patternData;
addPattern(navPattern, patternlab);
- //for the sake of the test, also imagining I have the following pages...
- patternlab.data.link['twitter-brad'] = 'https://twitter.com/brad_frost';
- patternlab.data.link['twitter-dave'] = 'https://twitter.com/dmolsen';
- patternlab.data.link['twitter-brian'] = 'https://twitter.com/bmuenzenmeyer';
-
patternlab.data.brad = { url: 'link.twitter-brad' };
patternlab.data.dave = { url: 'link.twitter-dave' };
patternlab.data.brian = { url: 'link.twitter-brian' };
+ patternlab.data.someone = { url: 'link.twitter-someone' };
+ patternlab.data.someone2 = { url: 'link.facebook-someone2' };
- let pattern;
- for (let i = 0; i < patternlab.patterns.length; i++) {
- if (patternlab.patterns[i].patternPartial === 'test-nav') {
- pattern = patternlab.patterns[i];
- }
- }
+ let pattern = patternlab.patterns.find(
+ (p) => p.patternPartial === 'test-nav'
+ );
//assert before
- test.equals(
+ test.equal(
pattern.jsonFileData.brad.url,
'link.twitter-brad',
'brad pattern data should be found'
);
- test.equals(
+ test.equal(
pattern.jsonFileData.dave.url,
'link.twitter-dave',
'dave pattern data should be found'
);
- test.equals(
+ test.equal(
pattern.jsonFileData.brian.url,
'link.twitter-brian',
'brian pattern data should be found'
);
+ test.equal(
+ pattern.jsonFileData.someone.url,
+ 'link.twitter-someone',
+ 'brian pattern data should be found'
+ );
+ test.equal(
+ pattern.jsonFileData.someone2.url,
+ 'link.facebook-someone2',
+ 'brian pattern data should be found'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-twitter'].url,
+ 'link.viewall-twitter-all',
+ 'view all twitter link should be found'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-twitter-people'].url,
+ 'link.viewall-twitter-people',
+ 'view all twitter people link should be found'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-facebook'].url,
+ 'link.viewall-facebook-all',
+ 'view all facebook link should be found'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-facebook-people'].url,
+ 'link.viewall-facebook-people',
+ 'view all facebook people link should be found'
+ );
//act
parseAllLinks(patternlab);
//assert after
- test.equals(
+ test.equal(
pattern.jsonFileData.brad.url,
- 'https://twitter.com/brad_frost',
+ '/patterns/twitter-brad/twitter-brad.rendered.html',
'brad pattern data should be replaced'
);
- test.equals(
+ test.equal(
pattern.jsonFileData.dave.url,
- 'https://twitter.com/dmolsen',
+ '/patterns/twitter-dave/twitter-dave.rendered.html',
'dave pattern data should be replaced'
);
- test.equals(
+ test.equal(
pattern.jsonFileData.brian.url,
- 'https://twitter.com/bmuenzenmeyer',
+ '/patterns/twitter-brian/twitter-brian.rendered.html',
'brian pattern data should be replaced'
);
+ test.equal(
+ pattern.jsonFileData.someone.url,
+ '/patterns/twitter-people-someone/twitter-people-someone.rendered.html',
+ 'twitter people someone pattern data should be replaced'
+ );
+ test.equal(
+ pattern.jsonFileData.someone2.url,
+ '/patterns/facebook-people-someone2/facebook-people-someone2.rendered.html',
+ 'facebook people someone2 pattern data should be replaced with prefix pattern'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-twitter'].url,
+ '/patterns/twitter/index.html',
+ 'view all twitter link should be replaced'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-twitter-people'].url,
+ '/patterns/twitter-people/index.html',
+ 'view all twitter people link should be replaced'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-facebook'].url,
+ '/patterns/facebook/index.html',
+ 'view all facebook link should be replaced'
+ );
+ test.equal(
+ pattern.jsonFileData['viewall-facebook-people'].url,
+ '/patterns/facebook-people/index.html',
+ 'view all facebook people link should be replaced'
+ );
- test.equals(
+ test.equal(
patternlab.data.brad.url,
- 'https://twitter.com/brad_frost',
+ '/patterns/twitter-brad/twitter-brad.rendered.html',
'global brad data should be replaced'
);
- test.equals(
+ test.equal(
patternlab.data.dave.url,
- 'https://twitter.com/dmolsen',
+ '/patterns/twitter-dave/twitter-dave.rendered.html',
'global dave data should be replaced'
);
- test.equals(
+ test.equal(
patternlab.data.brian.url,
- 'https://twitter.com/bmuenzenmeyer',
+ '/patterns/twitter-brian/twitter-brian.rendered.html',
'global brian data should be replaced'
);
+ test.equal(
+ patternlab.data.someone.url,
+ '/patterns/twitter-people-someone/twitter-people-someone.rendered.html',
+ 'twitter people someone pattern data should be replaced'
+ );
+ test.equal(
+ patternlab.data.someone2.url,
+ '/patterns/facebook-people-someone2/facebook-people-someone2.rendered.html',
+ 'facebook people someone2 pattern data should be replaced with prefix pattern'
+ );
test.end();
}
);
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/core/test/pattern_engines_tests.js b/packages/core/test/pattern_engines_tests.js
index f79b129dd..3a1e78f1f 100644
--- a/packages/core/test/pattern_engines_tests.js
+++ b/packages/core/test/pattern_engines_tests.js
@@ -10,15 +10,15 @@ patternEngines.loadAllEngines(config);
// the mustache test pattern, stolen from object_factory unit tests
var mustacheTestPattern = new Pattern(
- 'source/_patterns/00-atoms/00-global/00-colors-alt.mustache',
+ 'source/_patterns/atoms/global/colors-alt.mustache',
{ d: 123 }
);
var mustacheTestPseudoPatternBasePattern = new Pattern(
- 'source/_patterns/04-pages/00-homepage.mustache',
+ 'source/_patterns/pages/homepage.mustache',
{ d: 123 }
);
var mustacheTestPseudoPattern = new Pattern(
- 'source/_patterns/04-pages/00-homepage~emergency.json',
+ 'source/_patterns/pages/homepage~emergency.json',
{ d: 123 }
);
mustacheTestPseudoPattern.isPseudoPattern = true;
@@ -27,20 +27,19 @@ var engineNames = Object.keys(patternEngines);
tap.test(
'getEngineNameForPattern returns "mustache" from test pattern',
- function(test) {
- var engineName = patternEngines.getEngineNameForPattern(
- mustacheTestPattern
- );
- test.equals(engineName, 'mustache');
+ function (test) {
+ var engineName =
+ patternEngines.getEngineNameForPattern(mustacheTestPattern);
+ test.equal(engineName, 'mustache');
test.end();
}
);
tap.test(
'getEngineNameForPattern returns "mustache" for a plain string template as a backwards compatibility measure',
- function(test) {
+ function (test) {
test.plan(1);
- test.equals(
+ test.equal(
patternEngines.getEngineNameForPattern('plain text string'),
'mustache'
);
@@ -50,10 +49,10 @@ tap.test(
tap.test(
'getEngineNameForPattern returns "mustache" for an artificial empty template',
- function(test) {
+ function (test) {
test.plan(1);
var emptyPattern = Pattern.createEmpty();
- test.equals(
+ test.equal(
patternEngines.getEngineNameForPattern(emptyPattern),
'mustache'
);
@@ -63,40 +62,40 @@ tap.test(
tap.test(
'getEngineForPattern returns a reference to the mustache engine from test pattern',
- function(test) {
+ function (test) {
var engine = patternEngines.getEngineForPattern(mustacheTestPattern);
- test.equals(engine, patternEngines.mustache);
+ test.equal(engine, patternEngines.mustache);
test.end();
}
);
tap.test(
'getEngineForPattern returns a reference to the mustache engine from test pseudo-pattern',
- function(test) {
+ function (test) {
var engine = patternEngines.getEngineForPattern(mustacheTestPseudoPattern);
- test.equals(engine, patternEngines.mustache);
+ test.equal(engine, patternEngines.mustache);
test.end();
}
);
tap.test(
'isPseudoPatternJSON correctly identifies pseudo-pattern JSON filenames',
- function(test) {
+ function (test) {
// each test case
var filenames = {
- '00-homepage~emergency.json': true,
+ 'homepage~emergency.json': true,
'~emergency.json': true,
- '00-homepage~emergency.js': false,
- '00-homepage-emergency.js': false,
- '00-homepage.hbs': false,
- '00-homepage.json': false,
+ 'homepage~emergency.js': false,
+ 'homepage-emergency.js': false,
+ 'homepage.hbs': false,
+ 'homepage.json': false,
'greatpic.jpg': false,
};
// expect one test per test case
test.plan(Object.keys(filenames).length);
// loop over each test case and test it
- Object.keys(filenames).forEach(function(filename) {
+ Object.keys(filenames).forEach(function (filename) {
var expectedResult = filenames[filename],
actualResult = patternEngines.isPseudoPatternJSON(filename),
testMessage =
@@ -114,22 +113,22 @@ tap.test(
tap.test(
'isPatternFile correctly identifies pattern files and rejects non-pattern files',
- function(test) {
+ function (test) {
// each test case
var filenames = {
- '00-comment-thread.mustache': true,
- '00-comment-thread.fakeextthatdoesntexist': false,
- '00-comment-thread': false,
- '_00-comment-thread.mustache': true,
- '.00-comment-thread.mustache': false,
- '00-comment-thread.json': false,
- '00-homepage~emergency.json': true,
+ 'comment-thread.mustache': true,
+ 'comment-thread.fakeextthatdoesntexist': false,
+ 'comment-thread': false,
+ '_comment-thread.mustache': true,
+ '.comment-thread.mustache': false,
+ 'comment-thread.json': false,
+ 'homepage~emergency.json': true,
};
// expect one test per test case
test.plan(Object.keys(filenames).length);
// loop over each test case and test it
- Object.keys(filenames).forEach(function(filename) {
+ Object.keys(filenames).forEach(function (filename) {
var expectedResult = filenames[filename],
actualResult = patternEngines.isPatternFile(filename),
testMessage =
@@ -160,10 +159,10 @@ function testProps(object, propTests, test) {
}
var isOneOfTheseTypes = possibleTypes
- .map(function(type) {
+ .map(function (type) {
return typeof object[propName] === type;
})
- .reduce(function(isPrevType, isCurrentType) {
+ .reduce(function (isPrevType, isCurrentType) {
return isPrevType || isCurrentType;
});
@@ -183,7 +182,7 @@ function testProps(object, propTests, test) {
}
// go over each property test and run it
- Object.keys(propTests).forEach(function(propName) {
+ Object.keys(propTests).forEach(function (propName) {
var propType = propTests[propName];
testProp(propName, propType);
});
@@ -191,7 +190,7 @@ function testProps(object, propTests, test) {
tap.test(
'patternEngines object contains at least the default mustache engine',
- function(test) {
+ function (test) {
test.plan(1);
test.ok(patternEngines.hasOwnProperty('mustache'));
test.end();
@@ -200,7 +199,7 @@ tap.test(
tap.test(
'patternEngines object reports that it supports the .mustache extension',
- function(test) {
+ function (test) {
test.plan(1);
test.ok(patternEngines.isFileExtensionSupported('.mustache'));
test.end();
@@ -208,10 +207,10 @@ tap.test(
);
// make one big test group for each pattern engine
-engineNames.forEach(function(engineName) {
+engineNames.forEach(function (engineName) {
tap.test(
'engine ' + engineName + ' contains expected properties and methods',
- function(test) {
+ function (test) {
var propertyTests = {
engine: ['object', 'function'],
engineName: 'string',
@@ -229,7 +228,7 @@ engineNames.forEach(function(engineName) {
tap.test(
'patternEngines getSupportedFileExtensions flattens known engine extensions into a single array',
- function(test) {
+ function (test) {
//arrange
patternEngines.fooEngine = {
engineFileExtension: ['.foo1', '.foo2'],
diff --git a/packages/core/test/pattern_graph_tests.js b/packages/core/test/pattern_graph_tests.js
index a2618031c..4bbff233a 100644
--- a/packages/core/test/pattern_graph_tests.js
+++ b/packages/core/test/pattern_graph_tests.js
@@ -22,21 +22,21 @@ var patternlab = {
},
};
-var mockGraph = function() {
+var mockGraph = function () {
return PatternGraph.empty();
};
-tap.test('checkVersion - Current version returns true', test => {
+tap.test('checkVersion - Current version returns true', (test) => {
test.same(PatternGraph.checkVersion({ version: VERSION }), true);
test.end();
});
-tap.test('checkVersion - Older version returns false', test => {
+tap.test('checkVersion - Older version returns false', (test) => {
test.same(PatternGraph.checkVersion({ version: VERSION - 1 }), false);
test.end();
});
-tap.test('Loading an empty graph works', test => {
+tap.test('Loading an empty graph works', (test) => {
var g = PatternGraph.loadFromFile(
path.resolve(__dirname, 'public'),
'does not exist'
@@ -45,7 +45,7 @@ tap.test('Loading an empty graph works', test => {
test.end();
});
-tap.test('PatternGraph.fromJson() - Loading a graph from JSON', test => {
+tap.test('PatternGraph.fromJson() - Loading a graph from JSON', (test) => {
var graph = PatternGraph.loadFromFile(
path.resolve(__dirname, 'public'),
'testDependencyGraph.json'
@@ -58,9 +58,9 @@ tap.test('PatternGraph.fromJson() - Loading a graph from JSON', test => {
tap.test(
'PatternGraph.fromJson() - Loading a graph from JSON using an older version throws error',
- test => {
+ (test) => {
test.throws(
- function() {
+ function () {
PatternGraph.fromJson({ version: 0 });
},
{},
@@ -71,7 +71,7 @@ tap.test(
}
);
-tap.test('toJson() - Storing a graph to JSON correctly', test => {
+tap.test('toJson() - Storing a graph to JSON correctly', (test) => {
var graph = mockGraph();
graph.timestamp = 1337;
var atomFoo = Pattern.create('atom-foo', null, {
@@ -101,7 +101,7 @@ tap.test('toJson() - Storing a graph to JSON correctly', test => {
tap.test(
'Storing and loading a graph from JSON return the identical graph',
- test => {
+ (test) => {
var oldGraph = mockGraph();
oldGraph.timestamp = 1337;
var atomFoo = Pattern.create('atom-foo', null, {
@@ -128,7 +128,7 @@ tap.test(
}
);
-tap.test('clone()', test => {
+tap.test('clone()', (test) => {
var oldGraph = mockGraph();
oldGraph.timestamp = 1337;
var atomFoo = Pattern.create('atom-foo', null, {
@@ -154,7 +154,7 @@ tap.test('clone()', test => {
test.end();
});
-tap.test('Adding a node', test => {
+tap.test('Adding a node', (test) => {
var g = mockGraph();
var pattern = Pattern.create('atom-foo', null, {
compileState: CompileState.CLEAN,
@@ -170,7 +170,7 @@ tap.test('Adding a node', test => {
test.end();
});
-tap.test('Adding a node twice', test => {
+tap.test('Adding a node twice', (test) => {
var g = mockGraph();
var pattern = Pattern.create('atom-foo', null, {
compileState: CompileState.CLEAN,
@@ -182,7 +182,7 @@ tap.test('Adding a node twice', test => {
test.end();
});
-tap.test('Adding two nodes', test => {
+tap.test('Adding two nodes', (test) => {
var g = mockGraph();
var atomFoo = Pattern.create('atom-foo', {
compileState: CompileState.CLEAN,
@@ -197,25 +197,22 @@ tap.test('Adding two nodes', test => {
test.end();
});
-tap.test('Adding two nodes with only different subpattern types', test => {
+tap.test('Adding two nodes with only different subpattern types', (test) => {
var g = mockGraph();
- var atomFoo = Pattern.create('00-atoms/00-foo/baz.html', {
+ var atomFoo = Pattern.create('atoms/foo/baz.html', {
compileState: CompileState.CLEAN,
});
- var moleculeFoo = Pattern.create('00-atoms/00-bar/baz.html', {
+ var moleculeFoo = Pattern.create('atoms/bar/baz.html', {
compileState: CompileState.CLEAN,
});
g.add(atomFoo);
g.add(moleculeFoo);
var actual = g.nodes();
- test.same(posixPath(actual), [
- '00-atoms/00-foo/baz.html',
- '00-atoms/00-bar/baz.html',
- ]);
+ test.same(posixPath(actual), ['atoms/foo/baz.html', 'atoms/bar/baz.html']);
test.end();
});
-tap.test('Linking two nodes', test => {
+tap.test('Linking two nodes', (test) => {
var g = mockGraph();
var atomFoo = Pattern.create('atom-foo', null, {
compileState: CompileState.CLEAN,
@@ -234,7 +231,7 @@ tap.test('Linking two nodes', test => {
test.end();
});
-tap.test('remove() - Removing a node', test => {
+tap.test('remove() - Removing a node', (test) => {
var g = mockGraph();
var atomFoo = Pattern.create('atom-foo', null, {
compileState: CompileState.CLEAN,
@@ -259,7 +256,7 @@ tap.test('remove() - Removing a node', test => {
test.end();
});
-tap.test('filter() - Removing nodes via filter', test => {
+tap.test('filter() - Removing nodes via filter', (test) => {
var g = mockGraph();
var atomFoo = Pattern.create('atom-foo', null, {
compileState: CompileState.CLEAN,
@@ -270,7 +267,7 @@ tap.test('filter() - Removing nodes via filter', test => {
g.add(atomFoo);
g.add(moleculeFoo);
test.same(g.nodes(), ['atom-foo', 'molecule-foo']);
- g.filter(n => n != 'molecule-foo');
+ g.filter((n) => n != 'molecule-foo');
test.same(
g.graph.nodes(),
['atom-foo'],
@@ -286,23 +283,23 @@ tap.test('filter() - Removing nodes via filter', test => {
// Prevents nodes from escaping the scope, at the same time have some default graph for lineage to
// test on
-(function() {
- var atomFoo = Pattern.create('00-atom/xy/foo', null, {
+(function () {
+ var atomFoo = Pattern.create('atom/xy/foo', null, {
compileState: CompileState.CLEAN,
});
- var atomIsolated = Pattern.create('00-atom/xy/isolated', null, {
+ var atomIsolated = Pattern.create('atom/xy/isolated', null, {
compileState: CompileState.CLEAN,
});
- var moleculeFoo = Pattern.create('01-molecule/xy/foo', null, {
+ var moleculeFoo = Pattern.create('molecule/xy/foo', null, {
compileState: CompileState.CLEAN,
});
- var moleculeBar = Pattern.create('01-molecule/xy/bar', null, {
+ var moleculeBar = Pattern.create('molecule/xy/bar', null, {
compileState: CompileState.CLEAN,
});
- var organismFoo = Pattern.create('02-organism/xy/foo', null, {
+ var organismFoo = Pattern.create('organism/xy/foo', null, {
compileState: CompileState.CLEAN,
});
- var organismBar = Pattern.create('02-organism/xy/bar', null, {
+ var organismBar = Pattern.create('organism/xy/bar', null, {
compileState: CompileState.CLEAN,
});
@@ -327,26 +324,32 @@ tap.test('filter() - Removing nodes via filter', test => {
g.link(moleculeFoo, atomFoo);
g.link(moleculeBar, atomFoo);
- tap.test('lineage() - Calculate the lineage of a node', test => {
- test.same(posixPath(g.lineage(organismFoo).map(p => p.relPath)), [
- '01-molecule/xy/foo',
+ tap.test('lineage() - Calculate the lineage of a node', (test) => {
+ test.same(posixPath(g.lineage(organismFoo).map((p) => p.relPath)), [
+ 'molecule/xy/foo',
]);
- test.same(posixPath(g.lineage(organismBar).map(p => p.relPath)), [
- '01-molecule/xy/foo',
- '01-molecule/xy/bar',
+ test.same(posixPath(g.lineage(organismBar).map((p) => p.relPath)), [
+ 'molecule/xy/foo',
+ 'molecule/xy/bar',
]);
- test.same(posixPath(g.lineage(moleculeFoo).map(p => p.relPath)), [
- '00-atom/xy/foo',
+ test.same(posixPath(g.lineage(moleculeFoo).map((p) => p.relPath)), [
+ 'atom/xy/foo',
]);
- test.same(posixPath(g.lineage(moleculeBar).map(p => p.relPath)), [
- '00-atom/xy/foo',
+ test.same(posixPath(g.lineage(moleculeBar).map((p) => p.relPath)), [
+ 'atom/xy/foo',
]);
- test.same(g.lineage(atomFoo).map(p => p.relPath), []);
- test.same(g.lineage(atomIsolated).map(p => p.relPath), []);
+ test.same(
+ g.lineage(atomFoo).map((p) => p.relPath),
+ []
+ );
+ test.same(
+ g.lineage(atomIsolated).map((p) => p.relPath),
+ []
+ );
test.end();
});
- tap.test('lineageIndex() - Calculate the lineage of a node', test => {
+ tap.test('lineageIndex() - Calculate the lineage of a node', (test) => {
test.same(g.lineageIndex(organismFoo), ['molecule-foo']);
test.same(g.lineageIndex(organismBar), ['molecule-foo', 'molecule-bar']);
test.same(g.lineageIndex(moleculeFoo), ['atom-foo']);
@@ -356,68 +359,80 @@ tap.test('filter() - Removing nodes via filter', test => {
test.end();
});
- tap.test('lineageR() - Calculate the reverse lineage of a node', test => {
- test.same(g.lineageR(organismFoo).map(p => p.relPath), []);
- test.same(g.lineageR(organismBar).map(p => p.relPath), []);
- test.same(posixPath(g.lineageR(moleculeFoo).map(p => p.relPath)), [
- '02-organism/xy/foo',
- '02-organism/xy/bar',
+ tap.test('lineageR() - Calculate the reverse lineage of a node', (test) => {
+ test.same(
+ g.lineageR(organismFoo).map((p) => p.relPath),
+ []
+ );
+ test.same(
+ g.lineageR(organismBar).map((p) => p.relPath),
+ []
+ );
+ test.same(posixPath(g.lineageR(moleculeFoo).map((p) => p.relPath)), [
+ 'organism/xy/foo',
+ 'organism/xy/bar',
]);
- test.same(posixPath(g.lineageR(moleculeBar).map(p => p.relPath)), [
- '02-organism/xy/bar',
+ test.same(posixPath(g.lineageR(moleculeBar).map((p) => p.relPath)), [
+ 'organism/xy/bar',
]);
- test.same(posixPath(g.lineageR(atomFoo).map(p => p.relPath)), [
- '01-molecule/xy/foo',
- '01-molecule/xy/bar',
+ test.same(posixPath(g.lineageR(atomFoo).map((p) => p.relPath)), [
+ 'molecule/xy/foo',
+ 'molecule/xy/bar',
]);
- test.same(g.lineageR(atomIsolated).map(p => p.relPath), []);
+ test.same(
+ g.lineageR(atomIsolated).map((p) => p.relPath),
+ []
+ );
test.end();
});
- tap.test('lineageRIndex() - Calculate the lineage index of a node', test => {
- test.same(g.lineageRIndex(organismFoo), []);
- test.same(g.lineageRIndex(organismBar), []);
- test.same(g.lineageRIndex(moleculeFoo), ['organism-foo', 'organism-bar']);
- test.same(g.lineageRIndex(moleculeBar), ['organism-bar']);
- test.same(g.lineageRIndex(atomFoo), ['molecule-foo', 'molecule-bar']);
- test.same(g.lineageRIndex(atomIsolated), []);
- test.end();
- });
+ tap.test(
+ 'lineageRIndex() - Calculate the lineage index of a node',
+ (test) => {
+ test.same(g.lineageRIndex(organismFoo), []);
+ test.same(g.lineageRIndex(organismBar), []);
+ test.same(g.lineageRIndex(moleculeFoo), ['organism-foo', 'organism-bar']);
+ test.same(g.lineageRIndex(moleculeBar), ['organism-bar']);
+ test.same(g.lineageRIndex(atomFoo), ['molecule-foo', 'molecule-bar']);
+ test.same(g.lineageRIndex(atomIsolated), []);
+ test.end();
+ }
+ );
})();
-(function() {
+(function () {
function TestGraph() {
function csAt(args, idx) {
return { compileState: args[idx] || CompileState.CLEAN };
}
var i = 0;
var atomFoo = (this.atomFoo = Pattern.create(
- '00-atom/xy/foo',
+ 'atom/xy/foo',
null,
csAt(arguments, i++)
));
var atomIsolated = (this.atomIsolated = Pattern.create(
- '00-atom/xy/isolated',
+ 'atom/xy/isolated',
null,
csAt(arguments, i++)
));
var moleculeFoo = (this.moleculeFoo = Pattern.create(
- '01-molecule/xy/foo',
+ 'molecule/xy/foo',
null,
csAt(arguments, i++)
));
var moleculeBar = (this.moleculeBar = Pattern.create(
- '01-molecule/xy/bar',
+ 'molecule/xy/bar',
null,
csAt(arguments, i++)
));
var organismFoo = (this.organismFoo = Pattern.create(
- '02-organism/xy/foo',
+ 'organism/xy/foo',
null,
csAt(arguments, i++)
));
var organismBar = (this.organismBar = Pattern.create(
- '02-organism/xy/bar',
+ 'organism/xy/bar',
null,
csAt(arguments, i++)
));
@@ -446,17 +461,17 @@ tap.test('filter() - Removing nodes via filter', test => {
tap.test(
'compileOrder() - A clean graph results in no nodes to recompile',
- test => {
+ (test) => {
var g = new TestGraph();
var co = g.graph.compileOrder();
- test.equals(0, co.length);
+ test.equal(0, co.length);
test.end();
}
);
tap.test(
'compileOrder() - Recompile isolated atoms does not do anything else',
- test => {
+ (test) => {
var g = new TestGraph(
// atomFoo
CompileState.CLEAN,
@@ -466,7 +481,7 @@ tap.test('filter() - Removing nodes via filter', test => {
var co = g.graph.compileOrder();
test.same([g.atomIsolated], co, 'Only recompile atomIsolated');
- co.forEach(p =>
+ co.forEach((p) =>
test.same(
p.compileState,
CompileState.NEEDS_REBUILD,
@@ -480,18 +495,18 @@ tap.test('filter() - Removing nodes via filter', test => {
tap.test(
'compileOrder() - Changing a linked atom bubbles back to the organisms',
- test => {
+ (test) => {
// Almost every pattern - except atomIsolated - has a transitive dependency on atomFoo
var g = new TestGraph(CompileState.NEEDS_REBUILD);
var co = g.graph.compileOrder();
- test.equals(5, co.length);
+ test.equal(5, co.length);
test.same(
[g.atomFoo, g.moleculeFoo, g.organismFoo, g.moleculeBar, g.organismBar],
co,
'Recompile everything except atomIsolated'
);
- co.forEach(p =>
+ co.forEach((p) =>
test.same(
p.compileState,
CompileState.NEEDS_REBUILD,
@@ -505,7 +520,7 @@ tap.test('filter() - Removing nodes via filter', test => {
tap.test(
'compileOrder() - Changing a molecule leaves atoms untouched',
- test => {
+ (test) => {
// Bubble up from molecules to organisms, leaving atoms unchanged as they were not modified
var g = new TestGraph(null, null, CompileState.NEEDS_REBUILD);
var co = g.graph.compileOrder();
@@ -515,7 +530,7 @@ tap.test('filter() - Removing nodes via filter', test => {
co,
'Recompile moleculeFoo and transitive dependencies'
);
- co.forEach(p =>
+ co.forEach((p) =>
test.same(
p.compileState,
CompileState.NEEDS_REBUILD,
@@ -528,7 +543,7 @@ tap.test('filter() - Removing nodes via filter', test => {
tap.test(
'compileOrder() - Changing an organism leaves atoms and molecules untouched',
- test => {
+ (test) => {
// Almost every pattern - except atomIsolated - has a transitive dependency on atomFoo
var g = new TestGraph(
// atoms
@@ -552,7 +567,7 @@ tap.test('filter() - Removing nodes via filter', test => {
}
);
- tap.test('compileOrder() - Recompile everything', test => {
+ tap.test('compileOrder() - Recompile everything', (test) => {
// Almost every pattern - except atomIsolated - has a transitive dependency on atomFoo
// Also recompile atomIsolated
var g = new TestGraph(
@@ -573,7 +588,7 @@ tap.test('filter() - Removing nodes via filter', test => {
compileOrder,
'Recompile everything except atomIsolated'
);
- compileOrder.forEach(p =>
+ compileOrder.forEach((p) =>
test.same(
p.compileState,
CompileState.NEEDS_REBUILD,
diff --git a/packages/core/test/pattern_registry_tests.js b/packages/core/test/pattern_registry_tests.js
index bf2e71914..72eef2c4f 100644
--- a/packages/core/test/pattern_registry_tests.js
+++ b/packages/core/test/pattern_registry_tests.js
@@ -7,7 +7,7 @@ var tap = require('tap');
// #540 Copied from pattern_assembler_tests
tap.test(
'get_pattern_by_key - returns the fuzzy result when no others found',
- function(test) {
+ function (test) {
var pattern_registry = new PatternRegistry();
var pattern = {
@@ -21,13 +21,13 @@ tap.test(
//act
var result = pattern_registry.getPartial('character-han');
//assert
- test.equals(result, pattern);
+ test.equal(result, pattern);
test.end();
}
);
// #540 Copied from pattern_assembler_tests
-tap.test('remove - remove an existing pattern', function(test) {
+tap.test('remove - remove an existing pattern', function (test) {
var pattern_registry = new PatternRegistry();
var pattern = {
@@ -45,7 +45,7 @@ tap.test('remove - remove an existing pattern', function(test) {
});
// #540 Copied from pattern_assembler_tests
-tap.test('getPartial - returns the exact key if found', function(test) {
+tap.test('getPartial - returns the exact key if found', function (test) {
//arrange
var pattern_registry = new PatternRegistry();
let patterns = [
@@ -62,11 +62,11 @@ tap.test('getPartial - returns the exact key if found', function(test) {
fileName: 'molecules-primary-nav',
},
];
- patterns.forEach(p => pattern_registry.put(p));
+ patterns.forEach((p) => pattern_registry.put(p));
//act
var result = pattern_registry.getPartial('molecules-primary-nav');
//assert
- test.equals(result, patterns[1]);
+ test.equal(result, patterns[1]);
test.end();
});
diff --git a/packages/core/test/patternlab_tests.js b/packages/core/test/patternlab_tests.js
index 741fbca15..b2971bec6 100644
--- a/packages/core/test/patternlab_tests.js
+++ b/packages/core/test/patternlab_tests.js
@@ -9,16 +9,16 @@ var plEngineModule = rewire('../src/lib/patternlab');
//set up a global mocks - we don't want to be writing/rendering any files right now
const fsMock = {
- outputFileSync: function(path, content) {
+ outputFileSync: function (path, content) {
/* INTENTIONAL NOOP */
},
- readJSONSync: function(path, encoding) {
+ readJSONSync: function (path, encoding) {
return fs.readJSONSync(path, encoding);
},
- emptyDir: function(path) {
+ emptyDir: function (path) {
return fs.emptyDir(path);
},
- readFileSync: function(path, encoding) {
+ readFileSync: function (path, encoding) {
return fs.readFileSync(path, encoding);
},
};
@@ -30,27 +30,28 @@ plEngineModule.__set__({
tap.test(
'buildPatternData - should merge all JSON files in the data folder except listitems',
- function(test) {
+ function (test) {
const data_dir = `${__dirname}/files/_data/`;
var pl = new plEngineModule(config);
var dataResult = pl.buildPatternData(data_dir, fs);
- test.equals(dataResult.data, 'test');
- test.equals(dataResult.foo, 'bar');
- test.equals(dataResult.test_list_item, undefined);
+ test.equal(dataResult.data, 'test');
+ test.equal(dataResult.foo, 'bar');
+ test.equal(dataResult.test_list_item, undefined);
test.end();
}
);
-tap.test('buildPatternData - can load json, yaml, and yml files', function(
- test
-) {
- const data_dir = `${__dirname}/files/_data/`;
-
- var pl = new plEngineModule(config);
- var dataResult = pl.buildPatternData(data_dir, fs);
- test.equals(dataResult.from_yml, 'from_yml');
- test.equals(dataResult.from_yaml, 'from_yaml');
- test.equals(dataResult.from_json, 'from_json');
- test.end();
-});
+tap.test(
+ 'buildPatternData - can load json, yaml, and yml files',
+ function (test) {
+ const data_dir = `${__dirname}/files/_data/`;
+
+ var pl = new plEngineModule(config);
+ var dataResult = pl.buildPatternData(data_dir, fs);
+ test.equal(dataResult.from_yml, 'from_yml');
+ test.equal(dataResult.from_yaml, 'from_yaml');
+ test.equal(dataResult.from_json, 'from_json');
+ test.end();
+ }
+);
diff --git a/packages/core/test/processRecursive_tests.js b/packages/core/test/processRecursive_tests.js
index 8522c0403..e9ae0c4d8 100644
--- a/packages/core/test/processRecursive_tests.js
+++ b/packages/core/test/processRecursive_tests.js
@@ -16,14 +16,14 @@ engineLoader.loadAllEngines(config);
const patterns_dir = `${__dirname}/files/_patterns`;
-tap.test('processRecursive recursively includes partials', function(test) {
+tap.test('processRecursive recursively includes partials', function (test) {
//assert
const patternlab = util.fakePatternLab(patterns_dir);
- var fooPatternPath = path.join('00-test', '00-foo.mustache');
+ var fooPatternPath = path.join('test', 'foo.mustache');
var fooPattern = loadPattern(fooPatternPath, patternlab);
- var barPatternPath = path.join('00-test', '01-bar.mustache');
+ var barPatternPath = path.join('test', 'bar.mustache');
var barPattern = loadPattern(barPatternPath, patternlab);
var p1 = processIterative(fooPattern, patternlab);
@@ -36,7 +36,7 @@ tap.test('processRecursive recursively includes partials', function(test) {
.then(() => {
//assert
const expectedValue = 'bar';
- test.equals(
+ test.equal(
util.sanitized(fooPattern.extendedTemplate),
util.sanitized(expectedValue)
);
@@ -47,284 +47,18 @@ tap.test('processRecursive recursively includes partials', function(test) {
.catch(test.threw);
});
-tap.test(
- 'processRecursive - correctly replaces all stylemodifiers when multiple duplicate patterns with different stylemodifiers found',
- function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
-
- var atomPath = path.join('00-test', '03-styled-atom.mustache');
- var atomPattern = loadPattern(atomPath, patternlab);
-
- var groupPath = path.join('00-test', '04-group.mustache');
- var groupPattern = loadPattern(groupPath, patternlab);
-
- var p1 = processIterative(atomPattern, patternlab);
- var p2 = processIterative(groupPattern, patternlab);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- processRecursive(groupPath, patternlab)
- .then(() => {
- //assert
- const expectedValue =
- ' {{message}} {{message}} {{message}} {{message}}
';
- test.equals(
- util.sanitized(groupPattern.extendedTemplate),
- util.sanitized(expectedValue)
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
-tap.only(
- 'processRecursive - correctly replaces multiple stylemodifier classes on same partial',
- function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
-
- var atomPath = path.join('00-test', '03-styled-atom.mustache');
- var atomPattern = loadPattern(atomPath, patternlab);
-
- var groupPath = path.join(
- '00-test',
- '10-multiple-classes-numeric.mustache'
- );
- var groupPattern = loadPattern(groupPath, patternlab);
-
- var p1 = processIterative(atomPattern, patternlab);
- var p2 = processIterative(groupPattern, patternlab);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- processRecursive(groupPath, patternlab)
- .then(() => {
- //assert
- const expectedValue =
- ' {{message}} {{message}} bar
';
- test.equals(
- util.sanitized(groupPattern.extendedTemplate),
- util.sanitized(expectedValue)
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
-tap.test(
- 'processRecursive - correctly ignores a partial without a style modifier when the same partial later has a style modifier',
- function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
-
- var atomPath = path.join('00-test', '03-styled-atom.mustache');
- var atomPattern = loadPattern(atomPath, patternlab);
-
- var mixedPath = path.join('00-test', '06-mixed.mustache');
- var mixedPattern = loadPattern(mixedPath, patternlab);
-
- var p1 = processIterative(atomPattern, patternlab);
- var p2 = processIterative(mixedPattern, patternlab);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- processRecursive(mixedPath, patternlab)
- .then(() => {
- //assert. here we expect {{styleModifier}} to be in the first group, since it was not replaced by anything. rendering with data will then remove this (correctly)
- const expectedValue =
- ' {{message}} {{message}} {{message}} {{message}}
';
- test.equals(
- util.sanitized(mixedPattern.extendedTemplate),
- util.sanitized(expectedValue)
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
-tap.test(
- 'processRecursive - correctly ignores bookended partials without a style modifier when the same partial has a style modifier between',
- function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
-
- var atomPath = path.join('00-test', '03-styled-atom.mustache');
- var atomPattern = loadPattern(atomPath, patternlab);
-
- var bookendPath = path.join('00-test', '09-bookend.mustache');
- var bookendPattern = loadPattern(bookendPath, patternlab);
-
- var p1 = processIterative(atomPattern, patternlab);
- var p2 = processIterative(bookendPattern, patternlab);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- processRecursive(bookendPath, patternlab)
- .then(() => {
- //assert. here we expect {{styleModifier}} to be in the first and last group, since it was not replaced by anything. rendering with data will then remove this (correctly)
- const expectedValue =
- ' {{message}} {{message}} {{message}} {{message}}
';
- test.equals(
- util.sanitized(bookendPattern.extendedTemplate),
- util.sanitized(expectedValue)
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
-tap.test(
- 'processRecursive - correctly ignores a partial without a style modifier when the same partial later has a style modifier and pattern parameters',
- function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
-
- var atomPath = path.join('00-test', '03-styled-atom.mustache');
- var atomPattern = loadPattern(atomPath, patternlab);
-
- var mixedPath = path.join('00-test', '07-mixed-params.mustache');
- var mixedPattern = loadPattern(mixedPath, patternlab);
-
- var p1 = processIterative(atomPattern, patternlab);
- var p2 = processIterative(mixedPattern, patternlab);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- processRecursive(mixedPath, patternlab)
- .then(() => {
- //assert. here we expect {{styleModifier}} to be in the first span, since it was not replaced by anything. rendering with data will then remove this (correctly)
- const expectedValue =
- ' {{message}} 2 3 4
';
- test.equals(
- util.sanitized(mixedPattern.extendedTemplate),
- util.sanitized(expectedValue)
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
-tap.test(
- 'processRecursive - correctly ignores bookended partials without a style modifier when the same partial has a style modifier and pattern parameters between',
- function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
-
- var atomPath = path.join('00-test', '03-styled-atom.mustache');
- var atomPattern = loadPattern(atomPath, patternlab);
-
- var bookendPath = path.join('00-test', '08-bookend-params.mustache');
- var bookendPattern = loadPattern(bookendPath, patternlab);
-
- var p1 = processIterative(atomPattern, patternlab);
- var p2 = processIterative(bookendPattern, patternlab);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- processRecursive(bookendPath, patternlab)
- .then(() => {
- //assert. here we expect {{styleModifier}} to be in the first and last span, since it was not replaced by anything. rendering with data will then remove this (correctly)
- const expectedValue =
- ' {{message}} 2 3 {{message}}
';
- test.equals(
- util.sanitized(bookendPattern.extendedTemplate),
- util.sanitized(expectedValue)
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
-tap.test(
- 'processRecursive - does not pollute previous patterns when a later one is found with a styleModifier',
- function(test) {
- //arrange
- const patternlab = util.fakePatternLab(patterns_dir);
-
- var atomPath = path.join('00-test', '03-styled-atom.mustache');
- var atomPattern = loadPattern(atomPath, patternlab);
-
- var anotherPath = path.join('00-test', '12-another-styled-atom.mustache');
- var anotherPattern = loadPattern(anotherPath, patternlab);
-
- var p1 = processIterative(atomPattern, patternlab);
- var p2 = processIterative(anotherPattern, patternlab);
-
- Promise.all([p1, p2])
- .then(() => {
- //act
- processRecursive(anotherPath, patternlab)
- .then(() => {
- //assert
- const expectedCleanValue =
- ' {{message}} ';
- const expectedSetValue =
- ' {{message}} ';
-
- //this is the "atom" - it should remain unchanged
- test.equals(
- util.sanitized(atomPattern.template),
- util.sanitized(expectedCleanValue)
- );
- test.equals(
- util.sanitized(atomPattern.extendedTemplate),
- util.sanitized(expectedCleanValue)
- );
-
- // this is the style modifier pattern, which should resolve correctly
- test.equals(
- util.sanitized(anotherPattern.template),
- '{{> test-styled-atom:test_1 }}'
- );
- test.equals(
- util.sanitized(anotherPattern.extendedTemplate),
- util.sanitized(expectedSetValue)
- );
- test.end();
- })
- .catch(test.threw);
- })
- .catch(test.threw);
- }
-);
-
tap
- .test('processRecursive - ensure deep-nesting works', function(test) {
+ .test('processRecursive - ensure deep-nesting works', function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
- var atomPath = path.join('00-test', '01-bar.mustache');
+ var atomPath = path.join('test', 'bar.mustache');
var atomPattern = loadPattern(atomPath, patternlab);
- var templatePath = path.join('00-test', '00-foo.mustache');
+ var templatePath = path.join('test', 'foo.mustache');
var templatePattern = loadPattern(templatePath, patternlab);
- var pagesPath = path.join('00-test', '14-inception.mustache');
+ var pagesPath = path.join('test', 'inception.mustache');
var pagesPattern = loadPattern(pagesPath, patternlab);
var p1 = processIterative(atomPattern, patternlab);
@@ -342,31 +76,28 @@ tap
//act
return test.test(
'processRecursive - ensure deep-nesting works2',
- function(tt) {
+ function (tt) {
//assert
const expectedCleanValue = 'bar';
const expectedSetValue = 'bar';
//this is the "atom" - it should remain unchanged
- tt.equals(util.sanitized(atomPattern.template), expectedCleanValue);
- tt.equals(
+ tt.equal(util.sanitized(atomPattern.template), expectedCleanValue);
+ tt.equal(
util.sanitized(atomPattern.extendedTemplate),
expectedCleanValue
);
//this is the "template pattern" - it should have an updated extendedTemplate but an unchanged template
- tt.equals(
- util.sanitized(templatePattern.template),
- '{{> test-bar }}'
- );
- tt.equals(
+ tt.equal(util.sanitized(templatePattern.template), '{{> test-bar }}');
+ tt.equal(
util.sanitized(templatePattern.extendedTemplate),
expectedSetValue
);
//this is the "pages pattern" - it should have an updated extendedTemplate equal to the template pattern but an unchanged template
- tt.equals(util.sanitized(pagesPattern.template), '{{> test-foo }}');
- tt.equals(
+ tt.equal(util.sanitized(pagesPattern.template), '{{> test-foo }}');
+ tt.equal(
util.sanitized(pagesPattern.extendedTemplate),
expectedSetValue
);
@@ -378,18 +109,15 @@ tap
})
.catch(tap.threw);
-tap.test('hidden patterns can be called by their nice names', function(test) {
+tap.test('hidden patterns can be called by their nice names', function (test) {
//arrange
const patternlab = util.fakePatternLab(patterns_dir);
//act
- var hiddenPatternPath = path.join('00-test', '_00-hidden-pattern.mustache');
+ var hiddenPatternPath = path.join('test', '_hidden-pattern.mustache');
var hiddenPattern = loadPattern(hiddenPatternPath, patternlab);
- var testPatternPath = path.join(
- '00-test',
- '15-hidden-pattern-tester.mustache'
- );
+ var testPatternPath = path.join('test', 'hidden-pattern-tester.mustache');
var testPattern = loadPattern(testPatternPath, patternlab);
var p1 = processIterative(hiddenPattern, patternlab);
@@ -399,9 +127,9 @@ tap.test('hidden patterns can be called by their nice names', function(test) {
//act
processRecursive(hiddenPatternPath, patternlab).then(() => {
processRecursive(testPatternPath, patternlab).then(() => {
- testPattern.render().then(results => {
+ testPattern.render().then((results) => {
//assert
- test.equals(
+ test.equal(
util.sanitized(results),
util.sanitized(
"Hello there! Here's the hidden atom: [This is the hidden atom]"
@@ -415,39 +143,40 @@ tap.test('hidden patterns can be called by their nice names', function(test) {
});
});
-tap.test('parses pattern title correctly when frontmatter present', function(
- test
-) {
- //arrange
- var pl = util.fakePatternLab(patterns_dir);
+tap.test(
+ 'parses pattern title correctly when frontmatter present',
+ function (test) {
+ //arrange
+ var pl = util.fakePatternLab(patterns_dir);
- var testPatternPath = path.join('00-test', '01-bar.mustache');
- var testPattern = loadPattern(testPatternPath, pl);
+ var testPatternPath = path.join('test', 'bar.mustache');
+ var testPattern = loadPattern(testPatternPath, pl);
- //act
- Promise.all([
- processIterative(testPattern, pl),
- processRecursive(testPatternPath, pl),
- ])
- .then(results => {
- //assert
- test.equals(
- results[0].patternName,
- 'An Atom Walks Into a Bar',
- 'patternName not overridden'
- );
- test.end();
- })
- .catch(test.threw);
-});
+ //act
+ Promise.all([
+ processIterative(testPattern, pl),
+ processRecursive(testPatternPath, pl),
+ ])
+ .then((results) => {
+ //assert
+ test.equal(
+ results[0].patternName,
+ 'An Atom Walks Into a Bar',
+ 'patternName not overridden'
+ );
+ test.end();
+ })
+ .catch(test.threw);
+ }
+);
tap.test(
'parses pattern extra frontmatter correctly when frontmatter present',
- function(test) {
+ function (test) {
//arrange
var pl = util.fakePatternLab(patterns_dir);
- var testPatternPath = path.join('00-test', '01-bar.mustache');
+ var testPatternPath = path.join('test', 'bar.mustache');
var testPattern = loadPattern(testPatternPath, pl);
//act
@@ -455,9 +184,9 @@ tap.test(
processIterative(testPattern, pl),
processRecursive(testPatternPath, pl),
])
- .then(results => {
+ .then((results) => {
//assert
- test.equals(results[0].allMarkdown.joke, 'bad', 'extra key not added');
+ test.equal(results[0].allMarkdown.joke, 'bad', 'extra key not added');
test.end();
})
.catch(test.threw);
diff --git a/packages/core/test/pseudopattern_hunter_tests.js b/packages/core/test/pseudopattern_hunter_tests.js
index 1464f28b4..1f9c5e541 100644
--- a/packages/core/test/pseudopattern_hunter_tests.js
+++ b/packages/core/test/pseudopattern_hunter_tests.js
@@ -42,94 +42,145 @@ function stubPatternlab() {
return pl;
}
-tap.test('pseudpattern found and added as a pattern', function(test) {
+tap.test('pseudpattern found and added as a pattern', function (test) {
//arrange
var pl = stubPatternlab();
- var atomPattern = loadPattern('00-test/03-styled-atom.mustache', pl);
+ var atomPattern = loadPattern('test/styled-atom.mustache', pl);
addPattern(atomPattern, pl);
//act
var patternCountBefore = pl.patterns.length;
return pph.find_pseudopatterns(atomPattern, pl).then(() => {
//assert
- test.equals(patternCountBefore + 1, pl.patterns.length);
- test.equals(pl.patterns[1].patternPartial, 'test-styled-atom-alt');
- test.equals(
+ test.equal(patternCountBefore + 1, pl.patterns.length);
+ test.equal(pl.patterns[1].patternPartial, 'test-styled-atom-alt');
+ test.equal(
JSON.stringify(pl.patterns[1].jsonFileData),
JSON.stringify({ message: 'alternateMessage' })
);
- test.equals(
+ test.equal(
pl.patterns[1].patternLink,
- '00-test-03-styled-atom-alt' +
- path.sep +
- '00-test-03-styled-atom-alt.html'
+ 'test-styled-atom-alt' + path.sep + 'test-styled-atom-alt.html'
);
});
});
-tap.test('pseudpattern does not pollute base pattern data', function(test) {
+tap.test('pseudpattern does not pollute base pattern data', function (test) {
//arrange
var pl = stubPatternlab();
- var atomPattern = loadPattern('00-test/03-styled-atom.mustache', pl);
+ var atomPattern = loadPattern('test/styled-atom.mustache', pl);
//act
var patternCountBefore = pl.patterns.length;
return pph.find_pseudopatterns(atomPattern, pl).then(() => {
//assert
- test.equals(pl.patterns[0].patternPartial, 'test-styled-atom');
- test.equals(
+ test.equal(pl.patterns[0].patternPartial, 'test-styled-atom');
+ test.equal(
JSON.stringify(pl.patterns[0].jsonFileData),
JSON.stringify({ message: 'baseMessage' })
);
});
});
-tap.test(
- 'pseudpattern variant includes stylePartials and parameteredPartials',
- function(test) {
- //arrange
- var pl = stubPatternlab();
-
- var atomPattern = new Pattern('00-test/03-styled-atom.mustache');
- atomPattern.template = fs.readFileSync(
- patterns_dir + '00-test/03-styled-atom.mustache',
- 'utf8'
- );
- atomPattern.extendedTemplate = atomPattern.template;
- atomPattern.stylePartials = atomPattern.findPartialsWithStyleModifiers(
- atomPattern
- );
- atomPattern.parameteredPartials = atomPattern.findPartialsWithPatternParameters(
- atomPattern
- );
+tap.test('pseudpattern variant includes parameteredPartials', function (test) {
+ //arrange
+ var pl = stubPatternlab();
- var pseudoPattern = new Pattern('00-test/474-pseudomodifier.mustache');
- pseudoPattern.template = fs.readFileSync(
- patterns_dir + '00-test/474-pseudomodifier.mustache',
- 'utf8'
- );
- pseudoPattern.extendedTemplate = atomPattern.template;
- pseudoPattern.stylePartials = pseudoPattern.findPartialsWithStyleModifiers(
- pseudoPattern
+ var atomPattern = new Pattern('test/styled-atom.mustache');
+ atomPattern.template = fs.readFileSync(
+ patterns_dir + 'test/styled-atom.mustache',
+ 'utf8'
+ );
+ atomPattern.extendedTemplate = atomPattern.template;
+ atomPattern.parameteredPartials =
+ atomPattern.findPartialsWithPatternParameters(atomPattern);
+
+ var pseudoPattern = new Pattern('test/pseudomodifier.mustache');
+ pseudoPattern.template = fs.readFileSync(
+ patterns_dir + 'test/pseudomodifier.mustache',
+ 'utf8'
+ );
+ pseudoPattern.extendedTemplate = atomPattern.template;
+ pseudoPattern.parameteredPartials =
+ pseudoPattern.findPartialsWithPatternParameters(pseudoPattern);
+
+ addPattern(atomPattern, pl);
+ addPattern(pseudoPattern, pl);
+
+ //act
+ return pph.find_pseudopatterns(pseudoPattern, pl).then(() => {
+ //assert
+ test.equal(pl.patterns[2].patternPartial, 'test-pseudomodifier-test');
+ test.equal(
+ pl.patterns[2].parameteredPartials,
+ pseudoPattern.parameteredPartials
);
- pseudoPattern.parameteredPartials = pseudoPattern.findPartialsWithPatternParameters(
- pseudoPattern
+ });
+});
+
+tap.test('pseudo pattern variant data should merge arrays', function (test) {
+ const pl = stubPatternlab();
+ pl.config.patternMergeVariantArrays = true;
+
+ const pattern = loadPattern('test/variant-test.mustache', pl);
+
+ addPattern(pattern, pl);
+
+ return pph.find_pseudopatterns(pattern, pl).then(() => {
+ test.equal(pl.patterns[1].patternPartial, 'test-variant-test-merge');
+ test.equal(
+ JSON.stringify(pl.patterns[1].jsonFileData),
+ JSON.stringify({
+ a: 2,
+ b: [8, 3],
+ c: { d: [6, 7], e: 8, f: { a: ['a'], b: ['x'], c: ['c'] } },
+ })
);
+ });
+});
- addPattern(atomPattern, pl);
- addPattern(pseudoPattern, pl);
-
- //act
- return pph.find_pseudopatterns(pseudoPattern, pl).then(() => {
- //assert
- test.equals(pl.patterns[2].patternPartial, 'test-pseudomodifier-test');
- test.equals(pl.patterns[2].stylePartials, pseudoPattern.stylePartials);
- test.equals(
- pl.patterns[2].parameteredPartials,
- pseudoPattern.parameteredPartials
+tap.test(
+ 'pseudo pattern variant data should merge arrays if config "patternMergeVariantArrays" is not available as default behavior',
+ function (test) {
+ const pl = stubPatternlab();
+
+ const pattern = loadPattern('test/variant-test.mustache', pl);
+
+ addPattern(pattern, pl);
+
+ return pph.find_pseudopatterns(pattern, pl).then(() => {
+ test.equal(pl.patterns[1].patternPartial, 'test-variant-test-merge');
+ test.equal(
+ JSON.stringify(pl.patterns[1].jsonFileData),
+ JSON.stringify({
+ a: 2,
+ b: [8, 3],
+ c: { d: [6, 7], e: 8, f: { a: ['a'], b: ['x'], c: ['c'] } },
+ })
);
});
}
);
+
+tap.test('pseudo pattern variant data should override arrays', function (test) {
+ const pl = stubPatternlab();
+ pl.config.patternMergeVariantArrays = false;
+
+ const pattern = loadPattern('test/variant-test.mustache', pl);
+
+ addPattern(pattern, pl);
+
+ return pph.find_pseudopatterns(pattern, pl).then(() => {
+ test.equal(pl.patterns[1].patternPartial, 'test-variant-test-merge');
+ test.equal(
+ JSON.stringify(pl.patterns[1].jsonFileData),
+ JSON.stringify({
+ a: 2,
+ b: [8],
+ c: { d: [6, 7], e: 8, f: { a: ['a'], b: ['x'], c: ['c'] } },
+ })
+ );
+ });
+});
diff --git a/packages/core/test/replaceParameter_tests.js b/packages/core/test/replaceParameter_tests.js
index 41fde31c1..c3dfc129f 100644
--- a/packages/core/test/replaceParameter_tests.js
+++ b/packages/core/test/replaceParameter_tests.js
@@ -6,44 +6,44 @@ const tap = require('tap');
const replaceParameter = require('../src/lib/replaceParameter');
-tap.test('replaces simple value', function(test) {
+tap.test('replaces simple value', function (test) {
const result = replaceParameter('{{key}}', 'key', 'value');
- test.equals(result, 'value');
+ test.equal(result, 'value');
test.end();
});
-tap.test('replaces simple boolean true value', function(test) {
+tap.test('replaces simple boolean true value', function (test) {
const result = replaceParameter('{{key}}', 'key', true);
- test.equals(result, 'true');
+ test.equal(result, 'true');
test.end();
});
-tap.test('replaces simple boolean false value', function(test) {
+tap.test('replaces simple boolean false value', function (test) {
const result = replaceParameter('{{key}}', 'key', false);
- test.equals(result, 'false');
+ test.equal(result, 'false');
test.end();
});
-tap.test('replaces raw value', function(test) {
+tap.test('replaces raw value', function (test) {
const result = replaceParameter('{{{key}}}', 'key', 'value');
- test.equals(result, 'value');
+ test.equal(result, 'value');
test.end();
});
-tap.test('replaces boolean true section', function(test) {
+tap.test('replaces boolean true section', function (test) {
const result = replaceParameter('1{{#key}}value{{/key}}2', 'key', true);
- test.equals(result, '1value2');
+ test.equal(result, '1value2');
test.end();
});
-tap.only('replaces boolean true section with spaces', function(test) {
+tap.only('replaces boolean true section with spaces', function (test) {
const result = replaceParameter('1{{ #key }}value{{ /key }}2', 'key', true);
- test.equals(result, '1value2');
+ test.equal(result, '1value2');
test.end();
});
-tap.test('replaces boolean section false', function(test) {
+tap.test('replaces boolean section false', function (test) {
const result = replaceParameter('1{{#key}}value{{/key}}2', 'key', false);
- test.equals(result, '12');
+ test.equal(result, '12');
test.end();
});
diff --git a/packages/core/test/style_modifier_hunter_tests.js b/packages/core/test/style_modifier_hunter_tests.js
deleted file mode 100644
index bdbc1e994..000000000
--- a/packages/core/test/style_modifier_hunter_tests.js
+++ /dev/null
@@ -1,110 +0,0 @@
-'use strict';
-
-var tap = require('tap');
-
-var smh = require('../src/lib/style_modifier_hunter');
-
-tap.test(
- 'uses the partial stylemodifer to modify the patterns extendedTemplate',
- function(test) {
- //arrange
- var pl = {};
- pl.partials = {};
- pl.config = {};
- pl.config.logLevel = 'quiet';
-
- var pattern = {
- extendedTemplate: '
',
- };
-
- var style_modifier_hunter = new smh();
-
- //act
- style_modifier_hunter.consume_style_modifier(
- pattern,
- '{{> partial:bar}}',
- pl
- );
-
- //assert
- test.equals(pattern.extendedTemplate, '
');
- test.end();
- }
-);
-
-tap.test('replaces style modifiers with spaces in the syntax', function(test) {
- //arrange
- var pl = {};
- pl.partials = {};
- pl.config = {};
- pl.config.logLevel = 'quiet';
-
- var pattern = {
- extendedTemplate: '
',
- };
-
- var style_modifier_hunter = new smh();
-
- //act
- style_modifier_hunter.consume_style_modifier(
- pattern,
- '{{> partial:bar}}',
- pl
- );
-
- //assert
- test.equals(pattern.extendedTemplate, '
');
- test.end();
-});
-
-tap.test('replaces multiple style modifiers', function(test) {
- //arrange
- var pl = {};
- pl.partials = {};
- pl.config = {};
- pl.config.logLevel = 'quiet';
-
- var pattern = {
- extendedTemplate: '
',
- };
-
- var style_modifier_hunter = new smh();
-
- //act
- style_modifier_hunter.consume_style_modifier(
- pattern,
- '{{> partial:bar|baz|dum}}',
- pl
- );
-
- //assert
- test.equals(pattern.extendedTemplate, '
');
- test.end();
-});
-
-tap.test(
- 'does not alter pattern extendedTemplate if styleModifier not found in partial',
- function(test) {
- //arrange
- var pl = {};
- pl.partials = {};
- pl.config = {};
- pl.config.logLevel = 'quiet';
-
- var pattern = {
- extendedTemplate: '
',
- };
-
- var style_modifier_hunter = new smh();
-
- //act
- style_modifier_hunter.consume_style_modifier(pattern, '{{> partial}}', pl);
-
- //assert
- test.equals(
- pattern.extendedTemplate,
- '
'
- );
- test.end();
- }
-);
diff --git a/packages/core/test/ui_builder_tests.js b/packages/core/test/ui_builder_tests.js
index 607d9fd95..1070151d6 100644
--- a/packages/core/test/ui_builder_tests.js
+++ b/packages/core/test/ui_builder_tests.js
@@ -15,14 +15,14 @@ engineLoader.loadAllEngines(config);
//set up a global mocks - we don't want to be writing/rendering any files right now
var fsMock = {
- outputFileSync: function(path, data, cb) {},
- outputFile: function(path, data, cb) {},
+ outputFileSync: function (path, data, cb) {},
+ outputFile: function (path, data, cb) {},
};
-var renderMock = function(template, data, partials) {
+var renderMock = function (template, data, partials) {
return Promise.resolve('');
};
-var buildFooterMock = function(patternlab, patternPartial) {
+var buildFooterMock = function (patternlab, patternPartial) {
return Promise.resolve('');
};
@@ -69,48 +69,49 @@ function createFakePatternLab(customProps) {
tap.test(
'isPatternExcluded - returns true when pattern filename starts with underscore',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({});
- var pattern = new Pattern('00-test/_ignored-pattern.mustache');
+ var pattern = new Pattern('test/ignored-pattern.mustache');
+ pattern.hidden = true;
//act
var result = ui.isPatternExcluded(pattern, patternlab, uikit);
//assert
- test.equals(result, true);
+ test.equal(result, true);
test.end();
}
);
tap.test(
'isPatternExcluded - returns true when pattern is defaultPattern',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({});
- var pattern = new Pattern('00-test/foo.mustache');
+ var pattern = new Pattern('test/foo.mustache');
patternlab.config.defaultPattern = 'test-foo';
//act
var result = ui.isPatternExcluded(pattern, patternlab, uikit);
//assert
- test.equals(result, true);
+ test.equal(result, true);
test.end();
}
);
tap.test(
'isPatternExcluded - returns true when pattern within underscored directory - top level',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({});
var pattern = Pattern.createEmpty({
relPath:
path.sep +
- '_hidden' +
+ 'hidden' +
path.sep +
- 'patternsubtype' +
+ 'patternSubgroup' +
path.sep +
'foo.mustache',
isPattern: true,
@@ -118,45 +119,53 @@ tap.test(
patternPartial: 'hidden-foo',
});
+ pattern.patternGroupData = {
+ hidden: true,
+ };
+
//act
var result = ui.isPatternExcluded(pattern, patternlab, uikit);
//assert
- test.equals(result, true);
+ test.equal(result, true);
test.end();
}
);
tap.test(
- 'isPatternExcluded - returns true when pattern within underscored directory - subtype level',
- function(test) {
+ 'isPatternExcluded - returns true when pattern within underscored directory - subgroup level',
+ function (test) {
//arrange
var patternlab = createFakePatternLab({});
var pattern = Pattern.createEmpty({
relPath:
- 'shown' + path.sep + '_patternsubtype' + path.sep + 'foo.mustache',
+ 'shown' + path.sep + 'patternsubtype' + path.sep + 'foo.mustache',
isPattern: true,
fileName: 'foo.mustache',
patternPartial: 'shown-foo',
});
+ pattern.patternSubgroupData = {
+ hidden: true,
+ };
+
//act
var result = ui.isPatternExcluded(pattern, patternlab, uikit);
//assert
- test.equals(result, true);
+ test.equal(result, true);
test.end();
}
);
tap.test(
'isPatternExcluded - returns true when pattern state found withing uikit exclusions',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({});
var pattern = Pattern.createEmpty({
relPath:
- 'shown' + path.sep + '_patternsubtype' + path.sep + 'foo.mustache',
+ 'shown' + path.sep + '_patternSubgroup' + path.sep + 'foo.mustache',
isPattern: true,
fileName: 'foo.mustache',
patternPartial: 'shown-foo',
@@ -169,129 +178,147 @@ tap.test(
});
//assert
- test.equals(result, true);
+ test.equal(result, true);
test.end();
}
);
-tap.test('groupPatterns - creates pattern groups correctly', function(test) {
+tap.test('groupPatterns - creates pattern groups correctly', function (test) {
//arrange
var patternlab = createFakePatternLab({
patterns: [],
patternGroups: {},
- subtypePatterns: {},
+ subgroupPatterns: {},
});
patternlab.patterns.push(
- new Pattern('00-test/bar.mustache'),
- new Pattern('00-test/foo.mustache'),
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache'),
- new Pattern('patternType1/patternSubType2/black.mustache'),
- new Pattern('patternType1/patternSubType2/grey.mustache'),
- new Pattern('patternType1/patternSubType2/white.mustache')
+ new Pattern('foobar.mustache'),
+ new Pattern('test/bar.mustache'),
+ new Pattern('test/foo.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/black.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/grey.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/white.mustache')
);
ui.resetUIBuilderState(patternlab);
//act
var result = ui.groupPatterns(patternlab, uikit);
- test.equals(
- result.patternGroups.patternType1.patternSubType1.blue.patternPartial,
- 'patternType1-blue'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup1.blue.patternPartial,
+ 'patternGroup1-blue'
);
- test.equals(
- result.patternGroups.patternType1.patternSubType1.red.patternPartial,
- 'patternType1-red'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup1.red.patternPartial,
+ 'patternGroup1-red'
);
- test.equals(
- result.patternGroups.patternType1.patternSubType1.yellow.patternPartial,
- 'patternType1-yellow'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup1.yellow.patternPartial,
+ 'patternGroup1-yellow'
);
- test.equals(
- result.patternGroups.patternType1.patternSubType2.black.patternPartial,
- 'patternType1-black'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup2.black.patternPartial,
+ 'patternGroup1-black'
);
- test.equals(
- result.patternGroups.patternType1.patternSubType2.grey.patternPartial,
- 'patternType1-grey'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup2.grey.patternPartial,
+ 'patternGroup1-grey'
);
- test.equals(
- result.patternGroups.patternType1.patternSubType2.white.patternPartial,
- 'patternType1-white'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup2.white.patternPartial,
+ 'patternGroup1-white'
);
- test.equals(
- patternlab.patternTypes[0].patternItems[0].patternPartial,
+ // Pattern groups are now sorted. Because of the missing prefix, they won't be
+ // found from the recursive file issuer in the order that was given by the
+ // number prefix. Now it will be by name if no order is set by group or
+ // subgroup frontmatter.
+
+ //The groups for this test will be in the following order
+ //"patternGroup1", "root" (because it's a top-level flat pattern) and at last "test"
+
+ // Flat patterns
+ test.equal(
+ patternlab.patternGroups[1].patternItems[0].patternPartial,
+ 'root-foobar',
+ 'flat pattern foobar on root'
+ );
+ test.equal(
+ patternlab.patternGroups[2].patternItems[0].patternPartial,
'test-bar',
'first pattern item should be test-bar'
);
- test.equals(
- patternlab.patternTypes[0].patternItems[1].patternPartial,
+ test.equal(
+ patternlab.patternGroups[2].patternItems[1].patternPartial,
'test-foo',
'second pattern item should be test-foo'
);
- //todo: patternlab.patternTypes[0].patternItems[1] looks malformed
+ //todo: patternlab.patternGroups[0].patternItems[1] looks malformed
test.end();
});
-tap.test('groupPatterns - orders patterns when provided from md', function(
- test
-) {
- //arrange
- var patternlab = createFakePatternLab({
- patterns: [],
- patternGroups: {},
- subtypePatterns: {},
- });
+tap.test(
+ 'groupPatterns - orders patterns when provided from md',
+ function (test) {
+ //arrange
+ var patternlab = createFakePatternLab({
+ patterns: [],
+ patternGroups: {},
+ subgroupPatterns: {},
+ });
- patternlab.patterns.push(
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache')
- );
- ui.resetUIBuilderState(patternlab);
+ // Should be sorted by order and secondly by name
+ patternlab.patterns.push(
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache')
+ );
+ ui.resetUIBuilderState(patternlab);
- patternlab.patterns[1].order = 1;
+ // Set order of red to 1 to sort it after the others
+ patternlab.patterns[1].order = 1;
- //act
- ui.groupPatterns(patternlab, uikit);
-
- let patternType = _.find(patternlab.patternTypes, [
- 'patternType',
- 'patternType1',
- ]);
- let patternSubType = _.find(patternType.patternTypeItems, [
- 'patternSubtype',
- 'patternSubType1',
- ]);
- var items = patternSubType.patternSubtypeItems;
-
- //zero is viewall
- test.equals(items[1].patternPartial, 'patternType1-red');
- test.equals(items[2].patternPartial, 'patternType1-blue');
- test.equals(items[3].patternPartial, 'patternType1-yellow');
+ //act
+ ui.groupPatterns(patternlab, uikit);
- test.end();
-});
+ let patternGroup = _.find(patternlab.patternGroups, [
+ 'patternGroup',
+ 'patternGroup1',
+ ]);
+ let patternSubgroup = _.find(patternGroup.patternGroupItems, [
+ 'patternSubgroup',
+ 'patternSubgroup1',
+ ]);
+ var items = patternSubgroup.patternSubgroupItems;
+
+ // Viewall should come last since it shows all patterns that are above
+ test.equal(items[0].patternPartial, 'patternGroup1-blue');
+ test.equal(items[1].patternPartial, 'patternGroup1-yellow');
+ test.equal(items[2].patternPartial, 'patternGroup1-red');
+
+ test.end();
+ }
+);
tap.test(
'groupPatterns - retains pattern order from name when order provided from md is malformed',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({
patterns: [],
patternGroups: {},
- subtypePatterns: {},
+ subgroupPatterns: {},
});
patternlab.patterns.push(
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache')
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache')
);
ui.resetUIBuilderState(patternlab);
@@ -300,39 +327,39 @@ tap.test(
//act
ui.groupPatterns(patternlab, uikit);
- let patternType = _.find(patternlab.patternTypes, [
- 'patternType',
- 'patternType1',
+ let patternGroup = _.find(patternlab.patternGroups, [
+ 'patternGroup',
+ 'patternGroup1',
]);
- let patternSubType = _.find(patternType.patternTypeItems, [
- 'patternSubtype',
- 'patternSubType1',
+ let patternSubgroup = _.find(patternGroup.patternGroupItems, [
+ 'patternSubgroup',
+ 'patternSubgroup1',
]);
- var items = patternSubType.patternSubtypeItems;
+ var items = patternSubgroup.patternSubgroupItems;
- //zero is viewall
- test.equals(items[1].patternPartial, 'patternType1-blue');
- test.equals(items[2].patternPartial, 'patternType1-red');
- test.equals(items[3].patternPartial, 'patternType1-yellow');
+ // Viewall should come last since it shows all patterns that are above
+ test.equal(items[0].patternPartial, 'patternGroup1-blue');
+ test.equal(items[1].patternPartial, 'patternGroup1-red');
+ test.equal(items[2].patternPartial, 'patternGroup1-yellow');
test.end();
}
);
tap.test(
- 'groupPatterns - sorts viewall subtype pattern to the beginning',
- function(test) {
+ 'groupPatterns - sorts viewall subgroup pattern to the beginning',
+ function (test) {
//arrange
var patternlab = createFakePatternLab({
patterns: [],
patternGroups: {},
- subtypePatterns: {},
+ subgroupPatterns: {},
});
patternlab.patterns.push(
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache')
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache')
);
ui.resetUIBuilderState(patternlab);
@@ -343,48 +370,48 @@ tap.test(
//act
ui.groupPatterns(patternlab, uikit);
- let patternType = _.find(patternlab.patternTypes, [
- 'patternType',
- 'patternType1',
+ let patternGroup = _.find(patternlab.patternGroups, [
+ 'patternGroup',
+ 'patternGroup1',
]);
- let patternSubType = _.find(patternType.patternTypeItems, [
- 'patternSubtype',
- 'patternSubType1',
+ let patternSubgroup = _.find(patternGroup.patternGroupItems, [
+ 'patternSubgroup',
+ 'patternSubgroup1',
]);
- var items = patternSubType.patternSubtypeItems;
+ var items = patternSubgroup.patternSubgroupItems;
- //zero is viewall
- test.equals(
- items[0].patternPartial,
- 'viewall-patternType1-patternSubType1'
+ // Viewall should come last since it shows all patterns that are above
+ test.equal(
+ items[3].patternPartial,
+ 'viewall-patternGroup1-patternSubgroup1'
);
- test.equals(items[1].patternPartial, 'patternType1-blue');
- test.equals(items[2].patternPartial, 'patternType1-yellow');
- test.equals(items[3].patternPartial, 'patternType1-red');
+ test.equal(items[0].patternPartial, 'patternGroup1-blue');
+ test.equal(items[1].patternPartial, 'patternGroup1-yellow');
+ test.equal(items[2].patternPartial, 'patternGroup1-red');
test.end();
}
);
tap.test(
- 'groupPatterns - creates documentation patterns for each type and subtype if not exists',
- function(test) {
+ 'groupPatterns - creates documentation patterns for each type and subgroup if not exists',
+ function (test) {
//arrange
var patternlab = createFakePatternLab({
patterns: [],
patternGroups: {},
- subtypePatterns: {},
+ subgroupPatterns: {},
});
patternlab.patterns.push(
- new Pattern('00-test/foo.mustache'),
- new Pattern('00-test/bar.mustache'),
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache'),
- new Pattern('patternType1/patternSubType2/black.mustache'),
- new Pattern('patternType1/patternSubType2/grey.mustache'),
- new Pattern('patternType1/patternSubType2/white.mustache')
+ new Pattern('test/foo.mustache'),
+ new Pattern('test/bar.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/black.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/grey.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/white.mustache')
);
ui.resetUIBuilderState(patternlab);
@@ -392,17 +419,17 @@ tap.test(
var result = ui.groupPatterns(patternlab, uikit);
//assert
- test.equals(
- result.patternGroups.patternType1.patternSubType1[
- 'viewall-patternType1-patternSubType1'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup1[
+ 'viewall-patternGroup1-patternSubgroup1'
].patternPartial,
- 'viewall-patternType1-patternSubType1'
+ 'viewall-patternGroup1-patternSubgroup1'
);
- test.equals(
- result.patternGroups.patternType1.patternSubType2[
- 'viewall-patternType1-patternSubType2'
+ test.equal(
+ result.patternGroups.patternGroup1.patternSubgroup2[
+ 'viewall-patternGroup1-patternSubgroup2'
].patternPartial,
- 'viewall-patternType1-patternSubType2'
+ 'viewall-patternGroup1-patternSubgroup2'
);
test.end();
@@ -411,23 +438,23 @@ tap.test(
tap.test(
'groupPatterns - adds each pattern to the patternPaths object',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({
patterns: [],
patternGroups: {},
- subtypePatterns: {},
+ subgroupPatterns: {},
});
patternlab.patterns.push(
- new Pattern('00-test/foo.mustache'),
- new Pattern('00-test/bar.mustache'),
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache'),
- new Pattern('patternType1/patternSubType2/black.mustache'),
- new Pattern('patternType1/patternSubType2/grey.mustache'),
- new Pattern('patternType1/patternSubType2/white.mustache')
+ new Pattern('test/foo.mustache'),
+ new Pattern('test/bar.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/black.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/grey.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/white.mustache')
);
ui.resetUIBuilderState(patternlab);
@@ -435,31 +462,31 @@ tap.test(
var result = ui.groupPatterns(patternlab, uikit);
//assert
- test.equals(patternlab.patternPaths['test']['foo'], '00-test-foo');
- test.equals(patternlab.patternPaths['test']['bar'], '00-test-bar');
- test.equals(
- patternlab.patternPaths['patternType1']['blue'],
- 'patternType1-patternSubType1-blue'
+ test.equal(patternlab.patternPaths['test']['foo'], 'test-foo');
+ test.equal(patternlab.patternPaths['test']['bar'], 'test-bar');
+ test.equal(
+ patternlab.patternPaths['patternGroup1']['blue'],
+ 'patternGroup1-patternSubgroup1-blue'
);
- test.equals(
- patternlab.patternPaths['patternType1']['red'],
- 'patternType1-patternSubType1-red'
+ test.equal(
+ patternlab.patternPaths['patternGroup1']['red'],
+ 'patternGroup1-patternSubgroup1-red'
);
- test.equals(
- patternlab.patternPaths['patternType1']['yellow'],
- 'patternType1-patternSubType1-yellow'
+ test.equal(
+ patternlab.patternPaths['patternGroup1']['yellow'],
+ 'patternGroup1-patternSubgroup1-yellow'
);
- test.equals(
- patternlab.patternPaths['patternType1']['black'],
- 'patternType1-patternSubType2-black'
+ test.equal(
+ patternlab.patternPaths['patternGroup1']['black'],
+ 'patternGroup1-patternSubgroup2-black'
);
- test.equals(
- patternlab.patternPaths['patternType1']['grey'],
- 'patternType1-patternSubType2-grey'
+ test.equal(
+ patternlab.patternPaths['patternGroup1']['grey'],
+ 'patternGroup1-patternSubgroup2-grey'
);
- test.equals(
- patternlab.patternPaths['patternType1']['white'],
- 'patternType1-patternSubType2-white'
+ test.equal(
+ patternlab.patternPaths['patternGroup1']['white'],
+ 'patternGroup1-patternSubgroup2-white'
);
test.end();
@@ -468,23 +495,23 @@ tap.test(
tap.test(
'groupPatterns - adds each pattern to the view all paths object',
- function(test) {
+ function (test) {
//arrange
var patternlab = createFakePatternLab({
patterns: [],
patternGroups: {},
- subtypePatterns: {},
+ subgroupPatterns: {},
});
patternlab.patterns.push(
- new Pattern('00-test/foo.mustache'),
- new Pattern('00-test/bar.mustache'),
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache'),
- new Pattern('patternType1/patternSubType2/black.mustache'),
- new Pattern('patternType1/patternSubType2/grey.mustache'),
- new Pattern('patternType1/patternSubType2/white.mustache')
+ new Pattern('test/foo.mustache'),
+ new Pattern('test/bar.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/black.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/grey.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/white.mustache')
);
ui.resetUIBuilderState(patternlab);
@@ -492,40 +519,40 @@ tap.test(
var result = ui.groupPatterns(patternlab, uikit);
//assert
- test.equals('todo', 'todo');
+ test.equal('todo', 'todo');
test.end();
}
);
-tap.test('resetUIBuilderState - reset global objects', function(test) {
+tap.test('resetUIBuilderState - reset global objects', function (test) {
//arrange
var patternlab = createFakePatternLab({
patternPaths: { foo: 1 },
viewAllPaths: { bar: 2 },
- patternTypes: ['baz'],
+ patternGroups: ['baz'],
});
//act
ui.resetUIBuilderState(patternlab);
//assert
- test.equals(patternlab.patternPaths.foo, undefined);
- test.equals(patternlab.viewAllPaths.bar, undefined);
- test.equals(patternlab.patternTypes.length, 0);
+ test.equal(patternlab.patternPaths.foo, undefined);
+ test.equal(patternlab.viewAllPaths.bar, undefined);
+ test.equal(patternlab.patternGroups.length, 0);
test.end();
});
tap.test(
- 'buildViewAllPages - adds viewall page for each type and subtype',
- function(test) {
+ 'buildViewAllPages - adds viewall page for each type and subgroup NOT! for flat patterns',
+ function (test) {
//arrange
const mainPageHeadHtml = '';
const patternlab = createFakePatternLab({
patterns: [],
patternGroups: {},
- subtypePatterns: {},
+ subgroupPatterns: {},
footer: {},
userFoot: {},
cacheBuster: 1234,
@@ -533,53 +560,127 @@ tap.test(
patternlab.patterns.push(
//this flat pattern is found and causes trouble for the rest of the crew
- new Pattern('00-test/foo.mustache'),
- new Pattern('patternType1/patternSubType1/blue.mustache'),
- new Pattern('patternType1/patternSubType1/red.mustache'),
- new Pattern('patternType1/patternSubType1/yellow.mustache'),
- new Pattern('patternType1/patternSubType2/black.mustache'),
- new Pattern('patternType1/patternSubType2/grey.mustache'),
- new Pattern('patternType1/patternSubType2/white.mustache')
+ new Pattern('test/foo.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/black.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/grey.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/white.mustache')
);
ui.resetUIBuilderState(patternlab);
const styleguidePatterns = ui.groupPatterns(patternlab, uikit);
//act
- ui
- .buildViewAllPages(
- mainPageHeadHtml,
- patternlab,
- styleguidePatterns,
- uikit
- )
- .then(allPatterns => {
- //assert
- //this was a nuanced one. buildViewAllPages() had return false; statements
- //within _.forOwn(...) loops, causing premature termination of the entire loop
- //when what was intended was a continue
- //we expect 8 here because:
- // - foo.mustache is flat and therefore does not have a viewall page
- // - the colors.mustache files make 6
- // - patternSubType1 and patternSubType2 make 8
- //while most of that heavy lifting occurs inside groupPatterns and not buildViewAllPages,
- //it's important to ensure that this method does not get prematurely terminated
- //we choose to do that by checking it's return number of patterns
-
- //todo: this workaround matches the code at the moment
- const uniquePatterns = _.uniq(
- _.flatMapDeep(allPatterns, pattern => {
- return pattern;
- })
- );
-
- test.equals(
- uniquePatterns.length,
- 8,
- '2 viewall pages should be added'
- );
-
- test.end();
- });
+ ui.buildViewAllPages(
+ mainPageHeadHtml,
+ patternlab,
+ styleguidePatterns,
+ uikit
+ ).then((allPatterns) => {
+ // assert
+ // this was a nuanced one. buildViewAllPages() had return false; statements
+ // within _.forOwn(...) loops, causing premature termination of the entire loop
+ // when what was intended was a continue
+ // we expect 10 here because:
+ // - foo.mustache is flat and therefore does not have a viewall page
+ // - the colors.mustache files make 6
+ // - patternSubgroup1 and patternSubgroup2 make 8
+ // - the general view all page make 9
+ // while most of that heavy lifting occurs inside groupPatterns and not buildViewAllPages,
+ // it's important to ensure that this method does not get prematurely terminated
+ // we choose to do that by checking it's return number of patterns
+
+ const uniquePatterns = ui.uniqueAllPatterns(allPatterns, patternlab);
+
+ /**
+ * - view-patternGroup1-all
+ * -- viewall-patternGroup1-patternSubgroup1
+ * --- blue
+ * --- red
+ * --- yellow
+ * -- viewall-patternGroup1-patternSubgroup2
+ * --- black
+ * --- grey
+ * --- white
+ */
+ test.equal(uniquePatterns.length, 9, '3 viewall pages should be added');
+
+ test.end();
+ });
+ }
+);
+
+tap.test(
+ 'buildViewAllPages - adds viewall page for each type and subgroup FOR! flat patterns',
+ function (test) {
+ //arrange
+ const mainPageHeadHtml = '';
+ const patternlab = createFakePatternLab({
+ patterns: [],
+ patternGroups: {},
+ subgroupPatterns: {},
+ footer: {},
+ userFoot: {},
+ cacheBuster: 1234,
+ });
+
+ patternlab.config.renderFlatPatternsOnViewAllPages = true;
+
+ patternlab.patterns.push(
+ //this flat pattern is found and causes trouble for the rest of the crew
+ new Pattern('test/foo.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/blue.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/red.mustache'),
+ new Pattern('patternGroup1/patternSubgroup1/yellow.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/black.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/grey.mustache'),
+ new Pattern('patternGroup1/patternSubgroup2/white.mustache')
+ );
+ ui.resetUIBuilderState(patternlab);
+
+ const styleguidePatterns = ui.groupPatterns(patternlab, uikit);
+
+ //act
+ ui.buildViewAllPages(
+ mainPageHeadHtml,
+ patternlab,
+ styleguidePatterns,
+ uikit
+ ).then((allPatterns) => {
+ // assert
+ // this was a nuanced one. buildViewAllPages() had return false; statements
+ // within _.forOwn(...) loops, causing premature termination of the entire loop
+ // when what was intended was a continue
+ // we expect 8 here because:
+ // - foo.mustache is flat and therefore does not have a viewall page
+ // - the colors.mustache files make 6
+ // - patternSubgroup1 and patternSubgroup2 make 8
+ // - the general view all page make 9
+ // - the view-all page of test and test-foo make 11
+ // while most of that heavy lifting occurs inside groupPatterns and not buildViewAllPages,
+ // it's important to ensure that this method does not get prematurely terminated
+ // we choose to do that by checking it's return number of patterns
+
+ const uniquePatterns = ui.uniqueAllPatterns(allPatterns, patternlab);
+
+ /**
+ * - viewall-test-all
+ * -- test-foo
+ * - view-patternGroup1-all
+ * -- viewall-patternGroup1-patternSubgroup1
+ * --- blue
+ * --- red
+ * --- yellow
+ * -- viewall-patternGroup1-patternSubgroup2
+ * --- black
+ * --- grey
+ * --- white
+ */
+ test.equal(uniquePatterns.length, 11, '4 viewall pages should be added');
+
+ test.end();
+ });
}
);
diff --git a/packages/core/test/uikitExcludePattern_tests.js b/packages/core/test/uikitExcludePattern_tests.js
index a31f4c3f3..f19301d12 100644
--- a/packages/core/test/uikitExcludePattern_tests.js
+++ b/packages/core/test/uikitExcludePattern_tests.js
@@ -6,7 +6,7 @@ const uikitExcludePattern = require('../src/lib/uikitExcludePattern');
tap.test(
'uikitExcludePattern - returns false when uikit has no excluded states',
- test => {
+ (test) => {
//arrange
const uikit = { excludedPatternStates: [] };
const pattern = { patternState: 'complete' };
@@ -22,7 +22,7 @@ tap.test(
tap.test(
'uikitExcludePattern - returns false pattern does not have same state as uikit exclusions',
- test => {
+ (test) => {
//arrange
const uikit = { excludedPatternStates: ['complete'] };
const pattern = { patternState: 'inprogress' };
@@ -38,7 +38,7 @@ tap.test(
tap.test(
'uikitExcludePattern - returns true when uikit has same state as pattern',
- test => {
+ (test) => {
//arrange
const uikit = { excludedPatternStates: ['inreview', 'complete'] };
const pattern = { patternState: 'complete' };
@@ -51,3 +51,51 @@ tap.test(
test.end();
}
);
+
+tap.test(
+ 'uikitExcludePattern - returns false when uikit has no excluded tags',
+ (test) => {
+ //arrange
+ const uikit = { excludedTags: [] };
+ const pattern = { tags: 'foo-tag' };
+
+ //act
+ const result = uikitExcludePattern(pattern, uikit);
+
+ //assert
+ test.false(result);
+ test.end();
+ }
+);
+
+tap.test(
+ 'uikitExcludePattern - returns false pattern does not have same tags as uikit exclusions',
+ (test) => {
+ //arrange
+ const uikit = { excludedTags: ['bat-tag'] };
+ const pattern = { tags: 'foo-tag' };
+
+ //act
+ const result = uikitExcludePattern(pattern, uikit);
+
+ //assert
+ test.false(result);
+ test.end();
+ }
+);
+
+tap.test(
+ 'uikitExcludePattern - returns true when uikit has same tags as pattern',
+ (test) => {
+ //arrange
+ const uikit = { excludedTags: ['bar-tag', 'foo-tag'] };
+ const pattern = { tags: 'foo-tag' };
+
+ //act
+ const result = uikitExcludePattern(pattern, uikit);
+
+ //assert
+ test.true(result);
+ test.end();
+ }
+);
diff --git a/packages/core/test/util/patternlab-config.json b/packages/core/test/util/patternlab-config.json
index c2edf9561..e101b2ad4 100644
--- a/packages/core/test/util/patternlab-config.json
+++ b/packages/core/test/util/patternlab-config.json
@@ -7,12 +7,12 @@
"meta": "./test/files/_meta/",
"styleguide": "./test/files/styleguide/",
"patternlabFiles": {
- "general-header": "./test/files/partials/general-header.mustache",
- "general-footer": "./test/files/partials/general-footer.mustache",
- "patternSection": "./test/files/partials/patternSection.mustache",
- "patternSectionSubtype":
- "./test/files/partials/patternSectionSubtype.mustache",
- "viewall": "./test/files/viewall.mustache"
+ "general-header": "views/partials/general-header.mustache",
+ "general-footer": "views/partials/general-footer.mustache",
+ "patternSection": "views/partials/patternSection.mustache",
+ "patternSectionSubgroup":
+ "views/partials/patternSectionSubgroup.mustache",
+ "viewall": "views/viewall.mustache"
},
"js": "./test/files/js",
"images": "./test/files/images",
@@ -57,6 +57,8 @@
"patternExportPatternPartials": [],
"patternExportDirectory": "./pattern_exports/",
"patternExtension": "mustache",
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
"cacheBust": true,
"outputFileSuffixes": {
"rendered": ".rendered",
@@ -71,11 +73,28 @@
"density": "compact",
"layout": "horizontal"
},
+ "engines": {
+ "handlebars": {
+ "package": "@pattern-lab/engine-handlebars",
+ "fileExtensions": [
+ "handlebars",
+ "hbs"
+ ],
+ "extend": "helpers/*.js"
+ }
+ },
"uikits": [
{
"name": "uikit-workshop",
- "outputDir": "packages/core/test/",
+ "outputDir": "test/",
"enabled": true,
+ "excludedPatternStates": ["legacy"],
+ "excludedTags": ["baz"]
+ },
+ {
+ "name": "uikit-polyfills",
+ "outputDir": "test/",
+ "enabled": false,
"excludedPatternStates": [],
"excludedTags": []
}
diff --git a/packages/core/test/util/test_utils.js b/packages/core/test/util/test_utils.js
index 36d3f6e1d..0558f500a 100644
--- a/packages/core/test/util/test_utils.js
+++ b/packages/core/test/util/test_utils.js
@@ -11,7 +11,7 @@ module.exports = {
graph: PatternGraph.empty(),
partials: {},
patterns: [],
- subtypePatterns: {},
+ subgroupPatterns: {},
footer: '',
header: '',
listitems: {},
@@ -33,7 +33,7 @@ module.exports = {
* Strip out control characters from output if needed so make comparisons easier
* @param output - the template to strip
*/
- sanitized: outputTemplate => {
+ sanitized: (outputTemplate) => {
return outputTemplate
.replace(/\n/g, ' ')
.replace(/\r/g, ' ')
@@ -45,7 +45,7 @@ module.exports = {
* normalize a string (probably a path) to posix - style
* @param s - the string or array of strings to normalize path separators to posix - style
*/
- posixPath: s => {
+ posixPath: (s) => {
if (Array.isArray(s)) {
var paths = [];
for (let i = 0; i < s.length; i++) {
diff --git a/packages/core/test/watchAssets_tests.js b/packages/core/test/watchAssets_tests.js
index d72cd0715..ab96f3b0b 100644
--- a/packages/core/test/watchAssets_tests.js
+++ b/packages/core/test/watchAssets_tests.js
@@ -12,7 +12,7 @@ const patterns_dir = './test/files/_patterns';
tap.test(
'watchAssets - adds assetWatcher to patternlab.watchers for given key ',
- test => {
+ (test) => {
const pl = util.fakePatternLab(patterns_dir, { watchers: [] });
const key = 'images';
@@ -25,15 +25,15 @@ tap.test(
true
);
- test.equals(_.keys(pl.watchers)[0], 'images');
+ test.equal(_.keys(pl.watchers)[0], 'images');
test.end();
}
);
-tap.test('watchAssets - complete path copied', test => {
- const copyFileMock = function(p, des) {
- test.equals(des, path.resolve('/proj/public/images/sample/waterfall.jpg'));
+tap.test('watchAssets - complete path copied', (test) => {
+ const copyFileMock = function (p, des) {
+ test.equal(des, path.resolve('/proj/public/images/sample/waterfall.jpg'));
};
//set our mocks in place of usual require()
diff --git a/packages/core/test/watchPatternLabFiles_tests.js b/packages/core/test/watchPatternLabFiles_tests.js
index f61b873e6..0dcc7fbc1 100644
--- a/packages/core/test/watchPatternLabFiles_tests.js
+++ b/packages/core/test/watchPatternLabFiles_tests.js
@@ -12,7 +12,7 @@ const patterns_dir = './test/files/_patterns';
tap.test(
'watchPatternLabFiles - adds watcher to patternlab.watchers for given patternWatchPath',
- test => {
+ (test) => {
const pl = util.fakePatternLab(patterns_dir, {
watchers: [],
engines: {},
@@ -37,7 +37,7 @@ tap.test(
// should have two for _data and _meta
// should have five for '.json', '.yml', '.yaml', '.md' and '.mustache'
- test.equals(Object.keys(pl.watchers).length, 7);
+ test.equal(Object.keys(pl.watchers).length, 7);
test.end();
}
diff --git a/packages/create/CHANGELOG.md b/packages/create/CHANGELOG.md
new file mode 100644
index 000000000..edc41d235
--- /dev/null
+++ b/packages/create/CHANGELOG.md
@@ -0,0 +1,308 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+
+## [1.0.11](https://github.com/pattern-lab/patternlab-node/compare/create-pattern-lab@1.0.10...create-pattern-lab@1.0.11) (2019-10-14)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+
+## [1.0.8](https://github.com/pattern-lab/patternlab-node/compare/create-pattern-lab@1.0.7...create-pattern-lab@1.0.8) (2019-08-23)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+## [1.0.7](https://github.com/pattern-lab/patternlab-node/compare/create-pattern-lab@1.0.6...create-pattern-lab@1.0.7) (2019-08-23)
+
+**Note:** Version bump only for package create-pattern-lab
+
+
+
+
+
+
+## [1.0.6](https://github.com/sghoweri/patternlab-node/compare/create-pattern-lab@1.0.5...create-pattern-lab@1.0.6) (2019-05-16)
+
+**Note:** Version bump only for package create-pattern-lab
diff --git a/packages/create/README.md b/packages/create/README.md
index 53e6f5770..28d56e5da 100644
--- a/packages/create/README.md
+++ b/packages/create/README.md
@@ -12,5 +12,5 @@ This is the same as using the main Pattern Lab CLI's `init` command:
```bash
npm i -g @pattern-lab/cli
-pattern-lab init
+patternlab init
```
diff --git a/packages/create/package.json b/packages/create/package.json
index 1444122a0..2785e53c6 100644
--- a/packages/create/package.json
+++ b/packages/create/package.json
@@ -1,16 +1,20 @@
{
"name": "create-pattern-lab",
- "version": "1.0.5",
+ "version": "6.1.0",
"description": "",
"bin": "index.js",
"main": "index.js",
"scripts": {},
"dependencies": {
- "@pattern-lab/cli": "^0.0.3-alpha.0"
+ "@pattern-lab/cli": "^6.1.0"
},
"author": "",
"license": "MIT",
"publishConfig": {
"access": "public"
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac",
+ "engines": {
+ "node": ">=16.20.0"
}
}
diff --git a/packages/development-edition-engine-handlebars/.gitignore b/packages/development-edition-engine-handlebars/.gitignore
index 0679bd2b5..534543a52 100644
--- a/packages/development-edition-engine-handlebars/.gitignore
+++ b/packages/development-edition-engine-handlebars/.gitignore
@@ -7,3 +7,4 @@ Thumbs.db
.idea/
public
dependencyGraph.json
+source/*
diff --git a/packages/development-edition-engine-handlebars/.nvmrc b/packages/development-edition-engine-handlebars/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/development-edition-engine-handlebars/.nvmrc
+++ b/packages/development-edition-engine-handlebars/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/development-edition-engine-handlebars/CHANGELOG.md b/packages/development-edition-engine-handlebars/CHANGELOG.md
index e39939cb7..635e4b857 100644
--- a/packages/development-edition-engine-handlebars/CHANGELOG.md
+++ b/packages/development-edition-engine-handlebars/CHANGELOG.md
@@ -3,6 +3,500 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [6.0.3](https://github.com/pattern-lab/patternlab-node/compare/v6.0.2...v6.0.3) (2023-03-12)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+
+### Bug Fixes
+
+* **annotations:** displaying annotation tooltips correctly ([#1406](https://github.com/pattern-lab/patternlab-node/issues/1406)) ([3f33ce5](https://github.com/pattern-lab/patternlab-node/commit/3f33ce5c51f2f7a6afd86d3500b7659afd0198e6)), closes [#2](https://github.com/pattern-lab/patternlab-node/issues/2) [#1](https://github.com/pattern-lab/patternlab-node/issues/1)
+
+
+
+
+
+## [5.15.7](https://github.com/pattern-lab/patternlab-node/compare/v5.15.6...v5.15.7) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.15.6](https://github.com/pattern-lab/patternlab-node/compare/v5.15.5...v5.15.6) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/patternlab-node/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/patternlab-node/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.9.2](https://github.com/pattern-lab/patternlab-node/compare/v5.9.1...v5.9.2) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.7.2](https://github.com/pattern-lab/patternlab-node/compare/v5.7.1...v5.7.2) (2020-03-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.7.1](https://github.com/pattern-lab/patternlab-node/compare/v5.7.0...v5.7.1) (2020-02-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.6.0](https://github.com/pattern-lab/patternlab-node/compare/v5.5.0...v5.6.0) (2020-01-18)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/patternlab-node/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.4.2](https://github.com/pattern-lab/patternlab-node/compare/v5.4.1...v5.4.2) (2019-11-27)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.4.1](https://github.com/pattern-lab/patternlab-node/compare/v5.4.0...v5.4.1) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+
+### Features
+
+* major improvements to local UIKit workflow ([4dc9173](https://github.com/pattern-lab/patternlab-node/commit/4dc9173a5a44b422e9677824de3728048b7c4f05))
+
+
+
+
+
+## [5.3.3](https://github.com/pattern-lab/patternlab-node/compare/v5.3.2...v5.3.3) (2019-11-22)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+
+## [5.3.2](https://github.com/pattern-lab/patternlab-node/compare/v5.3.1...v5.3.2) (2019-11-14)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.3.1](https://github.com/pattern-lab/patternlab-node/compare/v5.3.0...v5.3.1) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.2.0](https://github.com/pattern-lab/patternlab-node/compare/v5.1.0...v5.2.0) (2019-11-12)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+
+### Features
+
+* **config:** add new default pattern export options ([a7487a0](https://github.com/pattern-lab/patternlab-node/commit/a7487a0681cb11e6f3c5c8eaefd62e5648ad5ea3))
+
+
+
+
+
+## [5.0.2](https://github.com/pattern-lab/patternlab-node/compare/v5.0.1...v5.0.2) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+## [5.0.1](https://github.com/pattern-lab/patternlab-node/compare/v5.0.0...v5.0.1) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* Rename Handlebars and Nunjucks extension setting to "extend" ([74e5af2](https://github.com/pattern-lab/patternlab-node/commit/74e5af28c4e714fdfc1db535b94c52f3dc14a3a4))
+* update the default pattern that displays in the Handlebars demo ([ff1d85f](https://github.com/pattern-lab/patternlab-node/commit/ff1d85f2852fc4f210841e8e0aaf14b55165ce58))
+
+
+### Features
+
+* **engine-handlebars:** Demonstration of custom Handlebars helper ([f330b5b](https://github.com/pattern-lab/patternlab-node/commit/f330b5bca72f2f34bfafe5c2c64e6b0b8823eb1c))
+* **plugin-tab, core:** initial plugin hook exploration ([2f3d39a](https://github.com/pattern-lab/patternlab-node/commit/2f3d39ac6b125ad4c6b872e27ee224ce2ea33a12))
+* introduce netlify preview ([6c5d332](https://github.com/pattern-lab/patternlab-node/commit/6c5d332479fb6836bd8bd5530a074d13440f8ae4))
+
+
+
+
+
+
+## [0.1.6](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/development-edition-engine-handlebars@0.1.5...@pattern-lab/development-edition-engine-handlebars@0.1.6) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+
+## [0.1.5](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/development-edition-engine-handlebars@0.1.4...@pattern-lab/development-edition-engine-handlebars@0.1.5) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+
+## [0.1.1](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/development-edition-engine-handlebars@0.1.0...@pattern-lab/development-edition-engine-handlebars@0.1.1) (2019-08-23)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
+# [0.1.0](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/development-edition-engine-handlebars@0.0.3...@pattern-lab/development-edition-engine-handlebars@0.1.0) (2019-08-23)
+
+
+### Bug Fixes
+
+* Rename Handlebars and Nunjucks extension setting to "extend" ([74e5af2](https://github.com/pattern-lab/patternlab-node/commit/74e5af2))
+
+
+### Features
+
+* **engine-handlebars:** Demonstration of custom Handlebars helper ([f330b5b](https://github.com/pattern-lab/patternlab-node/commit/f330b5b))
+
+
+
+
+
+
+## [0.0.3](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/development-edition-engine-handlebars@0.0.3-alpha.0...@pattern-lab/development-edition-engine-handlebars@0.0.3) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-handlebars
+
+
+
+
+
## 0.0.1-beta.0 (2019-02-09)
diff --git a/packages/development-edition-engine-handlebars/README.md b/packages/development-edition-engine-handlebars/README.md
index 722416c2a..27766e215 100644
--- a/packages/development-edition-engine-handlebars/README.md
+++ b/packages/development-edition-engine-handlebars/README.md
@@ -9,4 +9,20 @@ This Development Edition is a variant of [Edition Node](https://github.com/patte
* Develop the [Handlebars Engine](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars)
* Build and test against Handlebars pattern tree
-> Development Editions of Pattern Lab provide the ability to work on and commit changes to select packages within the overall Pattern Lab [ecosystem](http://patternlab.io/docs/advanced-ecosystem-overview.html). This Edition is NOT stable.
+> Development Editions of Pattern Lab provide the ability to work on and commit changes to select packages within the overall Pattern Lab [ecosystem](https://patternlab.io/docs/overview-of-pattern-lab's-ecosystem/). This Edition is NOT stable.
+
+
+## Working on Pattern Lab's UI Locally
+
+### Step 1: Install Dependencies
+Run the following in the root of the Pattern Lab repo:
+
+```
+yarn run setup
+```
+
+### Step 2 (Optional)
+If you want to build using a fuller set of examples than what comes with this default Handlebars demo, run `yarn run preview:hbs`. Otherwise skip to step 3.
+
+### Step 3
+Finally, go back into this folder, `cd packages/development-edition-engine-handlebars`, and start up the local dev server which watches UIKit and the local Pattern Lab instance for changes, live reloads, etc by running `yarn dev`
diff --git a/packages/development-edition-engine-handlebars/helpers/test.js b/packages/development-edition-engine-handlebars/helpers/test.js
new file mode 100644
index 000000000..6ddbc2bba
--- /dev/null
+++ b/packages/development-edition-engine-handlebars/helpers/test.js
@@ -0,0 +1,5 @@
+module.exports = function (Handlebars) {
+ Handlebars.registerHelper('test', function () {
+ return 'This is a test helper';
+ });
+};
diff --git a/packages/development-edition-engine-handlebars/package.json b/packages/development-edition-engine-handlebars/package.json
index 1869d4dd5..52c59b7d6 100644
--- a/packages/development-edition-engine-handlebars/package.json
+++ b/packages/development-edition-engine-handlebars/package.json
@@ -1,14 +1,16 @@
{
"name": "@pattern-lab/development-edition-engine-handlebars",
"private": true,
- "version": "0.0.3-alpha.0",
+ "version": "6.1.0",
"description": "The tree of components we use to test, develop and validate the Handlebars engine",
"scripts": {
"pl:build": "patternlab build --config ./patternlab-config.json",
"pl:help": "patternlab --help",
"pl:install": "patternlab install --config ./patternlab-config.json",
"pl:serve": "patternlab serve --config ./patternlab-config.json",
- "pl:version": "patternlab --version"
+ "pl:starterkit": "patternlab add --starterkits @pattern-lab/starterkit-handlebars-demo",
+ "pl:version": "patternlab --version",
+ "dev": "node ./node_modules/@pattern-lab/uikit-workshop/build-tools.js"
},
"keywords": [
"Pattern Lab",
@@ -24,14 +26,15 @@
"url": "git://github.com/pattern-lab/patternlab-node.git"
},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"dependencies": {
- "@pattern-lab/cli": "^0.0.3-alpha.0",
- "@pattern-lab/core": "^3.0.1-alpha.0",
- "@pattern-lab/engine-handlebars": "^2.0.0-beta.1",
- "@pattern-lab/engine-mustache": "^2.0.1-alpha.0",
- "@pattern-lab/starterkit-mustache-demo": "^5.0.0",
- "@pattern-lab/uikit-workshop": "^1.0.1-alpha.0"
+ "@pattern-lab/cli": "^6.1.0",
+ "@pattern-lab/core": "^6.1.0",
+ "@pattern-lab/engine-handlebars": "^6.1.0",
+ "@pattern-lab/engine-mustache": "^6.1.0",
+ "@pattern-lab/plugin-tab": "^6.1.0",
+ "@pattern-lab/starterkit-handlebars-demo": "^6.1.0",
+ "@pattern-lab/uikit-workshop": "^6.1.0"
}
}
diff --git a/packages/development-edition-engine-handlebars/patternlab-config.json b/packages/development-edition-engine-handlebars/patternlab-config.json
index dae655991..a8873d362 100644
--- a/packages/development-edition-engine-handlebars/patternlab-config.json
+++ b/packages/development-edition-engine-handlebars/patternlab-config.json
@@ -4,9 +4,9 @@
"defaultPattern": "all",
"defaultShowPatternInfo": false,
"ishControlsHide": {
- "s": true,
- "m": true,
- "l": true,
+ "s": false,
+ "m": false,
+ "l": false,
"full": false,
"random": true,
"disco": true,
@@ -21,9 +21,18 @@
"tools-docs": false
},
"ishViewportRange": {
- "s": [240, 500],
- "m": [500, 800],
- "l": [800, 2600]
+ "s": [
+ 240,
+ 500
+ ],
+ "m": [
+ 500,
+ 800
+ ],
+ "l": [
+ 800,
+ 2600
+ ]
},
"logLevel": "info",
"outputFileSuffixes": {
@@ -43,7 +52,7 @@
"general-header": "views/partials/general-header.mustache",
"general-footer": "views/partials/general-footer.mustache",
"patternSection": "views/partials/patternSection.mustache",
- "patternSectionSubtype": "views/partials/patternSectionSubtype.mustache",
+ "patternSectionSubgroup": "views/partials/patternSectionSubgroup.mustache",
"viewall": "views/viewall.mustache"
},
"js": "source/js",
@@ -64,9 +73,18 @@
}
},
"patternExtension": "hbs",
- "patternStateCascade": ["inprogress", "inreview", "complete"],
+ "patternStateCascade": [
+ "inprogress",
+ "inreview",
+ "complete"
+ ],
+ "patternExportAll": false,
"patternExportDirectory": "pattern_exports",
"patternExportPatternPartials": [],
+ "patternExportPreserveDirectoryStructure": true,
+ "patternExportRaw": false,
+ "patternMergeVariantArrays": false,
+ "renderFlatPatternsOnViewAllPages": false,
"serverOptions": {
"wait": 1000
},
@@ -75,15 +93,38 @@
"theme": {
"color": "dark",
"density": "compact",
- "layout": "horizontal"
+ "layout": "horizontal",
+ "noViewAll": false
},
"uikits": [
{
"name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
"outputDir": "",
"enabled": true,
"excludedPatternStates": [],
"excludedTags": []
}
- ]
+ ],
+ "engines": {
+ "handlebars": {
+ "package": "@pattern-lab/engine-handlebars",
+ "fileExtensions": [
+ "handlebars",
+ "hbs"
+ ],
+ "extend": "helpers/*.js"
+ }
+ },
+ "plugins": {
+ "@pattern-lab/plugin-tab": {
+ "enabled": true,
+ "initialized": false,
+ "options": {
+ "tabsToAdd": [
+ "scss"
+ ]
+ }
+ }
+ }
}
diff --git a/packages/development-edition-engine-handlebars/source/_data/data.json b/packages/development-edition-engine-handlebars/source/_data/data.json
index 250376db0..0967ef424 100644
--- a/packages/development-edition-engine-handlebars/source/_data/data.json
+++ b/packages/development-edition-engine-handlebars/source/_data/data.json
@@ -1,34 +1 @@
-{
- "version": "2",
- "swatches": [
- {
- "color": {
- "hex": "#031636",
- "cmyk": "94 59 0 79"
- },
- "label": "dark blue"
- },
- {
- "color": {
- "hex": "#0D80F0",
- "cmyk": "95 47 0 6"
- },
- "label": "light blue"
- },
- {
- "color": {
- "hex": "#4c4c4c",
- "cmyk": "0 0 0 70"
- },
- "label": "dark grey"
- },
- {
- "color": {
- "hex": "#b2b2b2",
- "cmyk": "0 0 0 30"
- },
- "label": "light grey",
- "inverted": true
- }
- ]
-}
+{}
diff --git a/packages/development-edition-engine-handlebars/source/_data/listitems.json b/packages/development-edition-engine-handlebars/source/_data/listitems.json
index c35d1076d..0967ef424 100644
--- a/packages/development-edition-engine-handlebars/source/_data/listitems.json
+++ b/packages/development-edition-engine-handlebars/source/_data/listitems.json
@@ -1,6 +1 @@
-{
- "1": {},
- "2": {},
- "3": {},
- "4": {}
-}
+{}
diff --git a/packages/development-edition-engine-handlebars/source/_meta/README.md b/packages/development-edition-engine-handlebars/source/_meta/README.md
index c6c8c3b8e..b5d2c4537 100644
--- a/packages/development-edition-engine-handlebars/source/_meta/README.md
+++ b/packages/development-edition-engine-handlebars/source/_meta/README.md
@@ -1,5 +1,5 @@
This is the default location to place meta files, otherwise known a pattern's header and footer.
-Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](http://patternlab.io/docs/pattern-header-footer.html).
+Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](https://patternlab.io/docs/modifying-the-pattern-header-and-footer/).
If you wish to rename this directory, make sure you update the `paths.source.meta` property within `patternlab-config.json`.
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_00-head.hbs b/packages/development-edition-engine-handlebars/source/_meta/_00-head.hbs
deleted file mode 100644
index 9058b6521..000000000
--- a/packages/development-edition-engine-handlebars/source/_meta/_00-head.hbs
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
- {{ title }}
-
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
-
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_foot.hbs b/packages/development-edition-engine-handlebars/source/_meta/_foot.hbs
new file mode 100644
index 000000000..2c8fd83b5
--- /dev/null
+++ b/packages/development-edition-engine-handlebars/source/_meta/_foot.hbs
@@ -0,0 +1,8 @@
+
+
+ {{{ patternLabFoot }}}
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_foot.mustache b/packages/development-edition-engine-handlebars/source/_meta/_foot.mustache
new file mode 100644
index 000000000..98d360860
--- /dev/null
+++ b/packages/development-edition-engine-handlebars/source/_meta/_foot.mustache
@@ -0,0 +1,9 @@
+
+
+
+
+ {{{ patternLabFoot }}}
+
+
+
+
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_head.hbs b/packages/development-edition-engine-handlebars/source/_meta/_head.hbs
new file mode 100644
index 000000000..76899a54a
--- /dev/null
+++ b/packages/development-edition-engine-handlebars/source/_meta/_head.hbs
@@ -0,0 +1,18 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
+
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_head.mustache b/packages/development-edition-engine-handlebars/source/_meta/_head.mustache
new file mode 100644
index 000000000..76899a54a
--- /dev/null
+++ b/packages/development-edition-engine-handlebars/source/_meta/_head.mustache
@@ -0,0 +1,18 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
+
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.hbs b/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.hbs
deleted file mode 100644
index 804dcbfe5..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.hbs
+++ /dev/null
@@ -1,5 +0,0 @@
-
- {{label}}
- hex: {{color.hex}}
- cmyk: {{color.cmyk}}
-
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.json b/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.json
deleted file mode 100644
index 15d3872ba..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "color": {
- "hex": "#031636",
- "cmyk": "94 59 0 79"
- },
- "label": "dark blue"
-}
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.md b/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.md
deleted file mode 100644
index 3f2d7ea0f..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/atoms/swatches/swatch.md
+++ /dev/null
@@ -1 +0,0 @@
-Pattern Lab Tip: Note the use of the [built-in handlebars helper, `if`](https://handlebarsjs.com/builtin_helpers.html) and the ability to address data using dot notation [paths](https://handlebarsjs.com/#paths).
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/atoms/type.md b/packages/development-edition-engine-handlebars/source/_patterns/atoms/type.md
deleted file mode 100644
index 245bc9dcd..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/atoms/type.md
+++ /dev/null
@@ -1 +0,0 @@
-Type
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/atoms/type/annotation.hbs b/packages/development-edition-engine-handlebars/source/_patterns/atoms/type/annotation.hbs
deleted file mode 100644
index 7d556dbab..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/atoms/type/annotation.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{#if annotation}}{{annotation}}{{else}}v{{version}}{{/if}}
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants.md b/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants.md
deleted file mode 100644
index 345e6aef7..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants.md
+++ /dev/null
@@ -1 +0,0 @@
-Test
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants/swatches.hbs b/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants/swatches.hbs
deleted file mode 100644
index 9cb654819..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants/swatches.hbs
+++ /dev/null
@@ -1,8 +0,0 @@
-
- hi12
- {{> atoms-annotation annotation="possible colors"}}
-
- {{#each swatches}}
- {{> atoms-swatch }}
- {{/each}}
-
diff --git a/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants/swatches.md b/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants/swatches.md
deleted file mode 100644
index 131286757..000000000
--- a/packages/development-edition-engine-handlebars/source/_patterns/molecules/variants/swatches.md
+++ /dev/null
@@ -1 +0,0 @@
-Pattern Lab Tip: Note the use of the [built-in handlebars helper, `each`](https://handlebarsjs.com/builtin_helpers.html).
diff --git a/packages/development-edition-engine-handlebars/source/css/style.css b/packages/development-edition-engine-handlebars/source/css/style.css
index 7f25a7fe6..e69de29bb 100644
--- a/packages/development-edition-engine-handlebars/source/css/style.css
+++ b/packages/development-edition-engine-handlebars/source/css/style.css
@@ -1,3 +0,0 @@
-.annotation {
- color: #b2b2b2;
-}
diff --git a/packages/development-edition-engine-handlebars/source/fonts/.gitkeep b/packages/development-edition-engine-handlebars/source/fonts/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/development-edition-engine-react/.nvmrc b/packages/development-edition-engine-react/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/development-edition-engine-react/.nvmrc
+++ b/packages/development-edition-engine-react/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/development-edition-engine-react/CHANGELOG.md b/packages/development-edition-engine-react/CHANGELOG.md
index 7d2ddb035..6924275e4 100644
--- a/packages/development-edition-engine-react/CHANGELOG.md
+++ b/packages/development-edition-engine-react/CHANGELOG.md
@@ -3,6 +3,460 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/edition-node-gulp/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [6.0.3](https://github.com/pattern-lab/edition-node-gulp/compare/v6.0.2...v6.0.3) (2023-03-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/edition-node-gulp/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/edition-node-gulp/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.15.7](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.6...v5.15.7) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.15.6](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.5...v5.15.6) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/edition-node-gulp/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/edition-node-gulp/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/edition-node-gulp/issues/1192) ([420e829](https://github.com/pattern-lab/edition-node-gulp/commit/420e8293c033557ede073bc13e68955a450a3c8e))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/edition-node-gulp/issues/1192) ([b4eb12e](https://github.com/pattern-lab/edition-node-gulp/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/edition-node-gulp/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.9.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.9.1...v5.9.2) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.7.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.7.1...v5.7.2) (2020-03-24)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.7.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.7.0...v5.7.1) (2020-02-24)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.6.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.5.0...v5.6.0) (2020-01-18)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.4.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.4.1...v5.4.2) (2019-11-27)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.4.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.4.0...v5.4.1) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.3.3](https://github.com/pattern-lab/edition-node-gulp/compare/v5.3.2...v5.3.3) (2019-11-22)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+
+## [5.3.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.3.1...v5.3.2) (2019-11-14)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.3.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.3.0...v5.3.1) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.2.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.1.0...v5.2.0) (2019-11-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/edition-node-gulp/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+
+### Features
+
+* **core:** fix pattern export all conflicts ([b210d82](https://github.com/pattern-lab/edition-node-gulp/commit/b210d820ba8ac0b64c82c7ff0f18c9f8a900fce2))
+
+
+
+
+
+## [5.0.2](https://github.com/pattern-lab/edition-node-gulp/compare/v5.0.1...v5.0.2) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+## [5.0.1](https://github.com/pattern-lab/edition-node-gulp/compare/v5.0.0...v5.0.1) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/edition-node-gulp/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+
+## [0.1.8](https://github.com/pattern-lab/edition-node-gulp/compare/@pattern-lab/engine-react-testing-tree@0.1.7...@pattern-lab/engine-react-testing-tree@0.1.8) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+
+## [0.1.7](https://github.com/pattern-lab/edition-node-gulp/compare/@pattern-lab/engine-react-testing-tree@0.1.6...@pattern-lab/engine-react-testing-tree@0.1.7) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+
+## [0.1.3](https://github.com/pattern-lab/edition-node-gulp/compare/@pattern-lab/engine-react-testing-tree@0.1.2...@pattern-lab/engine-react-testing-tree@0.1.3) (2019-08-23)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
+
+## [0.1.2](https://github.com/pattern-lab/edition-node-gulp/compare/@pattern-lab/engine-react-testing-tree@0.1.2-alpha.0...@pattern-lab/engine-react-testing-tree@0.1.2) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-react-testing-tree
+
+
+
+
+
## [0.1.1-beta.1](https://github.com/pattern-lab/edition-node-gulp/compare/@pattern-lab/engine-react-testing-tree@0.1.1-alpha.4...@pattern-lab/engine-react-testing-tree@0.1.1-beta.1) (2019-02-09)
diff --git a/packages/development-edition-engine-react/README.md b/packages/development-edition-engine-react/README.md
index bdb531d95..2c21a20f4 100644
--- a/packages/development-edition-engine-react/README.md
+++ b/packages/development-edition-engine-react/README.md
@@ -11,4 +11,4 @@ This Development Edition is a variant of [Edition Node Gulp](https://github.com/
If you'd like to help with the React Engine, please reference the [contribution guidelines](https://github.com/pattern-lab/patternlab-node/blob/master/.github/CONTRIBUTING.md).
-> Development Editions of Pattern Lab provide the ability to work on and commit changes to select packages within the overall Pattern Lab [ecosystem](http://patternlab.io/docs/advanced-ecosystem-overview.html). This Edition is NOT stable.
+> Development Editions of Pattern Lab provide the ability to work on and commit changes to select packages within the overall Pattern Lab [ecosystem](https://patternlab.io/docs/overview-of-pattern-lab's-ecosystem/). This Edition is NOT stable.
diff --git a/packages/development-edition-engine-react/gulpfile.js b/packages/development-edition-engine-react/gulpfile.js
index 8d8653659..3f3658f89 100644
--- a/packages/development-edition-engine-react/gulpfile.js
+++ b/packages/development-edition-engine-react/gulpfile.js
@@ -33,40 +33,36 @@ function serve() {
});
}
-gulp.task('patternlab:version', function() {
+gulp.task('patternlab:version', function () {
patternlab.version();
});
-gulp.task('patternlab:help', function() {
+gulp.task('patternlab:help', function () {
patternlab.help();
});
-gulp.task('patternlab:patternsonly', function() {
+gulp.task('patternlab:patternsonly', function () {
patternlab.patternsonly(config.cleanPublic);
});
-gulp.task('patternlab:liststarterkits', function() {
+gulp.task('patternlab:liststarterkits', function () {
patternlab.liststarterkits();
});
-gulp.task('patternlab:loadstarterkit', function() {
+gulp.task('patternlab:loadstarterkit', function () {
patternlab.loadstarterkit(argv.kit, argv.clean);
});
-gulp.task('patternlab:build', function() {
+gulp.task('patternlab:build', function () {
build().then(() => {
// do something else when this promise resolves
});
});
-gulp.task('patternlab:serve', function() {
+gulp.task('patternlab:serve', function () {
serve().then(() => {
// do something else when this promise resolves
});
});
-gulp.task('patternlab:installplugin', function() {
- patternlab.installplugin(argv.plugin);
-});
-
gulp.task('default', ['patternlab:help']);
diff --git a/packages/development-edition-engine-react/package.json b/packages/development-edition-engine-react/package.json
index befc52d5e..ed5c6f21d 100644
--- a/packages/development-edition-engine-react/package.json
+++ b/packages/development-edition-engine-react/package.json
@@ -1,16 +1,16 @@
{
"name": "@pattern-lab/engine-react-testing-tree",
"description": "The tree of components we use to test, develop and validate the React engine",
- "version": "0.1.2-alpha.0",
+ "version": "6.1.0",
"private": true,
"main": "gulpfile.js",
"dependencies": {
- "@pattern-lab/core": "^3.0.1-alpha.0",
- "@pattern-lab/engine-mustache": "^2.0.1-alpha.0",
- "@pattern-lab/engine-react": "^0.2.1-beta.1",
- "@pattern-lab/uikit-workshop": "^1.0.1-alpha.0",
- "gulp": "3.9.1",
- "minimist": "^1.2.0",
+ "@pattern-lab/core": "^6.1.0",
+ "@pattern-lab/engine-mustache": "^6.1.0",
+ "@pattern-lab/engine-react": "^6.1.0",
+ "@pattern-lab/uikit-workshop": "^6.1.0",
+ "gulp": "4.0.2",
+ "minimist": "^1.2.5",
"react": "16.2.0"
},
"keywords": [
@@ -31,6 +31,6 @@
},
"license": "MIT",
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
}
}
diff --git a/packages/development-edition-engine-react/patternlab-config.json b/packages/development-edition-engine-react/patternlab-config.json
index a50a29b60..23f8673e8 100644
--- a/packages/development-edition-engine-react/patternlab-config.json
+++ b/packages/development-edition-engine-react/patternlab-config.json
@@ -46,8 +46,8 @@
"./node_modules/@pattern-lab/uikit-workshop/views/partials/general-footer.mustache",
"patternSection":
"./node_modules/@pattern-lab/uikit-workshop/views/partials/patternSection.mustache",
- "patternSectionSubtype":
- "./node_modules/@pattern-lab/uikit-workshop/views/partials/patternSectionSubtype.mustache",
+ "patternSectionSubgroup":
+ "./node_modules/@pattern-lab/uikit-workshop/views/partials/patternSectionSubgroup.mustache",
"viewall":
"./node_modules/@pattern-lab/uikit-workshop/views/viewall.mustache"
},
@@ -70,8 +70,13 @@
},
"patternExtension": "mustache",
"patternStateCascade": ["inprogress", "inreview", "complete"],
+ "patternExportAll": false,
+ "patternExportPreserveDirectoryStructure": false,
+ "patternExportRaw": false,
"patternExportDirectory": "./pattern_exports/",
"patternExportPatternPartials": [],
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
"serverOptions": {
"wait": 1000
},
@@ -82,5 +87,13 @@
"color": "dark",
"density": "compact",
"layout": "horizontal"
+ },
+ "engines": {
+ "react": {
+ "package": "@pattern-lab/engine-react",
+ "fileExtensions": [
+ "jsx"
+ ]
+ }
}
}
diff --git a/packages/development-edition-engine-react/source/_annotations/README.md b/packages/development-edition-engine-react/source/_annotations/README.md
index 42592a09b..b67b5511f 100644
--- a/packages/development-edition-engine-react/source/_annotations/README.md
+++ b/packages/development-edition-engine-react/source/_annotations/README.md
@@ -1,5 +1,5 @@
This is the default location to place annotations.
-Pattern Lab uses annotations defined here to markup the UI. Read more about [annotations](http://patternlab.io/docs/pattern-adding-annotations.html).
+Pattern Lab uses annotations defined here to markup the UI. Read more about [annotations](https://patternlab.io/docs/adding-annotations/).
If you wish to rename this directory, make sure you update the `paths.source.annotations` property within `patternlab-config.json`.
diff --git a/packages/development-edition-engine-react/source/_data/README.md b/packages/development-edition-engine-react/source/_data/README.md
index 3b9ea1ea4..50589abc7 100644
--- a/packages/development-edition-engine-react/source/_data/README.md
+++ b/packages/development-edition-engine-react/source/_data/README.md
@@ -1,5 +1,5 @@
This is the default location to place global data files.
-Pattern Lab uses data defined here as the global fallback if a template does not provide its own data. Read more about [data](http://patternlab.io/docs/data-overview.html).
+Pattern Lab uses data defined here as the global fallback if a template does not provide its own data. Read more about [data](https://patternlab.io/docs/overview-of-data/).
If you wish to rename this directory, make sure you update the `paths.source.data` property within `patternlab-config.json`.
diff --git a/packages/development-edition-engine-react/source/_meta/README.md b/packages/development-edition-engine-react/source/_meta/README.md
index c6c8c3b8e..b5d2c4537 100644
--- a/packages/development-edition-engine-react/source/_meta/README.md
+++ b/packages/development-edition-engine-react/source/_meta/README.md
@@ -1,5 +1,5 @@
This is the default location to place meta files, otherwise known a pattern's header and footer.
-Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](http://patternlab.io/docs/pattern-header-footer.html).
+Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](https://patternlab.io/docs/modifying-the-pattern-header-and-footer/).
If you wish to rename this directory, make sure you update the `paths.source.meta` property within `patternlab-config.json`.
diff --git a/packages/development-edition-engine-react/source/_meta/_00-head.html b/packages/development-edition-engine-react/source/_meta/_00-head.html
deleted file mode 100644
index cf826617a..000000000
--- a/packages/development-edition-engine-react/source/_meta/_00-head.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
diff --git a/packages/development-edition-engine-react/source/_meta/_00-head.mustache b/packages/development-edition-engine-react/source/_meta/_00-head.mustache
deleted file mode 100644
index 069727248..000000000
--- a/packages/development-edition-engine-react/source/_meta/_00-head.mustache
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
-
diff --git a/packages/development-edition-engine-react/source/_meta/_01-foot.html b/packages/development-edition-engine-react/source/_meta/_01-foot.html
deleted file mode 100644
index 2feb91336..000000000
--- a/packages/development-edition-engine-react/source/_meta/_01-foot.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-{{{ patternLabFoot }}}
-
-
-
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_01-foot.mustache b/packages/development-edition-engine-react/source/_meta/_foot.hbs
similarity index 100%
rename from packages/development-edition-engine-handlebars/source/_meta/_01-foot.mustache
rename to packages/development-edition-engine-react/source/_meta/_foot.hbs
diff --git a/packages/edition-node/source/_meta/_01-foot.mustache b/packages/development-edition-engine-react/source/_meta/_foot.html
similarity index 100%
rename from packages/edition-node/source/_meta/_01-foot.mustache
rename to packages/development-edition-engine-react/source/_meta/_foot.html
diff --git a/packages/development-edition-engine-react/source/_meta/_01-foot.mustache b/packages/development-edition-engine-react/source/_meta/_foot.mustache
similarity index 100%
rename from packages/development-edition-engine-react/source/_meta/_01-foot.mustache
rename to packages/development-edition-engine-react/source/_meta/_foot.mustache
diff --git a/packages/development-edition-engine-handlebars/source/_meta/_00-head.mustache b/packages/development-edition-engine-react/source/_meta/_head.hbs
similarity index 87%
rename from packages/development-edition-engine-handlebars/source/_meta/_00-head.mustache
rename to packages/development-edition-engine-react/source/_meta/_head.hbs
index 45ce3bb7d..893481ae5 100644
--- a/packages/development-edition-engine-handlebars/source/_meta/_00-head.mustache
+++ b/packages/development-edition-engine-react/source/_meta/_head.hbs
@@ -1,8 +1,8 @@
-
+
{{ title }}
-
+
@@ -14,4 +14,3 @@
-
diff --git a/packages/development-edition-engine-react/source/_meta/_head.html b/packages/development-edition-engine-react/source/_meta/_head.html
new file mode 100644
index 000000000..9e3094352
--- /dev/null
+++ b/packages/development-edition-engine-react/source/_meta/_head.html
@@ -0,0 +1,23 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
diff --git a/packages/development-edition-engine-react/source/_meta/_head.mustache b/packages/development-edition-engine-react/source/_meta/_head.mustache
new file mode 100644
index 000000000..5921e94cf
--- /dev/null
+++ b/packages/development-edition-engine-react/source/_meta/_head.mustache
@@ -0,0 +1,17 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
+
diff --git a/packages/development-edition-engine-react/source/_patterns/README.md b/packages/development-edition-engine-react/source/_patterns/README.md
index 2f89266bf..8751c8669 100644
--- a/packages/development-edition-engine-react/source/_patterns/README.md
+++ b/packages/development-edition-engine-react/source/_patterns/README.md
@@ -1,5 +1,5 @@
This is the default location to place pattern files.
-Pattern Lab builds patterns and the ui from the structure defined within. Read more about [pattern organization](http://patternlab.io/docs/pattern-organization.html).
+Pattern Lab builds patterns and the ui from the structure defined within. Read more about [pattern organization](https://patternlab.io/docs/overview-of-patterns/).
If you wish to rename this directory, make sure you update the `paths.source.patterns` property within `patternlab-config.json`.
diff --git a/packages/development-edition-engine-react/source/_patterns/00-atoms/00-general/HelloWorld.jsx b/packages/development-edition-engine-react/source/_patterns/atoms/general/HelloWorld.jsx
similarity index 100%
rename from packages/development-edition-engine-react/source/_patterns/00-atoms/00-general/HelloWorld.jsx
rename to packages/development-edition-engine-react/source/_patterns/atoms/general/HelloWorld.jsx
diff --git a/packages/development-edition-engine-react/source/_patterns/01-molecules/00-general/HelloIncluder.jsx b/packages/development-edition-engine-react/source/_patterns/molecules/general/HelloIncluder.jsx
similarity index 89%
rename from packages/development-edition-engine-react/source/_patterns/01-molecules/00-general/HelloIncluder.jsx
rename to packages/development-edition-engine-react/source/_patterns/molecules/general/HelloIncluder.jsx
index 6b2f3c985..162681281 100644
--- a/packages/development-edition-engine-react/source/_patterns/01-molecules/00-general/HelloIncluder.jsx
+++ b/packages/development-edition-engine-react/source/_patterns/molecules/general/HelloIncluder.jsx
@@ -1,6 +1,6 @@
import React, { Component } from 'react';
-import HelloWorld from '../../00-atoms/00-general/HelloWorld';
+import HelloWorld from '../../atoms/general/HelloWorld';
// const HelloWorld = () => (
//
diff --git a/packages/development-edition-engine-twig/.gitignore b/packages/development-edition-engine-twig/.gitignore
new file mode 100644
index 000000000..0679bd2b5
--- /dev/null
+++ b/packages/development-edition-engine-twig/.gitignore
@@ -0,0 +1,9 @@
+node_modules/
+.DS_Store
+patternlab.json
+.sass-cache/*
+/sass-cache
+Thumbs.db
+.idea/
+public
+dependencyGraph.json
diff --git a/packages/development-edition-engine-twig/CHANGELOG.md b/packages/development-edition-engine-twig/CHANGELOG.md
new file mode 100644
index 000000000..86702f2f3
--- /dev/null
+++ b/packages/development-edition-engine-twig/CHANGELOG.md
@@ -0,0 +1,310 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [6.0.3](https://github.com/pattern-lab/patternlab-node/compare/v6.0.2...v6.0.3) (2023-03-12)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [6.0.2](https://github.com/pattern-lab/patternlab-node/compare/v6.0.1...v6.0.2) (2023-02-26)
+
+
+### Bug Fixes
+
+* **starterkit-twig-demo:** pages not rendering pattern-specific data from json ([#1490](https://github.com/pattern-lab/patternlab-node/issues/1490)) ([1c878df](https://github.com/pattern-lab/patternlab-node/commit/1c878dfa35d549f23e199b3e235ff79cb471ac86)), closes [#1486](https://github.com/pattern-lab/patternlab-node/issues/1486)
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.15.7](https://github.com/pattern-lab/patternlab-node/compare/v5.15.6...v5.15.7) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.15.6](https://github.com/pattern-lab/patternlab-node/compare/v5.15.5...v5.15.6) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/patternlab-node/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/patternlab-node/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.9.2](https://github.com/pattern-lab/patternlab-node/compare/v5.9.1...v5.9.2) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
+
+
+
+
+
+# [5.8.0](https://github.com/pattern-lab/patternlab-node/compare/v5.7.2...v5.8.0) (2020-04-03)
+
+**Note:** Version bump only for package @pattern-lab/development-edition-engine-twig
diff --git a/packages/development-edition-engine-twig/README.md b/packages/development-edition-engine-twig/README.md
new file mode 100644
index 000000000..b3ffdea7f
--- /dev/null
+++ b/packages/development-edition-engine-twig/README.md
@@ -0,0 +1,25 @@
+
+
+# Pattern Lab Node - Development Edition Engine Twig
+
+_here be dragons_
+
+This Development Edition is a variant of [Edition Node](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node) for convience purposes only, loaded with the Twig Engine. The goals of this Development Edition are two-fold:
+
+* Develop the [Twig Engine](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig)
+* Build and test against Twig pattern tree
+
+> Development Editions of Pattern Lab provide the ability to work on and commit changes to select packages within the overall Pattern Lab [ecosystem](https://patternlab.io/docs/overview-of-pattern-lab's-ecosystem/). This Edition is NOT stable.
+
+
+## Working on Pattern Lab's UI Locally
+
+### Step 1: Install Dependencies
+Run the following in the root of the Pattern Lab repo:
+
+```
+yarn run setup
+```
+
+### Step 2
+Finally, go back into this folder, `cd packages/development-edition-engine-twig`, and start up the local dev server which watches UIKit and the local Pattern Lab instance for changes, live reloads, etc by running `yarn dev`
diff --git a/packages/development-edition-engine-twig/package.json b/packages/development-edition-engine-twig/package.json
new file mode 100644
index 000000000..7b8010f68
--- /dev/null
+++ b/packages/development-edition-engine-twig/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "@pattern-lab/development-edition-engine-twig",
+ "private": true,
+ "version": "6.1.0",
+ "description": "The tree of components we use to test, develop and validate the twig engine (not engine-twig-php)",
+ "scripts": {
+ "postbootstrap": "patternlab install --starterkits @pattern-lab/starterkit-twig-demo",
+ "pl:build": "patternlab build --config ./patternlab-config.json",
+ "pl:debug": "node --inspect-brk=24984 node_modules/.bin/patternlab build --config ./patternlab-config.json",
+ "pl:help": "patternlab --help",
+ "pl:install": "patternlab install --config ./patternlab-config.json",
+ "pl:serve": "patternlab serve --config ./patternlab-config.json",
+ "pl:version": "patternlab --version",
+ "dev": "node ./node_modules/@pattern-lab/uikit-workshop/build-tools.js"
+ },
+ "keywords": [
+ "Pattern Lab",
+ "Atomic Web Design",
+ "Node",
+ "Twig",
+ "Edition"
+ ],
+ "author": "Ringo De Smet",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/pattern-lab/patternlab-node.git"
+ },
+ "engines": {
+ "node": ">=16.20.0"
+ },
+ "dependencies": {
+ "@pattern-lab/cli": "^6.1.0",
+ "@pattern-lab/core": "^6.1.0",
+ "@pattern-lab/engine-twig": "^6.1.0",
+ "@pattern-lab/starterkit-twig-demo": "^6.1.0",
+ "@pattern-lab/uikit-workshop": "^6.1.0"
+ },
+ "workspaces": {
+ "nohoist": [
+ "**/@pattern-lab/starterkit-twig-demo"
+ ]
+ }
+}
diff --git a/packages/development-edition-engine-twig/patternlab-config.json b/packages/development-edition-engine-twig/patternlab-config.json
new file mode 100644
index 000000000..c50ccbcda
--- /dev/null
+++ b/packages/development-edition-engine-twig/patternlab-config.json
@@ -0,0 +1,121 @@
+{
+ "cacheBust": true,
+ "cleanPublic": true,
+ "defaultPattern": "all",
+ "defaultShowPatternInfo": false,
+ "ishControlsHide": {
+ "s": false,
+ "m": false,
+ "l": false,
+ "full": false,
+ "random": false,
+ "disco": false,
+ "hay": true,
+ "mqs": false,
+ "find": false,
+ "views-all": false,
+ "views-annotations": false,
+ "views-code": false,
+ "views-new": false,
+ "tools-all": false,
+ "tools-docs": false
+ },
+ "ishViewportRange": {
+ "s": [
+ 240,
+ 500
+ ],
+ "m": [
+ 500,
+ 800
+ ],
+ "l": [
+ 800,
+ 2600
+ ]
+ },
+ "logLevel": "info",
+ "outputFileSuffixes": {
+ "rendered": ".rendered",
+ "rawTemplate": "",
+ "markupOnly": ".markup-only"
+ },
+ "paths": {
+ "source": {
+ "root": "source/",
+ "patterns": "source/_patterns/",
+ "data": "source/_data/",
+ "meta": "source/_meta/",
+ "annotations": "source/_annotations/",
+ "styleguide": "dist/",
+ "patternlabFiles": {
+ "general-header": "views/partials/general-header.mustache",
+ "general-footer": "views/partials/general-footer.mustache",
+ "patternSection": "views/partials/patternSection.mustache",
+ "patternSectionSubgroup": "views/partials/patternSectionSubgroup.mustache",
+ "viewall": "views/viewall.mustache"
+ },
+ "js": "source/js",
+ "images": "source/images",
+ "fonts": "source/fonts",
+ "css": "source/css"
+ },
+ "public": {
+ "root": "public/",
+ "patterns": "public/patterns/",
+ "data": "public/styleguide/data/",
+ "annotations": "public/annotations/",
+ "styleguide": "public/styleguide/",
+ "js": "public/js",
+ "images": "public/images",
+ "fonts": "public/fonts",
+ "css": "public/css"
+ }
+ },
+ "patternExtension": "twig",
+ "patternStateCascade": [
+ "inprogress",
+ "inreview",
+ "complete"
+ ],
+ "patternExportDirectory": "pattern_exports",
+ "patternExportPatternPartials": [],
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
+ "serverOptions": {
+ "wait": 1000
+ },
+ "starterkitSubDir": "dist",
+ "styleGuideExcludes": [],
+ "theme": {
+ "color": "dark",
+ "density": "compact",
+ "layout": "horizontal"
+ },
+ "uikits": [
+ {
+ "name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
+ "outputDir": "",
+ "enabled": true,
+ "excludedPatternStates": [],
+ "excludedTags": []
+ }
+ ],
+ "engines": {
+ "twig": {
+ "package": "@pattern-lab/engine-twig",
+ "fileExtensions": [
+ "twig"
+ ],
+ "namespaces": {
+ "atoms": "source/_patterns/atoms/",
+ "molecules": "source/_patterns/molecules/",
+ "organisms": "source/_patterns/organisms/",
+ "templates": "source/_patterns/templates/",
+ "pages": "source/_patterns/pages/",
+ "macros": "source/_patterns/macros/"
+ }
+ }
+ }
+}
diff --git a/packages/development-edition-engine-twig/source/.gitignore b/packages/development-edition-engine-twig/source/.gitignore
new file mode 100644
index 000000000..d6b7ef32c
--- /dev/null
+++ b/packages/development-edition-engine-twig/source/.gitignore
@@ -0,0 +1,2 @@
+*
+!.gitignore
diff --git a/packages/docs/.eleventy.js b/packages/docs/.eleventy.js
new file mode 100644
index 000000000..9e3b3a774
--- /dev/null
+++ b/packages/docs/.eleventy.js
@@ -0,0 +1,99 @@
+const rssPlugin = require('@11ty/eleventy-plugin-rss');
+const syntaxHighlight = require('@11ty/eleventy-plugin-syntaxhighlight');
+const eleventyNavigationPlugin = require('@11ty/eleventy-navigation');
+const fs = require('fs');
+
+// Import filters
+const dateFilter = require('./src/filters/date-filter.js');
+const markdownFilter = require('./src/filters/markdown-filter.js');
+const w3DateFilter = require('./src/filters/w3-date-filter.js');
+
+// Import transforms
+const htmlMinTransform = require('./src/transforms/html-min-transform.js');
+const parseTransform = require('./src/transforms/parse-transform.js');
+
+// Import data files
+const site = require('./src/_data/site.json');
+
+module.exports = function (config) {
+ // Filters
+ config.addFilter('dateFilter', dateFilter);
+ config.addFilter('markdownFilter', markdownFilter);
+ config.addFilter('w3DateFilter', w3DateFilter);
+
+ // Layout aliases
+ config.addLayoutAlias('home', 'layouts/home.njk');
+
+ // Transforms
+ config.addTransform('htmlmin', htmlMinTransform);
+ config.addTransform('parse', parseTransform);
+
+ // Passthrough copy
+ config.addPassthroughCopy('src/images');
+ config.addPassthroughCopy('src/js');
+ config.addPassthroughCopy('src/admin/config.yml');
+ config.addPassthroughCopy('src/admin/previews.js');
+ config.addPassthroughCopy({
+ '../../node_modules/nunjucks/browser/nunjucks-slim.js':
+ 'node_modules/nunjucks/browser/nunjucks-slim.js',
+ });
+
+ const now = new Date();
+
+ // Custom collections
+ const livePosts = (post) => post.date <= now && !post.data.draft;
+ config.addCollection('posts', (collection) => {
+ return [
+ ...collection.getFilteredByGlob('./src/posts/*.md').filter(livePosts),
+ ].reverse();
+ });
+
+ config.addCollection('demos', (collection) => {
+ return [...collection.getFilteredByGlob('./src/demos/*.md')].reverse();
+ });
+
+ config.addCollection('postFeed', (collection) => {
+ return [...collection.getFilteredByGlob('./src/posts/*.md').filter(livePosts)]
+ .reverse()
+ .slice(0, site.maxPostsPerPage);
+ });
+
+ config.addCollection('docs', (collection) => {
+ return [...collection.getFilteredByGlob('./src/docs/*.md')].reverse();
+ });
+
+ config.addCollection('docsOrdered', (collection) => {
+ const docs = collection.getFilteredByGlob('src/docs/*.md').sort((a, b) => {
+ return Number(a.data.order) - Number(b.data.order);
+ });
+ return docs;
+ });
+
+ // Plugins
+ config.addPlugin(rssPlugin);
+ config.addPlugin(syntaxHighlight);
+ config.addPlugin(eleventyNavigationPlugin);
+
+ // 404
+ config.setBrowserSyncConfig({
+ callbacks: {
+ ready: function (err, browserSync) {
+ const content_404 = fs.readFileSync('dist/404.html');
+
+ browserSync.addMiddleware('*', (req, res) => {
+ // Provides the 404 content without redirect.
+ res.write(content_404);
+ res.end();
+ });
+ },
+ },
+ });
+
+ return {
+ dir: {
+ input: 'src',
+ output: 'dist',
+ },
+ passthroughFileCopy: true,
+ };
+};
diff --git a/packages/docs/.gitignore b/packages/docs/.gitignore
new file mode 100644
index 000000000..a54bbf4b4
--- /dev/null
+++ b/packages/docs/.gitignore
@@ -0,0 +1,17 @@
+*.log
+npm-debug.*
+*.scssc
+*.log
+*.swp
+.DS_Store
+.sass-cache
+node_modules
+dist
+
+# Specifics
+
+# Hide design tokens
+src/scss/_tokens.scss
+
+# Hide compiled CSS
+src/_includes/assets/*
diff --git a/packages/docs/.prettierrc b/packages/docs/.prettierrc
new file mode 100644
index 000000000..fc46c20b4
--- /dev/null
+++ b/packages/docs/.prettierrc
@@ -0,0 +1,7 @@
+{
+ "printWidth": 90,
+ "useTabs": false,
+ "tabWidth": 3,
+ "singleQuote": true,
+ "bracketSpacing": false
+}
diff --git a/packages/docs/.vscode/launch.json b/packages/docs/.vscode/launch.json
new file mode 100644
index 000000000..2359da6e9
--- /dev/null
+++ b/packages/docs/.vscode/launch.json
@@ -0,0 +1,17 @@
+{
+ // Use IntelliSense to learn about possible attributes.
+ // Hover to view descriptions of existing attributes.
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "type": "node",
+ "request": "launch",
+ "name": "Launch Program",
+ "skipFiles": [
+ "
/**"
+ ],
+ "program": "${workspaceFolder}/index.js"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/docs/CHANGELOG.md b/packages/docs/CHANGELOG.md
new file mode 100644
index 000000000..97fdd21e5
--- /dev/null
+++ b/packages/docs/CHANGELOG.md
@@ -0,0 +1,182 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# [6.1.0](https://github.com/bradfrost/pl-website-eleventy/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/website
+
+
+
+
+
+# [6.0.0](https://github.com/bradfrost/pl-website-eleventy/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+
+### Features
+
+* activate prettier for scss ([#1468](https://github.com/bradfrost/pl-website-eleventy/issues/1468)) ([fac6ad4](https://github.com/bradfrost/pl-website-eleventy/commit/fac6ad4be48c95eccfe890a280cad441ee84f677))
+* **docs:** added plugin ([#1469](https://github.com/bradfrost/pl-website-eleventy/issues/1469)) ([535c5f0](https://github.com/bradfrost/pl-website-eleventy/commit/535c5f0805936a25eeddde0e360cb6000c000b1b))
+
+
+
+
+
+## [5.16.4](https://github.com/bradfrost/pl-website-eleventy/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+
+### Bug Fixes
+
+* code scanning alert ([#1442](https://github.com/bradfrost/pl-website-eleventy/issues/1442)) ([749a3e7](https://github.com/bradfrost/pl-website-eleventy/commit/749a3e722249846c522e3f7de6e73b5afa8531b1))
+
+
+
+
+
+## [5.16.1](https://github.com/bradfrost/pl-website-eleventy/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/website
+
+
+
+
+
+## [5.15.5](https://github.com/bradfrost/pl-website-eleventy/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+
+### Features
+
+* define initial viewport ([#1386](https://github.com/bradfrost/pl-website-eleventy/issues/1386)) ([6fa630e](https://github.com/bradfrost/pl-website-eleventy/commit/6fa630e2353ed68295550e59c31148269f3b7cd0))
+
+
+
+
+
+## [5.15.4](https://github.com/bradfrost/pl-website-eleventy/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+
+### Features
+
+* define initial viewport ([#1386](https://github.com/bradfrost/pl-website-eleventy/issues/1386)) ([6fa630e](https://github.com/bradfrost/pl-website-eleventy/commit/6fa630e2353ed68295550e59c31148269f3b7cd0))
+
+
+
+
+
+## [5.15.3](https://github.com/bradfrost/pl-website-eleventy/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+
+### Bug Fixes
+
+* **docs:** tiles z-index to not overlay the menu anymore ([#1370](https://github.com/bradfrost/pl-website-eleventy/issues/1370)) ([384dc89](https://github.com/bradfrost/pl-website-eleventy/commit/384dc8900ee5768f5a260fd00fe03d11ae047484))
+
+
+
+
+
+# [5.15.0](https://github.com/bradfrost/pl-website-eleventy/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+
+### Features
+
+* **docs:** adding a sitemap.xml ([#1329](https://github.com/bradfrost/pl-website-eleventy/issues/1329)) ([0a7fd95](https://github.com/bradfrost/pl-website-eleventy/commit/0a7fd95d5f1c3ce690bbe89cc30580ff58d1ab9c))
+* **documentation:** added (sub)groups documentation again [#1262](https://github.com/bradfrost/pl-website-eleventy/issues/1262) ([#1334](https://github.com/bradfrost/pl-website-eleventy/issues/1334)) ([9fac269](https://github.com/bradfrost/pl-website-eleventy/commit/9fac2699d2f6c64c4544e8e4d8e18c1a1ce7e49f))
+
+
+
+
+
+
+## [5.14.3](https://github.com/bradfrost/pl-website-eleventy/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/website
+
+
+
+
+
+
+## [5.14.2](https://github.com/bradfrost/pl-website-eleventy/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/website
+
+
+
+
+
+
+## [5.13.1](https://github.com/bradfrost/pl-website-eleventy/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/website
+
+
+
+
+
+
+## [5.11.1](https://github.com/bradfrost/pl-website-eleventy/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+
+### Bug Fixes
+
+* **docs:** fixed css code for custom patternstates color ([8995241](https://github.com/bradfrost/pl-website-eleventy/commit/89952416162c01d1e3e05221ce58a7755544131c)), closes [#1216](https://github.com/bradfrost/pl-website-eleventy/issues/1216)
+* **docs:** headlines styling breaks in edge cases [#1158](https://github.com/bradfrost/pl-website-eleventy/issues/1158) ([d8244a2](https://github.com/bradfrost/pl-website-eleventy/commit/d8244a2d307b0a81d0846491f8c5a12e0ae167a5))
+
+
+
+
+
+# [5.11.0](https://github.com/bradfrost/pl-website-eleventy/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+
+### Bug Fixes
+
+* **docs:** fixed css code for custom patternstates color ([8995241](https://github.com/bradfrost/pl-website-eleventy/commit/89952416162c01d1e3e05221ce58a7755544131c)), closes [#1216](https://github.com/bradfrost/pl-website-eleventy/issues/1216)
+* **docs:** headlines styling breaks in edge cases [#1158](https://github.com/bradfrost/pl-website-eleventy/issues/1158) ([d8244a2](https://github.com/bradfrost/pl-website-eleventy/commit/d8244a2d307b0a81d0846491f8c5a12e0ae167a5))
+
+
+
+
+
+## [5.10.1](https://github.com/bradfrost/pl-website-eleventy/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/website
+
+
+
+
+
+# [5.10.0](https://github.com/bradfrost/pl-website-eleventy/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** google lighthouse error - bg and text contrast ratio [#1197](https://github.com/bradfrost/pl-website-eleventy/issues/1197) ([f43978a](https://github.com/bradfrost/pl-website-eleventy/commit/f43978a3a121b661cfbf763ba72bcda2c36a5d3a))
+* **docs:** resolving broken link (new URL) in new docs site [#1192](https://github.com/bradfrost/pl-website-eleventy/issues/1192) ([8dc020a](https://github.com/bradfrost/pl-website-eleventy/commit/8dc020a217b51cfafdd62ceca95fc42811a6c285))
+* **docs:** resolving broken link (new URL) in new docs site [#1192](https://github.com/bradfrost/pl-website-eleventy/issues/1192) ([f557fdd](https://github.com/bradfrost/pl-website-eleventy/commit/f557fddeda640d88c7267d9d5fba8e8cc5e07929))
+* **docs:** resolving broken link (new URL) in new docs site [#1192](https://github.com/bradfrost/pl-website-eleventy/issues/1192) ([0023a91](https://github.com/bradfrost/pl-website-eleventy/commit/0023a910126a635006c1ad468a412af0e93338fb))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/bradfrost/pl-website-eleventy/issues/1192) ([c9635ec](https://github.com/bradfrost/pl-website-eleventy/commit/c9635ec2d9eb700b23188d5c72b83b3d16e6deda))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/bradfrost/pl-website-eleventy/issues/1192) ([f56ad39](https://github.com/bradfrost/pl-website-eleventy/commit/f56ad3951ea0319a43f0b1aeabba0d3ad96c5553))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/bradfrost/pl-website-eleventy/issues/1192) ([cae9420](https://github.com/bradfrost/pl-website-eleventy/commit/cae94208c52e4068430e048e729f4ff97847715a))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/bradfrost/pl-website-eleventy/issues/1192) ([84138c3](https://github.com/bradfrost/pl-website-eleventy/commit/84138c36cdfe5b9a38b34e32b177a0416b077716))
+* Contribution guidelines should refer to yarn ([c30cc81](https://github.com/bradfrost/pl-website-eleventy/commit/c30cc81a3e155072774438304b73d58b6635876d))
+
+
+
+
+
+## [5.9.3](https://github.com/bradfrost/pl-website-eleventy/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package patternlab-website
+
+
+
+
+
+# [5.9.0](https://github.com/bradfrost/pl-website-eleventy/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+
+### Features
+
+* **docs:** yarnify ([5a47dc7](https://github.com/bradfrost/pl-website-eleventy/commit/5a47dc7b90dc5c43c12a51143b41943dcbd8564c))
diff --git a/packages/docs/LICENSE.txt b/packages/docs/LICENSE.txt
new file mode 100644
index 000000000..312f7109c
--- /dev/null
+++ b/packages/docs/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 andy-bell.design and other contributors
+
+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.
diff --git a/packages/docs/README.md b/packages/docs/README.md
new file mode 100644
index 000000000..7b191158a
--- /dev/null
+++ b/packages/docs/README.md
@@ -0,0 +1,32 @@
+# Pattern Lab Website
+
+This is the website for patternlab.io. This site was build using the [Hylia starter kit](https://hylia.website/), which is a lightweight [Eleventy](https://11ty.io) starter kit.
+
+---
+
+## How to work with this project
+
+1. Clone this repository
+2. `cd` into the project directory and run `yarn`
+3. Once all the dependencies are installed run `yarn start`
+4. Open your browser at `http://localhost:8080`
+
+## Terminal commands
+
+### Serve the site locally
+
+```bash
+yarn start
+```
+
+### Build a production version of the site
+
+```bash
+yarn production
+```
+
+### Compile Sass
+
+```bash
+yarn sass:process
+```
diff --git a/packages/docs/package.json b/packages/docs/package.json
new file mode 100644
index 000000000..84613c39f
--- /dev/null
+++ b/packages/docs/package.json
@@ -0,0 +1,60 @@
+{
+ "name": "@pattern-lab/website",
+ "version": "6.1.0",
+ "description": "The website for patternlab.io",
+ "main": "index.js",
+ "dependencies": {
+ "@11ty/eleventy": "^0.12.1",
+ "@11ty/eleventy-plugin-rss": "^1.1.2",
+ "@11ty/eleventy-plugin-syntaxhighlight": "^3.1.3",
+ "@tbranyen/jsdom": "^13.0.0",
+ "concurrently": "^4.1.0",
+ "html-minifier": "^4.0.0",
+ "json-to-scss": "^1.6.2",
+ "nunjucks": "^3.2.3",
+ "sass": "^1.32.8",
+ "semver": "^6.3.0",
+ "slugify": "^1.5.0",
+ "stalfos": "github:hankchizljaw/stalfos#c8971d22726326cfc04089b2da4d51eeb1ebb0eb"
+ },
+ "devDependencies": {
+ "@11ty/eleventy-navigation": "^0.3.2",
+ "@erquhart/rollup-plugin-node-builtins": "^2.1.5",
+ "bl": "^3.0.0",
+ "chokidar-cli": "^2.1.0",
+ "cross-env": "^5.2.0",
+ "make-dir-cli": "^2.0.0",
+ "prettier": "^2.8.1",
+ "rollup": "^1.16.1",
+ "rollup-plugin-commonjs": "^10.0.0",
+ "rollup-plugin-json": "^4.0.0",
+ "rollup-plugin-node-resolve": "^5.0.3"
+ },
+ "scripts": {
+ "sass:tokens": "npx json-to-scss src/_data/tokens.json src/scss/_tokens.scss",
+ "sass:process": "yarn sass:tokens && sass src/scss/style.scss dist/css/style.css --style=compressed",
+ "cms:precompile": "make-dir dist/admin && nunjucks-precompile src/_includes > dist/admin/templates.js -i \"\\.(njk|css|svg)$\"",
+ "cms:bundle": "rollup --config",
+ "start": "concurrently \"yarn sass:process --watch\" \"yarn cms:bundle --watch\" \"chokidar \\\"src/_includes/**\\\" -c \\\"yarn cms:precompile\\\"\" \"yarn serve\"",
+ "serve": "cross-env ELEVENTY_ENV=development npx eleventy --serve",
+ "production": "yarn sass:process && yarn cms:precompile && yarn cms:bundle && npx eleventy"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/bradfrost/pl-website-eleventy.git"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "MIT",
+ "bugs": {
+ "url": "https://github.com/bradfrost/pl-website-eleventy/issues"
+ },
+ "publishConfig": {
+ "access": "public"
+ },
+ "homepage": "https://github.com/bradfrost/pl-website-eleventy/#readme",
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac",
+ "engines": {
+ "node": ">=16.20.0"
+ }
+}
diff --git a/packages/docs/php-docs/advanced-auto-regenerate.md b/packages/docs/php-docs/advanced-auto-regenerate.md
new file mode 100644
index 000000000..fc6985825
--- /dev/null
+++ b/packages/docs/php-docs/advanced-auto-regenerate.md
@@ -0,0 +1,55 @@
+---
+title: Watching for Changes and Auto Regenerating Patterns
+tags:
+ - docs
+---
+
+Pattern Lab can watch for changes to files in `./source/` and automatically rebuild the entire Pattern Lab website for you. Make your changes, save the file, and Pattern Lab takes care of the rest.
+
+## How to Start Watching for Changes
+
+To start watching for changes do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --watch`
+
+To stop watching files use `CTRL+C` in the same terminal window.
+
+### Only Watch for Changes to Pattern Lab Files
+
+If you use a task runner like Gulp or Grunt to compile Sass, JavaScript or images you may want Pattern Lab to only concern itself with its own files. To limit Pattern Lab to watch and move only its files do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --watch --patternsonly`
+
+Or, better yet, use this command within your Gulp or Grunt script.
+
+### Start the Web Server & Watch for Changes at the Same Time
+
+If you're relying on Pattern Lab's server to view your content you'll want to run the watch and server with the same command. Do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --server --with-watch`
+
+You can also start the server and watch only patterns:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --server --with-watch --patternsonly`
+
+To stop the server and watching files use `CTRL+C` in the same terminal window.
+
+### Start the Web Server, Watch for Changes, and Reload the Browser at the Same Time
+
+The ultimate solution for working with Pattern Lab if you're not using a task runner is Pattern Lab's [Auto-Reload Plugin](https://github.com/pattern-lab/plugin-php-reload). Do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Install the [Auto-Reload Plugin](https://github.com/pattern-lab/plugin-php-reload) using `composer require pattern-lab/plugin-reload`
+3. Type `php core/console --server --with-watch`
+
+The Auto-Reload Plugin is automatically enabled when you install it. You can always [disable the plugin](https://github.com/pattern-lab/plugin-php-reload#disabling-the-plugin) if you need to.
+
+To stop the server, watching files, and auto-reload service use `CTRL+C` in the same terminal window.
+
+## What Pattern Lab Will Watch
+
+By default, the PHP version of Pattern Lab will watch all files in `./source` except those that match the "ignore" configuration options in `config/config.yml`. When using `--patternsonly` Pattern Lab will only watch those directories in `./source` that start with an underscore. For example, `_patterns`. To learn how to modify what is ignored check out "[Managing Assets for a Pattern](/docs/pattern-managing-assets.html)".
diff --git a/packages/docs/php-docs/advanced-clean-public.md b/packages/docs/php-docs/advanced-clean-public.md
new file mode 100644
index 000000000..408e3ed37
--- /dev/null
+++ b/packages/docs/php-docs/advanced-clean-public.md
@@ -0,0 +1,5 @@
+---
+title: Stopping public/ from Being "Cleaned"
+tags:
+ - docs
+---
diff --git a/packages/docs/php-docs/advanced-config-options.md b/packages/docs/php-docs/advanced-config-options.md
new file mode 100644
index 000000000..e21791b71
--- /dev/null
+++ b/packages/docs/php-docs/advanced-config-options.md
@@ -0,0 +1,7 @@
+---
+title: Editing the Configuration Options
+tags:
+ - docs
+---
+
+Pattern Lab comes with a simple configuration file that allows you to modify certain aspects of the system. The configuration file can be found in `./config/config.yml`.
diff --git a/packages/docs/php-docs/advanced-exporting-patterns.md b/packages/docs/php-docs/advanced-exporting-patterns.md
new file mode 100644
index 000000000..49f4857d1
--- /dev/null
+++ b/packages/docs/php-docs/advanced-exporting-patterns.md
@@ -0,0 +1,17 @@
+---
+title: Exporting Patterns
+tags:
+ - docs
+---
+
+Pattern Lab can export all of your patterns for you sans Pattern Lab's CSS and JavaScript. To export your patterns do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --export`
+
+If you require your patterns to be exported without your global header and footer (_e.g. to export a clean molecule_) do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --export --clean`
+
+In both cases the patterns will be exported to `./export/patterns`. The export directory is one of the many directories that can be [configured and changed](/docs/editing-source-files.html).
diff --git a/packages/docs/php-docs/advanced-page-follow.md b/packages/docs/php-docs/advanced-page-follow.md
new file mode 100644
index 000000000..3e38bebfc
--- /dev/null
+++ b/packages/docs/php-docs/advanced-page-follow.md
@@ -0,0 +1,7 @@
+---
+title: Multi browser & Multi device Testing with Page Follow
+tags:
+ - docs
+---
+
+An auto-reload service was built into Pattern Lab 1. With Pattern Lab 2 this feature has been removed. This feature may return as a plugin in the same way that the [Auto-Reload service](/docs/advanced-reload-browser.html) did.
diff --git a/packages/docs/php-docs/advanced-pattern-lab-nav.md b/packages/docs/php-docs/advanced-pattern-lab-nav.md
new file mode 100644
index 000000000..2bd2c28c5
--- /dev/null
+++ b/packages/docs/php-docs/advanced-pattern-lab-nav.md
@@ -0,0 +1,29 @@
+---
+title: Modifying Pattern Lab's Navigation
+tags:
+ - docs
+---
+
+When sharing Pattern Lab with a client it may be beneficial to turn-off certain elements in the default navigation. To turn-off navigation elements do the following:
+
+1. Open `./config/config.yml`
+2. Add the keys for the elements you'd like to hide to the `ishControlsHide` configuration option
+3. Re-generate your Pattern Lab site
+
+The following keys are supported and will hide their respective elements:
+
+```
+s
+m
+l
+full
+random
+disco
+hay
+find
+views-new
+tools-all
+tools-docs
+```
+
+`hay` is disabled by default.
diff --git a/packages/docs/php-docs/advanced-reload-browser.md b/packages/docs/php-docs/advanced-reload-browser.md
new file mode 100644
index 000000000..4da045d5f
--- /dev/null
+++ b/packages/docs/php-docs/advanced-reload-browser.md
@@ -0,0 +1,14 @@
+---
+title: Auto Reloading the Browser Window When Changes Are Made
+tags:
+ - docs
+---
+
+An auto-reload service was built into Pattern Lab 1. With Pattern Lab 2 this feature has been turned into the [Auto-Reload Plugin](https://github.com/pattern-lab/plugin-php-reload). To install this plugin do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `composer require pattern-lab/plugin-reload`
+
+The Auto-Reload Plugin is automatically enabled when you install it. You can always [disable the plugin](https://github.com/pattern-lab/plugin-php-reload#disabling-the-plugin) if you need to.
+
+This service is enabled when using the `--watch` or `--server --with-watch` commands. Learn more about [watching for changes](/docs/advanced-auto-regenerate.html).
diff --git a/packages/docs/php-docs/advanced-starterkits.md b/packages/docs/php-docs/advanced-starterkits.md
new file mode 100644
index 000000000..5a90e0bdf
--- /dev/null
+++ b/packages/docs/php-docs/advanced-starterkits.md
@@ -0,0 +1,21 @@
+---
+title: Starterkits
+tags:
+ - docs
+---
+
+StarterKits can be installed via the following commands:
+
+```
+php core/console --starterkit --install [starterkit-name]
+```
+
+where [starterkit-name] is the name of the Starterkit.
+
+so... a complete example:
+
+```
+php core/console --starterkit --install pattern-lab/starterkit-mustache-demo
+```
+
+It is recommended that you do not install this StarterKit as a dependency for your Pattern Lab project via Composer.
diff --git a/packages/docs/php-docs/changes-1-to-2.md b/packages/docs/php-docs/changes-1-to-2.md
new file mode 100644
index 000000000..9b54e30be
--- /dev/null
+++ b/packages/docs/php-docs/changes-1-to-2.md
@@ -0,0 +1,46 @@
+---
+title: Pattern Lab 1 to Pattern Lab 2 Changes
+tags:
+ - docs
+---
+
+With Pattern Lab 2 in development for almost two years many under-the-hood changes have been implemented. For the most part a Pattern Lab 1 project should work with minimal changes in Pattern Lab 2. Here is a non-exhaustive list of new features in Pattern Lab 2:
+
+* complete rebuilding of core
+* support for Composer
+* support for more template languages (_currently Mustache and Twig_)
+* support for StarterKits allowing separation of a team's unique needs from Pattern Lab proper
+* event notification system, getters, setters, and a clean install process to allow for plugins
+* redesigned and rebuilt modal view
+* redesigned and rebuilt styleguide view
+* multi-source directory support
+* support for YAML in global data, pattern-specific data, and pseudo-patterns
+* can have multiple JSON/YAML files in `./_data/`
+* support for JSON/YAML linting to find errors
+* can set multiple classes using the style modifier
+* can use link.[pattern-name] within data to link to other patterns
+* pattern parameters support simple lists
+* pattern parameters act more like mustache (_but not exactly!_)
+* patternParameters can over listItem loop numbers
+* global pattern header and footer is now in `./source/_meta`
+* upgraded console utility
+* patterns and pattern subgroups can be documented in the styleguide by using `[pattern-name].md` or `[pattern-subgroup].md`
+* view all pages for pattern sub-types
+* annotations can be defined using Markdown
+* patterns can be exported minus Pattern Lab mark-up
+* can hide individual patterns from "view all" view still available via the nav
+* can set a pattern to be the default pattern when loading Pattern Lab
+* can turn on modal view by default
+* implemented server
+* sayings can now be defined in the config
+* install process that makes it easier to install various components
+
+These are the features of Pattern Lab 1 that have become plugins:
+
+* Automatic Browser Reload
+
+These are the features of Pattern Lab 1 that have been removed in Pattern Lab 2:
+
+* QR Code Generator
+* Page Follow
+* MQs
diff --git a/packages/docs/php-docs/command-line.md b/packages/docs/php-docs/command-line.md
new file mode 100644
index 000000000..b92f4947b
--- /dev/null
+++ b/packages/docs/php-docs/command-line.md
@@ -0,0 +1,22 @@
+---
+title: Using The Command Line Options
+tags:
+ - docs
+---
+
+To use Pattern Lab you must use the command line interface. To view the available commands when using Pattern Lab do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --help`
+
+To get the options for a particular command, for example the `--generate` command, you can type:
+
+ php core/console --help --generate
+
+## A Special Note About Windows
+
+To access the command prompt on Windows you can [follow the directions from Microsoft](https://support.microsoft.com/en-us/windows/powershell-is-replacing-command-prompt-fdb690cf-876c-d866-2124-21b6fb29a45f). After getting to the command prompt type the following to make sure you have PHP installed:
+
+ php -v
+
+If you get an error and know that you've installed PHP you may need to [update your path variable so Windows can find PHP](http://willj.co/2012/10/run-wamp-php-windows-7-command-line/).
diff --git a/packages/docs/php-docs/generating-pattern-lab.md b/packages/docs/php-docs/generating-pattern-lab.md
new file mode 100644
index 000000000..b9831d371
--- /dev/null
+++ b/packages/docs/php-docs/generating-pattern-lab.md
@@ -0,0 +1,14 @@
+---
+title: Generating Pattern Lab
+tags:
+ - docs
+---
+
+Pattern Lab consists of an empty shell when you first install it. To populate the public-facing side of Pattern Lab with your content and patterns do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --generate`
+
+Your Pattern Lab install should now be populated and [available for viewing](/docs/viewing-patterns.html). As you [make changes to your patterns](/docs/editing-source-files.html) you'll need re-generate your site using step 2 above.
+
+Manually re-generating your site after each change or collection of changes can be cumbersome. Pattern Lab can [watch files in the `./source/` directory for changes and re-generate the site automatically](/docs/advanced-auto-regenerate.html). The Pattern Lab website can also be [automatically reloaded](/docs/advanced-reload-browser.html).
diff --git a/packages/docs/php-docs/installation.md b/packages/docs/php-docs/installation.md
new file mode 100644
index 000000000..23b3ec3c4
--- /dev/null
+++ b/packages/docs/php-docs/installation.md
@@ -0,0 +1,5 @@
+---
+title: Installing Pattern Lab
+tags:
+ - docs
+---
diff --git a/packages/docs/php-docs/pattern-managing-assets.md b/packages/docs/php-docs/pattern-managing-assets.md
new file mode 100644
index 000000000..1f6927cde
--- /dev/null
+++ b/packages/docs/php-docs/pattern-managing-assets.md
@@ -0,0 +1,41 @@
+---
+title: Managing Pattern Assets
+tags:
+ - docs
+---
+
+Assets for patterns - including JavaScript, CSS, and images - should be stored and edited in the `./source/` directory. Pattern Lab will move these assets to the `./public/` directory for you when you generate your site or when you watch the `./source/` directory for changes. **You can name and organize your assets however you like.** If you would like to use `./source/stylesheets/` to store your styles instead of `./source/css/` you can do that. There is nothing to configure. The structure will be maintained when they're moved to the `./public/` directory.
+
+## Ignoring and Not Moving Assets Based on File Extension
+
+By default, Pattern Lab will not move assets with the following file extensions:
+
+- `.less`
+- `.scss`
+- `.DS_Store`
+
+To ignore more file extensions edit the `ie` configuration option in `./config/config.yml`. For example, to ignore `*.png` files your `ie` configuration option would look like:
+
+ ie:
+ - DS_Store
+ - less
+ - scss
+ - png
+
+## Ignoring and Not Moving Assets Based on Directory
+
+By default, the PHP version of Pattern Lab will ignore **all** assets in directories that exactly match:
+
+- `scss`
+
+To ignore more directories just edit the `id` configuration option in `./config/config.yml`. For example, to ignore directories named `test/` your `id` configuration option would look like:
+
+ id:
+ - scss
+ - test
+
+**Important:** Pattern Lab will only ignore exact matches of ignored directories. For example, if you had a directory named `cool_scss/` it, and the assets underneath it, _would_ be moved to `./public/` even though `scss` was in the name of the directory.
+
+## Adding Assets to the Pattern Header & Footer
+
+Static assets like Javascript and CSS **are not** added automagically to your patterns. You need to add them manually to the [shared pattern header and footer](/docs/pattern-header-footer.html).
diff --git a/packages/docs/php-docs/pattern-states.md b/packages/docs/php-docs/pattern-states.md
new file mode 100644
index 000000000..58dc72591
--- /dev/null
+++ b/packages/docs/php-docs/pattern-states.md
@@ -0,0 +1,45 @@
+---
+title: Using Pattern States
+tags:
+ - docs
+---
+
+Pattern states provide your team and client a simple visual of the current state of patterns in Pattern Lab. Pattern states can track progress of a pattern from development, through client review, to completion or they can be used to give certain patterns specific classes. It's important to note that the state of a pattern can be influenced by its pattern partials.
+
+## The Default Pattern States
+
+Pattern Lab comes with the following default pattern states:
+
+- **inprogress**: pattern is in development or being worked upon. a red dot.
+- **inreview**: pattern is ready for a client to look at and comment upon. a yellow dot.
+- **complete**: pattern is ready to be moved to production. a green dot.
+
+Any pattern that includes a pattern partial that has a lower pattern state will inherit that state. For example, a pattern with the state of `inreview` that includes a pattern partial with the state of `inprogress` will have its state overridden and set to `inprogress`. It will not change to `inreview` until the pattern partial has a state of `inreview` or `complete`.
+
+## Giving Patterns a State
+
+Giving patterns a state is simply a matter of modifying the file name. If we wanted to give our `molecules-media-block` pattern a state of `inprogress` we'd change the file name from:
+
+```
+./source/_patterns/molecules/blocks/media-block.mustache
+```
+
+to:
+
+```
+./source/_patterns/molecules/blocks/media-block@inprogress.mustache
+```
+
+## Adding Customized States
+
+The three default states included with Pattern Lab might not be enough for everyone. To add customized states you should modify your own CSS files. **DO NOT** modify `states.css` in `public/styleguide/css/`. This is because `states.css` will be overwritten in future upgrades.
+
+You can use the following as your CSS template for new pattern states:
+
+```css
+{% raw %}.newpatternstate::before {
+ color: #B10DC9 !important;
+}{% endraw %}
+```
+
+Then add `@newpatternstate` to your patterns to have the new look show up. If you want to add it to the cascade of the default patterns you can modify `./config/config.yml`. Simply add your new pattern state to the `patternStates` list.
diff --git a/packages/docs/php-docs/requirements.md b/packages/docs/php-docs/requirements.md
new file mode 100644
index 000000000..d823eddc3
--- /dev/null
+++ b/packages/docs/php-docs/requirements.md
@@ -0,0 +1,22 @@
+---
+title: Requirements
+tags:
+ - docs
+---
+
+
+
+The requirements for Pattern Lab 2 vary depending on what features you want to use.
+
+## Minimum Requirements
+
+To use the basic features of Pattern Lab to compile patterns, you must have **PHP 5.4+** installed. On Mac OS X Pattern Lab should work "out of the box." If you're on Windows you can [download PHP from PHP.net](https://windows.php.net/download/). Pattern Lab comes with its own built-in web server.
+
+Because Pattern Lab's output consists of HTML, CSS, and JavaScript there are **no requirements** for hosting your Pattern Lab site. Simply upload the `./public/` directory to your host and you should be good to go.
+
+## Highly Recommended: Composer
+
+Pattern Lab uses [Composer](https://getcomposer.org/) to manage project dependencies. While Pattern Lab can be downloaded as a Zip we highly recommend installing Composer so you can easily update your project in the future. Please follow the directions for [installing Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) on the Composer website. We recommend you [install it globally](https://getcomposer.org/doc/00-intro.md#globally).
+
+
+
diff --git a/packages/docs/php-docs/upgrading.md b/packages/docs/php-docs/upgrading.md
new file mode 100644
index 000000000..c0661f087
--- /dev/null
+++ b/packages/docs/php-docs/upgrading.md
@@ -0,0 +1,52 @@
+---
+title: Upgrading Pattern Lab
+tags:
+ - docs
+---
+
+
+
+Pattern Lab 2 uses [Composer](https://getcomposer.org) to manage project dependencies. To upgrade an edition based on Pattern Lab 2 do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `composer update`
+
+During the upgrade process Pattern Lab 2 will move or add any files that are required for the new version to work. It will also update your configuration as appropriate. If you don't have Composer installed please [follow the directions for installing Composer](https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx) that are available on the Composer website. We recommend you [install it globally](https://getcomposer.org/doc/00-intro.md#globally).
+
+## Upgrading Pattern Lab 1 to Pattern Lab 2
+
+Pattern Lab 2 was a complete rewrite and reorganization of Pattern Lab 1. [Learn about the changes](/docs/changes-1-to-2.html). To upgrade do the following:
+
+1. [Download](https://patternlab.io/docs/installing-pattern-lab/) the PHP edition that matches your needs
+
+If you chose a Mustache-based edition do the following:
+
+1. Copy `./source` from your old project to your new edition
+2. Copy `./source/_patterns/atoms/meta/_head.mustache` to `./source/_meta/_head.mustache`
+3. Copy `./source/_patterns/atoms/meta/_foot.mustache` to `./source/_meta/_foot.mustache` (you can then delete `source/_patterns/atoms/meta/` directory)
+4. In `./source/_meta/_head.mustache`, replace `{% raw %}{% pattern-lab-head %}{% endraw %}` with `{% raw %}{{{ patternLabHead }}}{% endraw %}`
+5. In `./source/_meta/_foot.mustache` replace `{% raw %}{% pattern-lab-foot %}{% endraw %}` with `{% raw %}{{{ patternLabFoot }}}{% endraw %}`
+6. Copy `./source/_data/annotations.js` to `./source/_annotations/annotations.js`
+7. Remove the underscore in front of the JSON files in `source/data` (i.e. `data.json` not `_data.json`).
+
+
+
+If you chose another version do the above and convert the templates as appropriate.
+
+## Learning About Upgrades
+
+New releases and upgrades are announced in Pattern Lab's [PHP room on Gitter](https://gitter.im/pattern-lab/php) and on Twitter at [@patternlabio](https://twitter.com/patternlabio).
+
+You can also determine if your version of Pattern Lab 2 can be upgraded yourself by doing the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `composer outdated`
+
+Two components of Pattern Lab 2 maintain CHANGELOGs as part of their "Releases" page on GitHub:
+
+* [pattern-lab/core](https://github.com/pattern-lab/patternlab-php-core/releases)
+* [pattern-lab/styleguidekit-assets-default](https://github.com/pattern-lab/styleguidekit-assets-default/releases)
+
+
+
+
diff --git a/packages/docs/php-docs/viewing-patterns.md b/packages/docs/php-docs/viewing-patterns.md
new file mode 100644
index 000000000..b2307acf5
--- /dev/null
+++ b/packages/docs/php-docs/viewing-patterns.md
@@ -0,0 +1,12 @@
+---
+title: Viewing Patterns
+tags:
+ - docs
+---
+
+Pattern Lab utilizes PHP's [built-in web server](https://www.php.net/manual/en/features.commandline.webserver.php) to let you browse your generated patterns. To start the server do the following:
+
+1. In a terminal window navigate to the root of your project
+2. Type `php core/console --server`
+
+Your local Pattern Lab install should now be available for browsing at [http://localhost:8080](http://localhost:8080).
diff --git a/packages/docs/rollup.config.js b/packages/docs/rollup.config.js
new file mode 100644
index 000000000..4fc2d3bc6
--- /dev/null
+++ b/packages/docs/rollup.config.js
@@ -0,0 +1,14 @@
+const builtins = require('@erquhart/rollup-plugin-node-builtins');
+const commonjs = require('rollup-plugin-commonjs');
+const nodeResolve = require('rollup-plugin-node-resolve');
+const json = require('rollup-plugin-json');
+
+export default {
+ input: 'src/admin/util',
+ output: {
+ file: 'dist/admin/util.js',
+ format: 'iife',
+ name: 'previewUtil',
+ },
+ plugins: [builtins(), nodeResolve(), commonjs(), json()],
+};
diff --git a/packages/docs/src/404.md b/packages/docs/src/404.md
new file mode 100644
index 000000000..b69a2386a
--- /dev/null
+++ b/packages/docs/src/404.md
@@ -0,0 +1,17 @@
+---
+title: '404 - not found'
+layout: layouts/page.njk
+permalink: 404.html
+sitemapIgnore: true
+---
+
+We’re sorry, but that content can’t be found. Please go [back to home](/).
+
+{% comment %}
+Read more: https://www.11ty.io/docs/quicktips/not-found/
+
+This will work for both GitHub pages and Netlify:
+
+- https://help.github.com/articles/creating-a-custom-404-page-for-your-github-pages-site/
+- https://www.netlify.com/docs/redirects/#custom-404
+ {% endcomment %}
diff --git a/packages/docs/src/_data/global.js b/packages/docs/src/_data/global.js
new file mode 100644
index 000000000..3c823d73b
--- /dev/null
+++ b/packages/docs/src/_data/global.js
@@ -0,0 +1,10 @@
+module.exports = {
+ random() {
+ const segment = () => {
+ // eslint-disable-next-line no-bitwise
+ return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
+ };
+ return `${segment()}-${segment()}-${segment()}`;
+ },
+ now: Date.now(),
+};
diff --git a/packages/docs/src/_data/helpers.js b/packages/docs/src/_data/helpers.js
new file mode 100644
index 000000000..bd6f173d3
--- /dev/null
+++ b/packages/docs/src/_data/helpers.js
@@ -0,0 +1,10 @@
+module.exports = {
+ getNextHeadingLevel(currentLevel) {
+ return parseInt(currentLevel, 10) + 1;
+ },
+ getReadingTime(text) {
+ const wordsPerMinute = 200;
+ const numberOfWords = text.split(/\s/g).length;
+ return Math.ceil(numberOfWords / wordsPerMinute);
+ },
+};
diff --git a/packages/docs/src/_data/navigation.json b/packages/docs/src/_data/navigation.json
new file mode 100644
index 000000000..d309386b1
--- /dev/null
+++ b/packages/docs/src/_data/navigation.json
@@ -0,0 +1,66 @@
+{
+ "items": [
+ {
+ "label": "Getting Started",
+ "url": "/docs/installing-pattern-lab/"
+ },
+ {
+ "label": "Documentation",
+ "url": "/docs/",
+ "subnavIsClosed": true,
+ "subnav": [
+ {
+ "label": "Getting Started",
+ "category": "getting-started"
+ },
+ {
+ "label": "Working with Patterns",
+ "category": "patterns"
+ },
+ {
+ "label": "Working with Data",
+ "category": "data"
+ },
+ {
+ "label": "Advanced",
+ "category": "advanced"
+ }
+ ]
+ },
+ {
+ "label": "Demos",
+ "url": "/demos/"
+ },
+ {
+ "label": "Support",
+ "url": "/support/"
+ },
+ {
+ "label": "Resources",
+ "url": "/resources/"
+ },
+ {
+ "label": "On Github",
+ "url": "https://github.com/pattern-lab/patternlab-node",
+ "external": true
+ }
+ ],
+ "footerNav": [
+ {
+ "label": "Resources",
+ "url": "/resources/"
+ },
+ {
+ "label": "Updates",
+ "url": "/updates/"
+ },
+ {
+ "label": "Demos",
+ "url": "/demos/"
+ },
+ {
+ "label": "On Github",
+ "url": "https://github.com/pattern-lab/patternlab-node"
+ }
+ ]
+}
diff --git a/packages/docs/src/_data/site.json b/packages/docs/src/_data/site.json
new file mode 100644
index 000000000..555f61950
--- /dev/null
+++ b/packages/docs/src/_data/site.json
@@ -0,0 +1,13 @@
+{
+ "showThemeCredit": true,
+ "name": "Pattern Lab",
+ "shortDesc": "Pattern Lab is a frontend workshop environment that helps you build, view, test, and showcase your design system's UI components.",
+ "url": "https://patternlab.io",
+ "authorEmail": "brad@bradfrost.com",
+ "authorHandle": "@bradfrost",
+ "authorName": "Brad Frost",
+ "enableThirdPartyComments": false,
+ "maxPostsPerPage": 5,
+ "paymentPointer": "$coil.xrptipbot.com/c1f8f05d-8d8c-4f37-b1ad-25677ae129da",
+ "faviconPath": "/images/favicon.ico"
+}
diff --git a/packages/docs/src/_data/styleguide.js b/packages/docs/src/_data/styleguide.js
new file mode 100644
index 000000000..a3977f9b0
--- /dev/null
+++ b/packages/docs/src/_data/styleguide.js
@@ -0,0 +1,28 @@
+const tokens = require('./tokens.json');
+
+module.exports = {
+ colors() {
+ let response = [];
+
+ Object.keys(tokens.colors).forEach((key) => {
+ response.push({
+ value: tokens.colors[key],
+ key,
+ });
+ });
+
+ return response;
+ },
+ sizes() {
+ let response = [];
+
+ Object.keys(tokens['size-scale']).forEach((key) => {
+ response.push({
+ value: tokens['size-scale'][key],
+ key,
+ });
+ });
+
+ return response;
+ },
+};
diff --git a/packages/docs/src/_data/tokens.json b/packages/docs/src/_data/tokens.json
new file mode 100644
index 000000000..b5bf4b3ae
--- /dev/null
+++ b/packages/docs/src/_data/tokens.json
@@ -0,0 +1,26 @@
+{
+ "size-scale": {
+ "base": "1rem",
+ "300": "0.8rem",
+ "500": "1.25rem",
+ "600": "1.56rem",
+ "700": "1.95rem",
+ "800": "2.44rem",
+ "900": "3.05rem",
+ "max": "4rem"
+ },
+ "colors": {
+ "primary": "#173854",
+ "primary-shade": "#102538",
+ "primary-glare": "#22547c",
+ "highlight": "#fedb8b",
+ "light": "#ffffff",
+ "mid": "#cccccc",
+ "dark": "#333333",
+ "slate": "#404040"
+ },
+ "fonts": {
+ "base": "\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'\"",
+ "serif": "\"'Lora', serif\""
+ }
+}
diff --git a/packages/docs/src/_includes/components/footer-nav.njk b/packages/docs/src/_includes/components/footer-nav.njk
new file mode 100644
index 000000000..54a448266
--- /dev/null
+++ b/packages/docs/src/_includes/components/footer-nav.njk
@@ -0,0 +1,10 @@
+
diff --git a/packages/docs/src/_includes/components/footer.njk b/packages/docs/src/_includes/components/footer.njk
new file mode 100644
index 000000000..7764312d2
--- /dev/null
+++ b/packages/docs/src/_includes/components/footer.njk
@@ -0,0 +1,10 @@
+
diff --git a/packages/docs/src/_includes/components/header.njk b/packages/docs/src/_includes/components/header.njk
new file mode 100644
index 000000000..5a5a508df
--- /dev/null
+++ b/packages/docs/src/_includes/components/header.njk
@@ -0,0 +1,22 @@
+
+
+
diff --git a/packages/docs/src/_includes/components/hero.njk b/packages/docs/src/_includes/components/hero.njk
new file mode 100644
index 000000000..7053c247c
--- /dev/null
+++ b/packages/docs/src/_includes/components/hero.njk
@@ -0,0 +1,16 @@
+
+
+
+
Create atomic design systems with Pattern Lab
+
+
+ Pattern Lab is a frontend workshop environment that helps you build, view, test, and showcase your design system's UI components.
+
+
+
+ Run the following command in your terminal and read the installation guide to get started:
+
+
npm create pattern-lab
+
+
+
\ No newline at end of file
diff --git a/packages/docs/src/_includes/components/icon-chevron-down.njk b/packages/docs/src/_includes/components/icon-chevron-down.njk
new file mode 100644
index 000000000..37c8e757a
--- /dev/null
+++ b/packages/docs/src/_includes/components/icon-chevron-down.njk
@@ -0,0 +1,4 @@
+
+cheveron-down
+
+
\ No newline at end of file
diff --git a/packages/docs/src/_includes/components/logo.njk b/packages/docs/src/_includes/components/logo.njk
new file mode 100644
index 000000000..fad8e3428
--- /dev/null
+++ b/packages/docs/src/_includes/components/logo.njk
@@ -0,0 +1,11 @@
+
+
+
diff --git a/packages/docs/src/_includes/components/meta-info.njk b/packages/docs/src/_includes/components/meta-info.njk
new file mode 100644
index 000000000..c7d6a3aa0
--- /dev/null
+++ b/packages/docs/src/_includes/components/meta-info.njk
@@ -0,0 +1,41 @@
+{% set pageTitle = title + ' - ' + site.name %}
+{% set pageDesc = '' %}
+{% set siteTitle = site.name %}
+{% set currentUrl = site.url + page.url %}
+
+{% if metaTitle %}
+ {% set pageTitle = metaTitle %}
+{% endif %}
+
+{% if metaDesc %}
+ {% set pageDesc = metaDesc %}
+{% endif %}
+
+{{ pageTitle }}
+
+
+
+
+
+
+
+{% if site.authorHandle %}
+
+{% endif %}
+
+{% if metaDesc %}
+
+
+
+{% endif %}
+
+{% if socialImage %}
+
+
+
+
+{% endif %}
+
+{% if site.paymentPointer %}
+
+{% endif %}
diff --git a/packages/docs/src/_includes/components/page-header.njk b/packages/docs/src/_includes/components/page-header.njk
new file mode 100644
index 000000000..8fbae6236
--- /dev/null
+++ b/packages/docs/src/_includes/components/page-header.njk
@@ -0,0 +1,13 @@
+
diff --git a/packages/docs/src/_includes/components/stacked-block.njk b/packages/docs/src/_includes/components/stacked-block.njk
new file mode 100644
index 000000000..fb351e919
--- /dev/null
+++ b/packages/docs/src/_includes/components/stacked-block.njk
@@ -0,0 +1,6 @@
+
+
+ {{ title }}
+
+
{{ description }}
+
diff --git a/packages/docs/src/_includes/components/tile.njk b/packages/docs/src/_includes/components/tile.njk
new file mode 100644
index 000000000..c6274f2e6
--- /dev/null
+++ b/packages/docs/src/_includes/components/tile.njk
@@ -0,0 +1,9 @@
+
+
+
+
{{ description | safe }}
+
+
+
diff --git a/packages/docs/src/_includes/components/tree-nav.njk b/packages/docs/src/_includes/components/tree-nav.njk
new file mode 100644
index 000000000..b2128fe34
--- /dev/null
+++ b/packages/docs/src/_includes/components/tree-nav.njk
@@ -0,0 +1,33 @@
+
+
+
+
+ {% for item in navigation.items %}
+
+ {% if item.subnav %}
+
+ {{ item.label }}
+ {% set className = "c-tree-nav__icon" %}
+ {% include "components/icon-chevron-down.njk" %}
+
+
+
+ {% for subnav in item.subnav %}
+
+
+
+ {{ subnav.label }}
+
+ {% set subnavCategory = subnav.category %}
+ {% include "components/tree-subnav.njk" %}
+
+ {% endfor %}
+
+ {% else %}
+ {{ item.label }}
+ {% endif %}
+
+ {% endfor %}
+
+
+
diff --git a/packages/docs/src/_includes/components/tree-subnav.njk b/packages/docs/src/_includes/components/tree-subnav.njk
new file mode 100644
index 000000000..ace03cb8c
--- /dev/null
+++ b/packages/docs/src/_includes/components/tree-subnav.njk
@@ -0,0 +1,11 @@
+{% set navPages = collections.docs | eleventyNavigation %}
+
+{% for entry in navPages %}
+ {% if entry.key == subnavCategory %}
+
+ {{ entry.title }}
+
+ {% endif %}
+{% endfor %}
+
+
diff --git a/packages/docs/src/_includes/icons/arrow.svg b/packages/docs/src/_includes/icons/arrow.svg
new file mode 100644
index 000000000..153b9eed7
--- /dev/null
+++ b/packages/docs/src/_includes/icons/arrow.svg
@@ -0,0 +1,13 @@
+
+
+
diff --git a/packages/docs/src/_includes/layouts/archive.njk b/packages/docs/src/_includes/layouts/archive.njk
new file mode 100644
index 000000000..d1b328ed8
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/archive.njk
@@ -0,0 +1,17 @@
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Post Archive' %}
+
+{# Intro content #}
+{% set introHeading = title %}
+{% set introSummary %}{{ content | safe }}{% endset %}
+
+{# Post list content #}
+{% set postListHeading = 'All posts' %}
+{% set postListItems = collections.posts %}
+
+{% block content %}
+
+ {% include "partials/components/intro.njk" %}
+ {% include "partials/components/post-list.njk" %}
+
+{% endblock %}
diff --git a/packages/docs/src/_includes/layouts/base.njk b/packages/docs/src/_includes/layouts/base.njk
new file mode 100644
index 000000000..6d21c8837
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/base.njk
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+ {% include "components/meta-info.njk" %}
+
+
+ {% block head %}
+ {% endblock %}
+
+
+
+
+
+
+
+
+ {% block content %}
+ {% endblock content %}
+
+
+ {% include "components/footer.njk" %}
+ {% block foot %}
+ {% endblock %}
+
+
+
+
+
+
diff --git a/packages/docs/src/_includes/layouts/blog.njk b/packages/docs/src/_includes/layouts/blog.njk
new file mode 100644
index 000000000..bc7b10eef
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/blog.njk
@@ -0,0 +1,17 @@
+{% extends 'layouts/base.njk' %}
+
+{# Intro content #}
+{% set introHeading = title %}
+{% set introDescription = description %}
+
+{# Post list content #}
+{% set postListItems = collections.posts %}
+
+{% block content %}
+
+
+ {% include "components/page-header.njk" %}
+ {% include "partials/components/post-list.njk" %}
+
+
+{% endblock %}
diff --git a/packages/docs/src/_includes/layouts/demos.njk b/packages/docs/src/_includes/layouts/demos.njk
new file mode 100644
index 000000000..f3746bbef
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/demos.njk
@@ -0,0 +1,23 @@
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Post Archive' %}
+
+{# Intro content #}
+{% set introHeading = title %}
+{% set introSummary %}{{ content | safe }}{% endset %}
+
+{# Post list content #}
+{% set demoListItems = collections.demos %}
+
+{% block content %}
+
+ {% include "components/page-header.njk" %}
+
+
+ {% set demoListCategory = 'example' %}
+ {% include "partials/components/demo-list.njk" %}
+
+
+ {% set demoListCategory = 'starterkit' %}
+ {% include "partials/components/demo-list.njk" %}
+
+{% endblock %}
\ No newline at end of file
diff --git a/packages/docs/src/_includes/layouts/docs.njk b/packages/docs/src/_includes/layouts/docs.njk
new file mode 100644
index 000000000..e29cc063e
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/docs.njk
@@ -0,0 +1,28 @@
+---
+permalink: docs/{{ title | slug }}/
+---
+
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Docs' %}
+
+{# Intro content #}
+{% set introHeading = title %}
+{% set introSummary %}
+
+{% endset %}
+
+{% block content %}
+
+
+
+ {% include "components/page-header.njk" %}
+
+ {{ content | safe }}
+
+
+
+
+
+{% endblock %}
+
+{{ content | safe }}
diff --git a/packages/docs/src/_includes/layouts/home.njk b/packages/docs/src/_includes/layouts/home.njk
new file mode 100644
index 000000000..b63fdb0da
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/home.njk
@@ -0,0 +1,101 @@
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Homepage' %}
+
+{% block content %}
+
+ {% set additionalClasses = 'c-tile--orange' %}
+ {% set title = 'Pattern Lab is archived. ' %}
+ {% set link = 'https://github.com/pattern-lab' %}
+ {% set description = "Read the full announcement , and thank you." %}
+
+ {% include "components/tile.njk" %}
+
+
+ {% include "components/hero.njk" %}
+
+
+
+
+ {% set additionalClasses = 'c-tile--green' %}
+ {% set title = 'Read the docs' %}
+ {% set link = '/docs/installing-pattern-lab/' %}
+ {% set description = "Learn how to get up and running with Pattern Lab, work with patterns, design with dynamic data, and use Pattern Lab's advanced features." %}
+ {% include "components/tile.njk" %}
+
+
+ {% set additionalClasses = 'c-tile--orange' %}
+ {% set title = 'Demos' %}
+ {% set link = '/demos/' %}
+ {% set description = "Demos of pattern starterkits for your project as well as a gallery of Pattern Lab projects in the wild" %}
+ {% include "components/tile.njk" %}
+
+
+ {% set additionalClasses = 'c-tile--purple' %}
+ {% set title = 'Resources' %}
+ {% set link = '/resources/' %}
+ {% set description = "Links to articles and resources around Pattern Lab and design systems" %}
+ {% include "components/tile.njk" %}
+
+
+
+
+
+
Pattern Lab features
+
At its core, Pattern Lab is a Node-powered static site generator that stitches together UI components. But there's a whole lot more to it than that!
+
+
+ {% set title="Nested Patterns" %}
+ {% set description="Include UI patterns inside each other like Russian nesting dolls. Make a change to a pattern and immediately see those changes reflected anywhere it is included." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Design With Dynamic Data" %}
+ {% set description="Create living UI prototypes using dynamic data to ensure your components can handle the dynamic nature of your content." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Tool Agnostic" %}
+ {% set description="Pattern Lab doesn't impose any tools or libraries on you, which means you have full control over how author your project." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Language Agnostic" %}
+ {% set description="Use atomic design language, or don't! it's totally up to you how you name, structure, and organize your Pattern Lab project." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Pattern Documentation" %}
+ {% set description="Define and describe your UI patterns so your entire team can start speaking the same language to collaborate more effectively." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Viewport Resizer Tools" %}
+ {% set description="Pattern Lab includes viewport resizing tools to ensure your design system's components and pages are fully responsive." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Pattern Lineage" %}
+ {% set description="X-ray vision! Quickly view where patterns where components are used, speeding up design, development, and QA time." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Pattern Starter Kits" %}
+ {% set description="Start your Pattern Lab project with a blank slate, a few sample components, or a full-on demo project." %}
+ {% include "components/stacked-block.njk" %}
+
+
+ {% set title="Flexible and Extensible" %}
+ {% set description="Pattern Lab supports Handlebars and Twig templating engines. Also you can or build a plugin to extend Pattern Lab's capabilities even further." %}
+ {% include "components/stacked-block.njk" %}
+
+
+
+ {% set additionalClasses = 'c-tile--orange' %}
+ {% set title = 'Open source and community driven' %}
+ {% set link = '/support/' %}
+ {% set description = "Pattern Lab is (and will always be) an open source project. Check out the project on
GitHub and join the
Pattern Lab Gitter community for conversation and support." %}
+ {% include "components/tile.njk" %}
+
+
+
+{% endblock %}
diff --git a/packages/docs/src/_includes/layouts/page-base.njk b/packages/docs/src/_includes/layouts/page-base.njk
new file mode 100644
index 000000000..4a921e27f
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/page-base.njk
@@ -0,0 +1,24 @@
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Resources' %}
+
+{# Intro content #}
+{% set introHeading = title %}
+{% set introSummary %}
+
+{% endset %}
+
+{% block content %}
+
+
+
+ {% include "components/page-header.njk" %}
+
+ {{ content | safe }}
+
+
+
+
+
+{% endblock %}
+
+{{ content | safe }}
diff --git a/packages/docs/src/_includes/layouts/page.njk b/packages/docs/src/_includes/layouts/page.njk
new file mode 100644
index 000000000..0714fa10c
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/page.njk
@@ -0,0 +1,19 @@
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Page' %}
+
+{# Intro content #}
+{% set introHeading = title %}
+
+{% block content %}
+
+
+
+ {% include "components/page-header.njk" %}
+ {{ content | safe }}
+
+
+
+
+{% endblock %}
+
+{{ content | safe }}
diff --git a/packages/docs/src/_includes/layouts/post.njk b/packages/docs/src/_includes/layouts/post.njk
new file mode 100644
index 000000000..6a4702769
--- /dev/null
+++ b/packages/docs/src/_includes/layouts/post.njk
@@ -0,0 +1,25 @@
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Post' %}
+
+{# Intro content #}
+{% if date %}
+{% set introKicker = date | dateFilter %}
+{% endif %}
+{% set introHeading = title %}
+
+
+{% block content %}
+
+
+
+ {% include "components/page-header.njk" %}
+
+
+ {{ content | safe }}
+
+
+
+
+{% endblock %}
+
+{{ content | safe }}
diff --git a/packages/docs/src/_includes/partials/components/demo-list.njk b/packages/docs/src/_includes/partials/components/demo-list.njk
new file mode 100644
index 000000000..c351dde08
--- /dev/null
+++ b/packages/docs/src/_includes/partials/components/demo-list.njk
@@ -0,0 +1,37 @@
+{% if demoListItems.length %}
+
+
+ {% for item in demoListItems %}
+
+ {% if item.data.category == demoListCategory %}
+
+
+
+
+
+
+ {{ item.data.title }}
+
+
+ {{ item.data.description}}
+
+
+
+
+ {% endif %}
+
+ {% endfor %}
+
+
+{% endif %}
diff --git a/packages/docs/src/_includes/partials/components/intro.njk b/packages/docs/src/_includes/partials/components/intro.njk
new file mode 100644
index 000000000..e5cc10c13
--- /dev/null
+++ b/packages/docs/src/_includes/partials/components/intro.njk
@@ -0,0 +1,8 @@
+
diff --git a/packages/docs/src/_includes/partials/components/nav.njk b/packages/docs/src/_includes/partials/components/nav.njk
new file mode 100644
index 000000000..0b9cbcf6f
--- /dev/null
+++ b/packages/docs/src/_includes/partials/components/nav.njk
@@ -0,0 +1,22 @@
+{% if navigation.items %}
+
+
+ {% for item in navigation.items %}
+ {% set relAttribute = '' %}
+ {% set currentAttribute = '' %}
+
+ {% if item.rel %}
+ {% set relAttribute = ' rel="' + item.rel + '"' %}
+ {% endif %}
+
+ {% if page.url == item.url %}
+ {% set currentAttribute = ' aria-current="page"' %}
+ {% endif %}
+
+
+ {{ item.text }}
+
+ {% endfor %}
+
+
+{% endif %}
diff --git a/packages/docs/src/_includes/partials/components/pagination.njk b/packages/docs/src/_includes/partials/components/pagination.njk
new file mode 100644
index 000000000..d78236a2a
--- /dev/null
+++ b/packages/docs/src/_includes/partials/components/pagination.njk
@@ -0,0 +1,23 @@
+{% set paginationLinkTokens = 'leading-tight text-500 weight-mid box-inline-flex align-center pad-bottom-300' %}
+
+{% if paginationNextUrl or paginationPrevUrl %}
+
+
+
+
+{% endif %}
diff --git a/packages/docs/src/_includes/partials/components/post-list.njk b/packages/docs/src/_includes/partials/components/post-list.njk
new file mode 100644
index 000000000..7a241e2e1
--- /dev/null
+++ b/packages/docs/src/_includes/partials/components/post-list.njk
@@ -0,0 +1,22 @@
+
+{% if postListItems.length %}
+
+
+ {% for item in postListItems %}
+
+
+ {{ item.data.date | dateFilter }}
+
+
+ {{ item.data.title }}
+
+
+ {{ item.data.description}}
+
+
+
+
+ {% endfor %}
+
+
+{% endif %}
diff --git a/packages/docs/src/admin.njk b/packages/docs/src/admin.njk
new file mode 100644
index 000000000..56f0d6566
--- /dev/null
+++ b/packages/docs/src/admin.njk
@@ -0,0 +1,23 @@
+---
+permalink: '/admin/index.html'
+sitemapIgnore: true
+---
+
+
+
+
+
+ Content Manager
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/src/admin/config.yml b/packages/docs/src/admin/config.yml
new file mode 100644
index 000000000..15abea8bc
--- /dev/null
+++ b/packages/docs/src/admin/config.yml
@@ -0,0 +1,243 @@
+backend:
+ name: git-gateway
+ branch: master
+publish_mode: editorial_workflow
+site_url: 'https://example.com'
+media_folder: 'src/images'
+public_folder: 'images'
+collections:
+ - name: 'pages'
+ label: 'Pages'
+ files:
+ - name: 'home'
+ label: 'Homepage'
+ delete: false
+ file: 'src/index.md'
+ slug: '{{slug}}'
+ create: false
+ fields:
+ - {
+ label: 'Layout',
+ name: 'layout',
+ widget: 'hidden',
+ default: 'layouts/njk.njk',
+ }
+ - {label: 'Title', name: 'title', widget: 'string'}
+ - {
+ label: 'SEO Meta Title',
+ name: 'metaTitle',
+ widget: 'string',
+ required: false,
+ }
+ - {
+ label: 'SEO Meta Description',
+ name: 'metaDesc',
+ widget: 'string',
+ required: false,
+ }
+ - {
+ label: 'Post Feed Heading',
+ name: 'postsHeading',
+ widget: 'string',
+ default: 'Latest posts',
+ }
+ - {
+ label: 'Archive Link Text',
+ name: 'archiveButtonText',
+ widget: 'string',
+ default: 'See all posts',
+ }
+ - {label: 'Social Image', name: 'socialImage', widget: 'image', required: false}
+ - {label: 'Body', name: 'body', widget: 'markdown'}
+ - name: 'generic_pages'
+ label: 'Generic Pages'
+ folder: 'src/pages'
+ slug: '{{slug}}'
+ preview_path: 'pages/{{slug}}'
+ create: true
+ fields:
+ - {label: 'Layout', name: 'layout', widget: 'hidden', default: 'layouts/page.njk'}
+ - {label: 'Title', name: 'title', widget: 'string'}
+ - {
+ label: "Permalink Override (Pattern: '/your-slug/index.html')",
+ name: 'permalink',
+ widget: 'string',
+ required: false,
+ }
+ - {label: 'SEO Meta Title', name: 'metaTitle', widget: 'string', required: false}
+ - {
+ label: 'SEO Meta Description',
+ name: 'metaDesc',
+ widget: 'string',
+ required: false,
+ }
+ - {label: 'Social Image', name: 'socialImage', widget: 'image', required: false}
+ - {label: 'Body', name: 'body', widget: 'markdown'}
+ - name: 'posts'
+ label: 'Posts'
+ folder: 'src/posts'
+ slug: '{{slug}}'
+ preview_path: 'posts/{{slug}}'
+ create: true
+ fields:
+ - {label: 'Layout', name: 'layout', widget: 'hidden', default: 'layouts/post.njk'}
+ - {label: 'Title', name: 'title', widget: 'string'}
+ - {label: 'SEO Meta Title', name: 'metaTitle', widget: 'string', required: false}
+ - {
+ label: 'SEO Meta Description',
+ name: 'metaDesc',
+ widget: 'string',
+ required: false,
+ }
+ - {label: 'Social Image', name: 'socialImage', widget: 'image', required: false}
+ - {label: 'Publish Date', name: 'date', widget: 'datetime'}
+ - {label: 'Tags', name: 'tags', widget: 'list', allow_add: true}
+ - {label: 'Body', name: 'body', widget: 'markdown'}
+ - name: 'docs'
+ label: 'Docs'
+ folder: 'src/docs'
+ slug: '{{slug}}'
+ preview_path: 'docs/{{slug}}'
+ create: true
+ fields:
+ - {label: 'Layout', name: 'layout', widget: 'hidden', default: 'layouts/post.njk'}
+ - {label: 'Title', name: 'title', widget: 'string'}
+ - {label: 'Publish Date', name: 'date', widget: 'datetime'}
+ - {label: 'Tags', name: 'tags', widget: 'list', allow_add: true}
+ - {label: 'Body', name: 'body', widget: 'markdown'}
+ - label: 'Globals'
+ name: 'globals'
+ files:
+ - label: 'Site Data'
+ name: 'site_data'
+ delete: false
+ file: 'src/_data/site.json'
+ fields:
+ - {label: 'Site Name', name: 'name', widget: 'string'}
+ - {label: 'Site Url', name: 'url', widget: 'string'}
+ - {label: 'Author Name', name: 'authorName', widget: 'string'}
+ - {label: 'Author Email Address', name: 'authorEmail', widget: 'string'}
+ - {
+ label: 'Author Twitter Handle',
+ name: 'authorHandle',
+ widget: 'string',
+ required: false,
+ }
+ - {label: 'Footer Short Description', name: 'shortDesc', widget: 'string'}
+ - {
+ label: 'Maximum Posts Per Page',
+ name: 'maxPostsPerPage',
+ widget: 'number',
+ default: 5,
+ }
+ - {
+ label: 'Show Theme Credit',
+ name: 'showThemeCredit',
+ widget: 'boolean',
+ default: true,
+ }
+ - {
+ label: 'Enable Third Party Comments Area',
+ name: 'enableThirdPartyComments',
+ widget: 'boolean',
+ default: false,
+ }
+ - {
+ label: 'Payment Pointer (Web Monetization: https://bit.ly/2kTRI1b)',
+ name: 'paymentPointer',
+ widget: 'string',
+ }
+ - {
+ label: 'Favicon path (EG: /images/favicon.png)',
+ name: 'faviconPath',
+ widget: 'string',
+ }
+ - label: 'Navigation'
+ name: 'nav'
+ delete: false
+ file: 'src/_data/navigation.json'
+ fields:
+ - label: 'Items'
+ name: 'items'
+ widget: 'list'
+ fields:
+ - {label: 'Text', name: 'text', widget: 'string'}
+ - {label: 'Url', name: 'url', widget: 'string'}
+ - {
+ label: 'Is url to external site?',
+ name: 'external',
+ widget: 'boolean',
+ required: false,
+ }
+ - label: 'Theme Settings'
+ name: 'theme'
+ delete: false
+ file: 'src/_data/tokens.json'
+ fields:
+ - label: 'Size Scale'
+ name: 'size-scale'
+ widget: 'object'
+ fields:
+ - {label: 'Base Size', name: 'base', widget: 'string', default: '1rem'}
+ - {label: 'Ratio: 300', name: '300', widget: 'string', default: '0.8rem'}
+ - {label: 'Ratio: 500', name: '500', widget: 'string', default: '1.25rem'}
+ - {label: 'Ratio: 600', name: '600', widget: 'string', default: '1.56rem'}
+ - {label: 'Ratio: 700', name: '700', widget: 'string', default: '1.95rem'}
+ - {label: 'Ratio: 800', name: '800', widget: 'string', default: '2.44rem'}
+ - {label: 'Ratio: 900', name: '900', widget: 'string', default: '3.05rem'}
+ - {label: 'Max Size', name: 'max', widget: 'string', default: '4rem'}
+ - label: 'Colors'
+ name: 'colors'
+ widget: 'object'
+ fields:
+ - {
+ label: 'Primary',
+ name: 'primary',
+ widget: 'string',
+ default: 'hsl(208, 57%, 21%)',
+ }
+ - {
+ label: 'Primary Shade (darker)',
+ name: 'primary-shade',
+ widget: 'string',
+ default: 'hsl(208, 56%, 14%)',
+ }
+ - {
+ label: 'Primary Glare (lighter)',
+ name: 'primary-glare',
+ widget: 'string',
+ default: 'hsl(207, 57%, 31%)',
+ }
+ - {
+ label: 'Highlight',
+ name: 'highlight',
+ widget: 'string',
+ default: 'hsl(42, 98%, 77%)',
+ }
+ - {
+ label: 'Light',
+ name: 'light',
+ widget: 'string',
+ default: 'hsl(0, 0%, 100%)',
+ }
+ - {label: 'Mid', name: 'mid', widget: 'string', default: 'hsl(0, 0%, 80%)'}
+ - {
+ label: 'Dark',
+ name: 'dark',
+ widget: 'string',
+ default: 'hsl(0, 0%, 20%)',
+ }
+ - {
+ label: 'Slate',
+ name: 'slate',
+ widget: 'string',
+ default: 'hsl(0, 0%, 25%)',
+ }
+ - label: 'Fonts'
+ name: 'fonts'
+ widget: 'hidden'
+ default:
+ {
+ 'base': '"-apple-system, BlinkMacSystemFont, ''Segoe UI'', Roboto, Helvetica, Arial, sans-serif, ''Apple Color Emoji'', ''Segoe UI Emoji'', ''Segoe UI Symbol''"',
+ 'serif': '"''Lora'', serif"',
+ }
diff --git a/packages/docs/src/admin/previews.js b/packages/docs/src/admin/previews.js
new file mode 100644
index 000000000..46a94b655
--- /dev/null
+++ b/packages/docs/src/admin/previews.js
@@ -0,0 +1,92 @@
+const {w3DateFilter, markdownFilter, dateFilter, helpers} = previewUtil;
+
+const env = nunjucks.configure();
+
+env.addFilter('w3DateFilter', w3DateFilter);
+env.addFilter('markdownFilter', markdownFilter);
+env.addFilter('dateFilter', dateFilter);
+
+const Preview = ({entry, path, context}) => {
+ const data = context(entry.get('data').toJS());
+ const html = env.render(path, {...data, helpers});
+ return
;
+};
+
+const Home = ({entry}) => (
+ ({
+ title,
+ content: markdownFilter(body),
+ postsHeading,
+ archiveButtonText,
+ collections: {
+ postFeed: [
+ {
+ url: 'javascript:void(0)',
+ date: new Date(),
+ data: {
+ title: 'Sample Post',
+ },
+ },
+ ],
+ },
+ })}
+ />
+);
+
+const Post = ({entry}) => (
+ ({
+ title,
+ date,
+ content: markdownFilter(body || ''),
+ })}
+ />
+);
+
+const Page = ({entry}) => (
+ ({
+ title,
+ content: markdownFilter(body || ''),
+ })}
+ />
+);
+
+const SiteData = ({entry}) => (
+ ({
+ site: {
+ name,
+ shortDesc,
+ showThemeCredit,
+ },
+ })}
+ />
+);
+
+const Nav = ({entry}) => (
+ ({
+ navigation: {
+ items,
+ },
+ })}
+ />
+);
+
+CMS.registerPreviewTemplate('home', Home);
+CMS.registerPreviewTemplate('posts', Post);
+CMS.registerPreviewTemplate('generic_pages', Page);
+CMS.registerPreviewTemplate('site_data', SiteData);
+CMS.registerPreviewTemplate('nav', Nav);
diff --git a/packages/docs/src/admin/util.js b/packages/docs/src/admin/util.js
new file mode 100644
index 000000000..53db2e8ec
--- /dev/null
+++ b/packages/docs/src/admin/util.js
@@ -0,0 +1,6 @@
+import helpers from '../_data/helpers';
+import dateFilter from '../filters/date-filter';
+import markdownFilter from '../filters/markdown-filter';
+import w3DateFilter from '../filters/w3-date-filter';
+
+export {helpers, dateFilter, markdownFilter, w3DateFilter};
diff --git a/packages/docs/src/archive.md b/packages/docs/src/archive.md
new file mode 100644
index 000000000..e594fe388
--- /dev/null
+++ b/packages/docs/src/archive.md
@@ -0,0 +1,5 @@
+---
+title: 'Posts Archive'
+layout: 'layouts/archive.njk'
+sitemapIgnore: true
+---
diff --git a/packages/docs/src/demos.md b/packages/docs/src/demos.md
new file mode 100644
index 000000000..d07d9d32f
--- /dev/null
+++ b/packages/docs/src/demos.md
@@ -0,0 +1,15 @@
+---
+layout: layouts/demos.njk
+title: Pattern Lab Demos
+category: getting-started
+sitemapPriority: '0.9'
+sitemapChangefreq: 'monthly'
+---
+
+
+
+Here’s a list of Pattern Lab’s UI starterkits that you can use to kickstart your UI design system project, as well as a list of Pattern Labs from around the web.
+
+
+
+
diff --git a/packages/docs/src/demos/bolt-design-systems.md b/packages/docs/src/demos/bolt-design-systems.md
new file mode 100644
index 000000000..107fd44fc
--- /dev/null
+++ b/packages/docs/src/demos/bolt-design-systems.md
@@ -0,0 +1,12 @@
+---
+title: Bolt Design System
+description: The Bolt Design System provides robust Twig and Web Component-powered UI components, reusable visual styles, and powerful tooling to help developers, designers, and content authors build, maintain, and scale best of class digital experiences.
+url: https://boltdesignsystem.com/
+category: example
+tags:
+ - demo-in-the-wild
+ - demo-content
+ - code
+refLink: https://boltdesignsystem.com/pattern-lab/?p=pages-d8-homepage
+sitemapIgnore: true
+---
diff --git a/packages/docs/src/demos/handlebars-base-starterkit.md b/packages/docs/src/demos/handlebars-base-starterkit.md
new file mode 100644
index 000000000..dccdb1107
--- /dev/null
+++ b/packages/docs/src/demos/handlebars-base-starterkit.md
@@ -0,0 +1,12 @@
+---
+title: Handlebars Base Starter Kit Preview
+description: The StarterKit for Handlebars is meant to be used as a demonstration of a Handlebars-based project in Pattern Lab.
+url: https://patternlab-handlebars-preview.netlify.com/?p=all
+category: starterkit
+tags:
+ - demo-hbs-starter-kits
+ - demo-content
+ - code
+refLink: https://patternlab-handlebars-preview.netlify.app/?p=all
+sitemapIgnore: true
+---
diff --git a/packages/docs/src/demos/handlebars-demo-starterkit.md b/packages/docs/src/demos/handlebars-demo-starterkit.md
new file mode 100644
index 000000000..6fc51cfa6
--- /dev/null
+++ b/packages/docs/src/demos/handlebars-demo-starterkit.md
@@ -0,0 +1,12 @@
+---
+title: Handlebars Demo Starter Kit
+description: The Demo StarterKit for Handlebars is meant to be used as a demonstration of a Handlebars-based project in Pattern Lab.
+url: https://www.npmjs.com/package/@pattern-lab/starterkit-handlebars-demo
+category: starterkit
+tags:
+ - demo-hbs-starter-kits
+ - demo-content
+ - code
+refLink: https://patternlab-handlebars-preview.netlify.app/?p=all
+sitemapIgnore: true
+---
diff --git a/packages/docs/src/demos/handlebars-vanilla-starterkit.md b/packages/docs/src/demos/handlebars-vanilla-starterkit.md
new file mode 100644
index 000000000..677c3cf29
--- /dev/null
+++ b/packages/docs/src/demos/handlebars-vanilla-starterkit.md
@@ -0,0 +1,12 @@
+---
+title: Handlebars Vanilla Starter Kit
+description: The Vanilla StarterKit for Handlebars is meant to be used as a demonstration of a Handlebars-based project in Pattern Lab.
+url: https://www.npmjs.com/package/@pattern-lab/starterkit-handlebars-vanilla
+category: starterkit
+tags:
+ - demo-hbs-starter-kits
+ - demo-content
+ - code
+refLink: https://patternlab-handlebars-preview.netlify.app/?p=all
+sitemapIgnore: true
+---
diff --git a/packages/docs/src/docs/a-post-with-code-samples.md b/packages/docs/src/docs/a-post-with-code-samples.md
new file mode 100644
index 000000000..dac628f4c
--- /dev/null
+++ b/packages/docs/src/docs/a-post-with-code-samples.md
@@ -0,0 +1,69 @@
+---
+title: DOCS DOCS DOCS
+tags:
+ - demo-content
+ - code
+ - blog
+eleventyNavigation:
+ key: DOCS DOCS DOCS
+ order: 300
+sitemapPriority: '0.8'
+sitemapIgnore: true
+---
+
+The best way to demo a code post is to display a real life post, so check out this one from [andy-bell.design](https://andy-bell.design/wrote/creating-a-full-bleed-css-utility/) about a full bleed CSS utility.
+
+---
+
+Sometimes you want to break your components out of the constraints that they find themselves in. A common situation where this occurs is when you don’t have much control of the container that it exists in, such as a CMS main content area.
+
+This is even more the case with editing tools such as the [WordPress Gutenberg editor](https://wordpress.org/gutenberg/), where in theory, you could pull in a component from a design system and utilise it in the main content of your web page. In these situations, it can be pretty darn handy to have a little utility that makes the element 100% of the viewport’s width _and_ still maintain its flow within its parent container.
+
+This is when I normally pull the `.full-bleed` utility class out of my back pocket.
+
+## The `.full-bleed` utility
+
+It’s small, but hella mighty:
+
+```css
+.full-bleed {
+ width: 100vw;
+ margin-left: 50%;
+ transform: translateX(-50%);
+}
+```
+
+Here it is in a context where it makes a fancy `` and a `` element bleed out of their parent container.
+
+
+
+The `.full-bleed` utility gives those elements prominence and _importantly_ keeps their semantic place in the page. Just how I like it.
+
+---
+
+🔥 **Pro tip**: When working with a utility like `.full-bleed`, it’s a good idea to add an inner container that has a max-width and auto horizontal margin. For this, I normal create a shared `.wrapper` component like this:
+
+```css
+.wrapper {
+ max-width: 50rem;
+ margin-left: auto;
+ margin-right: auto;
+}
+```
+
+Having a container like `.wrapper` helps to create consistent, centred content.
+
+---
+
+### How the `.full-bleed` utility works
+
+We set the container to be `width: 100vw`, which equates to the full viewport width. We couldn’t set it to `width: 100%` because it would only fill the space of its parent element. The parent element’s width _is_ useful though, because by setting `margin-left: 50%`, we are telling the component to align its **left edge** to the center of its parent element, because `50%` is half of the **parent element’s** width.
+
+Finally, we use CSS transforms to `translateX(-50%)`. Because the transform works off the element’s dimensions and not the parent’s dimensions, it’ll pull the element back `50vw`, because it’s `100vw` wide, thus making it sit perfectly flush with the viewport’s edges.
+
+## Wrapping up
+
+Hopefully this short and sweet trick will help you out on your projects. If it does, [drop me a tweet](https://twitter.com/andybelldesign), because I’d love to see it!
diff --git a/packages/docs/src/docs/advanced-auto-regenerate.md b/packages/docs/src/docs/advanced-auto-regenerate.md
new file mode 100644
index 000000000..ee07c4da5
--- /dev/null
+++ b/packages/docs/src/docs/advanced-auto-regenerate.md
@@ -0,0 +1,46 @@
+---
+title: Watching for Changes and Auto Regenerating Patterns
+tags:
+ - docs
+category: advanced
+eleventyNavigation:
+ key: Watching for Changes and Auto Regenerating Patterns
+ parent: advanced
+ order: 300
+sitemapPriority: '0.8'
+sitemapIgnore: true
+---
+
+Pattern Lab has the ability to watch for changes to patterns and frontend assets. When these files change, it will automatically rebuild the entire Pattern Lab website. You simply make your changes, save the file, and Pattern Lab will take care of the rest.
+
+## How to Start the Watch
+
+Open your terminal and navigate to the root of your project. Type:
+
+```
+gulp patternlab:build --watch
+```
+
+> If using grunt, substitute `grunt` for `gulp` above.
+
+## How to Start the Watch and Self-Host the Pattern Lab Website
+
+Rather than manually refreshing your browser when your patterns or frontend assets change you can have Pattern Lab watch for changes and [auto-reload your browser window](/docs/multi-browser-and-multi-device-testing-with-page-follow/) for you when it’s in watch mode.
+
+## How to Stop the Watch
+
+To stop watching files on Mac OS X and Windows you can press`CTRL+C` in the command line window where the process is running.
+
+## The Default Files That Are Watched
+
+By default, Pattern Lab monitors the following files:
+
+- all of the JSON files under `source/_annotations/`
+- all of the JSON files under `source/_data/`
+- all of the files under `source/_meta/`
+- all of the pattern templates under `source/_patterns/`
+- all of the CSS files under `source/css/`
+- all of the files under `source/images/` and `source/fonts/`
+- all of the Javascript files under `source/js/`
+
+The watch configuration is found within the Gruntfile or Gulpfile at the root of the project.
diff --git a/packages/docs/src/docs/advanced-config-options.md b/packages/docs/src/docs/advanced-config-options.md
new file mode 100644
index 000000000..460b79395
--- /dev/null
+++ b/packages/docs/src/docs/advanced-config-options.md
@@ -0,0 +1,469 @@
+---
+title: Editing the Configuration Options
+tags:
+ - docs
+category: getting-started
+eleventyNavigation:
+ key: getting-started
+ title: Editing the Configuration Options
+ order: 30
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Pattern Lab Node comes with a configuration file [(`patternlab-config.json`)](https://github.com/pattern-lab/patternlab-node/blob/master/packages/core/patternlab-config.json) that allows you to modify certain aspects of the system. The latest default values are included within. This file is shipped within [the editions](https://github.com/pattern-lab?utf8=%E2%9C%93&query=edition-node) or can be supplied from core and the command line interface. Below is a description of each configuration option and how it affects Pattern Lab Node.
+
+## cacheBust
+
+Instructs Pattern Lab to append a unique query string to Javascript and CSS assets throughout the frontend.
+
+```javascript
+"cacheBust": true
+```
+
+**default**: `true`
+
+## cleanPublic
+
+Sets whether or not to delete `public.patterns/` upon each build of Pattern Lab. When set to false, [incremental builds](https://github.com/pattern-lab/patternlab-node/wiki/Incremental-Builds) are also enabled.
+
+**default**: `true`
+
+## defaultPattern
+
+Sets a specific pattern upon launch of the styleguide. This pattern will not be available in the navigation, or in view all pages. The only way to get to it will be via a refresh. Set it using the [short-hand pattern-include syntax](/docs/including-patterns/):
+
+```javascript
+"defaultPattern": "pages-welcome",
+```
+
+A special value of `all` can also be supplied to display all patterns on load.
+
+**default**: `all`
+
+## defaultShowPatternInfo
+
+Sets whether or not you want the styleguide to load with the pattern info open or closed.
+
+**default**: `false`
+
+## defaultInitialViewportWidth (optional)
+
+Possibility to define whether the initial viewport width on opening pattern lab in the browser should take the default of `100%` (value `true`) or take the (permanently) persisted value after the users have interacted with the viewport resize buttons previously (value `false`). This is especially beneficial in case that you'd expect the pages in full viewport at revisits, and even further if your startpage is defined as a "static" markdown welcome / orientation page.
+
+**default**: `false`
+
+## defaultPatternInfoPanelCode (optional)
+
+Sets default active pattern info code panel by file extension - if unset, uses the value out of _patternExtension_ config value, or instead use value `html` to display the html code initially, or the value defined for the _patternExtension_.
+
+**default**: _patternExtension_ value (`"hbs"` | `"mustache"` | `"twig"` | `"html"`)
+
+## ishControlsHide
+
+Sets whether or not to hide navigation options within the styleguide.
+
+**default**:
+
+```javascript
+"ishControlsHide": {
+ "s": false,
+ "m": false,
+ "l": false,
+ "full": false,
+ "random": false,
+ "disco": false,
+ "hay": true,
+ "mqs": false,
+ "find": false,
+ "views-all": false,
+ "views-annotations": false,
+ "views-code": false,
+ "views-new": false,
+ "tools-all": false,
+ "tools-docs": false
+}
+```
+
+## ishViewportRange
+
+Sets the boundaries of each of the viewport toggles, 'S'mall, 'M'edium, and 'L'arge. Clicking on one of these buttons will randomly set the ish Viewport to a value within the given range. Setting the range to the same number can effectively set an exact value. The first entry in `ishViewportRange.s` is the `ishViewportMinimum`, which is now obsolete. The second entry in `ishViewportRange.l` is the `ishViewportMaximum`, which is now also obsolete.
+
+**default**:
+
+```javascript
+"ishViewportRange": {
+ "s": [240, 500],
+ "m": [500, 800],
+ "l": [800, 2600]
+},
+```
+
+## logLevel
+
+Sets the level of verbosity for Pattern Lab Node logging.
+
+- `error` will output a message as a thrown error
+- `warning` will output all warnings plus above
+- `info` will output all info messages, plus above (intended default)
+- `debug` will output all debug messages, plus above
+- `quiet` will output ZERO logs
+
+This replaces the now obsolete `debug` flag.
+
+**default**: `info`
+
+## noIndexHtmlremoval (optional)
+
+You might host your pattern lab in an environment that doesn't acknowledge the default file to be `index.html` in case that none is provided – Gitlab Pages is an example for this, where you might publish your preview builds to during development. So in case that you get a URL like `/index.html`, it will redirect to `/?p=all`. You might not be able to share this resulting URL or even do a refresh of the page, as the server would respond with a 404 error.
+
+To disable this redirect which is similar to how Single Page Applications work, you could set the optional configuration `"noIndexHtmlremoval"` to `true`.
+
+**default**: `false`
+
+## outputFileSuffixes
+
+Sets the naming of output pattern files. Suffixes are defined for 'rendered', 'rawTemplate', and 'markupOnly' files. This configuration is needed for some PatternEngines that use the same input and output file extensions. Most users will not have to change this.
+
+```javascript
+"outputFileSuffixes": {
+ "rendered": ".rendered",
+ "rawTemplate": "",
+ "markupOnly": ".markup-only"
+},
+```
+
+## paths
+
+Sets the configurable source and public directories for files Pattern Lab Node operates within. Build, copy, output, and server operations rely upon these paths. Some paths are relative to the current UIKit. See UIKit configuration for more info. Note the `patternlabFiles` which help create the front end styleguide. Note also the intentional repetition of the nested structure, made this way for maximum flexibility. These are unlikely to change unless you customize your environment or write custom UIKits.
+
+**default** :
+
+```javascript
+ "paths": {
+ "source": {
+ "root": "./source/",
+ "patterns": "./source/_patterns/",
+ "data": "./source/_data/",
+ "meta": "./source/_meta/",
+ "annotations": "./source/_annotations/",
+ "styleguide": "dist/",
+ "patternlabFiles": {
+ "general-header": "views/partials/general-header.mustache",
+ "general-footer": "views/partials/general-footer.mustache",
+ "patternSection": "views/partials/patternSection.mustache",
+ "patternSectionSubgroup": "views/partials/patternSectionSubgroup.mustache",
+ "viewall": "views/viewall.mustache"
+ },
+ "js": "./source/js",
+ "images": "./source/images",
+ "fonts": "./source/fonts",
+ "css": "./source/css"
+ },
+ "public": {
+ "root": "public/",
+ "patterns": "public/patterns/",
+ "data": "public/styleguide/data/",
+ "annotations": "public/annotations/",
+ "styleguide": "public/styleguide/",
+ "js": "public/js",
+ "images": "public/images",
+ "fonts": "public/fonts",
+ "css": "public/css"
+ }
+ },
+```
+
+## patternExtension
+
+Sets the panel name and language for the code tab on the styleguide. Since this only accepts one value, this is a place where mixed pattern trees (different PatternEngines in the same instance of Pattern Lab) does not quite work.
+
+**default**: `mustache`
+
+## engines
+
+An engine is a wrapper around a templating library like Handlebars, Twig or others. An [engine package](docs/template-language-and-patternengines/)
+is the bridge between Pattern Lab and the standalone NPM package supporting the templating language.
+
+`engines` accepts an map of Engine objects. The mandatory properties for each Pattern Lab engine are:
+
+- `package`: the NodeJS package name. Add the package of the engine as a dependency in `package.json` before you configure it here.
+- `fileExtensions`: list of pattern file extensions which will be handled by this pattern engine.
+
+Other engine specific configuration options can be added and will be passed to the pattern engine at loading time. See the NPM package documentation for the properties each pattern engine supports.
+
+**default**:
+
+```javascript
+ "engines": {
+ "handlebars": {
+ "package": "@pattern-lab/engine-handlebars",
+ "fileExtensions": [
+ "handlebars",
+ "hbs"
+ ],
+ "extend": "helpers/*.js"
+ ...
+ }
+ }
+```
+
+Configuring the engines in the config file was introduced in v5.14. The fallback lookup mode by scanning the
+`node_modules` folder is **deprecated** and will be removed in Pattern Lab v7.
+
+## patternStateCascade
+
+See the [Pattern State Documentation](/docs/using-pattern-states/)
+
+**default**:
+
+```javascript
+"patternStateCascade": ["inprogress", "inreview", "complete"],
+```
+
+## patternExportDirectory
+
+Sets the location that any export operations should output files to. This may be a relative or absolute path.
+
+**default**: `./pattern_exports/`
+
+## patternExportPatternPartials
+
+Sets an array of patterns (using the [short-hand pattern-include syntax](/docs/including-patterns/)) to be exported after a build.
+
+For example, to export the navigation, header, and footer, one might do:
+
+```javascript
+"patternExportPatternPartials": ["molecules-primary-nav", "organisms-footer", "organisms-header"],
+```
+
+**default**: `[]`
+
+## 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).
+
+- `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
+
+```javascript
+"patternMergeVariantArrays": true,
+```
+
+**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
+
+- `true` will render flat patterns on view all pages
+- `false` will make flat patterns available only in the menu
+
+```javascript
+"renderFlatPatternsOnViewAllPages": true,
+```
+
+**default**: `false` | `undefined`
+
+## serverOptions
+
+Sets [live-server options](https://github.com/pattern-lab/live-server#usage-from-node):
+
+| key | example value | description |
+|---------------|----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| port | 8181 | Set the server port. Defaults to 8080. |
+| host | "0.0.0.0" | Set the address to bind to. Defaults to 0.0.0.0 or process.env.IP. |
+| root | "/public" | Set root directory that's being served. Defaults to cwd. |
+| open | false | When false, it won't load your browser by default. |
+| ignore | 'scss,my/templates' | Live-Reload: Comma-separated string for paths to ignore from watching for changes in the filesystem. Use with caution: This would overwrite the default 'public' path, that's highly recommended to get ignored. |
+| ignorePattern | | Live-Reload: Regular expression for ignoring specific file types from being watched for changes in the filesystem. |
+| file | "index.html" | When set, serve this file for every 404 (useful for single-page applications). |
+| wait | 100 | Waits for all changes, before reloading. Defaults to 0 sec. |
+| mount | [['/components', './node_modules']] | Mount a directory to a route. |
+| logLevel | 2 | 0 = errors only, 1 = some, 2 = lots |
+| middleware | [function(req, res, next) { next(); }] | Takes an array of Connect-compatible middleware that are injected into the server middleware stack |
+| https | 'ssl/ssl.js' | adding the path to a configuration module for HTTPS dev servers, see detailed explanation on the[`running patternlab` page](/docs/running-pattern-lab/#heading-running-localhost-via-https) |
+
+**default**:
+
+```javascript
+"serverOptions": {
+ "wait": 1000
+},
+```
+
+## starterkitSubDir
+
+[Starterkits](/docs/starterkits/) by convention house their files within the `dist/` directory. Should someone ever wish to change this, this key is available.
+
+**default**:
+
+```javascript
+"starterkitSubDir": "dist",
+```
+
+## styleGuideExcludes
+
+Sets whole pattern types to be excluded from the "All" patterns page on the styleguide. This is useful to decrease initial load of the styleguide. For example, to exlude all patterns under `templates` and `pages`, add the following:
+
+```javascript
+"styleGuideExcludes": [
+ "templates",
+ "pages"
+]
+```
+
+These template and page patterns would still be accessible via navigation.
+
+**default**: `[]`
+
+## theme
+
+Sets the theme options for the styleguide. There are five options:
+* `"color"`
+* `"density"`
+* `"layout"`
+* `"noViewAll"` (optional)
+* `"logo"` (optional)
+
+Available values are:
+
+```javascript
+"theme" : {
+ "color" : "dark" | "light",
+ "density" : "compact" | "cozy" | "comfortable",
+ "layout" : "horizontal" | "vertical",
+ "noViewAll" : true | false,
+ "logo": {
+ "text": "Pattern Lab",
+ "altText": "Pattern Lab Logo",
+ "url": "./",
+ "srcLight": "styleguide/images/pattern-lab-logo--on-light.svg",
+ "srcDark": "styleguide/images/pattern-lab-logo--on-dark.svg",
+ "width": "187",
+ "height": "185"
+ }
+}
+```
+
+See the [initial release notes](https://github.com/pattern-lab/styleguidekit-assets-default/releases/tag/v4.0.0-alpha.2) for the theme feature for example output on `"color"`, `'density"` and `"layout"`.
+
+`"noViewAll"` provides the possibility to hide the "View All" pages and links within the navigation.
+
+And `"logo"` lets you finetune the different aspects of the logo displayed on the left top corner of the styleguide.
+
+**default**:
+
+```javascript
+"theme" : {
+ "color" : "dark",
+ "density" : "compact",
+ "layout" : "horizontal"
+}
+```
+
+## transformedAssetTypes (optional)
+
+Prevent specific filetypes being copied from your `source` to your `public` folder like e.g. CSS preprocessor source files (`.scss`), you could specify those within an array of your pattern lab config:
+
+```javascript
+"transformedAssetTypes": [
+ "scss"
+]
+```
+
+**default**: `[]`
+
+## uikits
+
+Introduced in Pattern Lab Node v3, UIKits are a new term in the Pattern Lab [Ecosystem](/docs/overview-of-pattern-lab's-ecosystem/). They are an evolution of the original Styleguidekit pattern which separated front-end templates from front-end assets like stylesheets and code. The existing `styleguidekit-assets-default` and `styleguidekit-mustache-default` have merged into `uikit-workshop`.
+
+`uikits` accepts an array of UIKit objects, shipping with the one above.
+
+- `name`: the name of the UIKit
+- `package`: the NodeJS package name. This property was introduced in version 5.13 to allow for a uikit package to be used multiple times with different names. Add the package as a dependency in `package.json` before you configure it here.
+- `outputDir` where to output this UIKit relative to the current root. By leaving this empty we retain the existing Pattern Lab 2.X behavior, outputting to `/public`. If you had multiple UIKits, however, you would provide different values, such as:
+
+```javascript
+ "uikits": [
+ {
+ "name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
+ "outputDir": "workshop",
+ ...
+ },
+ {
+ "name": "uikit-storefront",
+ "package": "@pattern-lab/uikit-storefront",
+ "outputDir": "storefront",
+ ...
+ }
+ ]
+```
+
+- `enabled`: quickly turn on or off the building of this UIKit
+- `excludedPatternStates`: tell Pattern Lab not to include patterns with these states in this UIKit's output
+- `excludedTags`: tell Pattern Lab not to include patterns with these tags in this UIKit's output
+
+Important details:
+
+- the [default `paths.source` object paths](https://github.com/pattern-lab/patternlab-node/pull/840/commits/a4961bd5d696a05fb516cdd951163b0f918d5e19) within `patternlab-config.json` are now relative to the current UIKit. See the [structure of uikit-workshop](https://github.com/pattern-lab/patternlab-node/tree/master/packages/uikit-workshop) for more info
+- the [default `paths.public` object paths](https://github.com/pattern-lab/patternlab-node/pull/840/commits/812bab3659f504043e8b61b1dc1cdac71f248449) within `patternlab-config.json` are now relative to the current UIKit's `outputDir`. Absolute paths will no longer work. Someone could test putting an absolute path in a UIKit `outputDir` property and see what happens I suppose.
+- `dependencyGraph.json` has moved to the project root rather than `public/` as we should only retain one
+- The lookup of the uikit by `name` is **deprecated** and will be removed in v7. The user will be notified of it. If the `package` property isn't defined, there is a default fallback lookup strategy where the value of `name` is tried as:
+ - ``
+ - `uikit-`
+ - `@pattern-lab/`
+ - `@pattern-lab/uikit-`
+
+**default**:
+
+```javascript
+ "uikits": [
+ {
+ "name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
+ "outputDir": "",
+ "enabled": true,
+ "excludedPatternStates": [],
+ "excludedTags": []
+ }
+ ]
+```
+
+## Pattern Engine-Twig
+### loadExtensionFile
+Adding custom TwingExtensions to `engine-twig` via setting a filename in
+
+```javascript
+"engine": {
+ "twig": {
+ "loadExtensionFile": ""
+ }
+}
+```
+
+- `loadExtensionFile`: filename in Patternlab root directory. Details: [engine-twig readme](https://github.com/pattern-lab/patternlab-node/blob/dev/packages/engine-twig/README.md)
diff --git a/packages/docs/src/docs/advanced-ecosystem-overview.md b/packages/docs/src/docs/advanced-ecosystem-overview.md
new file mode 100644
index 000000000..74d95894e
--- /dev/null
+++ b/packages/docs/src/docs/advanced-ecosystem-overview.md
@@ -0,0 +1,72 @@
+---
+title: Overview of Pattern Lab's Ecosystem
+tags:
+ - docs
+category: advanced
+eleventyNavigation:
+ key: advanced
+ title: Overview of Pattern Lab's Ecosystem
+ order: 300
+sitemapPriority: '0.8'
+---
+
+Pattern Lab 2 introduces the beginnings of an ecosystem that will allow teams to mix, match and extend Pattern Lab to meet their specific needs. It will also make it easier for the Pattern Lab team to push out new features. Documentation that explains how best to take advantage of the ecosystem will be released in the coming weeks.
+
+## Editions
+
+Editions let teams and agencies bundle all the things that support their unique workflows with Pattern Lab. An Edition can become the starting point for all of your projects while teams share and update functionality. The Node version of Pattern Lab uses [npm](https://www.npmjs.com/) to pull in separate components.
+
+## Components of an Edition
+
+The following is good overview of what components might make up an edition:
+
+
+
+This is by no means exhaustive and can be added to as needed. Here is a description of each component:
+
+### Pattern Lab Core
+
+Core is the guts of Pattern Lab and enables all of the other features. Because Core is standalone a team can update and stay current with the latest Pattern Lab features without disrupting the rest of their project.
+
+### StarterKits
+
+Have a trusty set of boilerplate code that you start every project with? Perhaps a common set of basic patterns, Sass mix-ins, and JavaScript libraries that are your go-to tools? A StarterKit is perfect for bundling these assets together into a boilerplate that makes sure each project starts off on the right foot.
+
+[Several starterkits](https://github.com/pattern-lab?utf8=%E2%9C%93&q=starterkit&type=&language=) already exist to kick your project off, whether you’re looking for a blank start, begin with a demo that showcases Pattern Lab’s features, or start with a popular framework like Bootstrap, Foundation, or Material Design. And you can roll your own, which can be fully version-controlled so your team’s StarterKit can evolve along with your tools.
+
+Importing a starterkit is only a few keystrokes away after installation.
+
+[Learn more about Starterkits](/docs/starterkits/)
+
+### UIKits
+
+UIKits are the front-end of Pattern Lab. We call this “The Viewer.” UIKits allow agencies and organizations to develop custom, branded Pattern Lab UIs to show off their patterns.
+
+### PatternEngines
+
+PatternEngines are the templating engines that are responsible for parsing patterns and turning them into HTML. PatternEngines give Pattern Lab Core the flexibility to render many different types of template languages. Current PatternEngines include Mustache and Twig, with others like Handlebars and Underscore in development. And there’s no stopping you from adding another templating engine to Pattern Lab.
+
+### Plugins
+
+Plugins allow developers to extend Pattern Lab Core and other parts of the ecosystem. Pattern Lab’s architecture allows developers to modify data at different stages, add their own commands or pattern rules, or change the front-end to modify and extend Pattern Lab’s capabilities.
+
+#### Node Plugins
+
+Currently the following plugins are provided by the community:
+* [plugin-tab](https://github.com/pattern-lab/patternlab-node/tree/master/packages/plugin-tab): Displaying sibling files next to a pattern in the filesystem as further code tab panels
+* [plugin-node-minify-html](https://github.com/JosefBredereck/plugin-node-minify-html): Patternlab Node HTML tabs panel compressor/minifier/beautifier
+* [patternlab-plugin-node-wrappable](https://github.com/networkteam/patternlab-plugin-node-wrappable): Configuration to wrap patterns styleguide HTML output (e.g. for inverse backgrounds)
+* [plugin-node-patternlab-inline-assets](https://github.com/michaelworm/plugin-node-patternlab-inline-assets): Consume and inline assets (out of the file system) into your templates before compiling
+* [plugin-node-patternlab-inline-remote-assets](https://github.com/mfranzke/plugin-node-patternlab-inline-remote-assets): Consume and inline remote assets (from a URL) into your templates before compiling
+* [plugin-node-uiextension](https://github.com/bmuenzenmeyer/plugin-node-uiextension): Provide a simple Patternlab chrome customization path versus forking the `StyleguideKit` / `UIKit`
+ * [@mfranzke/plugin-node-uiextension](https://github.com/mfranzke/plugin-node-uiextension): A fork of the previous plugin that mainly ensures Pattern Lab version 5 compability and enhances by some new features.
+
+Please feel to contribute and [add your plugin to this list as well](https://github.com/pattern-lab/patternlab-node/edit/dev/packages/docs/src/docs/advanced-ecosystem-overview.md).
+
+### Other Types of Components
+
+The flexibility of the Pattern Lab ecosystem means that teams can develop tools on top of Pattern Lab that meet _their_ needs. Want to standardize and push entire data sets to teams? Want to develop with granular collections of components instead of entire StarterKits? Only want to customize the CSS for the default StyleguideKit and distribute it as part of your projects? All of this and more is possible. We feel we're just scratching the surface on what it means to develop projects and design systems with a tool like Pattern Lab
+
+## Guidance and Help
+
+If you have ideas or would like guidance before we have all of the documentation done please learn how you can [engage with the Pattern Lab community](/support/).
diff --git a/packages/docs/src/docs/advanced-exporting-patterns.md b/packages/docs/src/docs/advanced-exporting-patterns.md
new file mode 100644
index 000000000..57f20c41b
--- /dev/null
+++ b/packages/docs/src/docs/advanced-exporting-patterns.md
@@ -0,0 +1,22 @@
+---
+title: Exporting Patterns
+tags:
+ - docs
+category: advanced
+eleventyNavigation:
+ title: Exporting Patterns
+ key: advanced
+ order: 300
+sitemapPriority: '0.8'
+---
+
+While the Pattern Lab website is great for design, iteration, alignment, and discussion - you may find yourself wanting to export whole pattern markup snippets into a different environment.
+
+In Pattern Lab Node, `patternlab-config.json` has two properties that work together to export completed patterns for use elsewhere. To export, provide an array of patternPartials and an output directory. Pattern Lab Node doesn't ship with any patternPartials specified for export. The default directory,`'./pattern_exports/'`, is created inside the install directory. Here is an example with three patternPartials set.
+
+```javascript
+"patternExportPatternPartials": ["molecules-primary-nav", "organisms-header", "organisms-footer"],
+"patternExportDirectory": "./pattern_exports/"
+```
+
+Couple this technique with exported CSS via tools like [grunt-contrib-copy](https://github.com/gruntjs/grunt-contrib-copy) to really make patterns portable.
diff --git a/packages/docs/src/docs/advanced-keyboard-shortcuts.md b/packages/docs/src/docs/advanced-keyboard-shortcuts.md
new file mode 100644
index 000000000..e2fddd3c1
--- /dev/null
+++ b/packages/docs/src/docs/advanced-keyboard-shortcuts.md
@@ -0,0 +1,37 @@
+---
+title: Keyboard Shortcuts
+tags:
+ - docs
+category: advanced
+eleventyNavigation:
+ title: Keyboard Shortcuts
+ key: advanced
+ order: 300
+sitemapPriority: '0.8'
+---
+
+> **Note:** This feature is currently disabled. It will be back in a future release of `styleguidekit-assets-default`.
+
+Pattern Lab comes with support for a number of special keyboard shortcuts to make using Pattern Lab easier. These are broken up by where they work or are most useful.
+
+Modifying the viewport:
+
+- **ctrl+alt+0**: set the viewport to 320px
+- **ctrl+alt+s**: set the viewport to "small"
+- **ctrl+alt+m**: set the viewport to "medium"
+- **ctrl+alt+l**: set the viewport to "large"
+- **ctrl+alt+h**: toggle Hay mode
+- **ctrl+alt+d**: toggle disco mode
+
+Modifying the views:
+
+- **ctrl+shift+a**: open/close info panels
+- **ctrl+shift+c**: open/close info panels
+- **cmd+a/ctrl+a**: select the content of the current open tab in code view
+- **ctrl+shift+u**: make the Mustache tab active
+- **ctrl+shift+y**: make the HTML tab active
+- **esc**: close the open view
+
+Other:
+
+- **ctrl+shift+f**: open/close the pattern search
diff --git a/packages/docs/src/docs/advanced-pattern-lab-nav.md b/packages/docs/src/docs/advanced-pattern-lab-nav.md
new file mode 100644
index 000000000..a27d4bb0b
--- /dev/null
+++ b/packages/docs/src/docs/advanced-pattern-lab-nav.md
@@ -0,0 +1,34 @@
+---
+title: Modifying Pattern Lab's Navigation
+tags:
+ - docs
+category: advanced
+eleventyNavigation:
+ title: Modifying Pattern Lab's Navigation
+ key: advanced
+ order: 300
+sitemapPriority: '0.8'
+---
+
+When sharing Pattern Lab with a client it may be beneficial to turn-off certain elements in the default navigation. To turn-off navigation elements, alter the flags inside the `ishControlsHide` object within `patternlab-config.json` and then re-generate the site. The following keys are supported and will hide their respective elements if toggled on:
+
+```javascript
+"ishControlsHide": {
+ "s": false,
+ "m": false,
+ "l": false,
+ "full": false,
+ "random": false,
+ "disco": false,
+ "hay": true,
+ "find": false,
+ "views-all": false,
+ "views-annotations": false,
+ "views-code": false,
+ "views-new": false,
+ "tools-all": false,
+ "tools-docs": false
+},
+```
+
+By default all navigation elements are visible except Hay Mode.
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...
+```
diff --git a/packages/docs/src/docs/advanced-starterkits.md b/packages/docs/src/docs/advanced-starterkits.md
new file mode 100644
index 000000000..87777da66
--- /dev/null
+++ b/packages/docs/src/docs/advanced-starterkits.md
@@ -0,0 +1,59 @@
+---
+title: Starterkits
+tags:
+ - docs
+category: advanced
+eleventyNavigation:
+ title: Starterkits
+ key: advanced
+ order: 300
+sitemapPriority: '0.8'
+---
+
+Starterkits are a potent way create or augment a Pattern Lab instance with a baseline set of patterns and assets. They are an important part of the [Pattern Lab Ecosystem](/docs/overview-of-pattern-lab's-ecosystem/) An agency or team could use it for each new client or project. [Several starterkits](https://github.com/pattern-lab?utf8=%E2%9C%93&q=starterkit&type=&language=) already exist to kick your project off, whether you’re looking for a blank start, begin with a demo that showcases Pattern Lab’s features, or start with a popular framework like Bootstrap, Foundation, or Material Design.
+
+## Structure
+
+A Starterkit's structure mirrors that of the default file structure of Pattern Lab. Usually this is found under the `dist/` directory:
+
+```
+_annotations/
+_data/
+_meta/
+_patterns/
+css/
+fonts/
+images/
+js/
+favicon.ico
+```
+
+Teams constructing their own Starterkits should stick to this structure if they wish to publish it externally, else may alter the structure to their [configured `paths`](/docs/editing-the-configuration-options/).
+
+## Installing Starterkits
+
+Open your terminal and navigate to the root of your project. Type:
+
+```
+npm install [starterkit-name]
+gulp patternlab:loadstarterkit --kit=[starterkit-name]
+```
+
+where [starterkit-name] is the name of the Starterkit.
+
+so... a complete example:
+
+```
+npm install @pattern-lab/starterkit-mustache-demo
+gulp patternlab:loadstarterkit --kit=@pattern-lab/starterkit-mustache-demo
+```
+
+The [Pattern Lab Node CLI](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli) will also support installation of Starterkits should you not be using gulp.
+
+## PSA
+
+**LOADING A STARTERKIT WILL OVERWRITE ANY MATCHES INSIDE `./source`** Users can pass another flag `--clean=true` to attempt to delete the contents of `./source` prior to load.
+
+- Sometimes users will run into file permissions issues. It's recommended to run all command prompts as administrator if you can.
+
+`patternlab-config.json` also defines a `starterkitSubDir` key (with a default value of `dist`) which can be used to target a directory inside the starterkit module if need be.
diff --git a/packages/docs/src/docs/advanced-template-language-and-pattern-engines.md b/packages/docs/src/docs/advanced-template-language-and-pattern-engines.md
new file mode 100644
index 000000000..0ad36ebe3
--- /dev/null
+++ b/packages/docs/src/docs/advanced-template-language-and-pattern-engines.md
@@ -0,0 +1,29 @@
+---
+title: Template Language and PatternEngines
+heading: Template Language and PatternEngines
+patternEnginesScript: true
+category: advanced
+eleventyNavigation:
+ title: Template Language and PatternEngines
+ key: advanced
+ order: 300
+sitemapPriority: '0.8'
+---
+
+By default Pattern Lab uses the Mustache template language, extended with [pattern parameters](/docs/using-pattern-parameters/). PatternEngines let you add support for a template language of your personal choice. Each PatternEngine has it's own set of features and caveats.
+
+Right now the most mature PatternEngines are Handlebars, Mustache and Twig.
+
+## Official PatternEngines for Node
+
+
+
+## Install and Configure a PatternEngine
+
+1. Install a new PatternEngine that you wish to use. For example, to install the Handlebars engine, run `npm install --save @pattern-lab/engine-handlebars`.
+2. (Optional) Change the `"patternExtension"` property of your config. This sets the panel name and language for the code tab on the styleguide.
+
+You'll need to restart Pattern Lab for changes to take effect. Some PatternEngines may provide further configuration.
diff --git a/packages/docs/src/docs/changes-1-to-2.md b/packages/docs/src/docs/changes-1-to-2.md
new file mode 100644
index 000000000..98abb3a67
--- /dev/null
+++ b/packages/docs/src/docs/changes-1-to-2.md
@@ -0,0 +1,11 @@
+---
+title: Pattern Lab 1 to Pattern Lab 2 Changes
+tags:
+ - docs
+eleventyNavigation:
+ title: Pattern Lab 1 to Pattern Lab 2 Changes
+ order: 300
+sitemapIgnore: true
+---
+
+The list of features is coming soon.
diff --git a/packages/docs/src/docs/data-json-mustache.md b/packages/docs/src/docs/data-json-mustache.md
new file mode 100644
index 000000000..1e6b5689f
--- /dev/null
+++ b/packages/docs/src/docs/data-json-mustache.md
@@ -0,0 +1,115 @@
+---
+title: Introduction to JSON & Mustache Variables
+tags:
+ - docs
+category: data
+eleventyNavigation:
+ title: Introduction to JSON & Mustache Variables
+ key: data
+ order: 300
+sitemapPriority: '0.8'
+---
+
+> This documentation is provided as a simple introduction to using one of the supported data types and one of the supported PatternEngines. The best reference for this topic is the [Mustache documentation](https://mustache.github.io/mustache.5.html) but this should provide a good beginner's primer.
+
+## Simple Variables
+
+At its core JSON is a simple key-value store. This means that any piece of data in JSON has a key and a value. The key is the name of an attribute and the value is what should be shown when that attribute is referenced. Here's a simple example:
+
+```javascript
+"src": "../../images/fpo_avatar.png"
+```
+
+In this case the key is `src` and the value is `../../images/fpo_avatar.png`. Let's look at how we might reference this data in a pattern template. Mustache variables are denoted by the double-curly braces (or mustaches).
+
+```html
+
+```
+
+The Mustache variable is `{% raw %}{{ src }}{% endraw %}`. Note that `src` matches the name of the key in our JSON example. When the Node version of Pattern Lab compile this template the end result will be:
+
+```html
+
+```
+
+Note that `{% raw %}{{ src }}{% endraw %}` was replaced by the value for `src` found in our JSON example.
+
+## Nested Variables
+
+We may want our JSON file to be a little more organized and our Mustache variable names to be a little more descriptive. For example, maybe we have multiple image sizes that we want to provide image sources for. We might organize our JSON key-values this way:
+
+```javascript
+"square": {
+ "src": "../../images/fpo_square.png",
+ "alt": "Square",
+ "width": "600",
+ "height": "600"
+},
+"avatar": {
+ "src": "../../images/fpo_avatar.png",
+ "alt": "Avatar",
+ "width": "300",
+ "height": "300"
+}
+```
+
+Note how their are attributes ( `src`, `alt`, `width`, `height` ) nested within a larger container ( `square` ). Also note how the attributes are separated by commas. If we wanted to use the attributes for the square image in our pattern we'd write:
+
+```html
+
+```
+
+This would compile to:
+
+```html
+
+```
+
+This nesting makes it easier to read how the attributes are organized in our patterns. The default `data.json` file has several examples of this type of nesting of attributes.
+
+## Rendering HTML in Variables
+
+You may want to include HTML in your variables. By default, Mustache will convert HTML mark-up to their HTML entity equivalents. For example, our JSON may look like:
+
+```javascript
+"lyrics": "Just good ol' boys , wouldn't change if they could, fightin' the system like a true modern day Robin Hood."
+```
+
+Based on our previous Mustache examples you would probably write out your template like so:
+
+```html
+TV Show Lyrics
+{% raw %}{{ lyrics }}{% endraw %}
+```
+
+Unfortunately, that would compile as:
+
+```html
+TV Show Lyrics
+
+ Just <em>good ol' boys</em>, wouldn't change if they could,
+ <strong>fightin'</strong> the system like a true modern day Robin Hood.
+
+```
+
+In order to make sure the mark-up doesn't get converted you must use _triple_ curly brackets like so:
+
+```html
+TV Show Lyrics
+{% raw %}{{{ lyrics }}}{% endraw %}
+```
+
+Now it would compile correctly:
+
+```html
+TV Show Lyrics
+
+ Just good ol' boys , wouldn't change if they could,
+ fightin' the system like a true modern day Robin Hood.
+
+```
diff --git a/packages/docs/src/docs/data-link-variable.md b/packages/docs/src/docs/data-link-variable.md
new file mode 100644
index 000000000..6069b7115
--- /dev/null
+++ b/packages/docs/src/docs/data-link-variable.md
@@ -0,0 +1,43 @@
+---
+title: Linking to Patterns with Pattern Lab's Default `link` Variable
+category: data
+eleventyNavigation:
+ title: Linking to Patterns with Pattern Lab's Default `link` Variable
+ key: data
+ order: 100
+sitemapPriority: '0.8'
+---
+
+You can build patterns that link to one another to help simulate using a real website. This is especially useful when working with the Pages and Templates pattern types. Rather than having to remember the actual path to a pattern you can use the same shorthand syntax you'd use to include one pattern within another. **Important:** Pattern links _do not_ support the same fuzzy matching of names as the shorthand partials syntax does. The basic format is:
+
+```html
+{% raw %}{{ link.pattern-name }}{% endraw %}
+```
+
+For example, if you wanted to add a link to the `article` page from your `blog` page you could write the following:
+
+```html
+Article Headline
+```
+
+This would compile to:
+
+```html
+Article Headline
+```
+
+Additionally, you can use pattern links within JSON to link to other pages, templates, or patterns within Pattern Lab. For instance, if you had a pattern containing the following:
+
+```html
+This is a link
+```
+
+You can set the URL to a pattern link via JSON like so:
+
+```javascript
+{
+ "url" : "link.pages-article"
+}
+```
+
+Using pattern links in JSON is especially helpful at keeping the pattern's structure and content entirely separate.
diff --git a/packages/docs/src/docs/data-overview.md b/packages/docs/src/docs/data-overview.md
new file mode 100644
index 000000000..c4d0a0a38
--- /dev/null
+++ b/packages/docs/src/docs/data-overview.md
@@ -0,0 +1,39 @@
+---
+title: Overview of Data
+tags:
+ - docs
+category: data
+eleventyNavigation:
+ title: Overview of Data
+ key: data
+ order: 300
+sitemapPriority: '0.8'
+---
+
+The primary default global source of data used when rendering Pattern Lab patterns can be found in `./source/_data/`.
+
+## Supported Data Formats
+
+The Node version of Pattern Lab only supports JSON.
+
+## Locations for Data
+
+There are three places to store data in Pattern Lab:
+
+- in `./source/_data`.
+- in [pattern-specific](/docs/creating-pattern-specific-values/) files in `./source/_patterns`.
+- in [pseudo-pattern](/docs/using-pseudo-patterns/) files in `./source/_patterns`.
+
+### A Special Note About Pattern Parameters
+
+[Pattern parameters](/docs/using-pattern-parameters/) are a simple find and replace of variables in the included pattern. As such they do not affect the context stack of Mustache and we don't consider them true data. They have no impact on overall data inheritance and they cannot be used any deeper than the included pattern. They are a hack.
+
+## Data Inheritance
+
+Data inheritance in Pattern Lab follows this flow:
+
+```
+Pattern-specific data for the pattern being rendered > Global data in _data
+```
+
+The only data that is loaded to render a pattern is its own data and global data. It will not include the data for any included patterns. For example, the pages template, `article`, might include the molecule, `block-hero`. `block-hero` may have its own pattern-specific data file, `block-hero.json`. The Node version of Pattern Lab **will not** use the `block-hero` data when rendering `article`. It will only use `article.json` (_if available_) and data found in `./source/_data`.
diff --git a/packages/docs/src/docs/data-pattern-specific.md b/packages/docs/src/docs/data-pattern-specific.md
new file mode 100644
index 000000000..d2863fa49
--- /dev/null
+++ b/packages/docs/src/docs/data-pattern-specific.md
@@ -0,0 +1,51 @@
+---
+title: Creating Pattern-specific Values
+tags:
+ - docs
+category: data
+eleventyNavigation:
+ title: Creating Pattern-specific Values
+ key: data
+ order: 300
+sitemapPriority: '0.8'
+---
+
+> **Note:** This article uses JSON because it is a standard between with the Node version of Pattern Lab.
+
+Storing data for your atoms, molecules, and organisms in `./source/_data` may work just fine. When fleshing out templates and pages, where data may need to be unique to each page even if they use the same molecules and organisms, data stored in `./source/_data` can become cumbersome. In order to work around this the Node version of Pattern Lab allows you to define pattern-specific data files that allow you to override the default values found in `./source/_data`.
+
+## Setting Up Pattern-specific Data
+
+In order to tell the Node version of Pattern Lab to use pattern-specific data to override the default global data create a JSON file with the same name as the pattern and put it in the same directory as the pattern. For example, if you wanted to provide pattern-specific data for the `article` pattern under the pattern type `pages` your `pages` directory would look like this:
+
+```
+pages/article.mustache
+pages/article.json
+```
+
+## Overriding the Default Variables
+
+To override the global data using pattern-specific data make sure the latter has the same variable names as the former. For example, the 4x3 landscape image source may look like this in `data.json`:
+
+```javascript
+"landscape-4x3": {
+ "src": "../../images/fpo-landscape-4x3.jpg",
+ "alt": "Landscape 4x3 Image"
+}
+```
+
+In our pattern-specific data file, `article.json`, we'd simply copy that structure and provide our own information:
+
+```javascript
+"landscape-4x3": {
+ "src": "../../images/a-team-hero.jpg"
+}
+```
+
+Now the article pattern will display an image of the A-Team when using `{% raw %}{{ landscape-4x3.src }}{% endraw %}`. All other patterns using `{% raw %}{{ landscape-4x3.src }}{% endraw %}` will display the default 4x3 image. Also, note that we **didn't** override the `landscape-4x3.alt` attribute. If we were to use that attribute in our pattern the default value, "Landscape 4x3 Image", would be displayed.
+
+**Important note:** You don't have to override every attribute. You can limit the data in your pattern-specific data file to just those variables you want. The Node version of Pattern Lab will fallback to using the default attributes from `data.json` if the attributes aren't defined in the pattern-specific data file.
+
+## Working With Includes
+
+The only data that is loaded to render a pattern is its own data and global data. It will not include the data for any included patterns. For example, the pages template, `article`, might include the molecule, `block-hero`. `block-hero` may have its own pattern-specific data file, `block-hero.json`. The Node version of Pattern Lab **will not** use the `block-hero` data when rendering `article`. It will only use `article.json` (_if available_) and data found in `./source/_data`.
diff --git a/packages/docs/src/docs/docs.json b/packages/docs/src/docs/docs.json
new file mode 100644
index 000000000..688f78f76
--- /dev/null
+++ b/packages/docs/src/docs/docs.json
@@ -0,0 +1,3 @@
+{
+ "layout": "layouts/docs.njk"
+}
diff --git a/packages/docs/src/docs/editing-source-files.md b/packages/docs/src/docs/editing-source-files.md
new file mode 100644
index 000000000..a4755fc6f
--- /dev/null
+++ b/packages/docs/src/docs/editing-source-files.md
@@ -0,0 +1,86 @@
+---
+title: Editing Pattern Lab Source Files
+tags:
+ - docs
+category: getting-started
+eleventyNavigation:
+ title: Editing Pattern Lab Source Files
+ key: getting-started
+ order: 20
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+When editing Pattern Lab you must put your files and edit them in the `./source/` directory. This includes your static assets like [JavaScript, CSS, and images](/docs/managing-pattern-assets/). Each time your site is generated your patterns will be compiled and your static assets will be moved to the `./public/` directory. Because of this you **should not edit** the files in the `./public/` directory.
+
+## Pattern Lab Directories
+
+For the most part you can organize `./source/` anyway you see fit. There are a few Pattern Lab-specific directories though. They are:
+
+- `_annotations/` - where your annotations reside. [learn more about adding annotations](/docs/adding-annotations/).
+- `_data/` - where the global data used to render your patterns resides. [learn more about (pattern) data](/docs/overview-of-data/).
+- `_meta/` - where the header and footer that get applied to all of your patterns resides. [learn more about meta files](/docs/modifying-the-pattern-header-and-footer/).
+- `_patterns/` - where your patterns, pattern documentation, and pattern-specific data reside. [learn more about how to organize patterns](/docs/reorganizing-patterns/).
+
+## Configuring Pattern Lab Directories
+
+All Pattern Lab directories can be configured to suit your needs.
+
+```js
+// base directories
+exportDir: 'value'; // default is exports. where clean mark-up sans PL code is exported to.
+publicDir: 'value'; // default is public
+sourceDir: 'value'; // default is source
+
+// exportDir is the base directory for the following directories (e.g. ./exports/patterns)
+patternExportDir: 'value'; // default is patterns
+
+// publicDir is the base directory for the following directories (e.g. ./public/patterns)
+componentDir: 'value'; // default is patternlab-components. where plugin components are installed.
+patternPublicDir: 'value'; // default is patterns
+
+// sourceDir is the base directory for the following directories (e.g. ./source/_patterns)
+annotationsDir: 'value'; // default is _annotations
+dataDir: 'value'; // default is _data
+metaDir: 'value'; // default is _meta
+patternSourceDir: 'value'; // default is _patterns
+```
+
+In the Node version of Pattern Lab you can modify the following configuration options in `patternlab-config.json`:
+
+```javascript
+"paths" : {
+ "source" : {
+ "root": "./source/",
+ "patterns" : "./source/_patterns/",
+ "data" : "./source/_data/",
+ "meta": "./source/_meta/",
+ "annotations" : "./source/_annotations/",
+ "styleguide" : "./node_modules/styleguidekit-assets-default/dist/",
+ "patternlabFiles" : "./node_modules/styleguidekit-mustache-default/views/",
+ "js" : "./source/js",
+ "images" : "./source/images",
+ "fonts" : "./source/fonts",
+ "css" : "./source/css/"
+ },
+ "public" : {
+ "root" : "./public/",
+ "patterns" : "./public/patterns/",
+ "data" : "./public/styleguide/data/",
+ "annotations" : "./public/annotations/",
+ "styleguide" : "./public/styleguide/",
+ "js" : "./public/js",
+ "images" : "./public/images",
+ "fonts" : "./public/fonts",
+ "css" : "./public/css"
+ }
+}
+```
+
+## Problems after changing the structure
+
+If you're doing bigger changes, especially to the file and folder structure, and recognize some errors on the console like, e.g. `TypeError: Cannot read property 'render' of undefined` or `Error building BuildFooterHTML`, it's recommended to stop pattern lab, delete the cache file `dependencyGraph.json` within the root of the project and start pattern lab again, as these changes might conflict with the existing cache structures.
+
+## Watching for Source File Changes
+
+Manually generating the Pattern Lab website after each change can be cumbersome. The Node version of Pattern Lab comes with the ability to watch files in the `./source/` directory for changes and re-generate the site automatically. The Pattern Lab website can also be automatically reloaded.
diff --git a/packages/docs/src/docs/installation.md b/packages/docs/src/docs/installation.md
new file mode 100644
index 000000000..62f522780
--- /dev/null
+++ b/packages/docs/src/docs/installation.md
@@ -0,0 +1,58 @@
+---
+title: Installing Pattern Lab
+tags:
+ - docs
+category: getting-started
+eleventyNavigation:
+ title: Installing Pattern Lab
+ key: getting-started
+ order: 0
+sitemapPriority: '0.9'
+sitemapChangefreq: 'monthly'
+---
+
+## Step 1: Install requirements
+
+Make sure you have [Node.js](https://nodejs.org/en/download/) installed before setting up Pattern Lab, e.g. by checking for the node version: `node -v`
+
+Please make sure to have at minimum version node 7 installed, but even better at least the node version that's being mentioned in [.nvmrc](https://github.com/pattern-lab/patternlab-node/blob/dev/); [Node version manager](https://github.com/nvm-sh/nvm) might be a good option if you can't update.
+
+## Step 2: Run the create Pattern Lab command
+
+Open [the command line](https://tutorial.djangogirls.org/en/intro_to_command_line/) and run the following command:
+
+```
+npm create pattern-lab
+```
+
+This will bring up an installation menu that presents the following steps:
+
+## Step 3: Choose a directory
+
+**`Please specify a directory for your Pattern Lab project.`** Choose the directory where you want to install Pattern Lab. The default location is the current directory.
+
+## Step 4: Choose templating language
+
+**`What templating language do you want to use with Pattern Lab?`** This determines what templating engine you'll use to author components. The options are:
+
+- **`Handlebars`** - uses the [Handlebars](https://handlebarsjs.com/) templating engine
+- **`Twig (PHP)*`** - uses the [Twig](https://twig.symfony.com/) templating engine
+
+**\*A note on Twig:** while Pattern Lab is powered by Node, behind the scenes Twig files are compiled by Twig PHP, _not_ by twig.js (which isn't fully on par with Twig PHP).
+
+## Step 5: Choose initial patterns
+
+**`What initial patterns do you want included in your project?`** - Choose the [Starterkit](/docs/starterkits/) you want to begin your project with. The options are:
+
+- **`Handlebars base patterns`** `(some basic patterns to get started with)`
+- **`Handlebars demo patterns`** `(full demo website and patterns)`
+- **`Twig (PHP) demo patterns`** `(full demo website and patterns)`
+- **`Custom starterkit`** - point to a custom Pattern Lab starterkit TODO: include instructions on including custom starterkits
+- **`Blank project (no patterns)`** - This won't include any initial patterns in your project so you can start completely from scratch
+
+You can find all starter kits on our [demos page](/demos/)
+
+## Step 6: Confirm your choices
+
+**`Are you happy with your choices? (Hit enter for YES)?`** - Confirm your choices, and when done the Pattern Lab installation will begin.
+
diff --git a/packages/docs/src/docs/pattern-add-new.md b/packages/docs/src/docs/pattern-add-new.md
new file mode 100644
index 000000000..bad9986f2
--- /dev/null
+++ b/packages/docs/src/docs/pattern-add-new.md
@@ -0,0 +1,27 @@
+---
+title: Adding New Patterns
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Adding New Patterns
+ key: patterns
+ order: 70
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+To add new patterns to the Node version of Pattern Lab just add new Mustache templates under the appropriate pattern type or pattern subgroup directories in `./source/_patterns`. For example, let's add a new pattern under the pattern type "molecules" and the pattern sub-type "blocks". The `./source/_patterns/molecules/blocks/` directory looks like:
+
+ block-hero.mustache
+ headline-byline.mustache
+ media-block.mustache
+
+If we want to add a new pattern we simply tack it onto the end:
+
+ block-hero.mustache
+ headline-byline.mustache
+ media-block.mustache
+ new-pattern.mustache
+
+If you want more control over their ordering please refer to "[Reorganizing Patterns](/docs/reorganizing-patterns/)."
diff --git a/packages/docs/src/docs/pattern-adding-annotations.md b/packages/docs/src/docs/pattern-adding-annotations.md
new file mode 100644
index 000000000..1062a5abb
--- /dev/null
+++ b/packages/docs/src/docs/pattern-adding-annotations.md
@@ -0,0 +1,73 @@
+---
+title: Adding Annotations
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Adding Annotations
+ key: patterns
+ order: 180
+sitemapPriority: '0.8'
+---
+
+Annotations provide an easy way to add notes to elements that may appear inside patterns. Annotations can be saved as a single JSON file at `./source/_annotations/annotations.json` or as multiple Markdown files in `./source/_annotations/`. They're _not_ tied to any specific patterns. When annotations are active they are compared against every pattern using a CSS selector syntax.
+
+## The Elements of an Annotation
+
+The elements of an annotation are:
+
+- **el** - the selector to be used to attach the annotation to a pattern
+- **title** - the title for a given annotation
+- **comment** - the description for a given annotation
+
+## JSON Example
+
+This is an example of an annotation saved as part of `annotations.json` that will be added to an element with the class `logo`:
+
+```javascript
+{
+ "el": ".logo",
+ "title" : "Logo",
+ "comment": "The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don't support SVG images.Further reading: Optimizing Web Experiences for High Resolution Screens
"
+}
+```
+
+Compare to e.g. [`handlebars` annotations](https://github.com/pattern-lab/patternlab-node/blob/dev/packages/starterkit-handlebars-demo/dist/_annotations/annotations.json) or [`twig` annotations](https://github.com/pattern-lab/patternlab-node/blob/dev/packages/starterkit-twig-demo/dist/_annotations/annotations.json) editions demo content as well.
+
+## Markdown Example
+
+This is an example of an annotation saved as part of `annotations.md` that will be added to an element with the class `logo`:
+
+```
+---
+el: .logo
+title: Logo
+---
+The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don't support SVG images.
+
+Further reading: [Optimizing Web Experiences for High Resolution Screens](https://bradfrost.com/blog/mobile/hi-res-optimization/)
+```
+
+To separate multiple annotations within one file use `~*~` between annotations.
+
+```
+---
+el: .logo
+title: Logo
+---
+The logo image is an SVG file, which ensures that the logo displays crisply even on high resolution displays. A PNG fallback is provided for browsers that don't support SVG images.
+
+Further reading: [Optimizing Web Experiences for High Resolution Screens](https://bradfrost.com/blog/mobile/hi-res-optimization/)
+~*~
+---
+el: .hamburger
+title: Sandwiches Considered Harmful
+---
+According to everyone, hamburger menus are not obvious, and obvious always wins.
+
+Further reading: [Hamburger Menus and Hidden Navigation Hurt UX Metrics](https://www.nngroup.com/articles/hamburger-menus/)
+```
+
+## Viewing Annotations
+
+In order to view annotations click "Show Pattern Info" in the Pattern Lab toolbar.
diff --git a/packages/docs/src/docs/pattern-documenting.md b/packages/docs/src/docs/pattern-documenting.md
new file mode 100644
index 000000000..e0bddca33
--- /dev/null
+++ b/packages/docs/src/docs/pattern-documenting.md
@@ -0,0 +1,74 @@
+---
+title: Documenting Patterns
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Documenting Patterns
+ key: patterns
+ order: 110
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Pattern documentation gives developers and designers the ability to provide context for their patterns and subgroups. The documentation file consists of Markdown with YAML front matter. It should follow this format:
+
+```
+---
+title: Title for my pattern
+---
+This is a *Markdown* description of my pattern.
+```
+
+Attributes overview:
+* The `title` attribute is used in Pattern Lab's navigation as well as in the styleguide views. Format: `string`
+* Pattern `tags` has to be an array, like `tags: [new, relaunch, dev]`
+* [Pattern `states`](/docs/using-pattern-states/) are defined like `state: incomplete` and [provide a simple visual indication](/docs/using-pattern-states/)
+* The `order` property to [Reorganize Patterns](/docs/reorganizing-patterns/)
+* The `hidden` property to [Hide Patterns in the Navigation](/docs/hiding-patterns-in-the-navigation/)
+
+Both `tags` and `states` could be used for [not including patterns in a UIKit specific build](/docs/editing-the-configuration-options/#heading-uikits).
+
+The `description` is used in the styleguide views.
+
+Pattern documentation needs to have a `.md` file extension and match the name of the pattern it's documenting. For example, to document the following pattern:
+
+ atoms/images/landscape-16x9.mustache
+
+We'd name our documentation file:
+
+ atoms/images/landscape-16x9.md
+
+## Documenting Pseudo-Patterns
+
+To add documentation to [pseudo-patterns](/docs/using-pseudo-patterns/), create an companion `.md` file for that pseudo-pattern.
+
+For example, to document the following pseudo-pattern:
+
+```
+atoms/button/button~red.mustache
+```
+
+We'd name our documentation file:
+
+```
+atoms/button/button~red.md
+```
+
+## Documenting Subgroups
+
+
+To document pattern subgroups, you need to create a companion `.md` file for that subgroup. For example create `_patters/atoms/buttons/_buttons.md` for a pattern subgroup. In the `.md` file, the above concept can be applied. The doc-file resolving works the following `{patternsRoot}/{pattern-group folder name}/{pattern-sub-group folder name}/_{pattern-sub-group raw name without prefixes}.md`
+
+
+```markdown
+
+This is a *Markdown* description of the subgroup button.
+```
+
+In the future we'll even also provide the possibility to document groups as well.
+
+## Adding More Attributes to the Front Matter
+
+A future update of Pattern Lab will support more front matter attributes including: excludeFromStyleguide and links.
+It will also support adding custom attributes that could be utilized by plugins. For example, GitHub issues related to patterns.
diff --git a/packages/docs/src/docs/pattern-header-footer.md b/packages/docs/src/docs/pattern-header-footer.md
new file mode 100644
index 000000000..b7f561995
--- /dev/null
+++ b/packages/docs/src/docs/pattern-header-footer.md
@@ -0,0 +1,28 @@
+---
+title: Modifying the Pattern Header & Footer
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Modifying the Pattern Header & Footer
+ key: patterns
+ order: 130
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+To add your own assets like JavaScript and CSS to your patterns' header and footer you need to modify two files:
+
+- `./source/_meta/_head.mustache`
+- `./source/_meta/_foot.mustache`
+
+These files are added to every rendered pattern, "view all" page and style guide. To see your changes simply re-generate your site.
+
+## Important: Don't Remove Two Things...
+
+**Do not remove the following two lines in these patterns:**
+
+- a tag referencing `patternLabHead` in `_head.mustache`
+- a tag referencing `patternLabFoot` in `_foot.mustache`
+
+Pattern Lab will not so mysteriously stop working if you do.
diff --git a/packages/docs/src/docs/pattern-hiding.md b/packages/docs/src/docs/pattern-hiding.md
new file mode 100644
index 000000000..e511bed4f
--- /dev/null
+++ b/packages/docs/src/docs/pattern-hiding.md
@@ -0,0 +1,61 @@
+---
+title: Hiding Patterns in the Navigation
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Hiding Patterns in the Navigation
+ key: patterns
+ order: 170
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Removing a pattern from Pattern Lab's drop-down navigation and style guide is accomplished by setting the `hidden` frontmatter key on any pattern's companion `.md` file. For example, we may have a Google Map-based pattern that we don't need for a particular project. The path might look like:
+
+ molecules/media/map.mustache
+
+We would create or edit a file in the same location, calling it `map.md`:
+
+```
+---
+hidden: true
+---
+The map component...
+```
+
+## Hiding Pattern Groups
+
+The same concept applies to `pattern-groups`. For example, you have a `pattern-group` named `atoms`, and you create a companion `.md` file for that group under `_patters/atoms/_atoms.md`. In that case, the whole `pattern-group` and all its components will be hidden in the UI. The doc-file resolving works the following `{patternsRoot}/{pattern-group folder name}/_{pattern-group raw name without prefixes}.md`
+
+```
+---
+hidden: true
+---
+# _atoms.md file
+```
+
+## Hiding Pattern Sub Groups
+
+The same concept applies to `pattern-sub-groups`. For example, you have a `pattern-sub-group` named `buttons` which is structured under `atoms`, and you create a companion `.md` file for that group under `_patters/atoms/buttons/_buttons.md`. In that case, the whole `pattern-sub-group` and all its components will be hidden in the UI. The doc-file resolving works the following `{patternsRoot}/{pattern-group folder name}/{pattern-sub-group folder name}/_{pattern-sub-group raw name without prefixes}.md`
+
+```
+---
+hidden: true
+---
+# _buttons.md file
+```
+
+## Additional Information
+
+A hidden pattern can still be included in other patterns.
+
+## Deactivate deprecation warning
+
+To deactivate the deprecation warning for hidden patterns, add
+
+```
+disableDeprecationWarningForHiddenPatterns: true
+```
+
+to the `patternlab-config.json`
diff --git a/packages/docs/src/docs/pattern-including.md b/packages/docs/src/docs/pattern-including.md
new file mode 100644
index 000000000..7e60fa338
--- /dev/null
+++ b/packages/docs/src/docs/pattern-including.md
@@ -0,0 +1,80 @@
+---
+title: Including Patterns
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Including Patterns
+ key: patterns
+ order: 90
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+To include one pattern within another, for example to create a molecule from several atoms, you can either use:
+
+- a shorthand include syntax or
+- the default include syntax for the template language you're using (e.g. Mustache, Twig, Handlebars).
+
+## The Shorthand Include Syntax
+
+The shorthand include syntax is less verbose than the default include syntax for many template languages. The shorthand syntax uses the following format:
+
+ [patternGroup]-[patternName]
+
+For example, to include the following pattern in a molecule:
+
+ atoms/images/landscape-16x9.mustache
+
+The shorthand include syntax would be:
+
+ atoms-landscape-16x9
+
+The pattern type matches the top-level folder and is `atoms`. The pattern name matches the template file and is `landscape-16x9`. Any digits used in the filename for ordering (which is deprecated, use [the order parameter](/docs/reorganizing-patterns/) instead) are _dropped_ from both the pattern type and pattern name references. Pattern subgroups are _never_ a part of the shorthand include syntax. This way patterns can be re-organized within a pattern type and/or by using digits (which is deprecated, use [the order parameter](/docs/reorganizing-patterns/) instead) without needing to change your pattern includes.
+
+The following are examples of using the shorthand include syntax with our supported PatternEngines:
+
+```
+{% raw %}{{> atoms-landscape-16x9 }} // Mustache{% endraw %}
+{% raw %}{% include "atoms-landscape-16x9" %} // Twig{% endraw %}
+```
+
+The shorthand syntax also allows for fuzzy matching on pattern names. This means that if you feel your pattern name is going to be unique within a given pattern type you can supply just the unique part of the pattern name and the partial will be included correctly. For example, using the shorthand syntax the pattern `atoms-landscape-16x9.mustache` could be written as:
+
+ atoms-16x9
+
+_Warning:_ Because subgroups are not included in the shorthand include syntax a given pattern name needs to be unique within its _pattern type_ and not just its pattern subgroup. If you run into this problem you can do one of two things:
+
+- use the default include syntax for your template language or
+- give your pattern a unique name and use [the pattern's documentation](/docs/documenting-patterns/) to provide the pattern name
+
+## The Default Include Syntax
+
+If you need more specificity when including patterns the Node version of Pattern Lab also support the include syntax for the template language that you're using. For example, the syntax for Mustache is the path to the pattern minus the `.mustache` extension. Let's say we wanted to include the following pattern in a molecule:
+
+ atoms/images/landscape-16x9.mustache
+
+The default Mustache include syntax would be:
+
+```handlebars
+{% raw %}{{> atoms/images/landscape-16x9 }}{% endraw %}
+```
+
+**Important:** Unlike the shorthand include syntax the template language specific include syntax **must** include any digits used for ordering (which is deprecated, use [the order parameter](/docs/reorganizing-patterns/) instead) and subgroup directories. Pattern paths need to be updated when either is changed for a given pattern.
+
+## Examples and Gotchas
+
+Here are some examples of how to include patterns as well as some gotchas.
+
+```handlebars
+{% raw %}// partials to match
+atoms/global/test.mustache
+atoms/global/test-with-picture.mustache
+
+// using the shorthand partials syntax
+{{> atoms-test }} // will match atoms/global/test.mustache
+{{> atoms-test-with-picture }} // will match atoms/global/test-with-picture.mustache
+
+// using the default mustache partials syntax
+{{> atoms/global/test }} // will match atoms/global/test.mustache{% endraw %}
+```
diff --git a/packages/docs/src/docs/pattern-linking.md b/packages/docs/src/docs/pattern-linking.md
new file mode 100644
index 000000000..abab4b087
--- /dev/null
+++ b/packages/docs/src/docs/pattern-linking.md
@@ -0,0 +1,114 @@
+---
+title: Pattern Lab's Special Query String Variables
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Pattern Lab's Special Query String Variables
+ key: patterns
+ order: 100
+sitemapPriority: '0.8'
+---
+
+Pattern Lab comes with support for a number of special query string variables to help you share patterns with clients. These query string variables include ways to link to patterns, set the Pattern Lab viewport to a specific width, open various views as well as start Hay and disco modes on page load. There are lots of options:
+
+- [Linking to Specific Patterns](#link-pattern)
+- [Setting the Default Width for the Viewport](#default-width)
+- [Opening Annotations View on Page Load](#annotations-view)
+- [Opening Code View on Page Load](#code-view)
+- [Starting Hay Mode on Page Load](#hay-mode)
+- [Starting Disco Mode on Page Load](#disco-mode)
+
+## Linking to Specific Patterns
+
+You can link directly to any pattern listed on the Pattern Lab website. This might be useful when asking clients for feedback on a particular template or page pattern. If you want to [link from one pattern to another use the `link` variable](/docs/linking-to-patterns-with-pattern-lab's-default-link-variable/).
+
+### Copy & Paste
+
+The simplest method is to copy the address found in the address bar.
+
+### Manually Creating the Link
+
+It's also very easy to create a link manually. Simply append `?p=pattern-name` to the end of the address for your Pattern Lab website. For example, if we wanted to link to the `templates-article` pattern we'd add the following to the address for our Pattern Lab website:
+
+```
+?p=templates-article
+```
+
+The direct link feature supports the [shorthand partials syntax](/docs/including-patterns/) found in the Node version of Pattern Lab. Just provide part of a pattern name and Pattern Lab will attempt to resolve it.
+
+## Setting the Default Width for the Viewport
+
+You can load a specific viewport size by using the `w` query string variable.
+
+```
+http://patternlab.localhost/?w=320 (sets the viewport to 320px)
+http://patternlab.localhost/?w=400px (sets the viewport to 400px)
+http://patternlab.localhost/?w=40em (sets the viewport to 40em or 640px)
+```
+
+And it works with the `p` query string variable so you can also do:
+
+```
+http://patternlab.localhost/?p=atoms-landscape-4x3&w=400px
+```
+
+## Opening Annotations View on Page Load
+
+When sending a particular pattern to a client for review you may not want to include directions for how to open annotations. You can force the annotations view to open on page load by using the `view` query string variables with the values `annotations` or `a`:
+
+```
+http://patternlab.localhost/?p=templates-homepage&view=annotations
+http://patternlab.localhost/?p=templates-homepage&view=a
+```
+
+You can also force the annotations panel to scroll to a particular item by including the query string variable `number`. To scroll to the fifth element in the list of annotations you'd do the following:
+
+```
+http://patternlab.localhost/?p=templates-homepage&view=annotations&number=5
+```
+
+## Opening Code View on Page Load
+
+When sending a particular pattern to a client for review you may not want to include directions for how to open the code view. You can force the code view to open on page load by using the `view` query string variables with the values `code` or `c`:
+
+```
+http://patternlab.localhost/?p=templates-homepage&view=code
+http://patternlab.localhost/?p=templates-homepage&view=c
+```
+
+You can also force the HTML tab mark-up to be highlighted for copying by including the query string variable `copy`.
+
+```
+http://patternlab.localhost/?p=templates-homepage&view=code©=true
+```
+
+## Starting Hay Mode on Page Load
+
+You can start Hay mode automatically when the page is loaded by using the `h` or `hay` query string variables.
+
+```
+http://patternlab.localhost/?h=true
+http://patternlab.localhost/?hay=true
+```
+
+And it works with the `p` query string variable so you can also do:
+
+```
+http://patternlab.localhost/?p=atoms-landscape-4x3&h=true
+```
+
+## Starting Disco Mode on Page Load
+
+You can start disco mode automatically when the page is loaded by using the `d` or `disco` query string variables.
+
+```
+http://patternlab.localhost/?d=true
+http://patternlab.localhost/?disco=true
+```
+
+And it works with the `p` query string variable so you can also do:
+
+```
+http://patternlab.localhost/?p=atoms-landscape-4x3&d=true
+```
diff --git a/packages/docs/src/docs/pattern-managing-assets.md b/packages/docs/src/docs/pattern-managing-assets.md
new file mode 100644
index 000000000..6771ef0b6
--- /dev/null
+++ b/packages/docs/src/docs/pattern-managing-assets.md
@@ -0,0 +1,72 @@
+---
+title: Managing Pattern Assets
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Managing Pattern Assets
+ key: patterns
+ order: 120
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Assets for patterns - including JavaScript, CSS, and images - should be stored and edited in the `./source/` directory. Pattern Lab will move these assets to the `./public/` directory for you when you generate your site or when you watch the `./source/` directory for changes. _You can name and organize your assets however you like._ If you would like to use `./source/stylesheets/` to store your styles instead of `./source/css/` you can do that. The structure will be maintained when they're moved to the `./public/` directory.
+
+Pattern Lab ships with copy tasks in the `Gruntfile.js` or `Gulpfile.js` of [the Editions](https://github.com/pattern-lab/?utf8=%E2%9C%93&query=edition-node) that copy your assets for you.
+
+This structure is meant to be extended to suit your purposes. Change targets, move files, or ignore certain filetypes altogether. **Note**: If you make changes to `Gruntfile.js` or `Gulpfile.js`, such as to copy a new directory, and have auto re-generation and browser reload enable, you will need to stop and start your tasks to pick up the changes.
+
+## Configuring Asset Locations
+
+Pattern Lab has a configuration object which allows users to separate source patterns and assets from what is generated. The paths are managed within `patternlab-config.json`, found at the root of the edition project. The contents are sampled here:
+
+```javascript
+ "paths" : {
+ "source" : {
+ "root": "./source/",
+ "patterns" : "./source/_patterns/",
+ "data" : "./source/_data/",
+ "meta": "./source/_meta/",
+ "annotations" : "./source/_annotations/",
+ "styleguide" : "./node_modules/styleguidekit-assets-default/dist/",
+ "patternlabFiles" : "./node_modules/styleguidekit-mustache-default/views/",
+ "js" : "./source/js",
+ "images" : "./source/images",
+ "fonts" : "./source/fonts",
+ "css" : "./source/css/"
+ },
+ "public" : {
+ "root" : "./public/",
+ "patterns" : "./public/patterns/",
+ "data" : "./public/styleguide/data/",
+ "annotations" : "./public/annotations/",
+ "styleguide" : "./public/styleguide/",
+ "js" : "./public/js",
+ "images" : "./public/images",
+ "fonts" : "./public/fonts",
+ "css" : "./public/css"
+ }
+ }
+```
+
+Note how some sets of files even extend into the "vendor" `./node_modules/` directory. Relative paths are the default but absolute paths are supported also. You may also use these paths within the Grunt or Gulp taskfiles by referring to the `paths()` function.
+
+## Preprocessed files
+
+In case you're using a preprocessor to e.g. compile TypeScript files to JavaScript files, or SCSS/SASS files to CSS files, you might want to use your solution of choice, that perfectly fits your needs. Pattern Lab doesn't restrict you at all on this, and as well doesn't deliver any defaults for the general pattern files. So e.g. you could install [`sass` node package](https://www.npmjs.com/package/sass) to compile `.scss` files, add a script to your `package.json` as well, and let those files get generated at the `./source/css` folder.
+
+You might want to even also ignore those source files from being copied over to your `public` folders, as they won't need to get delivered to a hosting environment, which we describe in the next section.
+
+## Preventing specific filetypes from being copied
+
+If you'd like to prevent specific filetypes from being copied from your `source` to your `public` folder like e.g. CSS preprocessor source files (`.scss`), you could specify those within an array of your pattern lab config:
+``` json
+{
+ "transformedAssetTypes": ["scss"],
+}
+```
+
+## Adding Assets to the Pattern Header & Footer
+
+Static assets like Javascript and CSS **are not** added automagically to your patterns. You need to add them manually to the [shared pattern header and footer](/docs/modifying-the-pattern-header-and-footer/).
diff --git a/packages/docs/src/docs/pattern-organization.md b/packages/docs/src/docs/pattern-organization.md
new file mode 100644
index 000000000..9119fac98
--- /dev/null
+++ b/packages/docs/src/docs/pattern-organization.md
@@ -0,0 +1,65 @@
+---
+title: Overview of Patterns
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Overview of Patterns
+ key: patterns
+ order: 10
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Patterns can be found in `./source/_patterns/`. Patterns must be written in the template languages supported by Pattern Lab's PatternEngines. For Node there are [several more PatternEngines to choose from](/docs/template-language-and-patternengines/).
+
+## How Patterns Are Organized
+
+Patterns are organized in a nested folder structure under `./source/_patterns/`. This allows the Node version of Pattern Lab to automatically find and build assets like the "view all" pages and the drop down navigation. Pattern Lab uses the following organizational structure:
+
+ [patternGroup]/[patternSubgroup]/[patternName].[patternExtension]
+
+Here are the parts:
+
+- `patternGroup` denotes the overall pattern type. If using Atomic Design this will be something like "atoms" or "molecules" but it can be anything you want. For example, "components" or "elements."
+- `patternSubgroup` denotes the sub-type of pattern and is _optional_. This helps to organize patterns under an overall pattern type in the drop downs in Pattern Lab. For example, a "blocks" pattern subgroup under the "molecules" pattern type.
+- `patternName` is the name of the pattern. This is used when the pattern is displayed in the drop downs in Pattern Lab.
+- `patternExtension` is the file extension that tells the PatternEngine to render the pattern. For example, `.mustache`.
+
+Dashes (`-`) in your pattern types, pattern subgroups or pattern names will be replaced with spaces. For example, if you want a pattern to be displayed in the drop-down as "Hamburger Navigation" and you're using the Mustache PatternEngine you should name it `hamburger-navigation.mustache`.
+
+## Pattern Type Naming Conventions
+
+You do **not** have to use the Atomic Design naming convention when organizing your patterns. You can name your pattern types whatever you like and use as many or as few as you like. For example, you could use the pattern types Nachos, Tacos, and Burritos instead of Atoms, Molecules, and Organisms.
+
+## Ordering
+
+By default, pattern types, pattern subgroups and patterns are ordered alphabetically. If you want more control over their ordering please refer to "[Reorganizing Patterns](/docs/reorganizing-patterns/)."
+
+## Deeper Nesting
+
+Node versions support nesting of folders under `patternSubgroup`. For example, you may want to organize your [pattern documentation](/docs/documenting-patterns/), pattern, Sass files and [pseudo-patterns](/docs/using-pseudo-patterns/) in one directory like so:
+
+ - molecules/
+ - blocks/
+ - media-block/
+ - media-block.md
+ - media-block.mustache
+ - media-block.scss
+ - media-block~variant1.json
+ - media-block~variant2.json
+
+In this example the `media-block/` directory is ignored for the purposes of generating breadcrumbs and navigation in the Pattern Lab front-end but the documentation, pattern and pseudo-patterns are still rendered.
+
+Folders can be nested under `media-block/` if desired but this is discouraged because of possible collisions when using the [shorthand partial syntax](/docs/including-patterns/).
+
+### Deeper Nesting Settings
+
+As documented in [Documenting Patterns](/docs/documenting-patterns/) there are several options to handle the patterns state or add additional information.
+
+The `deeplyNested` attribute is used to toggle the pattern building behavior and toggles the deeper nesting.
+
+- **deeplyNested not set or false** - Pattern won't be handled as a deeply nested pattern
+- **deeplyNested: true** - Pattern will be handled like mentioned under [Deeper Nesting](#heading-deeper-nesting)
+
+To turn on this behavior globally, just add `"allPatternsAreDeeplyNested": true` to your `patternlab-config.json`.
diff --git a/packages/docs/src/docs/pattern-parameters.md b/packages/docs/src/docs/pattern-parameters.md
new file mode 100644
index 000000000..c41130647
--- /dev/null
+++ b/packages/docs/src/docs/pattern-parameters.md
@@ -0,0 +1,14 @@
+---
+title: Using Pattern Parameters
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Using Pattern Parameters
+ key: patterns
+ order: 150
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Passing parameters parameters to included patterns are a **simple** mechanism for replacing variables in an included pattern, by each of the standard ways of how to do it either in handlebars ([Partial Parameters](https://handlebarsjs.com/guide/partials.html#partial-parameters)) or twig ([include with `with` keyword](https://twig.symfony.com/doc/3.x/tags/include.html#:~:text=You%20can%20add%20additional%20variables%20by%20passing%20them%20after%20the%20with%20keyword%3A)) template language. They are limited to replacing variables in the included pattern and **only** the included pattern. They are especially useful when including a single pattern multiple times in a molecule, template, or page and you want to supply unique data to that pattern each time it's included.
diff --git a/packages/docs/src/docs/pattern-pseudo-patterns.md b/packages/docs/src/docs/pattern-pseudo-patterns.md
new file mode 100644
index 000000000..397cc39bc
--- /dev/null
+++ b/packages/docs/src/docs/pattern-pseudo-patterns.md
@@ -0,0 +1,83 @@
+---
+title: Using Pseudo-Patterns
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Using Pseudo-Patterns
+ key: patterns
+ order: 140
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Pseudo-patterns give developers and designers the ability to quickly build multiple unique variants of an existing pattern. This feature is especially useful when developing template- and page-style patterns or showing the states of other patterns.
+
+## The Pseudo-Pattern File Naming Convention
+
+Pseudo-patterns are similar to [pattern-specific JSON files](/docs/creating-pattern-specific-values/) but are hinted in such a way that a developer can build a variant of an existing pattern. The basic syntax:
+
+ patternName~pseudo-pattern-name.json
+
+The tilde (`~`) and `.json` file extension are the hints that Pattern Lab uses to determine that this is a pseudo-pattern. The `patternName` tells Pattern Lab which existing pattern it should use when rendering the pseudo-pattern. The JSON file itself works exactly like the [pattern-specific JSON file](/docs/creating-pattern-specific-values/). It has the added benefit that the pseudo-pattern will also inherit any values from the existing pattern's pattern-specific JSON file.
+
+## The Pseudo-Pattern File Data
+
+By default, arrays in pseudo-pattern data will be merged with the base pattern's array data on an index basis, effectively creating an array having as many entries as the larger of the two, with the indices declared in the variant replacing the first n of the parent, while keeping the rest. Declaring a larger array in the variant results in only using the variant array. To override this behavior globally you can set the parameter `patternMergeVariantArrays` in your `patternlab-config.json` to `false`. Arrays will then be overwritten and you will only have the variant's array data left.
+
+```json
+"patternMergeVariantArrays": false
+```
+
+From a navigation and naming perspective `patternName` and `pseudoPatternName` will be combined.
+
+## Adding Pseudo-Patterns to Your Project
+
+Adding a pseudo-pattern is as simple as naming it correctly and following the [pattern-specific JSON file](/docs/creating-pattern-specific-values/) instructions for organizing its content. Let's look at a simple example where we want to show an emergency notification on our homepage Mustache template. Our `templates/` directory might look like this:
+
+ article.mustache
+ blog.mustache
+ homepage.mustache
+
+Our `homepage.mustache` template might look like this:
+
+```html
+{% raw %}
+
+ {{# emergency }}
+
Oh Noes! Emergency!
+ {{/ emergency }} { ...a bunch of other content... }
+
+{% endraw %}
+```
+
+If our `_data.json` file doesn't give a value for `emergency` that section will never show up when `homepage.mustache` is rendered. Obviously we'd need to show _both_ the regular and emergency states of the homepage but we don't want to duplicate the entire `homepage.mustache` template. That would be a maintenance nightmare. So let's add our pseudo-pattern:
+
+```
+article.mustache
+blog.mustache
+homepage.mustache
+homepage~emergency.json
+```
+
+In our pseudo-pattern, `homepage~emergency.json`, we add our `emergency` attribute:
+
+```javascript
+{% raw %}{
+ "emergency": true
+}{% endraw %}
+```
+
+Now when we generate our site we'll have our homepage template rendered twice. Once as the regular template and once as a pseudo-pattern showing the emergency section. Note that the pseudo-pattern will show up in our navigation as `Homepage Emergency`.
+
+## Using Pseudo-Patterns as Pattern Includes
+
+By default, pseudo-patterns **cannot** be used as pattern includes. The data included in the pseudo-pattern, the bit that actually controls the magic, cannot be accessed when rendering the pattern include.
+
+## Re-ordering Pseudo-Patterns
+
+To learn how to re-order pseudo-patterns, check the documentation for [Reorganizing Patterns](/docs/reorganizing-patterns/).
+
+## Documenting Pseudo-Patterns
+
+To learn how to document pseudo-patterns, check the documentation for [Documenting Patterns](/docs/documenting-patterns/) to learn more.
diff --git a/packages/docs/src/docs/pattern-reorganizing.md b/packages/docs/src/docs/pattern-reorganizing.md
new file mode 100644
index 000000000..1d2b80242
--- /dev/null
+++ b/packages/docs/src/docs/pattern-reorganizing.md
@@ -0,0 +1,120 @@
+---
+title: Reorganizing Patterns
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Reorganizing Patterns
+ key: patterns
+ order: 80
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+By default, the Node version of Pattern Lab organizes pattern groups, pattern subgroups, and patterns alphabetically when displaying them in the drop-down navigation, pattern subgroup "view all" pages, and the "all" style guide. This may not meet your needs. You can re-order pattern groups, pattern subgroups, and patterns by prefixing them with two-digit numbers.
+
+For example, we'll look at how we can re-organize patterns. Using alphabetical ordering the `lists` pattern subgroup in `atoms` looks like:
+
+```
+definition.mustache
+ordered.mustache
+unordered.mustache
+```
+
+This is also the order they'll show up in the drop-down navigation. Because you rarely need to see the definition list pattern, maybe you want to have it show up last in the navigation. To re-order the patterns add the parameter `order` to the documentation `.md` file of the pattern. If no documentation `.md` file exists, you can create one:
+
+The default value for `order` is `0`. That's why there is no file for `ordered.mustache` required.
+
+```
+---
+order: 2
+---
+# definition.md
+```
+
+```
+---
+order: 1
+---
+# unordered.md
+```
+
+Result
+
+```
+ordered.mustache
+unordered.mustache
+definition.mustache
+```
+
+## Re-ordering Pseudo-Patterns
+
+The rules for re-ordering [pseudo-patterns](/docs/using-pseudo-patterns/) are slightly different than normal patterns. By default, the `order` parameter will be inherited from the main-pattern but can be overwritten by creating a documentation `.md` file for the pattern variant and set the `order` parameter. There is no need to ensure that the order is higher or lower than the main pattern because the mechanism will sort your patterns the following way:
+
+- First: order by main-pattern `.md` - `order`
+- Second: order by pattern-variant `.md` - `order`
+- Third: order by `pattern-name` / `variant-name`
+
+```
+- some-other-pattern.mustache
+- some-pattern.mustache
+- some-pattern.yml
+- some-pattern~variation1.yml
+- some-pattern~variation2.yml
+- some-pattern~variation3.yml
+```
+
+```
+---
+order: -1
+---
+# some-pattern.md
+```
+
+```
+---
+order: 2
+---
+# some-pattern~variation1.md
+```
+
+```
+---
+order: 1
+---
+# some-pattern~variation3.md
+```
+
+Result
+
+```
+- some-pattern
+- some-pattern-variation2
+- some-pattern-variation3
+- some-pattern-variation1
+- some-other-pattern
+```
+
+## Re-ordering pattern groups and subgroups
+
+To re-order pattern groups and subgroups, you need to create a companion `.md` file for that group. For example create `_patters/atoms/_atoms.md` for a pattern group or `_patters/atoms/buttons/_buttons.md` for a pattern subgroup. In the `.md` file, the above concept can be applied. The doc-file resolving works the following `{patternsRoot}/{pattern-group folder name}/{pattern-sub-group folder name}/_{pattern-sub-group raw name without prefixes}.md`
+
+
+```
+---
+order: 1
+---
+# _patters/atoms/_atoms.md
+# or
+# _patters/atoms/buttons/_buttons.md
+```
+
+## Deactivate deprecation warning
+
+To deactivate the deprecation warning for ordering patterns, add
+
+```
+disableDeprecationWarningForOrderPatterns: true
+```
+
+to the `patternlab-config.json`
diff --git a/packages/docs/src/docs/pattern-states.md b/packages/docs/src/docs/pattern-states.md
new file mode 100644
index 000000000..3198faf91
--- /dev/null
+++ b/packages/docs/src/docs/pattern-states.md
@@ -0,0 +1,55 @@
+---
+title: Using Pattern States
+tags:
+ - docs
+category: patterns
+eleventyNavigation:
+ title: Using Pattern States
+ key: patterns
+ order: 160
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+Pattern states provide your team and client a simple visual of the current state of patterns in Pattern Lab. Pattern states can track progress of a pattern from development, through client review, to completion or they can be used to give certain patterns specific classes. It's important to note that the state of a pattern can be influenced by its pattern partials.
+
+## The Default Pattern States
+
+Pattern Lab comes with the following default pattern states:
+
+- **inprogress**: pattern is in development or being worked upon. a red dot.
+- **inreview**: pattern is ready for a client to look at and comment upon. a yellow dot.
+- **complete**: pattern is ready to be moved to production. a green dot.
+
+Any pattern that includes a pattern partial that has a lower pattern state will inherit that state. For example, a pattern with the state of `inreview` that includes a pattern partial with the state of `inprogress` will have its state overridden and set to `inprogress`. It will not change to `inreview` until the pattern partial has a state of `inreview` or `complete`.
+
+## Giving Patterns a State
+
+Giving patterns a state is accomplished by setting the `state` frontmatter key on any pattern's companion `.md` file. Consider this media block pattern:
+
+```
+./source/_patterns/molecules/blocks/media-block.mustache
+```
+
+We would create or edit a file in the same location, calling it `media-block.md`:
+
+```
+---
+state: inreview
+---
+The media block consists of...
+```
+
+## Adding Customized States
+
+The three default states included with Pattern Lab might not be enough for everyone. To add customized states you should modify your own CSS files. **DO NOT** modify pattern states in `public/`. You cannot be assured these files won't be overwritten.
+
+You can use the following as your CSS template for new pattern states:
+
+```css
+{% raw %}.pl-c-pattern-state--newpatternstate {
+ background-color: #B10DC9;
+}{% endraw %}
+```
+
+Place this class inside `./source/css/pattern-scaffolding.css` to separate it from your css. Then add `newpatternstate` to your patterns' markdown `state` to have the new look show up. If you want to add it to the cascade of the default patterns you can modify `./patternlab-config.json`. Simply add your new pattern state to the `patternStateCascade` array.
diff --git a/packages/docs/src/docs/php-compile.md b/packages/docs/src/docs/php-compile.md
new file mode 100644
index 000000000..6727f4362
--- /dev/null
+++ b/packages/docs/src/docs/php-compile.md
@@ -0,0 +1,16 @@
+---
+title: php-compile
+tags:
+ - demo-content
+ - code
+ - blog
+eleventyNavigation:
+ key: php-compile
+ order: 300
+sitemapChangefreq: 'never'
+sitemapIgnore: true
+---
+
+The PHP version of Pattern Lab is being deprecated in favor of a new unified Pattern Lab core. The PHP docs for this topic can be viewed here.
+
+The current version of PL's website includes full docs for PHP. The new version of PL runs exclusively through Node, but for PHP projects will compile PHP with a PHP renderer.
diff --git a/packages/docs/src/docs/running-patternlab.md b/packages/docs/src/docs/running-patternlab.md
new file mode 100644
index 000000000..78099fe62
--- /dev/null
+++ b/packages/docs/src/docs/running-patternlab.md
@@ -0,0 +1,90 @@
+---
+title: Running Pattern Lab
+tags:
+ - docs
+category: getting-started
+eleventyNavigation:
+ title: Running Pattern Lab
+ key: getting-started
+ order: 1
+sitemapPriority: '0.8'
+sitemapChangefreq: 'monthly'
+---
+
+## Running Pattern Lab
+
+It's as easy as running the following command:
+
+```
+npm run start
+```
+
+This will start the system and open the URL it's running on within your browser.
+Relevant information regarding and step and possible errors are being logged to the console so it's recommended to watch out for any problems possibly occuring with your installation or any of the content or data you're setting up.
+
+### Problems and errors after restructuring files and folders
+
+If you're doing bigger changes especially to the file and folder structure and recognize some errors on the console like e.g. `TypeError: Cannot read property 'render' of undefined` or `Error building BuildFooterHTML`, it's recommended to stop Pattern Lab, delete the cache file `dependencyGraph.json` within the projects root and start Pattern Lab again, as these changes might conflict with the existing cache structures.
+
+### Running localhost via HTTPS
+
+There might be use cases in which you'd like to let your [localhost dev server run via HTTPS instead of HTTP](https://github.com/pattern-lab/live-server#https), like e.g. when consuming from other secure contexts to prevent browser errors or problems.
+
+Achieving this is a three-step process:
+- generate a self-signed SSL certificate
+- add it to the trusted certificates
+- configure the certificates for `live-server`
+
+#### Generate a self-signed SSL certificate
+
+First, create a folder like, e.g., `ssl` at the root of your project.
+
+Then run the following command in your terminal:
+
+```
+openssl req -x509 -nodes -out ssl/localhost.crt \
+ -keyout ssl/localhost.key \
+ -newkey rsa:2048 -sha256 \
+ -subj '/CN=localhost' -extensions EXT \
+ -config <( \
+ printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
+```
+
+This has been adapted from according to the [`Let's encrypt` instructions](https://letsencrypt.org/docs/certificates-for-localhost/); additionally, DigitalOcean provides some further explanations in [a tutorial](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-in-ubuntu-16-04).
+
+#### Add the certificate to the trusted certificates
+
+A [stack overflow entry](https://stackoverflow.com/a/56074120) as well mentions using the following command to add the certificate to the trusted certificates, as [suggested on a blog](https://derflounder.wordpress.com/2011/03/13/adding-new-trusted-root-certificates-to-system-keychain/):
+
+```
+sudo security add-trusted-cert -d -r trustRoot -k "/Library/Keychains/System.keychain" "ssl/localhost.crt"
+```
+
+You could as well skip this step and accept the certificate after opening the secured pattern lab in your browser for the first time, as described in step 5 of the [DigitalOcean tutorial](https://www.digitalocean.com/community/tutorials/how-to-create-a-self-signed-ssl-certificate-for-nginx-in-ubuntu-16-04#step-5-test-encryption).
+
+#### Configure the certificates for `live-server`
+
+According to the [`live-server` documentation](https://github.com/pattern-lab/live-server#https), you'll then add those certificates to the local dev server:
+
+> To enable HTTPS support, you'll need to create a configuration module.
+
+In our case, you could, e.g., create a file called `ssl.js` in the `ssl` folder with the following contents:
+
+```js
+var fs = require("fs");
+
+module.exports = {
+ cert: fs.readFileSync(__dirname + "/localhost.crt"),
+ key: fs.readFileSync(__dirname + "/localhost.key")
+};
+```
+
+Finally, you'll have to add this as a configuration module to the pattern lab `serverOptions` within the `patternlab-config.json` file:
+```json
+"serverOptions": {
+ ...
+ "https": "ssl/ssl.js"
+},
+```
+
+Et voilà, after starting the process of serving pattern lab the next time, it'll open as a secured page.
diff --git a/packages/docs/src/feed.njk b/packages/docs/src/feed.njk
new file mode 100644
index 000000000..70001f5f2
--- /dev/null
+++ b/packages/docs/src/feed.njk
@@ -0,0 +1,29 @@
+---
+permalink: '/feed.xml'
+sitemapIgnore: true
+---
+
+
+ {{ site.name }}
+
+
+
+ {{ collections.posts | rssLastUpdatedDate }}
+ {{ site.url }}
+
+ {{ site.authorName }}
+ {{ site.authorEmail }}
+
+ {% for post in collections.posts %}
+ {% set absolutePostUrl %}{{ site.url }}{{ post.url | url }}{% endset %}
+
+ {{ post.data.title }}
+
+ {{ post.date | rssDate }}
+ {{ absolutePostUrl }}
+
+
+ {% endfor %}
+
diff --git a/packages/docs/src/filters/date-filter.js b/packages/docs/src/filters/date-filter.js
new file mode 100644
index 000000000..fb0976d44
--- /dev/null
+++ b/packages/docs/src/filters/date-filter.js
@@ -0,0 +1,28 @@
+// Stolen from https://stackoverflow.com/a/31615643
+const appendSuffix = (n) => {
+ const s = ['th', 'st', 'nd', 'rd'];
+ const v = n % 100;
+ return n + (s[(v - 20) % 10] || s[v] || s[0]);
+};
+
+module.exports = function dateFilter(value) {
+ const dateObject = new Date(value);
+
+ const months = [
+ 'January',
+ 'February',
+ 'March',
+ 'April',
+ 'May',
+ 'June',
+ 'July',
+ 'August',
+ 'September',
+ 'October',
+ 'November',
+ 'December',
+ ];
+ const dayWithSuffix = appendSuffix(dateObject.getDate());
+
+ return `${dayWithSuffix} ${months[dateObject.getMonth()]} ${dateObject.getFullYear()}`;
+};
diff --git a/packages/docs/src/filters/markdown-filter.js b/packages/docs/src/filters/markdown-filter.js
new file mode 100644
index 000000000..ed05546a5
--- /dev/null
+++ b/packages/docs/src/filters/markdown-filter.js
@@ -0,0 +1,9 @@
+const markdownIt = require('markdown-it')({
+ html: true,
+ breaks: true,
+ linkify: true,
+});
+
+module.exports = function markdown(value) {
+ return markdownIt.render(value);
+};
diff --git a/packages/docs/src/filters/w3-date-filter.js b/packages/docs/src/filters/w3-date-filter.js
new file mode 100644
index 000000000..23257bb12
--- /dev/null
+++ b/packages/docs/src/filters/w3-date-filter.js
@@ -0,0 +1,5 @@
+module.exports = function w3cDate(value) {
+ const dateObject = new Date(value);
+
+ return dateObject.toISOString();
+};
diff --git a/packages/docs/src/images/1createpl.png b/packages/docs/src/images/1createpl.png
new file mode 100644
index 000000000..b92a451e0
Binary files /dev/null and b/packages/docs/src/images/1createpl.png differ
diff --git a/packages/docs/src/images/2choosedirectory.png b/packages/docs/src/images/2choosedirectory.png
new file mode 100644
index 000000000..11f331997
Binary files /dev/null and b/packages/docs/src/images/2choosedirectory.png differ
diff --git a/packages/docs/src/images/3chooseedition.png b/packages/docs/src/images/3chooseedition.png
new file mode 100644
index 000000000..7af97103a
Binary files /dev/null and b/packages/docs/src/images/3chooseedition.png differ
diff --git a/packages/docs/src/images/4choosestarterkit.png b/packages/docs/src/images/4choosestarterkit.png
new file mode 100644
index 000000000..4a7ef6a37
Binary files /dev/null and b/packages/docs/src/images/4choosestarterkit.png differ
diff --git a/packages/docs/src/images/5.png b/packages/docs/src/images/5.png
new file mode 100644
index 000000000..f7502ec4e
Binary files /dev/null and b/packages/docs/src/images/5.png differ
diff --git a/packages/docs/src/images/5areyouhappy.png b/packages/docs/src/images/5areyouhappy.png
new file mode 100644
index 000000000..43db88232
Binary files /dev/null and b/packages/docs/src/images/5areyouhappy.png differ
diff --git a/packages/docs/src/images/6.png b/packages/docs/src/images/6.png
new file mode 100644
index 000000000..f462b8db4
Binary files /dev/null and b/packages/docs/src/images/6.png differ
diff --git a/packages/docs/src/images/6settingup.png b/packages/docs/src/images/6settingup.png
new file mode 100644
index 000000000..6b4e3938e
Binary files /dev/null and b/packages/docs/src/images/6settingup.png differ
diff --git a/packages/docs/src/images/7.png b/packages/docs/src/images/7.png
new file mode 100644
index 000000000..4ee99b733
Binary files /dev/null and b/packages/docs/src/images/7.png differ
diff --git a/packages/docs/src/images/800x600.png b/packages/docs/src/images/800x600.png
new file mode 100644
index 000000000..d765b0574
Binary files /dev/null and b/packages/docs/src/images/800x600.png differ
diff --git a/packages/docs/src/images/createPL1.mp4 b/packages/docs/src/images/createPL1.mp4
new file mode 100644
index 000000000..d9686b649
Binary files /dev/null and b/packages/docs/src/images/createPL1.mp4 differ
diff --git a/packages/docs/src/images/favicon.ico b/packages/docs/src/images/favicon.ico
new file mode 100644
index 000000000..eee4aa78f
Binary files /dev/null and b/packages/docs/src/images/favicon.ico differ
diff --git a/packages/docs/src/images/icon-atom.svg b/packages/docs/src/images/icon-atom.svg
new file mode 100644
index 000000000..10bf0adf0
--- /dev/null
+++ b/packages/docs/src/images/icon-atom.svg
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/src/images/icon-molecule.svg b/packages/docs/src/images/icon-molecule.svg
new file mode 100644
index 000000000..2dc151733
--- /dev/null
+++ b/packages/docs/src/images/icon-molecule.svg
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/src/images/icon-organism.svg b/packages/docs/src/images/icon-organism.svg
new file mode 100644
index 000000000..c12cc435b
--- /dev/null
+++ b/packages/docs/src/images/icon-organism.svg
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/src/images/icon-page.svg b/packages/docs/src/images/icon-page.svg
new file mode 100644
index 000000000..fe5751723
--- /dev/null
+++ b/packages/docs/src/images/icon-page.svg
@@ -0,0 +1,144 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/src/images/icon-template.svg b/packages/docs/src/images/icon-template.svg
new file mode 100644
index 000000000..3aa6df78e
--- /dev/null
+++ b/packages/docs/src/images/icon-template.svg
@@ -0,0 +1,134 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/docs/src/images/pattern-lab-2-image_18-large-opt.png b/packages/docs/src/images/pattern-lab-2-image_18-large-opt.png
new file mode 100644
index 000000000..93c28c2e2
Binary files /dev/null and b/packages/docs/src/images/pattern-lab-2-image_18-large-opt.png differ
diff --git a/packages/docs/src/index.md b/packages/docs/src/index.md
new file mode 100644
index 000000000..f84d95851
--- /dev/null
+++ b/packages/docs/src/index.md
@@ -0,0 +1,6 @@
+---
+layout: home
+title: Create atomic design systems with Pattern Lab
+sitemapPriority: '1.0'
+sitemapChangefreq: 'monthly'
+---
diff --git a/packages/docs/src/js/components/theme-toggle.js b/packages/docs/src/js/components/theme-toggle.js
new file mode 100644
index 000000000..7b73887a1
--- /dev/null
+++ b/packages/docs/src/js/components/theme-toggle.js
@@ -0,0 +1,101 @@
+// For syntax highlighting only
+const html = String.raw;
+
+class ThemeToggle extends HTMLElement {
+ constructor() {
+ super();
+
+ this.STORAGE_KEY = 'user-color-scheme';
+ this.COLOR_MODE_KEY = '--color-mode';
+ }
+
+ connectedCallback() {
+ this.render();
+ }
+
+ getCSSCustomProp(propKey) {
+ let response = getComputedStyle(document.documentElement).getPropertyValue(propKey);
+
+ // Tidy up the string if there’s something to work with
+ if (response.length) {
+ response = response.replace(/\'|"/g, '').trim();
+ }
+
+ // Return the string response by default
+ return response;
+ }
+
+ applySetting(passedSetting) {
+ const currentSetting = passedSetting || localStorage.getItem(this.STORAGE_KEY);
+
+ if (currentSetting) {
+ document.documentElement.setAttribute('data-user-color-scheme', currentSetting);
+ this.setButtonLabelAndStatus(currentSetting);
+ } else {
+ this.setButtonLabelAndStatus(this.getCSSCustomProp(this.COLOR_MODE_KEY));
+ }
+ }
+
+ toggleSetting() {
+ let currentSetting = localStorage.getItem(this.STORAGE_KEY);
+
+ switch (currentSetting) {
+ case null:
+ currentSetting =
+ this.getCSSCustomProp(this.COLOR_MODE_KEY) === 'dark' ? 'light' : 'dark';
+ break;
+ case 'light':
+ currentSetting = 'dark';
+ break;
+ case 'dark':
+ currentSetting = 'light';
+ break;
+ }
+
+ localStorage.setItem(this.STORAGE_KEY, currentSetting);
+
+ return currentSetting;
+ }
+
+ setButtonLabelAndStatus(currentSetting) {
+ this.modeToggleButton.innerText = `${
+ currentSetting === 'dark' ? 'Light' : 'Dark'
+ } theme`;
+ this.modeStatusElement.innerText = `Color mode is now "${currentSetting}"`;
+ }
+
+ render() {
+ this.innerHTML = html`
+
+ `;
+
+ this.afterRender();
+ }
+
+ afterRender() {
+ this.modeToggleButton = document.querySelector('.js-mode-toggle');
+ this.modeStatusElement = document.querySelector('.js-mode-status');
+
+ this.modeToggleButton.addEventListener('click', (evt) => {
+ evt.preventDefault();
+
+ this.applySetting(this.toggleSetting());
+ });
+
+ this.applySetting();
+ }
+}
+
+if ('customElements' in window) {
+ customElements.define('theme-toggle', ThemeToggle);
+}
+
+export default ThemeToggle;
diff --git a/packages/docs/src/js/primary-nav.js b/packages/docs/src/js/primary-nav.js
new file mode 100644
index 000000000..7171fc15e
--- /dev/null
+++ b/packages/docs/src/js/primary-nav.js
@@ -0,0 +1,85 @@
+/*------------------------------------*\
+ #PRIMARY NAVIGATION
+\*------------------------------------*/
+/**
+ * Toggles active class on the primary nav item
+ * 1) Select all nav dropdown triggers and cycle through them
+ * 2) On click, find the nav dropdown trigger parent
+ * 3) If the nav dropdown trigger parent already has active class, remove it.
+ * 4) If the nav dropdown trigger parent does not have an active class, add it.
+ */
+(function () {
+ var navDropdownListItem = document.querySelector('.js-nav-dropdown');
+ var navLink = document.querySelectorAll('.js-nav-dropdown-trigger'); /* 1 */
+
+ for (i = 0; i < navLink.length; i++) {
+ /* 1 */
+
+ navLink[i].addEventListener('click', function (event) {
+ /* 2 */
+ event.preventDefault();
+ var navLinkParent = this.parentNode; /* 2 */
+
+ if (navLinkParent.classList.contains('is-active')) {
+ /* 3 */
+ navLinkParent.classList.remove('is-active');
+
+ this.setAttribute('aria-expanded', 'false');
+ } else {
+ /* 4 */
+ navLinkParent.classList.add('is-active');
+
+ this.setAttribute('aria-expanded', 'true');
+ }
+ });
+ }
+
+ /**
+ * Expose docs dropdown if on a docs page
+ */
+ if (window.location.href.indexOf('docs') > -1) {
+ navDropdownListItem.classList.add('is-active');
+ }
+
+ var pathName = location.pathname;
+
+ var navLinks = document.querySelectorAll('.c-tree-nav a');
+
+ for (i = 0; i < navLinks.length; i++) {
+ var subnavLink = navLinks[i].getAttribute('href');
+ if (subnavLink == pathName) {
+ navLinks[i].classList.add('is-active');
+ }
+ }
+
+ /**
+ * Toggles active class on the primary nav panel
+ * 1) Select all nav triggers and cycle through them
+ * 2) On click, find the nav panel within the header
+ * 3) If the navPanel already has active class, remove it on click, as well as the aria-expanded attributes value.
+ * 4) If the navPanel does not have an active class, add it on click, as well as the aria-expanded attributes value.
+ */
+ var navToggle = document.querySelectorAll('.js-nav-trigger'); /* 1 */
+
+ for (i = 0; i < navToggle.length; i++) {
+ /* 1 */
+
+ navToggle[i].addEventListener('click', function (event) {
+ /* 2 */
+ event.preventDefault();
+ var navToggleElement = this;
+ var navToggleParent = navToggleElement.parentNode; /* 2 */
+ var navPanel = navToggleParent.querySelector('.js-nav-panel'); /* 2 */
+
+ if (navPanel.classList.contains('is-active')) {
+ /* 3 */
+ navPanel.classList.remove('is-active');
+ navToggleElement.setAttribute('aria-expanded', 'false');
+ } else {
+ /* 4 */
+ navPanel.classList.add('is-active');
+ navToggleElement.setAttribute('aria-expanded', 'true');
+ }
+ });
+ }
+})();
diff --git a/packages/docs/src/pages/pages.json b/packages/docs/src/pages/pages.json
new file mode 100644
index 000000000..04d34aa3d
--- /dev/null
+++ b/packages/docs/src/pages/pages.json
@@ -0,0 +1,3 @@
+{
+ "layout": "layouts/page.njk"
+}
diff --git a/packages/docs/src/posts/pattern-lab-website-redesign.md b/packages/docs/src/posts/pattern-lab-website-redesign.md
new file mode 100644
index 000000000..47f4de397
--- /dev/null
+++ b/packages/docs/src/posts/pattern-lab-website-redesign.md
@@ -0,0 +1,15 @@
+---
+title: Pattern Lab website redesign
+description: The Pattern Lab website got a new facelift
+date: '2020-02-17'
+tags:
+ - blog
+url: '/posts/pattern-lab-website-redesign'
+sitemapChangefreq: 'never'
+---
+
+We're pleased to announce the Pattern Lab website is undergoing a much-needed facelift!
+
+There has been a lot of work on the Pattern Lab product that hasn't been reflected on the website. Over the coming months, we'll be updating the documentation to represent these improvements as well as bring home the new look and feel of the website.
+
+Stay tuned!
diff --git a/packages/docs/src/posts/posts.json b/packages/docs/src/posts/posts.json
new file mode 100644
index 000000000..d0428c43f
--- /dev/null
+++ b/packages/docs/src/posts/posts.json
@@ -0,0 +1,3 @@
+{
+ "layout": "layouts/post.njk"
+}
diff --git a/packages/docs/src/resources.md b/packages/docs/src/resources.md
new file mode 100644
index 000000000..e88c5c291
--- /dev/null
+++ b/packages/docs/src/resources.md
@@ -0,0 +1,38 @@
+---
+layout: layouts/page-base.njk
+title: Resources
+sitemapPriority: '0.8'
+---
+
+## Style guides and atomic design
+
+- [Styleguides.io](http://styleguides.io)
+- [Atomic Design by Brad Frost](https://atomicdesign.bradfrost.com/)
+- [Atomic design article](https://bradfrost.com/blog/post/atomic-web-design/)
+- [A new link](https://www.google.com/)
+
+## Pattern Lab Examples
+
+- [Pattern Lab Demo](https://demo.patternlab.io/)
+- [Altinn](https://altinn.github.io/DesignSystem/)
+- [hTWOo UI Framework](https://lab.n8d.studio/htwoo/) - [Demo](https://lab.n8d.studio/htwoo/htwoo-core/)
+
+## Articles
+
+- [Making And Maintaining Atomic Design Systems With Pattern Lab 2 by Brad Frost, Dave Olsen, Brian Muenzenmeyer](https://www.smashingmagazine.com/2016/07/building-maintaining-atomic-design-systems-pattern-lab/)
+- [Using Pattern Lab to Design Build and Maintain a (Jekyll) Website by Brian Muenzenmeyer](http://www.brianmuenzenmeyer.com/using-patternlab-to-design-build-and-maintain-a-website)
+- [Solving Problems with Pattern Lab - Small Team Workflow by Brian Muenzenmeyer](https://www.brianmuenzenmeyer.com/solving-problems-with-pattern-lab-small-team-workflow)
+- [Adding Common Gulp Tasks to Pattern Lab Node by Brian Muenzenmeyer](http://www.brianmuenzenmeyer.com/adding-common-gulp-tasks-to-pattern-lab-node)
+- [Why and How to Test Your Pattern Library: Testing Strategy by Jim Newbery](https://tinnedfruit.com/writing/why-and-how-to-test-your-pattern-library.html)
+- [Why and How to Test Your Pattern Library: Testing a Pattern Lab Project by Jim Newbery](https://tinnedfruit.com/writing/why-and-how-to-test-your-pattern-library-2.html)
+
+## Podcasts
+
+- [Dave Olsen talking Pattern Lab 2 on Non-Breaking Space Podcast](https://open.spotify.com/episode/4IMyd92WWZyaXP04Unxdip)
+- [Brian Muenzenmeyer talking Pattern Lab 2 on the MS DEV SHOW Podcast](https://msdevshow.com/2015/12/pattern-lab-with-brian-muenzenmeyer/)
+
+## Presentations
+
+- [Screencast: A Quick Intro to Pattern Lab Node with Brian Muenzenmeyer](https://css-tricks.com/video-screencasts/149-quick-intro-pattern-lab-node-brian-muenzenmeyer/)
+- [Screencast: Migrating to Pattern Lab 3.0](https://www.youtube.com/watch?v=hIH-lI1QTns&t=1s)
+- [Code: Migrating to Pattern Lab 3.0](https://github.com/bmuenzenmeyer/pl-migrate-example)
diff --git a/packages/docs/src/robots.njk b/packages/docs/src/robots.njk
new file mode 100644
index 000000000..08ba9aeb4
--- /dev/null
+++ b/packages/docs/src/robots.njk
@@ -0,0 +1,7 @@
+---
+permalink: /robots.txt
+sitemapIgnore: true
+---
+User-agent: *
+Allow: /
+Sitemap: {{ site.url }}/sitemap.xml
diff --git a/packages/docs/src/scss/abstracts/_colors.scss b/packages/docs/src/scss/abstracts/_colors.scss
new file mode 100644
index 000000000..e67aa711c
--- /dev/null
+++ b/packages/docs/src/scss/abstracts/_colors.scss
@@ -0,0 +1,63 @@
+/*------------------------------------*\
+ #COLORS
+\*------------------------------------*/
+
+/**
+ * In this file, we take the literal colors from our palette (defined in variables.scss)
+ * and define them against variables that we can utilise anywhere throughout the project.
+ */
+
+/*------------------------------------*\
+ #GLOBAL TEXT COLOR
+\*------------------------------------*/
+
+/**
+ * Body text and background colors
+ */
+$color-text: $color-gray-93 !default;
+$color-text-bg: $color-white !default;
+
+/**
+ * Highlight colors
+ */
+$color-text-highlight: $color-gray-93;
+$color-text-highlight-bg: $color-gray-13;
+
+/*------------------------------------*\
+ #LINKS
+\*------------------------------------*/
+
+$color-links: $color-gray-73 !default;
+$color-links-hover: $color-gray-50 !default;
+$color-links-active: $color-gray-93 !default;
+$color-links-visited: $color-gray-93 !default;
+
+/*------------------------------------*\
+ #BUTTONS
+\*------------------------------------*/
+
+$color-btn-primary: $color-white !default;
+$color-btn-primary-bg: $color-gray-93 !default;
+$color-btn-primary-bg-hover: $color-gray-50 !default;
+$color-btn-primary-border: $color-gray-93 !default;
+
+$color-btn-secondary: $color-gray-93 !default;
+$color-btn-secondary-bg: $color-white !default;
+$color-btn-secondary-bg-hover: $color-gray-07 !default;
+$color-btn-secondary-border: $color-gray-93 !default;
+
+$color-btn-disabled: $color-gray-50 !default;
+$color-btn-disabled-bg: $color-gray-07 !default;
+
+/*------------------------------------*\
+ #FORMS
+\*------------------------------------*/
+
+$color-form: $color-gray-93 !default;
+$color-form-bg: $color-white !default;
+$color-form-border: $color-gray-73 !default;
+$color-form-border-focus: $color-gray-93 !default;
+$color-form-border-error: $color-utility-error !default;
+$color-form-label: $color-gray-93 !default;
+$color-form-info: $color-gray-73;
+$color-form-placeholder: $color-gray-50;
diff --git a/packages/docs/src/scss/abstracts/_mixins.scss b/packages/docs/src/scss/abstracts/_mixins.scss
new file mode 100644
index 000000000..c86c6d5e2
--- /dev/null
+++ b/packages/docs/src/scss/abstracts/_mixins.scss
@@ -0,0 +1,178 @@
+/*------------------------------------*\
+ #MIXINS
+\*------------------------------------*/
+
+/**
+ * Body Styles
+ * 1) Prevent Mobile Safari from scaling up text: https://blog.55minutes.com/2012/04/iphone-text-resizing/
+ */
+@mixin typographyBody() {
+ font-family: $font-primary;
+ font-size: $font-size-med-2;
+ font-weight: 500;
+ line-height: 1.6;
+ -webkit-text-size-adjust: 100%; /* 1 */
+}
+
+/**
+ * XL Type Styles
+ */
+@mixin typographyBodyLarge() {
+ font-size: $font-size-med-2;
+ line-height: $line-height-large;
+}
+
+/**
+ * XL Heading Styles
+ */
+@mixin typographyHeadingXl() {
+ font-weight: $font-weight-bold;
+ font-size: $font-size-large-2;
+ line-height: $line-height-med-2;
+
+ @media all and (min-width: $bp-med) {
+ font-size: $font-size-xl;
+ }
+}
+
+/**
+ * Large Heading Styles
+ */
+@mixin typographyHeadingLarge() {
+ font-size: $font-size-large;
+ font-weight: 700;
+ line-height: 1.6;
+}
+
+/**
+ * Medium 2 Heading Styles
+ */
+@mixin typographyHeadingMed2() {
+ font-size: $font-size-med-2;
+ font-weight: 700;
+ line-height: 1.2;
+}
+
+/**
+ * Medium Heading Styles
+ */
+@mixin typographyHeadingMed() {
+ font-size: $font-size-med;
+ font-weight: 700;
+ line-height: 1.2;
+}
+
+/*------------------------------------*\
+ #FOCUS
+\*------------------------------------*/
+
+@mixin focus() {
+ outline: 2px dotted $color-black;
+ outline-offset: 4px;
+}
+
+@mixin focusInverted() {
+ outline: 1px dotted $color-white;
+ outline-offset: 4px;
+}
+
+/*------------------------------------*\
+ #DECORATIVE
+\*------------------------------------*/
+
+@mixin textShadowEffect() {
+ position: relative;
+ z-index: 1;
+
+ &::after {
+ position: absolute;
+ left: 4px;
+ top: 4px;
+ z-index: 0;
+ content: attr(data-text);
+
+ // Mitigating the positioning by 4px from the left to not have the words break incorrectly (see #GH-1158)
+ margin-right: -4px;
+
+ background-image: radial-gradient(
+ $color-brand-purple 0%,
+ $color-brand-purple 60%,
+ transparent 60%
+ );
+ background-size: 4px 4px;
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ z-index: -5;
+ display: block;
+ text-shadow: none;
+
+ @media all and (max-width: $bp-large) {
+ left: 2px;
+ top: 2px;
+ background-size: 2px 2px;
+ }
+ }
+}
+
+@mixin boxShadowEffect($color: 'green') {
+ @if $color == 'green' {
+ box-shadow: 6px 6px 0 $color-brand-green, 12px 12px 0 $color-brand-green-light;
+ } @else if $color == 'orange' {
+ box-shadow: 6px 6px 0 $color-brand-orange, 12px 12px 0 $color-brand-orange-light;
+ } @else {
+ box-shadow: 6px 6px 0 $color-brand-purple, 12px 12px 0 $color-brand-purple-light;
+ }
+}
+
+@mixin stripedBoxShadow($color: 'green') {
+ @if $color == 'green' {
+ background-image: repeating-linear-gradient(
+ 45deg,
+ $color-brand-green,
+ $color-brand-green 1px,
+ transparent 1px,
+ transparent 4px
+ );
+ } @else if $color == 'orange' {
+ background-image: repeating-linear-gradient(
+ 45deg,
+ $color-brand-orange,
+ $color-brand-orange 1px,
+ transparent 1px,
+ transparent 4px
+ );
+ } @else {
+ background-image: repeating-linear-gradient(
+ 45deg,
+ $color-brand-purple,
+ $color-brand-purple 1px,
+ transparent 1px,
+ transparent 4px
+ );
+ }
+}
+
+@mixin hideScrollbar() {
+ -webkit-overflow-scrolling: touch;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ scrollbar-width: none;
+ scrollbar-color: transparent;
+
+ &::-webkit-scrollbar {
+ height: var(--scrollbar-size);
+ width: var(--scrollbar-size);
+ }
+ &::-webkit-scrollbar-track {
+ background-color: var(--scrollbar-track-color);
+ }
+ &::-webkit-scrollbar-thumb {
+ background-color: var(--scrollbar-color);
+ /* Add :hover, :active as needed */
+ }
+ &::-webkit-scrollbar-thumb:vertical {
+ min-height: var(--scrollbar-minlength);
+ }
+ &::-webkit-scrollbar-thumb:horizontal {
+ min-width: var(--scrollbar-minlength);
+ }
+}
diff --git a/packages/docs/src/scss/abstracts/_typography.scss b/packages/docs/src/scss/abstracts/_typography.scss
new file mode 100644
index 000000000..ac1fb2c7b
--- /dev/null
+++ b/packages/docs/src/scss/abstracts/_typography.scss
@@ -0,0 +1,10 @@
+/*------------------------------------*\
+ #BREAKPOINTS
+\*------------------------------------*/
+
+/**
+ * In this file, we take the literal colors from our palette and define them
+ * against variables that we can utilise anywhere throughout the project.
+ */
+
+$body-font-size: $font-size-med;
diff --git a/packages/docs/src/scss/abstracts/_variables.scss b/packages/docs/src/scss/abstracts/_variables.scss
new file mode 100644
index 000000000..0e8b2cb2f
--- /dev/null
+++ b/packages/docs/src/scss/abstracts/_variables.scss
@@ -0,0 +1,192 @@
+/*------------------------------------*\
+ #VARIABLES
+\*------------------------------------*/
+
+/**
+ * CONTENTS
+ *
+ * COLORS
+ * Brand Colors...............Globally-available variables and config
+ * Neutral Colors.............Grayscale colors, including white and black
+ * Utility Colors.............Info, Warning, Error, Success
+ *
+ * TYPOGRAPHY
+ * Font Families..............The fonts used in the design system
+ * Sizing.....................Font sizing
+ *
+ * LAYOUT
+ * Max-widths.................Maximum layout container width
+ *
+
+ * SPACING
+ * Spacing defaults...........Spacing between elements
+ *
+ * BORDERS
+ * Border Width...............Border thicknesses
+ * Border Radius..............Border radius definitions
+ *
+ * ANIMATION
+ * Animation Speed............Transition/animation speed variables
+ * Animation easing...........Easing variables
+ *
+ * BREAKPOINTS
+ * Breakpoints................Global breakpoint definitions
+ */
+
+/*------------------------------------*\
+ #COLORS
+ \*------------------------------------*/
+
+/**
+ * Brand Colors
+ * 1) Brand=specific colors
+ */
+$color-brand-purple: #aa85ba;
+$color-brand-purple-dark: #22062e;
+$color-brand-purple-light: #f9f5fc;
+$color-brand-green: #7ec699;
+$color-brand-green-dark: #376548;
+$color-brand-green-light: #f4fdf6;
+$color-brand-orange: #eeb31b;
+$color-brand-orange-dark: #946900;
+$color-brand-orange-light: #fef8ea;
+
+/**
+ * Neutral Colors
+ * 1) Neutral colors are grayscale values used throughout the UI
+ */
+$color-white: #fff;
+$color-gray-02: #f2f2f2;
+$color-gray-07: #eee;
+$color-gray-13: #ddd;
+$color-gray-27: #bbb;
+$color-gray-50: #777677;
+$color-gray-60: #666;
+$color-gray-73: #444;
+$color-gray-88: #1f1f1f;
+$color-gray-93: #131313;
+$color-black: #000;
+
+/**
+ * Utility Colors
+ * 1) Utility colors are colors used to provide feedback, such as alert messages,
+ * form validation, etc.
+ */
+$color-utility-info: #0192d0;
+$color-utility-info-light: #d3f2ff;
+$color-utility-error: #b12a0b;
+$color-utility-error-light: #fdded8;
+$color-utility-success: #03804d;
+$color-utility-success-light: #d4f3e6;
+$color-utility-warning: #a59b15;
+$color-utility-warning-light: #fffecf;
+
+/*------------------------------------*\
+ #TYPOGRAPHY
+\*------------------------------------*/
+
+/**
+ * Font Family
+ */
+$font-primary: neue-haas-grotesk-display, sans-serif;
+$font-secondary: monospace;
+
+/**
+ * Font Sizing
+ */
+$font-size-sm: 0.75rem;
+$font-size-sm-2: 0.85rem;
+$font-size-med: 1rem;
+$font-size-med-2: 1.2rem;
+$font-size-large: 2rem;
+$font-size-large-2: 2.6rem;
+$font-size-xl: 5rem;
+
+$font-weight-bold: 700;
+
+/**
+ * Line Height
+ */
+$line-height-sm: 0.8;
+$line-height-sm-2: 0.9;
+$line-height-med: 1;
+$line-height-med-2: 1.2;
+$line-height-large: 1.6;
+$line-height-xl: 1.8;
+
+/*------------------------------------*\
+ #LAYOUT
+\*------------------------------------*/
+
+/**
+ * Max Width
+ */
+$l-max-width: 70rem !default;
+$l-linelength-width: 40rem !default;
+
+$l-sidebar-width: 18.75rem;
+
+/*------------------------------------*\
+ #SPACING
+\*------------------------------------*/
+
+/**
+ * Spacing and offsets
+ * 1) Used to space grids and body padding
+ */
+
+$spacing: 1rem;
+$spacing-small: round(0.5 * $spacing);
+$spacing-large: round(2 * $spacing);
+$spacing-xl: round(4 * $spacing);
+
+/*------------------------------------*\
+ #BORDERS
+\*------------------------------------*/
+
+/**
+ * Border
+ */
+$border-width: 1px;
+$border-width-thick: 0.5rem;
+
+/**
+ * Border radius
+ */
+$border-radius: 4px;
+
+/*------------------------------------*\
+ #ANIMATION
+\*------------------------------------*/
+
+/**
+ * Transition Speed
+ */
+$anim-fade-quick: 0.15s;
+$anim-fade-long: 0.4s;
+
+/**
+ * Transition Ease
+ */
+$anim-ease: ease-out;
+
+/*------------------------------------*\
+ #BREAKPOINTS
+\*------------------------------------*/
+
+/**
+ * Breakpoints used in media queries
+ * 1) These are not the only breakpoints used, but they provide a few defaults
+ */
+$bp-small: 28em;
+$bp-med: 47em;
+$bp-large: 60em;
+$bp-xl: 70em;
+
+:root {
+ --scrollbar-track-color: transparent;
+ --scrollbar-color: rgba(0, 0, 0, 0.2);
+
+ --scrollbar-size: 0.375rem;
+ --scrollbar-minlength: 1.5rem; /* Minimum length of scrollbar thumb (width of horizontal, height of vertical) */
+}
diff --git a/packages/docs/src/scss/base/_body.scss b/packages/docs/src/scss/base/_body.scss
new file mode 100644
index 000000000..054b8818e
--- /dev/null
+++ b/packages/docs/src/scss/base/_body.scss
@@ -0,0 +1,28 @@
+/*------------------------------------*\
+ #BODY
+\*------------------------------------*/
+
+/**
+ * HTML base styles
+ * 1) Set the html element's height to at least 100% of the viewport.
+ * This is used to achieve a sticky footer
+ */
+html {
+ min-height: 100vh; /* 1 */
+}
+
+/**
+ * Body base styles
+ * 1) Set the body element's height to at least 100% of the viewport.
+ * This is used to achieve a sticky footer
+ * 2) Prevent Mobile Safari from scaling up text: https://blog.55minutes.com/2012/04/iphone-text-resizing/
+ */
+body {
+ display: flex; /* 1 */
+ flex-direction: column; /* 1 */
+ min-height: 100vh; /* 1 */
+ @include typographyBody;
+ -webkit-text-size-adjust: 100%; /* 2 */
+ background-color: $color-white;
+ color: $color-gray-88;
+}
diff --git a/packages/docs/src/scss/base/_buttons.scss b/packages/docs/src/scss/base/_buttons.scss
new file mode 100644
index 000000000..8c108cf75
--- /dev/null
+++ b/packages/docs/src/scss/base/_buttons.scss
@@ -0,0 +1,15 @@
+/*------------------------------------*\
+ #BUTTONS
+\*------------------------------------*/
+
+/**
+ * Button and submit inputs reset
+ * 1) These should be styled using c-btn
+ */
+button {
+ cursor: pointer;
+
+ &:focus {
+ @include focus();
+ }
+}
diff --git a/packages/docs/src/scss/base/_forms.scss b/packages/docs/src/scss/base/_forms.scss
new file mode 100644
index 000000000..06ed10dff
--- /dev/null
+++ b/packages/docs/src/scss/base/_forms.scss
@@ -0,0 +1,130 @@
+/*------------------------------------*\
+ #FORMS
+\*------------------------------------*/
+
+/**
+ * 1) Form element base styles
+ */
+
+/**
+ * Input placeholder text base styles
+ */
+::-webkit-input-placeholder {
+ color: $color-form-placeholder;
+}
+
+::-moz-placeholder {
+ color: $color-form-placeholder;
+}
+
+:-ms-input-placeholder {
+ color: $color-form-placeholder;
+}
+
+/**
+ * Fieldset base styles
+ */
+fieldset {
+ border: 0;
+ padding: 0;
+ margin: 0;
+}
+
+/**
+ * Legend base styles
+ */
+legend {
+ margin-bottom: 0.25rem;
+}
+
+/**
+ * Label base styles
+ */
+label {
+ display: block;
+ padding-bottom: 0.25rem;
+ color: $color-form-label;
+}
+
+/**
+ * Add font size 100% of form element and margin 0 to these elements
+ */
+button,
+input,
+select,
+textarea {
+ font-family: inherit;
+ font-size: $font-size-med;
+ margin: 0;
+}
+
+/**
+ * Text area base styles
+ */
+textarea {
+ resize: none;
+}
+
+/**
+ * Input and text area base styles
+ */
+input,
+textarea {
+ width: 100%;
+ padding: 0.5rem;
+ border: $border-width solid $color-form-border;
+ background: $color-form-bg;
+
+ &:focus {
+ border-color: $color-form-border-focus;
+ }
+}
+
+/**
+ * Remove webkit appearance styles from these elements
+ */
+input[type='text'],
+input[type='search'],
+input[type='search']::-webkit-search-cancel-button,
+input[type='search']::-webkit-search-decoration,
+input[type='url'],
+input[type='number'],
+textarea {
+ -webkit-appearance: none;
+}
+
+/**
+ * Checkbox and radio button base styles
+ */
+input[type='checkbox'],
+input[type='radio'] {
+ width: auto;
+ margin-right: 0.3rem;
+ border-color: $color-form-border;
+}
+
+/**
+ * Search input base styles
+ */
+input[type='search'] {
+ -webkit-appearance: none;
+ border-radius: 0;
+}
+
+/**
+ * Select
+ * 1) Remove default styling
+ */
+select {
+ display: block;
+ font-size: $font-size-med;
+ width: 100%;
+ border: $border-width solid $color-form-border;
+ padding: 0.5rem;
+ background: $color-form-bg;
+ color: $color-form;
+
+ &:focus {
+ border-color: $color-form-border-focus;
+ }
+}
diff --git a/packages/docs/src/scss/base/_headings.scss b/packages/docs/src/scss/base/_headings.scss
new file mode 100644
index 000000000..9983cdc3d
--- /dev/null
+++ b/packages/docs/src/scss/base/_headings.scss
@@ -0,0 +1,35 @@
+/*------------------------------------*\
+ #HEADINGS
+\*------------------------------------*/
+
+/**
+ * Heading 1 base styles
+ */
+h1 {
+ @include typographyHeadingXl();
+ position: relative;
+}
+
+/**
+ * Heading 2 base styles
+ */
+h2 {
+ @include typographyHeadingLarge();
+ position: relative;
+}
+
+/**
+ * Heading 3 base styles
+ */
+h3 {
+ @include typographyHeadingMed2();
+ position: relative;
+}
+
+/**
+ * Heading 4 base styles
+ */
+h4 {
+ @include typographyHeadingMed();
+ position: relative;
+}
diff --git a/packages/docs/src/scss/base/_links.scss b/packages/docs/src/scss/base/_links.scss
new file mode 100644
index 000000000..70f673583
--- /dev/null
+++ b/packages/docs/src/scss/base/_links.scss
@@ -0,0 +1,25 @@
+/*------------------------------------*\
+ #LINKS
+\*------------------------------------*/
+
+/**
+ * Link base styles
+ */
+a {
+ color: $color-links;
+ text-decoration: none;
+ transition: color $anim-fade-quick $anim-ease;
+
+ &:hover,
+ &:focus {
+ color: $color-links-hover;
+ }
+
+ &:focus {
+ @include focus();
+ }
+
+ &:active {
+ color: $color-links-active;
+ }
+}
diff --git a/packages/docs/src/scss/base/_lists.scss b/packages/docs/src/scss/base/_lists.scss
new file mode 100644
index 000000000..aef0fb90e
--- /dev/null
+++ b/packages/docs/src/scss/base/_lists.scss
@@ -0,0 +1,15 @@
+/*------------------------------------*\
+ #LISTS
+\*------------------------------------*/
+
+/**
+ * 1) List base styles
+ */
+
+/**
+ * Remove list styles from unordered and ordered lists
+ */
+ol,
+ul {
+ list-style: none;
+}
diff --git a/packages/docs/src/scss/base/_main.scss b/packages/docs/src/scss/base/_main.scss
new file mode 100644
index 000000000..05ca77cee
--- /dev/null
+++ b/packages/docs/src/scss/base/_main.scss
@@ -0,0 +1,23 @@
+/*------------------------------------*\
+ #MAIN ELEMENT
+\*------------------------------------*/
+
+/**
+ * Main element
+ */
+main {
+ display: block;
+ margin-top: 2rem;
+
+ @media all and (min-width: $bp-med) {
+ margin-top: 5rem;
+ }
+}
+
+.c-main--flush {
+ margin-top: 0;
+
+ @media all and (min-width: $bp-med) {
+ margin-top: 0;
+ }
+}
diff --git a/packages/docs/src/scss/base/_media.scss b/packages/docs/src/scss/base/_media.scss
new file mode 100644
index 000000000..4481b6350
--- /dev/null
+++ b/packages/docs/src/scss/base/_media.scss
@@ -0,0 +1,13 @@
+/*------------------------------------*\
+ #MEDIA
+\*------------------------------------*/
+
+/**
+ * Responsive image styling
+ * 1) Allows for images to flex with varying screen size
+ */
+img,
+video {
+ max-width: 100%;
+ height: auto;
+}
diff --git a/packages/docs/src/scss/base/_reset.scss b/packages/docs/src/scss/base/_reset.scss
new file mode 100644
index 000000000..373ab9991
--- /dev/null
+++ b/packages/docs/src/scss/base/_reset.scss
@@ -0,0 +1,54 @@
+/*------------------------------------*\
+ #RESET
+\*------------------------------------*/
+
+/**
+ * Border-Box http:/paulirish.com/2012/box-sizing-border-box-ftw/
+ */
+* {
+ box-sizing: border-box;
+}
+
+/**
+ * 1) Zero out margins and padding for elements
+ */
+html,
+body,
+div,
+object,
+iframe,
+h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+blockquote,
+ol,
+ul,
+li,
+form,
+legend,
+label,
+table,
+header,
+footer,
+nav,
+section,
+figure {
+ margin: 0;
+ padding: 0;
+}
+
+/**
+ * 1) Set HTML5 elements to display: block
+ */
+header,
+footer,
+nav,
+section,
+article,
+figure {
+ display: block;
+}
diff --git a/packages/docs/src/scss/base/_table.scss b/packages/docs/src/scss/base/_table.scss
new file mode 100644
index 000000000..2bedbfada
--- /dev/null
+++ b/packages/docs/src/scss/base/_table.scss
@@ -0,0 +1,26 @@
+/*------------------------------------*\
+ #TABLES
+\*------------------------------------*/
+
+/**
+ * Table
+ */
+table {
+ border-collapse: collapse;
+ border-spacing: 0;
+ width: 100%;
+}
+
+/**
+ * Table header cell
+ */
+th {
+ text-align: left;
+}
+
+/**
+ * Table row
+ */
+tr {
+ vertical-align: top;
+}
diff --git a/packages/docs/src/scss/base/_text.scss b/packages/docs/src/scss/base/_text.scss
new file mode 100644
index 000000000..2fe6b2042
--- /dev/null
+++ b/packages/docs/src/scss/base/_text.scss
@@ -0,0 +1,86 @@
+/*------------------------------------*\
+ #TEXT
+\*------------------------------------*/
+
+/**
+ * Paragraph base styles
+ */
+p {
+ margin-bottom: $spacing;
+}
+
+/**
+ * Blockquote base styles
+ */
+blockquote {
+ font-style: italic;
+ border-left: 1px solid $color-gray-50;
+ color: $color-gray-50;
+ padding-left: 1rem;
+ margin-bottom: $spacing;
+}
+
+/**
+ * Horizontal rule base styles
+ */
+hr {
+ border: 0;
+ height: $border-width-thick;
+ background: $color-gray-13;
+ margin: 2rem 0;
+}
+
+/**
+ * Selection styles
+ */
+::-moz-selection {
+ color: $color-text-highlight;
+ background: $color-text-highlight-bg; /* Gecko Browsers */
+}
+
+::selection {
+ color: $color-text-highlight;
+ background: $color-text-highlight-bg; /* WebKit/Blink Browsers */
+}
+
+/**
+ * Code base styles
+ */
+code {
+ display: inline;
+ background: $color-brand-purple-light;
+ padding: 0.2rem;
+ line-height: 1.2;
+ color: $color-gray-60;
+}
+
+/**
+ * Preformatted text base styles
+ */
+pre {
+ background: $color-gray-88;
+ padding: 2rem;
+ @include boxShadowEffect('green');
+ color: $color-white;
+ position: relative;
+ @include hideScrollbar();
+
+ /**
+ * Remove border from code within preformatted text block
+ */
+ code {
+ border: 0;
+ background: transparent;
+ color: inherit;
+ white-space: pre-wrap;
+ }
+}
+
+// /**
+// * Code with languages associated with them
+// * 1) Override Prism sysles for code blocks with language
+// */
+// code[class*='language-'],
+// pre[class*='language-'] {
+// font-family: monospace !important;
+// }
diff --git a/packages/docs/src/scss/components/_block-grid.scss b/packages/docs/src/scss/components/_block-grid.scss
new file mode 100644
index 000000000..32992857a
--- /dev/null
+++ b/packages/docs/src/scss/components/_block-grid.scss
@@ -0,0 +1,86 @@
+.c-block-grid {
+ display: grid;
+ grid-template-columns: repeat(auto-fill, 250px);
+ grid-gap: $spacing-large;
+ margin-bottom: $spacing-large;
+}
+
+.c-stacked-block {
+ &__description {
+ font-size: $font-size-med;
+ }
+
+ &__preview-container {
+ position: relative;
+ width: 100%;
+ height: 280px;
+ padding: 8px;
+ border-radius: 6px;
+ margin-bottom: 0.75rem;
+
+ display: flex;
+ flex-direction: column;
+ background-color: $color-gray-07;
+ }
+
+ &__bar {
+ height: 24px;
+ display: flex;
+ padding-top: 4px;
+ }
+
+ &__bar &__bar-dots {
+ width: 12px;
+ flex: 0 0 12px;
+ border-radius: 50%;
+ margin-right: 0.5rem;
+
+ &:last-child {
+ margin-right: 0;
+ margin-left: 0.5rem;
+ }
+ }
+
+ &__bar &__bar-uri,
+ &__bar &__bar-dots {
+ height: 12px;
+ background-color: darken($color-gray-07, 8%);
+ }
+
+ &__bar &__bar-uri,
+ &__bar &__bar-dots {
+ height: 12px;
+ background-color: darken($color-gray-07, 8%);
+ }
+
+ &__bar &__bar-uri {
+ position: relative;
+ flex: 1 1 100%;
+ margin: 0 1rem;
+ border-radius: 999px;
+ }
+
+ &__preview-content {
+ flex-grow: 1;
+ overflow: hidden;
+ position: relative;
+ max-width: 100%;
+ border-radius: 3px;
+ }
+
+ &__frame-item {
+ width: 200%;
+ height: 200%;
+ border: 0;
+ transform: scale(0.5);
+ transform-origin: 0 0;
+ }
+
+ &__frame-overlay {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ }
+}
diff --git a/packages/docs/src/scss/components/_buttons.scss b/packages/docs/src/scss/components/_buttons.scss
new file mode 100644
index 000000000..7e09be3b9
--- /dev/null
+++ b/packages/docs/src/scss/components/_buttons.scss
@@ -0,0 +1,47 @@
+/*------------------------------------*\
+ #BUTTONS
+\*------------------------------------*/
+
+/**
+ *
+ * 1) Button or link that has functionality to it
+ */
+.c-btn {
+ font-family: $font-secondary;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: $border-width solid $color-btn-primary-border;
+ background: $color-brand-green;
+ color: $color-black;
+ line-height: 1;
+ padding: 1rem 2rem;
+ border: 0;
+ text-align: center;
+ transition: all $anim-fade-quick $anim-ease;
+
+ &:hover,
+ &:focus {
+ background: $color-btn-primary-bg-hover;
+ }
+}
+
+.c-btn--inverted {
+ background: none;
+ border: 1px solid $color-gray-50;
+ color: $color-gray-27;
+}
+
+.c-btn--small {
+ padding: 1rem;
+}
+
+/*
+ * Button icon
+ */
+.c-btn__icon {
+ width: 1rem;
+ height: 1rem;
+ fill: $color-btn-primary;
+ transition: fill $anim-fade-quick $anim-ease;
+}
diff --git a/packages/docs/src/scss/components/_demo-list.scss b/packages/docs/src/scss/components/_demo-list.scss
new file mode 100644
index 000000000..f2098e0eb
--- /dev/null
+++ b/packages/docs/src/scss/components/_demo-list.scss
@@ -0,0 +1,10 @@
+.c-demo-list {
+ display: grid;
+ grid-column-gap: 1rem;
+ grid-row-gap: 2rem;
+ grid-template-columns: repeat(auto-fill, minmax(350px, 1fr));
+}
+
+.c-header-demo-page {
+ padding-bottom: 2rem;
+}
diff --git a/packages/docs/src/scss/components/_field.scss b/packages/docs/src/scss/components/_field.scss
new file mode 100644
index 000000000..2173b7dbe
--- /dev/null
+++ b/packages/docs/src/scss/components/_field.scss
@@ -0,0 +1,35 @@
+/*------------------------------------*\
+ #FIELDS
+\*------------------------------------*/
+
+/**
+ * 1) Consists of a label, form control, and an optional note about the field.
+ */
+.c-field {
+ margin-bottom: $spacing-large;
+}
+
+/**
+ * Field label
+ */
+.c-field__label {
+ margin-bottom: 0.5rem;
+ font-size: $font-size-med;
+ font-weight: bold;
+}
+
+/**
+ * Field body
+ */
+.c-field__body {
+ position: relative;
+}
+
+/**
+ * Field note
+ */
+.c-field__note {
+ display: inline-block;
+ font-size: $font-size-sm;
+ color: $color-gray-50;
+}
diff --git a/packages/docs/src/scss/components/_footer-nav.scss b/packages/docs/src/scss/components/_footer-nav.scss
new file mode 100644
index 000000000..f5e8b38ec
--- /dev/null
+++ b/packages/docs/src/scss/components/_footer-nav.scss
@@ -0,0 +1,21 @@
+/*------------------------------------*\
+ #FOOTER NAV
+\*------------------------------------*/
+
+/**
+ * The nav inside the footer
+ */
+.c-footer-nav {
+ font-size: $font-size-sm-2;
+ margin-bottom: $spacing;
+
+ @media all and (min-width: $bp-med) {
+ display: flex;
+ }
+}
+
+.c-footer-nav__item {
+ @media all and (min-width: $bp-med) {
+ margin-right: $spacing-large;
+ }
+}
diff --git a/packages/docs/src/scss/components/_footer.scss b/packages/docs/src/scss/components/_footer.scss
new file mode 100644
index 000000000..d18b83bb4
--- /dev/null
+++ b/packages/docs/src/scss/components/_footer.scss
@@ -0,0 +1,22 @@
+/*------------------------------------*\
+ $FOOTER
+\*------------------------------------*/
+
+/**
+ * 1) Global block at the bottom of each page that contains a navigation and other information
+ */
+.c-footer {
+ padding: $spacing-large 0;
+}
+
+/**
+ * Footer note
+ * 1) Small paragraph of text in the footer
+ */
+.c-footer__note {
+ font-size: $font-size-sm;
+
+ a {
+ text-decoration: underline;
+ }
+}
diff --git a/packages/docs/src/scss/components/_header.scss b/packages/docs/src/scss/components/_header.scss
new file mode 100644
index 000000000..dce6e3eee
--- /dev/null
+++ b/packages/docs/src/scss/components/_header.scss
@@ -0,0 +1,99 @@
+/*------------------------------------*\
+ #HEADER
+\*------------------------------------*/
+
+/**
+ * Global block at the top of each page containing the navigation, logo, and other potential contents
+ */
+.c-header {
+ position: relative;
+ background: $color-gray-88;
+ color: $color-gray-27;
+ padding: $spacing;
+ @include hideScrollbar();
+
+ @media all and (min-width: $bp-large) {
+ padding: $spacing-large;
+ min-height: 100vh;
+ flex-direction: column;
+ position: fixed;
+ top: 0;
+ left: 0;
+ height: 100vh;
+ overflow: auto;
+ width: $l-sidebar-width; //Because fixed position
+ }
+}
+
+/**
+ * Header inner
+ */
+.c-header__inner {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+
+ @media all and (min-width: $bp-large) {
+ justify-content: flex-start;
+ align-items: flex-start;
+ flex-direction: column;
+ }
+}
+
+/**
+ * Header navigation button
+ * 1) Button used to toggle the navigation on/off on small screens
+ */
+.c-header__nav-btn {
+ margin-left: auto;
+
+ // Pseudo / breakout element that enables clicking/tabbing outside of the menu to close it
+ &[aria-expanded='true']::after {
+ position: fixed;
+ top: 0;
+ left: 0;
+
+ content: '';
+
+ width: 100vw;
+ height: 100vh;
+ }
+
+ @media all and (min-width: $bp-large) {
+ display: none;
+ }
+}
+
+/**
+ * Header navigation conntainer
+ * 1) Contains the primary navigation and other possible patterns
+ */
+.c-header__nav-container {
+ display: none;
+
+ @media all and (min-width: $bp-large) {
+ display: block;
+ }
+}
+
+/**
+ * Active header nav container
+ */
+.c-header__nav-container.is-active {
+ display: block;
+ position: absolute;
+ background: $color-gray-88;
+ top: 100%;
+ left: 0;
+ width: 100%;
+ z-index: 5;
+ padding: $spacing;
+
+ @media all and (min-width: $bp-large) {
+ display: block;
+ position: static;
+ padding: 0;
+ margin-left: auto;
+ width: inherit;
+ }
+}
diff --git a/packages/docs/src/scss/components/_heading-permalink.scss b/packages/docs/src/scss/components/_heading-permalink.scss
new file mode 100644
index 000000000..e96a1a1e1
--- /dev/null
+++ b/packages/docs/src/scss/components/_heading-permalink.scss
@@ -0,0 +1,38 @@
+/*------------------------------------*\
+ #HEADING PERMALINK
+\*------------------------------------*/
+
+/**
+ * Dynamically applied link icon
+ */
+
+.heading-permalink {
+ position: absolute;
+ top: -3px;
+ left: -20px;
+ display: block;
+ padding-right: 4px;
+
+ .c-text-passage & {
+ opacity: 0;
+ border-bottom: 0;
+ background: none;
+ transition: opacity 0.15s ease;
+
+ &:focus {
+ opacity: 1;
+ }
+ }
+
+ .c-text-passage h2:hover &,
+ .c-text-passage h2:focus &,
+ .c-text-passage h3:hover &,
+ .c-text-passage h3:focus & {
+ opacity: 1;
+ }
+}
+
+.heading-permalink__icon {
+ width: 16px;
+ height: 16px;
+}
diff --git a/packages/docs/src/scss/components/_hero.scss b/packages/docs/src/scss/components/_hero.scss
new file mode 100644
index 000000000..8936ef091
--- /dev/null
+++ b/packages/docs/src/scss/components/_hero.scss
@@ -0,0 +1,53 @@
+/*------------------------------------*\
+ #HERO
+\*------------------------------------*/
+
+.c-hero {
+ background-color: $color-brand-purple-light;
+ color: $color-black;
+ padding: 2rem 0;
+ margin-bottom: 2rem;
+}
+
+.c-hero__inner {
+ display: grid;
+ align-items: center;
+
+ @media all and (min-width: $bp-large) {
+ min-height: 60vh;
+ padding-top: 2rem;
+ padding-bottom: 2rem;
+ }
+}
+
+.c-hero__body {
+ max-width: 47rem;
+}
+
+.c-hero__title {
+ color: $color-brand-purple-dark;
+ font-size: $font-size-large-2;
+ line-height: 1;
+ @include textShadowEffect();
+ margin-bottom: 1rem;
+
+ @media all and (min-width: $bp-large) {
+ font-size: 4.5rem;
+ }
+
+ @media all and (min-width: $bp-xl) {
+ font-size: 6rem;
+ }
+}
+
+.c-hero__description {
+ font-weight: bold;
+}
+
+.c-hero__instructions a {
+ text-decoration: underline;
+}
+
+.c-hero__code {
+ display: inline-block;
+}
diff --git a/packages/docs/src/scss/components/_icon.scss b/packages/docs/src/scss/components/_icon.scss
new file mode 100644
index 000000000..991957a1f
--- /dev/null
+++ b/packages/docs/src/scss/components/_icon.scss
@@ -0,0 +1,11 @@
+/*------------------------------------*\
+ #ICON
+\*------------------------------------*/
+
+/**
+ * 1) Small image that represents functionality
+ */
+.c-icon {
+ height: 16px;
+ width: 16px;
+}
diff --git a/packages/docs/src/scss/components/_logo.scss b/packages/docs/src/scss/components/_logo.scss
new file mode 100644
index 000000000..ec70ed028
--- /dev/null
+++ b/packages/docs/src/scss/components/_logo.scss
@@ -0,0 +1,70 @@
+/*------------------------------------*\
+ #LOGO
+\*------------------------------------*/
+
+/**
+ * Branding image or text of the site
+ */
+.c-logo {
+ @media all and (min-width: $bp-med) {
+ margin-bottom: $spacing-large;
+ }
+}
+
+/**
+ * Logo link
+ */
+.c-logo__link {
+ display: flex;
+ align-items: center;
+
+ &:focus {
+ @include focusInverted();
+ }
+}
+
+/**
+ * Logo image
+ */
+.c-logo__img {
+ display: block;
+ max-width: 2.4rem;
+ margin-right: 0.5rem;
+ animation: rotate 10s linear infinite;
+}
+
+/**
+ * Logo body
+ * 1) contains the logo text and meta info
+ */
+.c-logo__body {
+ position: relative;
+}
+
+/**
+ * Logo text
+ */
+.c-logo__text {
+ text-transform: lowercase;
+ font-weight: bold;
+ color: $color-white;
+}
+
+.c-logo__meta {
+ display: block;
+ padding-top: 0.2rem;
+ font-size: $font-size-sm;
+ color: $color-gray-27;
+ font-weight: 500;
+ position: absolute;
+ top: 100%;
+}
+
+@keyframes rotate {
+ from {
+ transform: rotate(0deg);
+ }
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/packages/docs/src/scss/components/_page-header.scss b/packages/docs/src/scss/components/_page-header.scss
new file mode 100644
index 000000000..83adb586b
--- /dev/null
+++ b/packages/docs/src/scss/components/_page-header.scss
@@ -0,0 +1,30 @@
+/*------------------------------------*\
+ #PAGE HEADER
+\*------------------------------------*/
+/**
+ * 1) Container that consists of of a page header title and description
+ */
+.c-page-header {
+ margin-bottom: $spacing-large;
+}
+
+.c-page-header__kicker {
+ color: $color-gray-50;
+ margin-bottom: 0.5rem;
+}
+
+/**
+ * Page header title
+ */
+.c-page-header__title {
+ margin-bottom: $spacing;
+ @include textShadowEffect();
+}
+
+/**
+ * Page description
+ */
+.c-page-header__desc {
+ margin-top: 1rem;
+ margin-bottom: 2rem;
+}
diff --git a/packages/docs/src/scss/components/_primary-nav.scss b/packages/docs/src/scss/components/_primary-nav.scss
new file mode 100644
index 000000000..79918ce81
--- /dev/null
+++ b/packages/docs/src/scss/components/_primary-nav.scss
@@ -0,0 +1,42 @@
+/*------------------------------------*\
+ #PRIMARY NAVIGATION
+\*------------------------------------*/
+
+/**
+ * Primary navigation existing in the header and maybe the footer
+ */
+.c-primary-nav {
+ margin-left: auto;
+}
+
+/**
+ * Primary navigation list
+ */
+.c-primary-nav__list {
+ display: flex;
+}
+
+/**
+ * Primary navigation item
+ */
+.c-primary-nav__item {
+ margin-right: 1rem;
+}
+
+/**
+ * Primary navigation link
+ */
+.c-primary-nav__link {
+ display: block;
+ padding: 0.5rem 0;
+ transition: color 0.2s ease;
+
+ &:hover {
+ color: $color-white;
+ }
+
+ &:focus {
+ color: $color-white;
+ font-weight: bold;
+ }
+}
diff --git a/packages/docs/src/scss/components/_stacked-block-list.scss b/packages/docs/src/scss/components/_stacked-block-list.scss
new file mode 100644
index 000000000..d8aa3a6a4
--- /dev/null
+++ b/packages/docs/src/scss/components/_stacked-block-list.scss
@@ -0,0 +1,12 @@
+/*------------------------------------*\
+ #STACKED BLOCK LIST
+\*------------------------------------*/
+
+/**
+ * Stacked block list item
+ */
+.c-stacked-block-list__item {
+ border-bottom: 1px solid $color-gray-27;
+ padding-bottom: 1rem;
+ margin-bottom: 2rem;
+}
diff --git a/packages/docs/src/scss/components/_stacked-block.scss b/packages/docs/src/scss/components/_stacked-block.scss
new file mode 100644
index 000000000..8096b2fcd
--- /dev/null
+++ b/packages/docs/src/scss/components/_stacked-block.scss
@@ -0,0 +1,19 @@
+/*------------------------------------*\
+ #STACKED BLOCK
+\*------------------------------------*/
+
+/**
+ * Stacked block list item
+ */
+.c-stacked-block__title {
+ line-height: 1.2;
+ margin-bottom: 0.25rem;
+}
+
+/**
+ * Stacked block list item
+ */
+.c-stacked-block__kicker {
+ font-size: $font-size-sm-2;
+ color: $color-gray-50;
+}
diff --git a/packages/docs/src/scss/components/_table.scss b/packages/docs/src/scss/components/_table.scss
new file mode 100644
index 000000000..5b643fc56
--- /dev/null
+++ b/packages/docs/src/scss/components/_table.scss
@@ -0,0 +1,52 @@
+/*------------------------------------*\
+ #TABLE
+\*------------------------------------*/
+
+/**
+ * 1) Data Table
+ */
+.c-table {
+ margin-bottom: 1rem;
+ min-width: 600px; /* 2 */
+}
+
+/**
+ * Table Header
+ */
+.c-table__header {
+ background: $color-gray-07;
+}
+
+/**
+ * Table Header Cell
+ */
+.c-table__header-cell {
+ padding: 0.8rem;
+}
+
+/**
+ * Table Row
+ */
+.c-table__row {
+ border-bottom: 1px solid $color-gray-07;
+}
+
+/**
+ * Table Cell
+ */
+.c-table__cell {
+ padding: 1.6rem 0.8rem;
+}
+
+/**
+ * Table Footer
+ */
+.c-table__footer {
+}
+
+/**
+ * Table Footer Cell
+ */
+.c-table__footer-cell {
+ padding: 0.8rem;
+}
diff --git a/packages/docs/src/scss/components/_text-passage.scss b/packages/docs/src/scss/components/_text-passage.scss
new file mode 100644
index 000000000..ef93eb93a
--- /dev/null
+++ b/packages/docs/src/scss/components/_text-passage.scss
@@ -0,0 +1,110 @@
+/*------------------------------------*\
+ #TEXT PASSAGE
+\*------------------------------------*/
+
+/**
+ * 1) A passage of text, including various components (i.e. article, blog post)
+ */
+.c-text-passage {
+ p {
+ margin-bottom: $spacing-large;
+ }
+
+ /**
+ * Link within the text passage
+ */
+ a {
+ border-bottom: 1px solid $color-black;
+ background: $color-brand-green-light;
+
+ &:hover,
+ &:focus {
+ color: $color-black;
+ border-bottom-color: $color-brand-green;
+ }
+ }
+
+ /**
+ * Blockquote within text passage
+ */
+ blockquote {
+ padding-left: 0.8rem;
+ border-left: 3px solid $color-gray-73;
+ color: $color-gray-50;
+ font-size: 1rem;
+ }
+
+ /**
+ * First-level heading within text passage
+ */
+ h1 {
+ margin-bottom: $spacing;
+ }
+
+ /**
+ * Second-level heading within text passage
+ */
+ h2 {
+ margin: 3rem 0 $spacing;
+ color: $color-gray-73;
+ }
+
+ /**
+ * Third-level heading within text passage
+ */
+ h3 {
+ margin: 3rem 0 $spacing;
+ }
+
+ /**
+ * Fourth-level heading within text passage
+ */
+ h4 {
+ margin: 3rem 0 $spacing;
+ }
+
+ /**
+ * Fifth-level heading within text passage
+ */
+ h5 {
+ margin: 3rem 0 $spacing;
+ }
+
+ /**
+ * Sixth-level heading within text passage
+ */
+ h6 {
+ margin: 3rem 0 $spacing;
+ }
+
+ /**
+ * Unordered list within text passage
+ */
+ ul {
+ list-style: disc;
+ margin-left: 1.25rem;
+ margin-bottom: $spacing-large;
+
+ li:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ /**
+ * Ordered list within text passage
+ */
+ ol {
+ list-style: decimal;
+ margin-left: $spacing;
+ margin-bottom: $spacing-large;
+
+ li:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ li {
+ margin-bottom: $spacing;
+ line-height: 1.6;
+ }
+}
diff --git a/packages/docs/src/scss/components/_tile-list.scss b/packages/docs/src/scss/components/_tile-list.scss
new file mode 100644
index 000000000..548134685
--- /dev/null
+++ b/packages/docs/src/scss/components/_tile-list.scss
@@ -0,0 +1,31 @@
+/*------------------------------------*\
+ #TILE
+\*------------------------------------*/
+
+.c-tile-list {
+ display: grid;
+ grid-gap: $spacing-large;
+ margin-bottom: $spacing-xl;
+
+ @media all and (min-width: $bp-xl) {
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+.c-tile-list__item:nth-child(1) {
+ @media all and (min-width: $bp-xl) {
+ grid-row: span 2;
+ }
+}
+
+.c-tile-list__item:nth-child(2) {
+ @media all and (min-width: $bp-xl) {
+ grid-column: 2/3;
+ }
+}
+.c-tile-list__item:nth-child(3) {
+ @media all and (min-width: $bp-xl) {
+ grid-row: 2;
+ grid-column: 2/3;
+ }
+}
diff --git a/packages/docs/src/scss/components/_tile.scss b/packages/docs/src/scss/components/_tile.scss
new file mode 100644
index 000000000..e14c24f3d
--- /dev/null
+++ b/packages/docs/src/scss/components/_tile.scss
@@ -0,0 +1,75 @@
+/*------------------------------------*\
+ #TILE
+\*------------------------------------*/
+
+.c-tile {
+ position: relative;
+ height: 100%;
+ display: flex;
+ flex-direction: column;
+}
+
+.c-tile__body {
+ padding: 2rem;
+ position: relative;
+ z-index: 1; // TODO: Evaluate whether this declaration is (still) necessary
+ flex: 1;
+
+ .c-tile--green & {
+ color: $color-brand-green-dark;
+ background: $color-brand-green-light;
+ }
+
+ .c-tile--orange & {
+ color: $color-brand-orange-dark;
+ background: $color-brand-orange-light;
+ }
+
+ .c-tile--purple & {
+ color: $color-brand-purple-dark;
+ background: $color-brand-purple-light;
+ }
+}
+
+.c-tile__shadow {
+ width: 100%;
+ height: 100%;
+ position: absolute;
+ right: -10px;
+ bottom: -10px;
+ z-index: 0; // TODO: Evaluate whether this declaration is (still) necessary
+ @include stripedBoxShadow('green');
+
+ .c-tile--orange & {
+ @include stripedBoxShadow('orange');
+ }
+
+ .c-tile--purple & {
+ @include stripedBoxShadow('purple');
+ }
+}
+
+.c-tile__title {
+ color: inherit;
+}
+
+.c-tile__link {
+ color: inherit;
+
+ &:hover,
+ &:focus {
+ color: inherit;
+ text-decoration: underline;
+ }
+}
+
+.c-tile__description a {
+ color: inherit;
+ text-decoration: underline;
+
+ &:hover,
+ &:focus {
+ color: inherit;
+ text-decoration: none;
+ }
+}
diff --git a/packages/docs/src/scss/components/_tree-nav.scss b/packages/docs/src/scss/components/_tree-nav.scss
new file mode 100644
index 000000000..754852c6a
--- /dev/null
+++ b/packages/docs/src/scss/components/_tree-nav.scss
@@ -0,0 +1,95 @@
+/*------------------------------------*\
+ #TREE NAV
+\*------------------------------------*/
+
+/**
+ * 1) A tree nav is a nested accordion-style navigation, similar
+ * to operating system file manager navigations
+ */
+.c-tree-nav {
+}
+
+.c-tree-nav__link {
+ display: flex;
+ align-items: center;
+ margin-bottom: 1.2rem;
+ color: inherit;
+ font-weight: $font-weight-bold;
+ transition: color 0.2s ease;
+
+ &:hover,
+ &.is-active {
+ color: $color-white;
+ }
+
+ &:focus {
+ color: $color-white;
+ @include focusInverted();
+ }
+}
+
+.c-tree-nav__link--is-active {
+ color: $color-white;
+ font-weight: bold;
+}
+
+/**
+ * Subnav
+ */
+.c-tree-nav__subnav {
+ padding-left: 1rem;
+ border-left: 1px solid $color-gray-73;
+ margin-bottom: 1rem;
+ font-size: $font-size-med;
+ display: none;
+
+ .c-tree-nav__item.is-active & {
+ display: block;
+ }
+}
+
+.c-tree-nav__icon {
+ transition: transform $anim-fade-quick $anim-ease;
+
+ .c-tree-nav__item.is-active & {
+ transform: rotate(180deg);
+ }
+}
+
+.c-tree-nav__subnav-title {
+ font-weight: bold;
+ display: block;
+ margin-bottom: 1rem;
+}
+
+.c-tree-nav__subnav-link {
+ color: inherit;
+ display: block;
+ margin-bottom: 1rem;
+
+ &:hover,
+ &:focus,
+ &.is-active {
+ color: $color-white;
+ }
+
+ &:focus {
+ @include focusInverted();
+ }
+}
+
+.c-tree-nav__link--btn {
+ background: transparent;
+ border: 0;
+ padding: 0;
+ font-size: inherit;
+
+ svg {
+ fill: currentColor;
+ }
+}
+
+.c-tree-nav__subnav-link--heading {
+ font-weight: bold;
+ color: $color-white;
+}
diff --git a/packages/docs/src/scss/layout/_layout.scss b/packages/docs/src/scss/layout/_layout.scss
new file mode 100644
index 000000000..57d4527ca
--- /dev/null
+++ b/packages/docs/src/scss/layout/_layout.scss
@@ -0,0 +1,42 @@
+/*------------------------------------*\
+ #LAYOUT
+\*------------------------------------*/
+
+/**
+ * Layout Container
+ * 1) Caps the width of the content to the maximum width
+ * and centers the container
+ */
+.l-container {
+ max-width: $l-max-width;
+ margin: 0 auto;
+ padding: 0 2rem;
+
+ @media all and (min-width: $bp-large) {
+ padding: 0 4rem;
+ }
+}
+
+/**
+ *
+ * 1) This narrow layout container is for lists, forms,
+ * and other singular objects that aren't dashboard-y
+ * kinds of displays
+ */
+.l-linelength-container {
+ max-width: $l-linelength-width;
+}
+
+/*------------------------------------*\
+ #GRID
+\*------------------------------------*/
+
+/**
+ * Grid Container
+ */
+.l-grid {
+ @media all and (min-width: $bp-large) {
+ display: grid;
+ grid-template-columns: $l-sidebar-width 1fr;
+ }
+}
diff --git a/packages/docs/src/scss/mixins/_dark-mode.scss b/packages/docs/src/scss/mixins/_dark-mode.scss
new file mode 100644
index 000000000..880638322
--- /dev/null
+++ b/packages/docs/src/scss/mixins/_dark-mode.scss
@@ -0,0 +1,21 @@
+/**
+ * DARK MODE MIXIN
+ *
+ * A little wrapper that lets you define your dark mode custom
+ * properties in a way that supports the theme toggle web component
+ */
+@mixin dark-mode() {
+ @media (prefers-color-scheme: dark) {
+ :root {
+ --color-mode: 'dark';
+ }
+
+ :root:not([data-user-color-scheme]) {
+ @content;
+ }
+ }
+
+ [data-user-color-scheme='dark'] {
+ @content;
+ }
+}
diff --git a/packages/docs/src/scss/style.scss b/packages/docs/src/scss/style.scss
new file mode 100644
index 000000000..d6b95459d
--- /dev/null
+++ b/packages/docs/src/scss/style.scss
@@ -0,0 +1,71 @@
+/*------------------------------------*\
+ #TABLE OF CONTENTS
+\*------------------------------------*/
+/**
+ * ABSTRACTS..............................Declarations of Sass variables & mixins
+ * BASE...................................Default element styles
+ * LAYOUT.................................Layout-specific styles
+ * COMPONENTS.............................Component styles
+ * UTILITIES..............................Utility classes
+ */
+
+/*------------------------------------*\
+ #ABSTRACTS
+\*------------------------------------*/
+@import 'abstracts/variables';
+@import 'abstracts/mixins';
+@import 'abstracts/colors';
+@import 'abstracts/typography';
+
+/*------------------------------------*\
+ #BASE
+\*------------------------------------*/
+@import 'base/reset';
+@import 'base/body';
+@import 'base/links';
+@import 'base/lists';
+@import 'base/headings';
+@import 'base/forms';
+@import 'base/buttons';
+@import 'base/main';
+@import 'base/media';
+@import 'base/text';
+@import 'base/table';
+
+/*------------------------------------*\
+ #LAYOUT
+\*------------------------------------*/
+@import 'layout/layout';
+
+/*------------------------------------*\
+ #COMPONENTS
+\*------------------------------------*/
+@import 'components/buttons';
+@import 'components/footer';
+@import 'components/footer-nav';
+@import 'components/header';
+@import 'components/heading-permalink';
+@import 'components/hero';
+@import 'components/logo';
+@import 'components/icon';
+@import 'components/page-header';
+@import 'components/primary-nav';
+@import 'components/tree-nav';
+@import 'components/text-passage';
+@import 'components/tile';
+@import 'components/tile-list';
+@import 'components/field';
+@import 'components/stacked-block';
+@import 'components/stacked-block-list';
+@import 'components/demo-list';
+@import 'components/block-grid';
+
+/*------------------------------------*\
+ #UTILITIES
+\*------------------------------------*/
+@import 'utilities/visibility';
+
+/*------------------------------------*\
+ #VENDOR
+\*------------------------------------*/
+@import 'vendor/prism';
diff --git a/packages/docs/src/scss/utilities/_visibility.scss b/packages/docs/src/scss/utilities/_visibility.scss
new file mode 100644
index 000000000..376fae5ff
--- /dev/null
+++ b/packages/docs/src/scss/utilities/_visibility.scss
@@ -0,0 +1,26 @@
+/*------------------------------------*\
+ #VISIBILITY CLASSES
+\*------------------------------------*/
+
+/**
+ * Is Hidden
+ * 1) Completely remove from the flow and screen readers.
+ */
+.u-is-hidden {
+ display: none !important;
+ visibility: hidden !important;
+}
+
+/**
+ * Is Visibly Hidden
+ * 1) Completely remove from the flow but leave available to screen readers.
+ */
+.u-is-vishidden {
+ position: absolute !important;
+ overflow: hidden;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ border: 0;
+ clip: rect(1px, 1px, 1px, 1px);
+}
diff --git a/packages/docs/src/scss/vendor/_prism.scss b/packages/docs/src/scss/vendor/_prism.scss
new file mode 100644
index 000000000..3b33b79cc
--- /dev/null
+++ b/packages/docs/src/scss/vendor/_prism.scss
@@ -0,0 +1,124 @@
+/* PrismJS 1.17.1
+https://prismjs.com/download.html#themes=prism-tomorrow&languages=markup+css+clike+javascript+markup-templating+handlebars+php+json+scss+twig */
+/**
+ * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML
+ * Based on https://github.com/chriskempson/tomorrow-theme
+ * @author Rose Pritchard
+ */
+
+code[class*='language-'],
+pre[class*='language-'] {
+ color: #ccc;
+ background: none;
+ font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
+ font-size: $font-size-med;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ word-wrap: normal;
+ // white-space: pre-wrap;
+ line-height: 1.5;
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+}
+
+/* Code blocks */
+pre[class*='language-'] {
+ padding: 1em;
+ margin: 0.5em 0;
+ overflow: auto;
+}
+
+:not(pre) > code[class*='language-'],
+pre[class*='language-'] {
+ background: #2d2d2d;
+}
+
+/* Inline code */
+:not(pre) > code[class*='language-'] {
+ padding: 0.1em;
+ border-radius: 0.3em;
+ white-space: normal;
+}
+
+.token.comment,
+.token.block-comment,
+.token.prolog,
+.token.doctype,
+.token.cdata {
+ color: #999;
+}
+
+.token.punctuation {
+ color: #ccc;
+}
+
+.token.tag,
+.token.attr-name,
+.token.namespace,
+.token.deleted {
+ color: #e2777a;
+}
+
+.token.function-name {
+ color: #6196cc;
+}
+
+.token.boolean,
+.token.number,
+.token.function {
+ color: #f08d49;
+}
+
+.token.property,
+.token.class-name,
+.token.constant,
+.token.symbol {
+ color: #f8c555;
+}
+
+.token.selector,
+.token.important,
+.token.atrule,
+.token.keyword,
+.token.builtin {
+ color: #cc99cd;
+}
+
+.token.string,
+.token.char,
+.token.attr-value,
+.token.regex,
+.token.variable {
+ color: #7ec699;
+}
+
+.token.operator,
+.token.entity,
+.token.url {
+ color: #67cdcc;
+}
+
+.token.important,
+.token.bold {
+ font-weight: bold;
+}
+.token.italic {
+ font-style: italic;
+}
+
+.token.entity {
+ cursor: help;
+}
+
+.token.inserted {
+ color: green;
+}
diff --git a/packages/docs/src/sitemap.njk b/packages/docs/src/sitemap.njk
new file mode 100644
index 000000000..d87ee9df4
--- /dev/null
+++ b/packages/docs/src/sitemap.njk
@@ -0,0 +1,17 @@
+---
+permalink: /sitemap.xml
+sitemapIgnore: true
+---
+
+
+{% for item in collections.all %}
+{% if not item.data.sitemapIgnore %}
+
+ {{ site.url }}{{ item.url }}
+ {{ item.date | w3DateFilter()}}
+ {{ item.data.sitemapChangefreq | default("yearly") }}
+ {{ item.data.sitemapPriority | default(0.7) }}
+
+{% endif %}
+{% endfor %}
+
diff --git a/packages/docs/src/styleguide.njk b/packages/docs/src/styleguide.njk
new file mode 100644
index 000000000..e7e2fc117
--- /dev/null
+++ b/packages/docs/src/styleguide.njk
@@ -0,0 +1,113 @@
+---
+title: 'Styleguide'
+permalink: /styleguide/
+sitemapIgnore: true
+---
+
+{% extends 'layouts/base.njk' %}
+
+{# Intro content #}
+{% set introHeading = title %}
+
+{% block head %}
+
+{% endblock %}
+{% block content %}
+
+ {% include "partials/components/intro.njk" %}
+
+
+ Colours
+ Colour swatches with various values that you can copy.
+
+ {% for color in styleguide.colors() %}
+
+
+ {{ color.key }}
+
+ Value
+ {{ color.value }}
+ Sass function
+ get-color('{{ color.key }}')
+ Custom Property
+ var(--color-{{ color.key }})
+ Text util class
+ color-{{ color.key }}
+ Background util class
+ bg-{{ color.key }}
+
+
+ {% endfor %}
+
+ Fonts
+ Base — System stack
+
+ The quick brown fox jumps over the lazy fox
+ .font-base
+
+ Serif — Lora
+
+ The quick brown fox jumps over the lazy fox
+ .font-serif
+
+ Text sizes
+ Text sizes are available as standard classes or media query prefixed, such as lg:text-500.
+ {% for size in styleguide.sizes() %}
+ {{ size.value }} - text-{{ size.key }}
+ {% endfor %}
+ Spacing
+ There’s size ratio utilities that give you margin (gap-top, gap-bottom) and padding (pad-top, pad-left, pad-bottom).
+
Margin
+ Margin token classes that you can copy
+
+ {% for size in styleguide.sizes() %}
+
+ gap-top-{{ size.key }}
+
+ {% endfor %}
+
+ Padding
+ Padding token classes that you can copy
+ {% for size in styleguide.sizes() %}
+
+ pad-top-{{ size.key }}
+
+
+ pad-bottom-{{ size.key }}
+
+
+ pad-left-{{ size.key }}
+
+ {% endfor %}
+
+
+
+{% endblock %}
diff --git a/packages/docs/src/support.md b/packages/docs/src/support.md
new file mode 100644
index 000000000..9f227fbc0
--- /dev/null
+++ b/packages/docs/src/support.md
@@ -0,0 +1,13 @@
+---
+layout: layouts/post.njk
+title: Pattern Lab Support
+sitemapPriority: '0.8'
+---
+
+## GitHub
+
+[GitHub](https://github.com/pattern-lab/) is the home base for the Pattern Lab project. You can explore the repository and submit/track [issues](https://github.com/pattern-lab/patternlab-node/issues) per the [contribution guidelines](https://github.com/pattern-lab/patternlab-node/blob/master/.github/CONTRIBUTING.md).
+
+## Gitter
+
+You can head over to [Pattern Lab's Gitter](https://gitter.im/pattern-lab/home) to chat with the Pattern Lab community. This is a great place to talk shop, ask questions, and get (and give!) help.
diff --git a/packages/docs/src/tags.njk b/packages/docs/src/tags.njk
new file mode 100644
index 000000000..fc07b9b12
--- /dev/null
+++ b/packages/docs/src/tags.njk
@@ -0,0 +1,37 @@
+---
+title: Tag Archive
+pagination:
+ data: collections
+ size: 1
+ alias: tag
+ filter:
+ - all
+ - nav
+ - post
+ - posts
+ - tagList
+ - postFeed
+ addAllPagesToCollections: true
+permalink: /tags/{{ tag }}/
+sitemapIgnore: true
+---
+
+{% extends 'layouts/base.njk' %}
+{% set pageType = 'Tag Archive' %}
+
+{# Intro content #}
+{% set introHeading %}Posts filed under “{{ tag }}”{% endset %}
+{% set introHeadingLevel = '2' %}
+
+{# Post list content #}
+{% set postListHeadingLevel = '2' %}
+{% set postListHeading = 'Posts' %}
+{% set postListItems = collections[tag] %}
+
+{% block content %}
+
+ {% include "partials/components/intro.njk" %}
+ {% include "partials/components/post-list.njk" %}
+ {% include "partials/components/pagination.njk" %}
+
+{% endblock %}
diff --git a/packages/docs/src/transforms/html-min-transform.js b/packages/docs/src/transforms/html-min-transform.js
new file mode 100644
index 000000000..9b9432d39
--- /dev/null
+++ b/packages/docs/src/transforms/html-min-transform.js
@@ -0,0 +1,14 @@
+const htmlmin = require('html-minifier');
+
+module.exports = function htmlMinTransform(value, outputPath) {
+ if (outputPath.indexOf('.html') > -1) {
+ const minified = htmlmin.minify(value, {
+ useShortDoctype: true,
+ removeComments: true,
+ collapseWhitespace: true,
+ minifyCSS: true,
+ });
+ return minified;
+ }
+ return value;
+};
diff --git a/packages/docs/src/transforms/parse-transform.js b/packages/docs/src/transforms/parse-transform.js
new file mode 100644
index 000000000..3cc0bf6d7
--- /dev/null
+++ b/packages/docs/src/transforms/parse-transform.js
@@ -0,0 +1,78 @@
+const jsdom = require('@tbranyen/jsdom');
+const {JSDOM} = jsdom;
+const minify = require('../utils/minify.js');
+const slugify = require('slugify');
+
+module.exports = function (value, outputPath) {
+ if (outputPath.endsWith('.html')) {
+ const DOM = new JSDOM(value, {
+ resources: 'usable',
+ });
+
+ const document = DOM.window.document;
+ const articleImages = [...document.querySelectorAll('main article img')];
+ const articleHeadings = [
+ ...document.querySelectorAll('main article h2, main article h3'),
+ ];
+ const articleEmbeds = [...document.querySelectorAll('main article iframe')];
+
+ if (articleImages.length) {
+ articleImages.forEach((image) => {
+ image.setAttribute('loading', 'lazy');
+
+ // If an image has a title it means that the user added a caption
+ // so replace the image with a figure containing that image and a caption
+ if (image.hasAttribute('title')) {
+ const figure = document.createElement('figure');
+ const figCaption = document.createElement('figcaption');
+
+ figCaption.innerHTML = image.getAttribute('title');
+
+ image.removeAttribute('title');
+
+ figure.appendChild(image.cloneNode(true));
+ figure.appendChild(figCaption);
+
+ image.replaceWith(figure);
+ }
+ });
+ }
+
+ if (articleHeadings.length) {
+ // Loop each heading and add a little anchor and an ID to each one
+ articleHeadings.forEach((heading) => {
+ const headingSlug = slugify(heading.textContent.toLowerCase());
+ const anchor = document.createElement('a');
+
+ anchor.setAttribute('href', `#heading-${headingSlug}`);
+ anchor.classList.add('heading-permalink');
+ anchor.innerHTML = minify(`
+ permalink
+
+
+ `);
+
+ heading.setAttribute('id', `heading-${headingSlug}`);
+ heading.appendChild(anchor);
+ });
+ }
+
+ // Look for videos are wrap them in a container element
+ if (articleEmbeds.length) {
+ articleEmbeds.forEach((embed) => {
+ if (embed.hasAttribute('allowfullscreen')) {
+ const player = document.createElement('div');
+
+ player.classList.add('video-player');
+
+ player.appendChild(embed.cloneNode(true));
+
+ embed.replaceWith(player);
+ }
+ });
+ }
+
+ return '\r\n' + document.documentElement.outerHTML;
+ }
+ return value;
+};
diff --git a/packages/docs/src/updates.md b/packages/docs/src/updates.md
new file mode 100644
index 000000000..b2a2be380
--- /dev/null
+++ b/packages/docs/src/updates.md
@@ -0,0 +1,6 @@
+---
+layout: layouts/blog.njk
+title: Pattern Lab Updates
+description: The latest news about the Pattern Lab project
+sitemapIgnore: true
+---
diff --git a/packages/docs/src/utils/minify.js b/packages/docs/src/utils/minify.js
new file mode 100644
index 000000000..cb20f3609
--- /dev/null
+++ b/packages/docs/src/utils/minify.js
@@ -0,0 +1,3 @@
+module.exports = function minify(input) {
+ return input.replace(/\s{2,}/g, '').replace(/\'/g, '"');
+};
diff --git a/packages/edition-node-gulp/.nvmrc b/packages/edition-node-gulp/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/edition-node-gulp/.nvmrc
+++ b/packages/edition-node-gulp/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/edition-node-gulp/CHANGELOG.md b/packages/edition-node-gulp/CHANGELOG.md
index 1ff6151c1..75a92b671 100644
--- a/packages/edition-node-gulp/CHANGELOG.md
+++ b/packages/edition-node-gulp/CHANGELOG.md
@@ -3,6 +3,482 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [6.0.3](https://github.com/pattern-lab/patternlab-node/compare/v6.0.2...v6.0.3) (2023-03-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.15.7](https://github.com/pattern-lab/patternlab-node/compare/v5.15.6...v5.15.7) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.15.6](https://github.com/pattern-lab/patternlab-node/compare/v5.15.5...v5.15.6) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+
+### Bug Fixes
+
+* corrected some github urls ([#1388](https://github.com/pattern-lab/patternlab-node/issues/1388)) ([7f37e9d](https://github.com/pattern-lab/patternlab-node/commit/7f37e9d56b553dc4be53590766c0fc6251458829))
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+
+### Bug Fixes
+
+* corrected some github urls ([#1388](https://github.com/pattern-lab/patternlab-node/issues/1388)) ([7f37e9d](https://github.com/pattern-lab/patternlab-node/commit/7f37e9d56b553dc4be53590766c0fc6251458829))
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/issues/1192) ([420e829](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/commit/420e8293c033557ede073bc13e68955a450a3c8e))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.9.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.9.1...v5.9.2) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.7.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.7.1...v5.7.2) (2020-03-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.7.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.7.0...v5.7.1) (2020-02-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.6.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.5.0...v5.6.0) (2020-01-18)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.4.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.4.1...v5.4.2) (2019-11-27)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.4.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.4.0...v5.4.1) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.3.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.3.2...v5.3.3) (2019-11-22)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+
+## [5.3.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.3.1...v5.3.2) (2019-11-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.3.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.3.0...v5.3.1) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.2.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.1.0...v5.2.0) (2019-11-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+
+### Features
+
+* **config:** add new default pattern export options ([a7487a0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/commit/a7487a0681cb11e6f3c5c8eaefd62e5648ad5ea3))
+
+
+
+
+
+## [5.0.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.0.1...v5.0.2) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [5.0.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v5.0.0...v5.0.1) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+
+## [2.0.9](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/@pattern-lab/edition-node-gulp@2.0.8...@pattern-lab/edition-node-gulp@2.0.9) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+
+## [2.0.8](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/@pattern-lab/edition-node-gulp@2.0.7...@pattern-lab/edition-node-gulp@2.0.8) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+
+## [2.0.4](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/@pattern-lab/edition-node-gulp@2.0.3...@pattern-lab/edition-node-gulp@2.0.4) (2019-08-23)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+## [2.0.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/@pattern-lab/edition-node-gulp@2.0.2...@pattern-lab/edition-node-gulp@2.0.3) (2019-08-23)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
+
+## [2.0.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/@pattern-lab/edition-node-gulp@2.0.2-alpha.0...@pattern-lab/edition-node-gulp@2.0.2) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/edition-node-gulp
+
+
+
+
+
# [2.0.0-beta.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node-gulp/compare/@pattern-lab/edition-node-gulp@2.0.0-beta.0...@pattern-lab/edition-node-gulp@2.0.0-beta.2) (2019-02-09)
diff --git a/packages/edition-node-gulp/LICENSE b/packages/edition-node-gulp/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/edition-node-gulp/LICENSE
+++ b/packages/edition-node-gulp/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/edition-node-gulp/README.md b/packages/edition-node-gulp/README.md
index c735382a0..4769ff0ea 100644
--- a/packages/edition-node-gulp/README.md
+++ b/packages/edition-node-gulp/README.md
@@ -5,21 +5,21 @@
# Pattern Lab Node - Gulp Edition
-The Gulp wrapper around [Pattern Lab Node Core](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core)), the default PatternEngine, and supporting frontend assets.
+The Gulp wrapper around [Pattern Lab Node Core](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core), the default PatternEngine, and supporting frontend assets.
-[Online Demo of Pattern Lab Output](http://demo.patternlab.io/)
+[Online Demo of Pattern Lab Output](https://demo.patternlab.io/)
## Packaged Components
This Edition comes with the following components:
* `@pattern-lab/core`: [GitHub](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core) | [npm](https://www.npmjs.com/package/@pattern-lab/core)
-* `@pattern-lab/engine-mustache`: [GitHub](https://github.com/pattern-lab/tree/master/packages/engine-mustache) | [npm](https://www.npmjs.com/package/@pattern-lab/engine-mustache)
-* `@pattern-lab/uikit-workshop`: [GitHub](https://github.com/pattern-lab/tree/master/packages/uikit-workshop) | [npm](https://www.npmjs.com/package/@pattern-lab/uikit-workshop)
+* `@pattern-lab/engine-mustache`: [GitHub](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache) | [npm](https://www.npmjs.com/package/@pattern-lab/engine-mustache)
+* `@pattern-lab/uikit-workshop`: [GitHub](https://github.com/pattern-lab/patternlab-node/tree/master/packages/uikit-workshop) | [npm](https://www.npmjs.com/package/@pattern-lab/uikit-workshop)
## Prerequisites
-This Edition uses [Node](https://nodejs.org) for core processing, [npm](https://www.npmjs.com/) to manage project dependencies, and [gulp.js](http://gulpjs.com/) to run tasks and interface with the core library. You can follow the directions for [installing Node](https://nodejs.org/en/download/) on the Node website if you haven't done so already. Installation of Node will include npm.
+This Edition uses [Node](https://nodejs.org/) for core processing, [npm](https://www.npmjs.com/) to manage project dependencies, and [gulp.js](https://gulpjs.com/) to run tasks and interface with the core library. You can follow the directions for [installing Node](https://nodejs.org/en/download/) on the Node website if you haven't done so already. Installation of Node will include npm.
## Installing
diff --git a/packages/edition-node-gulp/gulpfile.js b/packages/edition-node-gulp/gulpfile.js
index e1947e4fd..fd039bad7 100644
--- a/packages/edition-node-gulp/gulpfile.js
+++ b/packages/edition-node-gulp/gulpfile.js
@@ -27,42 +27,39 @@ function serve() {
return patternlab.server
.serve({
cleanPublic: config.cleanPublic,
+ watch: true,
})
.then(() => {
// do something else when this promise resolves
});
}
-gulp.task('patternlab:version', function() {
+gulp.task('patternlab:version', function () {
console.log(patternlab.version());
});
-gulp.task('patternlab:patternsonly', function() {
+gulp.task('patternlab:patternsonly', function () {
patternlab.patternsonly(config.cleanPublic);
});
-gulp.task('patternlab:liststarterkits', function() {
+gulp.task('patternlab:liststarterkits', function () {
patternlab.liststarterkits();
});
-gulp.task('patternlab:loadstarterkit', function() {
+gulp.task('patternlab:loadstarterkit', function () {
patternlab.loadstarterkit(argv.kit, argv.clean);
});
-gulp.task('patternlab:build', function() {
+gulp.task('patternlab:build', function () {
build().then(() => {
// do something else when this promise resolves
});
});
-gulp.task('patternlab:serve', function() {
+gulp.task('patternlab:serve', function () {
serve().then(() => {
// do something else when this promise resolves
});
});
-gulp.task('patternlab:installplugin', function() {
- patternlab.installplugin(argv.plugin);
-});
-
gulp.task('default', ['patternlab:help']);
diff --git a/packages/edition-node-gulp/package.json b/packages/edition-node-gulp/package.json
index f5b798bd0..d6fc1857b 100644
--- a/packages/edition-node-gulp/package.json
+++ b/packages/edition-node-gulp/package.json
@@ -1,15 +1,15 @@
{
"name": "@pattern-lab/edition-node-gulp",
"description": "The gulp wrapper around patternlab-node core, providing tasks to interact with the core library and move supporting frontend assets.",
- "version": "2.0.2-alpha.0",
+ "version": "6.1.0",
"main": "gulpfile.js",
"dependencies": {
- "@pattern-lab/cli": "^0.0.3-alpha.0",
- "@pattern-lab/core": "^3.0.1-alpha.0",
- "@pattern-lab/engine-mustache": "^2.0.1-alpha.0",
- "@pattern-lab/uikit-workshop": "^1.0.1-alpha.0",
- "gulp": "3.9.1",
- "minimist": "1.2.0"
+ "@pattern-lab/cli": "^6.1.0",
+ "@pattern-lab/core": "^6.1.0",
+ "@pattern-lab/engine-mustache": "^6.1.0",
+ "@pattern-lab/uikit-workshop": "^6.1.0",
+ "gulp": "4.0.2",
+ "minimist": "1.2.5"
},
"keywords": [
"Pattern Lab",
@@ -27,9 +27,10 @@
},
"license": "MIT",
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/edition-node-gulp/patternlab-config.json b/packages/edition-node-gulp/patternlab-config.json
index 82596cdee..7a6e89dd8 100644
--- a/packages/edition-node-gulp/patternlab-config.json
+++ b/packages/edition-node-gulp/patternlab-config.json
@@ -46,8 +46,8 @@
"views/partials/general-footer.mustache",
"patternSection":
"views/partials/patternSection.mustache",
- "patternSectionSubtype":
- "views/partials/patternSectionSubtype.mustache",
+ "patternSectionSubgroup":
+ "views/partials/patternSectionSubgroup.mustache",
"viewall":
"views/viewall.mustache"
},
@@ -70,8 +70,13 @@
},
"patternExtension": "mustache",
"patternStateCascade": ["inprogress", "inreview", "complete"],
- "patternExportDirectory": "./pattern_exports/",
+ "patternExportAll": false,
+ "patternExportDirectory": "pattern_exports",
"patternExportPatternPartials": [],
+ "patternExportPreserveDirectoryStructure": true,
+ "patternExportRaw": false,
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
"serverOptions": {
"wait": 1000
},
@@ -82,9 +87,20 @@
"density": "compact",
"layout": "horizontal"
},
+ "engines": {
+ "handlebars": {
+ "package": "@pattern-lab/engine-handlebars",
+ "fileExtensions": [
+ "handlebars",
+ "hbs"
+ ],
+ "extend": "helpers/*.js"
+ }
+ },
"uikits": [
{
"name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
"outputDir": "",
"enabled": true,
"excludedPatternStates": [],
diff --git a/packages/edition-node-gulp/source/_annotations/README.md b/packages/edition-node-gulp/source/_annotations/README.md
index 42592a09b..b67b5511f 100644
--- a/packages/edition-node-gulp/source/_annotations/README.md
+++ b/packages/edition-node-gulp/source/_annotations/README.md
@@ -1,5 +1,5 @@
This is the default location to place annotations.
-Pattern Lab uses annotations defined here to markup the UI. Read more about [annotations](http://patternlab.io/docs/pattern-adding-annotations.html).
+Pattern Lab uses annotations defined here to markup the UI. Read more about [annotations](https://patternlab.io/docs/adding-annotations/).
If you wish to rename this directory, make sure you update the `paths.source.annotations` property within `patternlab-config.json`.
diff --git a/packages/edition-node-gulp/source/_data/README.md b/packages/edition-node-gulp/source/_data/README.md
index 3b9ea1ea4..50589abc7 100644
--- a/packages/edition-node-gulp/source/_data/README.md
+++ b/packages/edition-node-gulp/source/_data/README.md
@@ -1,5 +1,5 @@
This is the default location to place global data files.
-Pattern Lab uses data defined here as the global fallback if a template does not provide its own data. Read more about [data](http://patternlab.io/docs/data-overview.html).
+Pattern Lab uses data defined here as the global fallback if a template does not provide its own data. Read more about [data](https://patternlab.io/docs/overview-of-data/).
If you wish to rename this directory, make sure you update the `paths.source.data` property within `patternlab-config.json`.
diff --git a/packages/edition-node-gulp/source/_meta/README.md b/packages/edition-node-gulp/source/_meta/README.md
index c6c8c3b8e..b5d2c4537 100644
--- a/packages/edition-node-gulp/source/_meta/README.md
+++ b/packages/edition-node-gulp/source/_meta/README.md
@@ -1,5 +1,5 @@
This is the default location to place meta files, otherwise known a pattern's header and footer.
-Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](http://patternlab.io/docs/pattern-header-footer.html).
+Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](https://patternlab.io/docs/modifying-the-pattern-header-and-footer/).
If you wish to rename this directory, make sure you update the `paths.source.meta` property within `patternlab-config.json`.
diff --git a/packages/edition-node-gulp/source/_meta/_01-foot.mustache b/packages/edition-node-gulp/source/_meta/_foot.mustache
similarity index 100%
rename from packages/edition-node-gulp/source/_meta/_01-foot.mustache
rename to packages/edition-node-gulp/source/_meta/_foot.mustache
diff --git a/packages/edition-node-gulp/source/_meta/_head.mustache b/packages/edition-node-gulp/source/_meta/_head.mustache
new file mode 100644
index 000000000..5921e94cf
--- /dev/null
+++ b/packages/edition-node-gulp/source/_meta/_head.mustache
@@ -0,0 +1,17 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
+
diff --git a/packages/edition-node-gulp/source/_patterns/README.md b/packages/edition-node-gulp/source/_patterns/README.md
index 2f89266bf..8751c8669 100644
--- a/packages/edition-node-gulp/source/_patterns/README.md
+++ b/packages/edition-node-gulp/source/_patterns/README.md
@@ -1,5 +1,5 @@
This is the default location to place pattern files.
-Pattern Lab builds patterns and the ui from the structure defined within. Read more about [pattern organization](http://patternlab.io/docs/pattern-organization.html).
+Pattern Lab builds patterns and the ui from the structure defined within. Read more about [pattern organization](https://patternlab.io/docs/overview-of-patterns/).
If you wish to rename this directory, make sure you update the `paths.source.patterns` property within `patternlab-config.json`.
diff --git a/packages/edition-node-gulp/source/css/pattern-scaffolding.css b/packages/edition-node-gulp/source/css/pattern-scaffolding.css
index 2a69457ed..b09172fc8 100644
--- a/packages/edition-node-gulp/source/css/pattern-scaffolding.css
+++ b/packages/edition-node-gulp/source/css/pattern-scaffolding.css
@@ -5,7 +5,7 @@
*/
#sg-patterns {
-webkit-box-sizing: border-box !important;
- box-sizing: border-box !important;
+ box-sizing: border-box !important;
max-width: 100%;
padding: 0 0.5em;
}
@@ -24,15 +24,15 @@
display: -ms-flexbox;
display: flex;
-ms-flex-wrap: wrap;
- flex-wrap: wrap;
+ flex-wrap: wrap;
list-style: none !important;
padding: 0 !important;
margin: 0 !important;
}
.sg-colors li {
-webkit-box-flex: 1;
- -ms-flex: auto;
- flex: auto;
+ -ms-flex: auto;
+ flex: auto;
padding: 0.3em;
margin: 0 0.5em 0.5em 0;
min-width: 5em;
diff --git a/packages/edition-node-gulp/source/css/style.css b/packages/edition-node-gulp/source/css/style.css
index 588a45915..04f745349 100644
--- a/packages/edition-node-gulp/source/css/style.css
+++ b/packages/edition-node-gulp/source/css/style.css
@@ -1,3 +1,3 @@
/*
* YOUR STYLES HERE
- */
\ No newline at end of file
+ */
diff --git a/packages/edition-node/.nvmrc b/packages/edition-node/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/edition-node/.nvmrc
+++ b/packages/edition-node/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/edition-node/CHANGELOG.md b/packages/edition-node/CHANGELOG.md
index ab817001d..517af9e39 100644
--- a/packages/edition-node/CHANGELOG.md
+++ b/packages/edition-node/CHANGELOG.md
@@ -3,6 +3,498 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [6.0.3](https://github.com/pattern-lab/patternlab-node/compare/v6.0.2...v6.0.3) (2023-03-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.15.7](https://github.com/pattern-lab/patternlab-node/compare/v5.15.6...v5.15.7) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.15.6](https://github.com/pattern-lab/patternlab-node/compare/v5.15.5...v5.15.6) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+
+### Bug Fixes
+
+* corrected some github urls ([#1388](https://github.com/pattern-lab/patternlab-node/issues/1388)) ([7f37e9d](https://github.com/pattern-lab/patternlab-node/commit/7f37e9d56b553dc4be53590766c0fc6251458829))
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+
+### Bug Fixes
+
+* corrected some github urls ([#1388](https://github.com/pattern-lab/patternlab-node/issues/1388)) ([7f37e9d](https://github.com/pattern-lab/patternlab-node/commit/7f37e9d56b553dc4be53590766c0fc6251458829))
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/issues/1192) ([420e829](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/commit/420e8293c033557ede073bc13e68955a450a3c8e))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.9.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.9.1...v5.9.2) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.7.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.7.1...v5.7.2) (2020-03-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.7.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.7.0...v5.7.1) (2020-02-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.6.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.5.0...v5.6.0) (2020-01-18)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.4.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.4.1...v5.4.2) (2019-11-27)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.4.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.4.0...v5.4.1) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.3.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.3.2...v5.3.3) (2019-11-22)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+
+## [5.3.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.3.1...v5.3.2) (2019-11-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.3.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.3.0...v5.3.1) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.2.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.1.0...v5.2.0) (2019-11-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+
+### Features
+
+* **config:** add new default pattern export options ([a7487a0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/commit/a7487a0681cb11e6f3c5c8eaefd62e5648ad5ea3))
+
+
+
+
+
+## [5.0.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.0.1...v5.0.2) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+## [5.0.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v5.0.0...v5.0.1) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Features
+
+* **edition-node:** switch to engine-handlebars ([b481e22](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/commit/b481e22dc1f41ddd4da709621640a15190fba257))
+
+
+### BREAKING CHANGES
+
+* **edition-node:** use handlebars over mustache
+
+
+
+
+
+
+## [2.0.6](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/@pattern-lab/edition-node@2.0.5...@pattern-lab/edition-node@2.0.6) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+
+## [2.0.5](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/@pattern-lab/edition-node@2.0.4...@pattern-lab/edition-node@2.0.5) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+
+## [2.0.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/@pattern-lab/edition-node@2.0.0...@pattern-lab/edition-node@2.0.1) (2019-08-23)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
+# [2.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/@pattern-lab/edition-node@1.0.2...@pattern-lab/edition-node@2.0.0) (2019-08-23)
+
+
+### Features
+
+* **edition-node:** switch to engine-handlebars ([b481e22](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/commit/b481e22))
+
+
+### BREAKING CHANGES
+
+* **edition-node:** use handlebars over mustache
+
+
+
+
+
+
+## [1.0.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/@pattern-lab/edition-node@1.0.2-alpha.0...@pattern-lab/edition-node@1.0.2) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/edition-node
+
+
+
+
+
# [1.0.0-beta.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/edition-node/compare/@pattern-lab/edition-node@1.0.0-beta.0...@pattern-lab/edition-node@1.0.0-beta.2) (2019-02-09)
diff --git a/packages/edition-node/LICENSE b/packages/edition-node/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/edition-node/LICENSE
+++ b/packages/edition-node/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/edition-node/README.md b/packages/edition-node/README.md
index 2846a0671..a582cbe27 100644
--- a/packages/edition-node/README.md
+++ b/packages/edition-node/README.md
@@ -7,16 +7,16 @@
The pure wrapper around [Pattern Lab Node Core](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core), the default pattern engine, and supporting frontend assets.
-[Online Demo of Pattern Lab Output](http://demo.patternlab.io/)
+[Online Demo of Pattern Lab Output](https://demo.patternlab.io/)
## Packaged Components
This Edition comes with the following components:
* `@pattern-lab/core`: [GitHub](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core) | [npm](https://www.npmjs.com/package/@pattern-lab/core)
-* `@pattern-lab/cli`: [GitHub](https://github.com/pattern-lab/tree/master/packages/cli) | [npm](https://www.npmjs.com/package/@pattern-lab/cli)
-* `@pattern-lab/engine-mustache`: [GitHub](https://github.com/pattern-lab/tree/master/packages/engine-mustache) | [npm](https://www.npmjs.com/package/@pattern-lab/engine-mustache)
-* `@pattern-lab/uikit-workshop`: [GitHub](https://github.com/pattern-lab/tree/master/packages/uikit-workshop) | [npm](https://www.npmjs.com/package/@pattern-lab/uikit-workshop)
+* `@pattern-lab/cli`: [GitHub](https://github.com/pattern-lab/patternlab-node/tree/master/packages/cli) | [npm](https://www.npmjs.com/package/@pattern-lab/cli)
+* `@pattern-lab/engine-handlebars`: [GitHub](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars) | [npm](https://www.npmjs.com/package/@pattern-lab/engine-handlebars)
+* `@pattern-lab/uikit-workshop`: [GitHub](https://github.com/pattern-lab/patternlab-node/tree/master/packages/uikit-workshop) | [npm](https://www.npmjs.com/package/@pattern-lab/uikit-workshop)
## Prerequisites
@@ -24,7 +24,7 @@ This Edition uses [Node](https://nodejs.org) for core processing and [npm](https
## Installing
-Pattern Lab Node can be used different ways. Editions lilke this one are **example** pairings of Pattern Lab code and do not always have an upgrade path or simple means to run as a dependency within a larger project. Users wishing to be most current and have the greatest flexibility are encouraged to consume `core` directly. Users wanting to learn more about Pattern Lab and have a tailored default experience are encouraged to start with an Edition. Both methods still expect to interact with other elements of the [Pattern Lab Ecosystem](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core#ecosystem).
+The Pattern Lab Node can be used in different ways. Editions like this one are **example** pairings of Pattern Lab code and do not always have an upgrade path or simple means to run as a dependency within a larger project. Users wishing to be most current and have the greatest flexibility are encouraged to consume `core` directly. Users wanting to learn more about Pattern Lab and have a tailored default experience are encouraged to start with an edition. Both methods still expect to interact with other elements of the [Pattern Lab Ecosystem](https://github.com/pattern-lab/patternlab-node/tree/master/packages/core#ecosystem).
Read the [installation instructions](https://github.com/pattern-lab/patternlab-node/tree/master#installation).
diff --git a/packages/edition-node/helpers/test.js b/packages/edition-node/helpers/test.js
new file mode 100644
index 000000000..6ddbc2bba
--- /dev/null
+++ b/packages/edition-node/helpers/test.js
@@ -0,0 +1,5 @@
+module.exports = function (Handlebars) {
+ Handlebars.registerHelper('test', function () {
+ return 'This is a test helper';
+ });
+};
diff --git a/packages/edition-node/package.json b/packages/edition-node/package.json
index b8f508229..e4d9fa885 100644
--- a/packages/edition-node/package.json
+++ b/packages/edition-node/package.json
@@ -1,13 +1,13 @@
{
"name": "@pattern-lab/edition-node",
"description": "A pure wrapper around patternlab-node core, the default pattern engine, and supporting frontend assets.",
- "version": "1.0.2-alpha.0",
+ "version": "6.1.0",
"main": "patternlab-config.json",
"dependencies": {
- "@pattern-lab/cli": "^0.0.3-alpha.0",
- "@pattern-lab/core": "^3.0.1-alpha.0",
- "@pattern-lab/engine-mustache": "^2.0.1-alpha.0",
- "@pattern-lab/uikit-workshop": "^1.0.1-alpha.0"
+ "@pattern-lab/cli": "^6.1.0",
+ "@pattern-lab/core": "^6.1.0",
+ "@pattern-lab/engine-handlebars": "^6.1.0",
+ "@pattern-lab/uikit-workshop": "^6.1.0"
},
"keywords": [
"Pattern Lab",
@@ -23,13 +23,15 @@
"pl:help": "patternlab --help",
"pl:install": "patternlab install --config ./patternlab-config.json",
"pl:serve": "patternlab serve --config ./patternlab-config.json",
- "pl:version": "patternlab --version"
+ "pl:version": "patternlab --version",
+ "start": "npm run pl:serve"
},
"license": "MIT",
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/edition-node/patternlab-config.json b/packages/edition-node/patternlab-config.json
index 3576a5e5d..1296ff103 100644
--- a/packages/edition-node/patternlab-config.json
+++ b/packages/edition-node/patternlab-config.json
@@ -46,8 +46,8 @@
"views/partials/general-footer.mustache",
"patternSection":
"views/partials/patternSection.mustache",
- "patternSectionSubtype":
- "views/partials/patternSectionSubtype.mustache",
+ "patternSectionSubgroup":
+ "views/partials/patternSectionSubgroup.mustache",
"viewall":
"views/viewall.mustache"
},
@@ -68,10 +68,15 @@
"css": "public/css"
}
},
- "patternExtension": "mustache",
+ "patternExtension": "hbs",
"patternStateCascade": ["inprogress", "inreview", "complete"],
- "patternExportDirectory": "./pattern_exports/",
+ "patternExportAll": false,
+ "patternExportDirectory": "pattern_exports",
"patternExportPatternPartials": [],
+ "patternExportPreserveDirectoryStructure": true,
+ "patternExportRaw": false,
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
"serverOptions": {
"wait": 1000
},
@@ -85,10 +90,21 @@
"uikits": [
{
"name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
"outputDir": "",
"enabled": true,
"excludedPatternStates": [],
"excludedTags": []
}
- ]
+ ],
+ "engines": {
+ "handlebars": {
+ "package": "@pattern-lab/engine-handlebars",
+ "fileExtensions": [
+ "handlebars",
+ "hbs"
+ ],
+ "extend": "helpers/*.js"
+ }
+ }
}
diff --git a/packages/edition-node/source/_annotations/README.md b/packages/edition-node/source/_annotations/README.md
index 42592a09b..b67b5511f 100644
--- a/packages/edition-node/source/_annotations/README.md
+++ b/packages/edition-node/source/_annotations/README.md
@@ -1,5 +1,5 @@
This is the default location to place annotations.
-Pattern Lab uses annotations defined here to markup the UI. Read more about [annotations](http://patternlab.io/docs/pattern-adding-annotations.html).
+Pattern Lab uses annotations defined here to markup the UI. Read more about [annotations](https://patternlab.io/docs/adding-annotations/).
If you wish to rename this directory, make sure you update the `paths.source.annotations` property within `patternlab-config.json`.
diff --git a/packages/edition-node/source/_data/README.md b/packages/edition-node/source/_data/README.md
index 3b9ea1ea4..50589abc7 100644
--- a/packages/edition-node/source/_data/README.md
+++ b/packages/edition-node/source/_data/README.md
@@ -1,5 +1,5 @@
This is the default location to place global data files.
-Pattern Lab uses data defined here as the global fallback if a template does not provide its own data. Read more about [data](http://patternlab.io/docs/data-overview.html).
+Pattern Lab uses data defined here as the global fallback if a template does not provide its own data. Read more about [data](https://patternlab.io/docs/overview-of-data/).
If you wish to rename this directory, make sure you update the `paths.source.data` property within `patternlab-config.json`.
diff --git a/packages/edition-node/source/_meta/README.md b/packages/edition-node/source/_meta/README.md
index c6c8c3b8e..b5d2c4537 100644
--- a/packages/edition-node/source/_meta/README.md
+++ b/packages/edition-node/source/_meta/README.md
@@ -1,5 +1,5 @@
This is the default location to place meta files, otherwise known a pattern's header and footer.
-Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](http://patternlab.io/docs/pattern-header-footer.html).
+Pattern Lab builds each pattern while prepending and appending the header and footer. Read more about [pattern headers and footers](https://patternlab.io/docs/modifying-the-pattern-header-and-footer/).
If you wish to rename this directory, make sure you update the `paths.source.meta` property within `patternlab-config.json`.
diff --git a/packages/edition-node/source/_meta/_00-head.mustache b/packages/edition-node/source/_meta/_00-head.mustache
deleted file mode 100644
index 45ce3bb7d..000000000
--- a/packages/edition-node/source/_meta/_00-head.mustache
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
-
diff --git a/packages/edition-twig/source/_meta/_01-foot.mustache b/packages/edition-node/source/_meta/_foot.mustache
similarity index 100%
rename from packages/edition-twig/source/_meta/_01-foot.mustache
rename to packages/edition-node/source/_meta/_foot.mustache
diff --git a/packages/edition-node/source/_meta/_head.mustache b/packages/edition-node/source/_meta/_head.mustache
new file mode 100644
index 000000000..5921e94cf
--- /dev/null
+++ b/packages/edition-node/source/_meta/_head.mustache
@@ -0,0 +1,17 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
+
diff --git a/packages/edition-node/source/_patterns/README.md b/packages/edition-node/source/_patterns/README.md
index 2f89266bf..8751c8669 100644
--- a/packages/edition-node/source/_patterns/README.md
+++ b/packages/edition-node/source/_patterns/README.md
@@ -1,5 +1,5 @@
This is the default location to place pattern files.
-Pattern Lab builds patterns and the ui from the structure defined within. Read more about [pattern organization](http://patternlab.io/docs/pattern-organization.html).
+Pattern Lab builds patterns and the ui from the structure defined within. Read more about [pattern organization](https://patternlab.io/docs/overview-of-patterns/).
If you wish to rename this directory, make sure you update the `paths.source.patterns` property within `patternlab-config.json`.
diff --git a/packages/edition-twig/.patternlabrc.js b/packages/edition-twig/.patternlabrc.js
new file mode 100644
index 000000000..698dedca8
--- /dev/null
+++ b/packages/edition-twig/.patternlabrc.js
@@ -0,0 +1,4 @@
+module.exports = {
+ // target the UIKit installed / symlinked under node_modules
+ buildDir: __dirname + '/node_modules/@pattern-lab/uikit-workshop/dist',
+};
diff --git a/packages/edition-twig/CHANGELOG.md b/packages/edition-twig/CHANGELOG.md
new file mode 100644
index 000000000..25fd83c01
--- /dev/null
+++ b/packages/edition-twig/CHANGELOG.md
@@ -0,0 +1,482 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+
+### Features
+
+* **engine-twig-php:** update @basalt/twig-renderer to v3.0.1 using Twig v3.7.1 ([#1499](https://github.com/pattern-lab/patternlab-node/issues/1499)) ([2e5c9e1](https://github.com/pattern-lab/patternlab-node/commit/2e5c9e1c6a3318ba1cd3765d448c181e4a3a9a27)), closes [#1496](https://github.com/pattern-lab/patternlab-node/issues/1496) [#1496](https://github.com/pattern-lab/patternlab-node/issues/1496)
+
+
+
+
+
+## [6.0.3](https://github.com/pattern-lab/patternlab-node/compare/v6.0.2...v6.0.3) (2023-03-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+
+### Bug Fixes
+
+* **twig engine:** startup and running problems ([#1478](https://github.com/pattern-lab/patternlab-node/issues/1478)) ([e5a1904](https://github.com/pattern-lab/patternlab-node/commit/e5a19049f083315939406677b1c0480f4b420569))
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.15.7](https://github.com/pattern-lab/patternlab-node/compare/v5.15.6...v5.15.7) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.15.6](https://github.com/pattern-lab/patternlab-node/compare/v5.15.5...v5.15.6) (2021-12-07)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/patternlab-node/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/patternlab-node/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.9.2](https://github.com/pattern-lab/patternlab-node/compare/v5.9.1...v5.9.2) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.9.1](https://github.com/pattern-lab/patternlab-node/compare/v5.9.0...v5.9.1) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.7.2](https://github.com/pattern-lab/patternlab-node/compare/v5.7.1...v5.7.2) (2020-03-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.7.1](https://github.com/pattern-lab/patternlab-node/compare/v5.7.0...v5.7.1) (2020-02-24)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.6.0](https://github.com/pattern-lab/patternlab-node/compare/v5.5.0...v5.6.0) (2020-01-18)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/patternlab-node/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.4.2](https://github.com/pattern-lab/patternlab-node/compare/v5.4.1...v5.4.2) (2019-11-27)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.4.1](https://github.com/pattern-lab/patternlab-node/compare/v5.4.0...v5.4.1) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+
+### Features
+
+* test adding cross-env to Twig Edition test ([3f8bb01](https://github.com/pattern-lab/patternlab-node/commit/3f8bb01bc4e96a0aba61c213ea1619c02593defc))
+
+
+
+
+
+## [5.3.3](https://github.com/pattern-lab/patternlab-node/compare/v5.3.2...v5.3.3) (2019-11-22)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+
+## [5.3.2](https://github.com/pattern-lab/patternlab-node/compare/v5.3.1...v5.3.2) (2019-11-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.3.1](https://github.com/pattern-lab/patternlab-node/compare/v5.3.0...v5.3.1) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.2.0](https://github.com/pattern-lab/patternlab-node/compare/v5.1.0...v5.2.0) (2019-11-12)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+
+### Features
+
+* **config:** add new default pattern export options ([a7487a0](https://github.com/pattern-lab/patternlab-node/commit/a7487a0681cb11e6f3c5c8eaefd62e5648ad5ea3))
+
+
+
+
+
+## [5.0.2](https://github.com/pattern-lab/patternlab-node/compare/v5.0.1...v5.0.2) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [5.0.1](https://github.com/pattern-lab/patternlab-node/compare/v5.0.0...v5.0.1) (2019-10-28)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* add better pre-rendering support ([8ecd615](https://github.com/pattern-lab/patternlab-node/commit/8ecd6159a89232f42e0a9dc3c688b6e21de8fc30))
+* fix Twig Edition examples by adding missing Twig namespaces to config ([b4c20ef](https://github.com/pattern-lab/patternlab-node/commit/b4c20ef88ee0d3010760584c6f05ff7f92b711a6))
+
+
+
+
+
+
+## [3.1.8](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/edition-twig@3.1.7...@pattern-lab/edition-twig@3.1.8) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+
+## [3.1.7](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/edition-twig@3.1.6...@pattern-lab/edition-twig@3.1.7) (2019-10-14)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+
+## [3.1.3](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/edition-twig@3.1.2...@pattern-lab/edition-twig@3.1.3) (2019-08-23)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
+
+
+
+
+
+## [3.1.2](https://github.com/pattern-lab/patternlab-node/compare/@pattern-lab/edition-twig@3.1.1...@pattern-lab/edition-twig@3.1.2) (2019-08-23)
+
+
+### Bug Fixes
+
+* add better pre-rendering support ([8ecd615](https://github.com/pattern-lab/patternlab-node/commit/8ecd615))
+
+
+
+
+
+
+## [3.1.1](https://github.com/sghoweri/patternlab-node/compare/@pattern-lab/edition-twig@3.1.0...@pattern-lab/edition-twig@3.1.1) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/edition-twig
diff --git a/packages/edition-twig/README.md b/packages/edition-twig/README.md
new file mode 100644
index 000000000..2d8d9f3d0
--- /dev/null
+++ b/packages/edition-twig/README.md
@@ -0,0 +1,11 @@
+## Working on Pattern Lab's UI Locally
+
+### Step 1: Install Dependencies
+Run the following in the root of the Pattern Lab repo:
+
+```
+yarn run setup
+```
+
+### Step 2
+Finally, go back into this folder, `cd packages/edition-twig`, and start up the local dev server which watches UIKit and the local Pattern Lab instance for changes, live reloads, etc by running `yarn dev`
diff --git a/packages/edition-twig/alter-twig.php b/packages/edition-twig/alter-twig.php
index 0c7c2918c..425775ae6 100644
--- a/packages/edition-twig/alter-twig.php
+++ b/packages/edition-twig/alter-twig.php
@@ -1,15 +1,17 @@
Hello {{ customTwigFunctionThatSaysWorld() }}!` => `Hello Custom World `
*/
-// $env->addFunction(new \Twig_SimpleFunction('customTwigFunctionThatSaysWorld', function () {
+// $env->addFunction(new TwigFunction('customTwigFunctionThatSaysWorld', function () {
// return 'Custom World';
// }));
@@ -18,7 +20,7 @@ function addCustomExtension(\Twig_Environment &$env, $config) {
* @param string $theString
* @example `{{ reverse('abc') }}
` => `cba
`
*/
-// $env->addFunction(new \Twig_SimpleFunction('reverse', function ($theString) {
+// $env->addFunction(new TwigFunction('reverse', function ($theString) {
// return strrev($theString);
// }));
@@ -29,6 +31,5 @@ function addCustomExtension(\Twig_Environment &$env, $config) {
// $env->addGlobal('foo', 'bar');
// example of enabling the Twig debug mode extension (ex. {{ dump(my_variable) }} to check out the template's available data) -- comment out to disable
- // $env->addExtension(new \Twig_Extension_Debug());
-
+ // $env->addExtension(new Twig\Extension\DebugExtension());
}
diff --git a/packages/edition-twig/package-lock.json b/packages/edition-twig/package-lock.json
deleted file mode 100644
index cb30f303e..000000000
--- a/packages/edition-twig/package-lock.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "name": "@pattern-lab/edition-twig",
- "version": "3.0.0-alpha.1",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "@pattern-lab/starterkit-twig-demo": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@pattern-lab/starterkit-twig-demo/-/starterkit-twig-demo-4.0.0.tgz",
- "integrity": "sha512-GDSKRgDT4BugTcEDRv3oH0+Lc9sUHWbUS6L1GPsLHr5PsJ/AdGdQOqTfrePZJMq2d/4xxGxQLAH2Ua6wagg0eg=="
- }
- }
-}
diff --git a/packages/edition-twig/package.json b/packages/edition-twig/package.json
index a45997654..9d1c2416a 100644
--- a/packages/edition-twig/package.json
+++ b/packages/edition-twig/package.json
@@ -1,10 +1,10 @@
{
"name": "@pattern-lab/edition-twig",
- "version": "3.1.0",
+ "version": "6.1.0",
"description": "Pattern Lab node with Twig PHP Engine",
"author": {
"name": "Evan Lovely",
- "url": "http://evanlovely.com"
+ "url": "https://www.evanlovely.com"
},
"maintainers": [
{
@@ -13,21 +13,23 @@
],
"main": "patternlab-config.json",
"scripts": {
+ "build:uikit": "cross-env-shell PL_CONFIG_PATH='${INIT_CWD}/.patternlabrc.js' npm run build --prefix node_modules/@pattern-lab/uikit-workshop -- --patternlabrc '$PL_CONFIG_PATH'",
"build": "patternlab build --config ./patternlab-config.json",
"help": "patternlab --help",
"install": "patternlab install --config ./patternlab-config.json",
"serve": "patternlab serve --config ./patternlab-config.json",
"start": "npm run serve",
- "version": "patternlab --version"
+ "version": "patternlab --version",
+ "dev": "node ./node_modules/@pattern-lab/uikit-workshop/build-tools.js"
},
"dependencies": {
- "@pattern-lab/cli": "^0.0.3-alpha.0",
- "@pattern-lab/core": "^3.0.1-alpha.0",
- "@pattern-lab/engine-twig-php": "^3.0.0",
- "@pattern-lab/uikit-workshop": "^1.0.1-alpha.0"
+ "@pattern-lab/cli": "^6.1.0",
+ "@pattern-lab/core": "^6.1.0",
+ "@pattern-lab/engine-twig-php": "^6.1.0",
+ "@pattern-lab/uikit-workshop": "^6.1.0"
},
"engines": {
- "node": ">=6.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
@@ -40,5 +42,6 @@
"Design",
"Twig"
],
- "license": "MIT"
+ "license": "MIT",
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/edition-twig/patternlab-config.json b/packages/edition-twig/patternlab-config.json
index 653fc1dca..40d5301c4 100644
--- a/packages/edition-twig/patternlab-config.json
+++ b/packages/edition-twig/patternlab-config.json
@@ -1,6 +1,10 @@
{
"engines": {
- "twig": {
+ "twig-php": {
+ "package": "@pattern-lab/engine-twig-php",
+ "fileExtensions": [
+ "twig"
+ ],
"namespaces": [
{
"id": "uikit",
@@ -8,6 +12,41 @@
"paths": [
"./node_modules/@pattern-lab/uikit-workshop/views-twig"
]
+ },
+ {
+ "id": "atoms",
+ "recursive": true,
+ "paths": [
+ "./source/_patterns/atoms"
+ ]
+ },
+ {
+ "id": "molecules",
+ "recursive": true,
+ "paths": [
+ "./source/_patterns/molecules"
+ ]
+ },
+ {
+ "id": "organisms",
+ "recursive": true,
+ "paths": [
+ "./source/_patterns/organisms"
+ ]
+ },
+ {
+ "id": "templates",
+ "recursive": true,
+ "paths": [
+ "./source/_patterns/templates"
+ ]
+ },
+ {
+ "id": "pages",
+ "recursive": true,
+ "paths": [
+ "./source/_patterns/pages"
+ ]
}
],
"alterTwigEnv": [
@@ -73,7 +112,7 @@
"general-header": "views/partials/general-header.mustache",
"general-footer": "views/partials/general-footer.mustache",
"patternSection": "views/partials/patternSection.mustache",
- "patternSectionSubtype": "views/partials/patternSectionSubtype.mustache",
+ "patternSectionSubgroup": "views/partials/patternSectionSubgroup.mustache",
"viewall": "views/viewall.mustache"
},
"js": "./source/js",
@@ -99,8 +138,13 @@
"inreview",
"complete"
],
- "patternExportDirectory": "./pattern_exports/",
+ "patternExportAll": false,
+ "patternExportDirectory": "pattern_exports",
"patternExportPatternPartials": [],
+ "patternExportPreserveDirectoryStructure": true,
+ "patternExportRaw": false,
+ "patternMergeVariantArrays": true,
+ "renderFlatPatternsOnViewAllPages": false,
"serverOptions": {
"wait": 1000
},
@@ -109,11 +153,13 @@
"theme": {
"color": "light",
"density": "compact",
- "layout": "horizontal"
+ "layout": "horizontal",
+ "noViewAll": false
},
"uikits": [
{
"name": "uikit-workshop",
+ "package": "@pattern-lab/uikit-workshop",
"outputDir": "",
"enabled": true,
"excludedPatternStates": [],
diff --git a/packages/edition-twig/source/_annotations/annotations.js b/packages/edition-twig/source/_annotations/annotations.json
similarity index 100%
rename from packages/edition-twig/source/_annotations/annotations.js
rename to packages/edition-twig/source/_annotations/annotations.json
diff --git a/packages/edition-twig/source/_meta/_00-head.mustache b/packages/edition-twig/source/_meta/_00-head.mustache
deleted file mode 100644
index 45ce3bb7d..000000000
--- a/packages/edition-twig/source/_meta/_00-head.mustache
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
-
diff --git a/packages/engine-handlebars/_meta/_01-foot.hbs b/packages/edition-twig/source/_meta/_foot.mustache
similarity index 100%
rename from packages/engine-handlebars/_meta/_01-foot.hbs
rename to packages/edition-twig/source/_meta/_foot.mustache
diff --git a/packages/edition-twig/source/_meta/_01-foot.twig b/packages/edition-twig/source/_meta/_foot.twig
old mode 100755
new mode 100644
similarity index 100%
rename from packages/edition-twig/source/_meta/_01-foot.twig
rename to packages/edition-twig/source/_meta/_foot.twig
diff --git a/packages/edition-twig/source/_meta/_head.mustache b/packages/edition-twig/source/_meta/_head.mustache
new file mode 100644
index 000000000..5921e94cf
--- /dev/null
+++ b/packages/edition-twig/source/_meta/_head.mustache
@@ -0,0 +1,17 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
+
diff --git a/packages/starterkit-twig-demo/dist/_meta/_00-head.twig b/packages/edition-twig/source/_meta/_head.twig
old mode 100755
new mode 100644
similarity index 86%
rename from packages/starterkit-twig-demo/dist/_meta/_00-head.twig
rename to packages/edition-twig/source/_meta/_head.twig
index 123ccf8a8..bdbd3483f
--- a/packages/starterkit-twig-demo/dist/_meta/_00-head.twig
+++ b/packages/edition-twig/source/_meta/_head.twig
@@ -1,17 +1,17 @@
-
+
{{ title }}
-
+
-
+
{{ patternLabHead | raw }}
-
+
-
+
diff --git a/packages/edition-twig/source/_patterns/00-atoms/05-buttons/button-dark-demo.twig b/packages/edition-twig/source/_patterns/00-atoms/05-buttons/button-dark-demo.twig
deleted file mode 100644
index 7899b77f8..000000000
--- a/packages/edition-twig/source/_patterns/00-atoms/05-buttons/button-dark-demo.twig
+++ /dev/null
@@ -1,4 +0,0 @@
-{% include '@atoms/05-buttons/_button.twig' with {
- text: 'Click Me',
- dark: true,
-} only %}
diff --git a/packages/edition-twig/source/_patterns/00-atoms/05-buttons/button-simple-demo.twig b/packages/edition-twig/source/_patterns/00-atoms/05-buttons/button-simple-demo.twig
deleted file mode 100644
index b8afb5833..000000000
--- a/packages/edition-twig/source/_patterns/00-atoms/05-buttons/button-simple-demo.twig
+++ /dev/null
@@ -1,3 +0,0 @@
-{% include '@atoms/05-buttons/_button.twig' with {
- text: 'Click Me',
-} only %}
diff --git a/packages/edition-twig/source/_patterns/atoms/buttons/button-dark-demo.twig b/packages/edition-twig/source/_patterns/atoms/buttons/button-dark-demo.twig
new file mode 100644
index 000000000..5a61b3cb7
--- /dev/null
+++ b/packages/edition-twig/source/_patterns/atoms/buttons/button-dark-demo.twig
@@ -0,0 +1,4 @@
+{% include '@atoms/buttons/button.twig' with {
+ text: 'Click Me',
+ dark: true,
+} only %}
diff --git a/packages/edition-twig/source/_patterns/atoms/buttons/button-simple-demo.twig b/packages/edition-twig/source/_patterns/atoms/buttons/button-simple-demo.twig
new file mode 100644
index 000000000..81cf5f6cb
--- /dev/null
+++ b/packages/edition-twig/source/_patterns/atoms/buttons/button-simple-demo.twig
@@ -0,0 +1,3 @@
+{% include '@atoms/buttons/button.twig' with {
+ text: 'Click Me',
+} only %}
diff --git a/packages/edition-twig/source/_patterns/atoms/buttons/button.md b/packages/edition-twig/source/_patterns/atoms/buttons/button.md
new file mode 100644
index 000000000..683af9f1a
--- /dev/null
+++ b/packages/edition-twig/source/_patterns/atoms/buttons/button.md
@@ -0,0 +1,3 @@
+---
+hidden: true
+---
diff --git a/packages/edition-twig/source/_patterns/00-atoms/05-buttons/_button.twig b/packages/edition-twig/source/_patterns/atoms/buttons/button.twig
similarity index 61%
rename from packages/edition-twig/source/_patterns/00-atoms/05-buttons/_button.twig
rename to packages/edition-twig/source/_patterns/atoms/buttons/button.twig
index 1d124b4ed..5dd552d23 100644
--- a/packages/edition-twig/source/_patterns/00-atoms/05-buttons/_button.twig
+++ b/packages/edition-twig/source/_patterns/atoms/buttons/button.twig
@@ -1 +1 @@
-{{ text }}
+{{ text }}
diff --git a/packages/edition-twig/source/_patterns/atoms/text/headings.twig b/packages/edition-twig/source/_patterns/atoms/text/headings.twig
new file mode 100644
index 000000000..deb727bab
--- /dev/null
+++ b/packages/edition-twig/source/_patterns/atoms/text/headings.twig
@@ -0,0 +1,6 @@
+Heading Level 1
+Heading Level 2
+Heading Level 3
+Heading Level 4
+Heading Level 5
+Heading Level 6
diff --git a/packages/edition-twig/source/_patterns/01-molecules/.gitkeep b/packages/edition-twig/source/_patterns/molecules/.gitkeep
old mode 100755
new mode 100644
similarity index 100%
rename from packages/edition-twig/source/_patterns/01-molecules/.gitkeep
rename to packages/edition-twig/source/_patterns/molecules/.gitkeep
diff --git a/packages/edition-twig/source/_patterns/01-molecules/05-card/card.twig b/packages/edition-twig/source/_patterns/molecules/card/card.twig
similarity index 64%
rename from packages/edition-twig/source/_patterns/01-molecules/05-card/card.twig
rename to packages/edition-twig/source/_patterns/molecules/card/card.twig
index 0d8840f90..dbea5a7a8 100644
--- a/packages/edition-twig/source/_patterns/01-molecules/05-card/card.twig
+++ b/packages/edition-twig/source/_patterns/molecules/card/card.twig
@@ -1,6 +1,6 @@
Card Title here
- {% include '@atoms/05-buttons/_button.twig' with {
+ {% include '@atoms/buttons/button.twig' with {
text: 'some text from card'
} only %}
diff --git a/packages/edition-twig/source/_patterns/02-organisms/.gitkeep b/packages/edition-twig/source/_patterns/organisms/.gitkeep
old mode 100755
new mode 100644
similarity index 100%
rename from packages/edition-twig/source/_patterns/02-organisms/.gitkeep
rename to packages/edition-twig/source/_patterns/organisms/.gitkeep
diff --git a/packages/edition-twig/source/_patterns/03-templates/.gitkeep b/packages/edition-twig/source/_patterns/pages/.gitkeep
old mode 100755
new mode 100644
similarity index 100%
rename from packages/edition-twig/source/_patterns/03-templates/.gitkeep
rename to packages/edition-twig/source/_patterns/pages/.gitkeep
diff --git a/packages/edition-twig/source/_patterns/04-pages/.gitkeep b/packages/edition-twig/source/_patterns/templates/.gitkeep
old mode 100755
new mode 100644
similarity index 100%
rename from packages/edition-twig/source/_patterns/04-pages/.gitkeep
rename to packages/edition-twig/source/_patterns/templates/.gitkeep
diff --git a/packages/engine-handlebars/.nvmrc b/packages/engine-handlebars/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/engine-handlebars/.nvmrc
+++ b/packages/engine-handlebars/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/engine-handlebars/CHANGELOG.md b/packages/engine-handlebars/CHANGELOG.md
index edfcda323..2fc04404b 100644
--- a/packages/engine-handlebars/CHANGELOG.md
+++ b/packages/engine-handlebars/CHANGELOG.md
@@ -3,6 +3,145 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/issues/1192) ([374c103](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/374c103a59504ba239b16680f86a89b4d95e304f))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/issues/1192) ([48de8c2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/48de8c2e134a61c0b4440375254bc9590a3e2563))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/issues/1192) ([363f22c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/363f22c643239ef4ca48d6f5942111604fda5ead))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/issues/1192) ([487cc78](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/487cc783388043ec16ab1e54a3bfd8490038d058))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/issues/1192) ([571017f](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/571017ffafa2cf6e8fa01b7ea7effc88922b05d1))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+**Note:** Version bump only for package @pattern-lab/engine-handlebars
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* **lint:** Use const instead of var ([ad1e782](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/ad1e782ef71295eb610f56d019eaa35499fb3f85))
+* Rename Handlebars and Nunjucks extension setting to "extend" ([74e5af2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/74e5af28c4e714fdfc1db535b94c52f3dc14a3a4))
+
+
+### Features
+
+* **engine-handlebars:** Default location for helpers, like engine-nunjucks ([11c4180](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/11c41805e0c3dbebb7109719c4f3c780d32feab5))
+* **engine-handlebars:** Document the Helpers feature ([a01e040](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/a01e040429a7f77dfeb28d67c690e835b97881de))
+* **engine-handlebars:** Load Handlebars helpers specified in the config ([a12df36](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/a12df36d2a644dfac8ded1dfd94b987e99c29d79))
+
+
+
+
+
+
+# [2.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/@pattern-lab/engine-handlebars@2.0.0-beta.1...@pattern-lab/engine-handlebars@2.0.0) (2019-08-23)
+
+
+### Bug Fixes
+
+* **lint:** Use const instead of var ([ad1e782](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/ad1e782))
+* Rename Handlebars and Nunjucks extension setting to "extend" ([74e5af2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/74e5af2))
+
+
+### Features
+
+* **engine-handlebars:** Default location for helpers, like engine-nunjucks ([11c4180](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/11c4180))
+* **engine-handlebars:** Document the Helpers feature ([a01e040](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/a01e040))
+* **engine-handlebars:** Load Handlebars helpers specified in the config ([a12df36](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/commit/a12df36))
+
+
+
+
+
+
# [2.0.0-beta.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-handlebars/compare/@pattern-lab/engine-handlebars@2.0.0-beta.0...@pattern-lab/engine-handlebars@2.0.0-beta.1) (2019-02-09)
**Note:** Version bump only for package @pattern-lab/engine-handlebars
diff --git a/packages/engine-handlebars/LICENSE b/packages/engine-handlebars/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/engine-handlebars/LICENSE
+++ b/packages/engine-handlebars/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-handlebars/README.md b/packages/engine-handlebars/README.md
index d85db9ea5..8e34ce81c 100644
--- a/packages/engine-handlebars/README.md
+++ b/packages/engine-handlebars/README.md
@@ -1,13 +1,44 @@
# The Handlebars PatternEngine for Pattern Lab / Node
-To install the Handlebars PatternEngine in your edition, `npm install @pattern-lab/engine-handlebars` should do the trick.
+To install the Handlebars PatternEngine in your edition, `npm install --save @pattern-lab/engine-handlebars` should do the trick.
## Supported features
-* [x] [Includes](http://patternlab.io/docs/pattern-including.html)
+* [x] [Includes](https://patternlab.io/docs/including-patterns/)
* [x] Lineage
-* [x] [Hidden Patterns](http://patternlab.io/docs/pattern-hiding.html)
-* [x] [Pseudo-Patterns](http://patternlab.io/docs/pattern-pseudo-patterns.html)
-* [x] [Pattern States](http://patternlab.io/docs/pattern-states.html)
-* [ ] [Pattern Parameters](http://patternlab.io/docs/pattern-parameters.html) (Accomplished instead using [native Handlebars partial arguments](http://handlebarsjs.com/partials.html))
-* [ ] [Style Modifiers](http://patternlab.io/docs/pattern-stylemodifier.html) (Accomplished instead using [native Handlebars partial arguments](http://handlebarsjs.com/partials.html))
+* [x] [Hidden Patterns](https://patternlab.io/docs/hiding-patterns-in-the-navigation/)
+* [x] [Pseudo-Patterns](https://patternlab.io/docs/using-pseudo-patterns/)
+* [x] [Pattern States](https://patternlab.io/docs/using-pattern-states/)
+* [ ] ~~[Pattern Parameters](https://patternlab.io/docs/using-pattern-parameters/)~~ (Accomplished instead using [native Handlebars partial arguments](https://handlebarsjs.com/guide/partials.html))
+* [ ] ~~[Style Modifiers](https://github.com/pattern-lab/patternlab-node/issues/1177)~~ (Accomplished instead using [native Handlebars partial arguments](https://handlebarsjs.com/guide/partials.html))
+
+## Helpers
+
+To add custom [helpers](https://handlebarsjs.com/api-reference/helpers.html) or otherwise interact with Handlebars directly, create a file named `patternlab-handlebars-config.js` in the root of your Pattern Lab project, or override the default location by specifying one or several glob patterns in the Pattern Lab config:
+
+```json
+ {
+ ...
+ "engines": {
+ "handlebars": {
+ "extend": [
+ "handlebars-helpers.js",
+ "helpers/**/*.js"
+ ]
+ }
+ }
+ }
+```
+
+Each file should export a function which takes Handlebars as an argument.
+
+```js
+module.exports = function(Handlebars) {
+ // Put helpers here
+
+ Handlebars.registerHelper('fullName', function(person) {
+ // Example: person = {firstName: "Alan", lastName: "Johnson"}
+ return person.firstName + " " + person.lastName;
+ });
+};
+```
diff --git a/packages/engine-handlebars/_meta/_00-head.hbs b/packages/engine-handlebars/_meta/_00-head.hbs
deleted file mode 100644
index b1f5c1ce0..000000000
--- a/packages/engine-handlebars/_meta/_00-head.hbs
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
diff --git a/packages/engine-liquid/_meta/_01-foot.liquid b/packages/engine-handlebars/_meta/_foot.hbs
similarity index 100%
rename from packages/engine-liquid/_meta/_01-foot.liquid
rename to packages/engine-handlebars/_meta/_foot.hbs
diff --git a/packages/engine-handlebars/_meta/_head.hbs b/packages/engine-handlebars/_meta/_head.hbs
new file mode 100644
index 000000000..893481ae5
--- /dev/null
+++ b/packages/engine-handlebars/_meta/_head.hbs
@@ -0,0 +1,16 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
diff --git a/packages/engine-handlebars/lib/engine_handlebars.js b/packages/engine-handlebars/lib/engine_handlebars.js
index dbeb88312..d182971c1 100644
--- a/packages/engine-handlebars/lib/engine_handlebars.js
+++ b/packages/engine-handlebars/lib/engine_handlebars.js
@@ -25,21 +25,31 @@
const fs = require('fs-extra');
const path = require('path');
const Handlebars = require('handlebars');
+const glob = require('glob');
// regexes, stored here so they're only compiled once
const findPartialsRE = /{{#?>\s*([\w-\/.]+)(?:.|\s+)*?}}/g;
-const findListItemsRE = /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g;
+const findListItemsRE =
+ /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g;
const findAtPartialBlockRE = /{{#?>\s*@partial-block\s*}}/g;
function escapeAtPartialBlock(partialString) {
- var partial = partialString.replace(
+ const partial = partialString.replace(
findAtPartialBlockRE,
'{{> @partial-block }}'
);
return partial;
}
-var engine_handlebars = {
+function loadHelpers(helpers) {
+ helpers.forEach((globPattern) => {
+ glob.sync(globPattern).forEach((filePath) => {
+ require(path.join(process.cwd(), filePath))(Handlebars);
+ });
+ });
+}
+
+const engine_handlebars = {
engine: Handlebars,
engineName: 'handlebars',
engineFileExtension: ['.hbs', '.handlebars'],
@@ -54,12 +64,12 @@ var engine_handlebars = {
Handlebars.registerPartial(partials);
}
- var compiled = Handlebars.compile(escapeAtPartialBlock(pattern.template));
+ const compiled = Handlebars.compile(escapeAtPartialBlock(pattern.template));
return Promise.resolve(compiled(data));
},
- registerPartial: function(pattern) {
+ registerPartial: function (pattern) {
// register exact partial name
Handlebars.registerPartial(pattern.patternPartial, pattern.template);
@@ -68,35 +78,30 @@ var engine_handlebars = {
// find and return any {{> template-name }} within pattern
findPartials: function findPartials(pattern) {
- var matches = pattern.template.match(findPartialsRE);
+ const matches = pattern.template.match(findPartialsRE);
return matches;
},
- findPartialsWithStyleModifiers: function() {
- // TODO: make the call to this from oPattern objects conditional on their
- // being implemented here.
- return [];
- },
// returns any patterns that match {{> value(foo:"bar") }} or {{>
// value:mod(foo:"bar") }} within the pattern
- findPartialsWithPatternParameters: function() {
+ findPartialsWithPatternParameters: function () {
// TODO: make the call to this from oPattern objects conditional on their
// being implemented here.
return [];
},
- findListItems: function(pattern) {
- var matches = pattern.template.match(findListItemsRE);
+ findListItems: function (pattern) {
+ const matches = pattern.template.match(findListItemsRE);
return matches;
},
// given a pattern, and a partial string, tease out the "pattern key" and
// return it.
- findPartial: function(partialString) {
- var partial = partialString.replace(findPartialsRE, '$1');
+ findPartial: function (partialString) {
+ const partial = partialString.replace(findPartialsRE, '$1');
return partial;
},
- spawnFile: function(config, fileName) {
+ spawnFile: function (config, fileName) {
const paths = config.paths;
const metaFilePath = path.resolve(paths.source.meta, fileName);
try {
@@ -118,9 +123,39 @@ var engine_handlebars = {
* @param {object} config - the global config object from core, since we won't
* assume it's already present
*/
- spawnMeta: function(config) {
- this.spawnFile(config, '_00-head.hbs');
- this.spawnFile(config, '_01-foot.hbs');
+ spawnMeta: function (config) {
+ this.spawnFile(config, '_head.hbs');
+ this.spawnFile(config, '_foot.hbs');
+ },
+
+ /**
+ * Accept a Pattern Lab config object from the core and use the settings to
+ * load helpers.
+ *
+ * @param {object} config - the global config object from core
+ */
+ usePatternLabConfig: function (config) {
+ let helpers;
+
+ try {
+ // Look for helpers in the config
+ helpers = config.engines.handlebars.extend;
+
+ if (typeof helpers === 'string') {
+ helpers = [helpers];
+ }
+ } catch (error) {
+ // Look for helpers in default location
+ const configPath = 'patternlab-handlebars-config.js';
+ if (fs.existsSync(path.join(process.cwd(), configPath))) {
+ helpers = [configPath];
+ }
+ }
+
+ // Load helpers if they were found
+ if (helpers) {
+ loadHelpers(helpers);
+ }
},
};
diff --git a/packages/engine-handlebars/package.json b/packages/engine-handlebars/package.json
index 97a577473..30878bef1 100644
--- a/packages/engine-handlebars/package.json
+++ b/packages/engine-handlebars/package.json
@@ -1,11 +1,12 @@
{
"name": "@pattern-lab/engine-handlebars",
"description": "The Handlebars engine for Pattern Lab / Node",
- "version": "2.0.0-beta.1",
+ "version": "6.1.0",
"main": "lib/engine_handlebars.js",
"dependencies": {
- "fs-extra": "0.30.0",
- "handlebars": "4.0.5"
+ "fs-extra": "^10.0.0",
+ "glob": "^7.1.6",
+ "handlebars": "^4.7.7"
},
"keywords": [
"Pattern Lab",
@@ -22,9 +23,10 @@
"license": "MIT",
"scripts": {},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/engine-liquid/.nvmrc b/packages/engine-liquid/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/engine-liquid/.nvmrc
+++ b/packages/engine-liquid/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/engine-liquid/CHANGELOG.md b/packages/engine-liquid/CHANGELOG.md
index ea6b10e38..84d0b1a82 100644
--- a/packages/engine-liquid/CHANGELOG.md
+++ b/packages/engine-liquid/CHANGELOG.md
@@ -3,6 +3,98 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/issues/1192) ([374c103](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/commit/374c103a59504ba239b16680f86a89b4d95e304f))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/issues/1192) ([48de8c2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/commit/48de8c2e134a61c0b4440375254bc9590a3e2563))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/issues/1192) ([363f22c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/commit/363f22c643239ef4ca48d6f5942111604fda5ead))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/issues/1192) ([487cc78](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/commit/487cc783388043ec16ab1e54a3bfd8490038d058))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/issues/1192) ([571017f](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/commit/571017ffafa2cf6e8fa01b7ea7effc88922b05d1))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+**Note:** Version bump only for package @pattern-lab/engine-liquid
+
+
+
+
+
+
# [1.0.0-beta.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-liquid/compare/@pattern-lab/engine-liquid@1.0.0-beta.0...@pattern-lab/engine-liquid@1.0.0-beta.1) (2019-02-09)
**Note:** Version bump only for package @pattern-lab/engine-liquid
diff --git a/packages/engine-liquid/LICENSE b/packages/engine-liquid/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/engine-liquid/LICENSE
+++ b/packages/engine-liquid/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-liquid/README.md b/packages/engine-liquid/README.md
index 518aba27f..a61555604 100644
--- a/packages/engine-liquid/README.md
+++ b/packages/engine-liquid/README.md
@@ -10,13 +10,13 @@ To install the Liquid PatternEngine in your edition, `npm install @pattern-lab/e
This PatternEngine is in alpha and considered a work in progress.
-* [x] [Includes](http://patternlab.io/docs/pattern-including.html)
+* [x] [Includes](https://patternlab.io/docs/including-patterns/)
* [x] Lineage
**TBD**
-* [ ] [Hidden Patterns](http://patternlab.io/docs/pattern-hiding.html)
-* [ ] [Pseudo-Patterns](http://patternlab.io/docs/pattern-pseudo-patterns.html)
-* [ ] [Pattern States](http://patternlab.io/docs/pattern-states.html)
-* [ ] [Pattern Parameters](http://patternlab.io/docs/pattern-parameters.html)
-* [ ] [Style Modifiers](http://patternlab.io/docs/pattern-stylemodifier.html)
+* [ ] [Hidden Patterns](https://patternlab.io/docs/hiding-patterns-in-the-navigation/)
+* [ ] [Pseudo-Patterns](https://patternlab.io/docs/using-pseudo-patterns/)
+* [ ] [Pattern States](https://patternlab.io/docs/using-pattern-states/)
+* [ ] [Pattern Parameters](https://patternlab.io/docs/using-pattern-parameters/)
+* [ ] [Style Modifiers](https://github.com/pattern-lab/patternlab-node/issues/1177)
diff --git a/packages/engine-liquid/_meta/_00-head.liquid b/packages/engine-liquid/_meta/_00-head.liquid
deleted file mode 100644
index b1f5c1ce0..000000000
--- a/packages/engine-liquid/_meta/_00-head.liquid
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
diff --git a/packages/engine-mustache/_meta/_01-foot.mustache b/packages/engine-liquid/_meta/_foot.liquid
similarity index 100%
rename from packages/engine-mustache/_meta/_01-foot.mustache
rename to packages/engine-liquid/_meta/_foot.liquid
diff --git a/packages/core/test/files/_meta/_00-head.html b/packages/engine-liquid/_meta/_head.liquid
similarity index 92%
rename from packages/core/test/files/_meta/_00-head.html
rename to packages/engine-liquid/_meta/_head.liquid
index b1f5c1ce0..578f7cb71 100644
--- a/packages/core/test/files/_meta/_00-head.html
+++ b/packages/engine-liquid/_meta/_head.liquid
@@ -1,5 +1,5 @@
-
+
{{ title }}
diff --git a/packages/engine-liquid/lib/engine_liquid.js b/packages/engine-liquid/lib/engine_liquid.js
index 0f61aff59..b5e5dd56b 100644
--- a/packages/engine-liquid/lib/engine_liquid.js
+++ b/packages/engine-liquid/lib/engine_liquid.js
@@ -11,11 +11,11 @@
const fs = require('fs-extra');
const path = require('path');
-const isDirectory = source => fs.lstatSync(source).isDirectory();
-const getDirectories = source =>
+const isDirectory = (source) => fs.lstatSync(source).isDirectory();
+const getDirectories = (source) =>
fs
.readdirSync(source)
- .map(name => path.join(source, name))
+ .map((name) => path.join(source, name))
.filter(isDirectory);
const { lstatSync, readdirSync } = require('fs');
@@ -53,10 +53,10 @@ module.exports = {
renderPattern: function renderPattern(pattern, data, partials) {
return engine
.parseAndRender(pattern.template, data)
- .then(function(html) {
+ .then(function (html) {
return html;
})
- .catch(function(ex) {
+ .catch(function (ex) {
console.log(40, ex);
});
},
@@ -86,7 +86,7 @@ module.exports = {
var matches = this.patternMatcher(pattern, this.findPartialsRE);
return matches;
},
- findPartialsWithStyleModifiers: function(pattern) {
+ findPartialsWithStyleModifiers: function (pattern) {
var matches = this.patternMatcher(
pattern,
this.findPartialsWithStyleModifiersRE
@@ -96,28 +96,28 @@ module.exports = {
// returns any patterns that match {{> value(foo:"bar") }} or {{>
// value:mod(foo:"bar") }} within the pattern
- findPartialsWithPatternParameters: function(pattern) {
+ findPartialsWithPatternParameters: function (pattern) {
var matches = this.patternMatcher(
pattern,
this.findPartialsWithPatternParametersRE
);
return matches;
},
- findListItems: function(pattern) {
+ findListItems: function (pattern) {
var matches = this.patternMatcher(pattern, this.findListItemsRE);
return matches;
},
// given a pattern, and a partial string, tease out the "pattern key" and
// return it.
- findPartial_new: function(partialString) {
+ findPartial_new: function (partialString) {
var partial = partialString.replace(this.findPartialRE, '$1');
return partial;
},
// GTP: the old implementation works better. We might not need
// this.findPartialRE anymore if it works in all cases!
- findPartial: function(partialString) {
+ findPartial: function (partialString) {
//strip out the template cruft
var foundPatternPartial = partialString
.replace('{{> ', '')
@@ -145,7 +145,7 @@ module.exports = {
*
* @param {object} config - the global config object from core
*/
- usePatternLabConfig: function(config) {
+ usePatternLabConfig: function (config) {
patternLabConfig = config;
let patternsPath = patternLabConfig.paths.source.patterns;
@@ -163,7 +163,7 @@ module.exports = {
});
},
- spawnFile: function(config, fileName) {
+ spawnFile: function (config, fileName) {
const paths = config.paths;
const metaFilePath = path.resolve(paths.source.meta, fileName);
@@ -187,8 +187,8 @@ module.exports = {
* @param {object} config - the global config object from core, since we won't
* assume it's already present
*/
- spawnMeta: function(config) {
- this.spawnFile(config, '_00-head.liquid');
- this.spawnFile(config, '_01-foot.liquid');
+ spawnMeta: function (config) {
+ this.spawnFile(config, '_head.liquid');
+ this.spawnFile(config, '_foot.liquid');
},
};
diff --git a/packages/engine-liquid/package.json b/packages/engine-liquid/package.json
index a0940f7dd..07a419444 100644
--- a/packages/engine-liquid/package.json
+++ b/packages/engine-liquid/package.json
@@ -1,10 +1,10 @@
{
"name": "@pattern-lab/engine-liquid",
"description": "The Liquid engine for Pattern Lab / Node",
- "version": "1.0.0-beta.1",
+ "version": "6.1.0",
"main": "lib/engine_liquid.js",
"dependencies": {
- "fs-extra": "5.0.0",
+ "fs-extra": "10.0.0",
"liquidjs": "2.2.0"
},
"keywords": [
@@ -22,9 +22,10 @@
"license": "MIT",
"scripts": {},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/engine-mustache/.nvmrc b/packages/engine-mustache/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/engine-mustache/.nvmrc
+++ b/packages/engine-mustache/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/engine-mustache/CHANGELOG.md b/packages/engine-mustache/CHANGELOG.md
index d185a823c..531153bef 100644
--- a/packages/engine-mustache/CHANGELOG.md
+++ b/packages/engine-mustache/CHANGELOG.md
@@ -3,6 +3,106 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+**Note:** Version bump only for package @pattern-lab/engine-mustache
+
+
+
+
+
+
# [2.0.0-beta.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-mustache/compare/@pattern-lab/engine-mustache@2.0.0-beta.0...@pattern-lab/engine-mustache@2.0.0-beta.1) (2019-02-09)
**Note:** Version bump only for package @pattern-lab/engine-mustache
diff --git a/packages/engine-mustache/LICENSE b/packages/engine-mustache/LICENSE
index f4b26b73e..099ac3c30 100644
--- a/packages/engine-mustache/LICENSE
+++ b/packages/engine-mustache/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Dan White, https://github.com/danwhite85 & Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Dan White, https://github.com/danwhite85 & Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-mustache/_meta/_00-head.mustache b/packages/engine-mustache/_meta/_00-head.mustache
deleted file mode 100644
index 45ce3bb7d..000000000
--- a/packages/engine-mustache/_meta/_00-head.mustache
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
-
diff --git a/packages/engine-underscore/_meta/_01-foot.html b/packages/engine-mustache/_meta/_foot.mustache
similarity index 100%
rename from packages/engine-underscore/_meta/_01-foot.html
rename to packages/engine-mustache/_meta/_foot.mustache
diff --git a/packages/engine-mustache/_meta/_head.mustache b/packages/engine-mustache/_meta/_head.mustache
new file mode 100644
index 000000000..5921e94cf
--- /dev/null
+++ b/packages/engine-mustache/_meta/_head.mustache
@@ -0,0 +1,17 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
+
+
diff --git a/packages/engine-mustache/lib/engine_mustache.js b/packages/engine-mustache/lib/engine_mustache.js
index dc0838cfd..e39359490 100644
--- a/packages/engine-mustache/lib/engine_mustache.js
+++ b/packages/engine-mustache/lib/engine_mustache.js
@@ -29,7 +29,7 @@ const utilMustache = require('./util_mustache');
// it does, so we're cool, right?
let patternLabConfig = {};
-var engine_mustache = {
+const engine_mustache = {
engine: Mustache,
engineName: 'mustache',
engineFileExtension: '.mustache',
@@ -69,7 +69,7 @@ var engine_mustache = {
* @returns {array|null} An array if a match is found, null if not.
*/
patternMatcher: function patternMatcher(pattern, regex) {
- var matches;
+ let matches;
if (typeof pattern === 'string') {
matches = pattern.match(regex);
} else if (
@@ -81,7 +81,7 @@ var engine_mustache = {
return matches;
},
- spawnFile: function(config, fileName) {
+ spawnFile: function (config, fileName) {
const paths = config.paths;
const metaFilePath = path.resolve(paths.source.meta, fileName);
try {
@@ -103,50 +103,42 @@ var engine_mustache = {
* @param {object} config - the global config object from core, since we won't
* assume it's already present
*/
- spawnMeta: function(config) {
- this.spawnFile(config, '_00-head.mustache');
- this.spawnFile(config, '_01-foot.mustache');
+ spawnMeta: function (config) {
+ this.spawnFile(config, '_head.mustache');
+ this.spawnFile(config, '_foot.mustache');
},
// find and return any {{> template-name }} within pattern
findPartials: function findPartials(pattern) {
- var matches = this.patternMatcher(pattern, this.findPartialsRE);
- return matches;
+ return this.patternMatcher(pattern, this.findPartialsRE);
},
- findPartialsWithStyleModifiers: function(pattern) {
- var matches = this.patternMatcher(
- pattern,
- this.findPartialsWithStyleModifiersRE
- );
- return matches;
+ findPartialsWithStyleModifiers: function (pattern) {
+ return this.patternMatcher(pattern, this.findPartialsWithStyleModifiersRE);
},
// returns any patterns that match {{> value(foo:"bar") }} or {{>
// value:mod(foo:"bar") }} within the pattern
- findPartialsWithPatternParameters: function(pattern) {
- var matches = this.patternMatcher(
+ findPartialsWithPatternParameters: function (pattern) {
+ return this.patternMatcher(
pattern,
this.findPartialsWithPatternParametersRE
);
- return matches;
},
- findListItems: function(pattern) {
- var matches = this.patternMatcher(pattern, this.findListItemsRE);
- return matches;
+ findListItems: function (pattern) {
+ return this.patternMatcher(pattern, this.findListItemsRE);
},
// given a pattern, and a partial string, tease out the "pattern key" and
// return it.
- findPartial_new: function(partialString) {
- var partial = partialString.replace(this.findPartialRE, '$1');
- return partial;
+ findPartial_new: function (partialString) {
+ return partialString.replace(this.findPartialRE, '$1');
},
// GTP: the old implementation works better. We might not need
// this.findPartialRE anymore if it works in all cases!
- findPartial: function(partialString) {
+ findPartial: function (partialString) {
//strip out the template cruft
- var foundPatternPartial = partialString
+ let foundPatternPartial = partialString
.replace('{{> ', '')
.replace(' }}', '')
.replace('{{>', '')
@@ -172,7 +164,7 @@ var engine_mustache = {
*
* @param {object} config - the global config object from core
*/
- usePatternLabConfig: function(config) {
+ usePatternLabConfig: function (config) {
patternLabConfig = config;
},
};
diff --git a/packages/engine-mustache/package.json b/packages/engine-mustache/package.json
index 0a43dc015..8cf0b1506 100644
--- a/packages/engine-mustache/package.json
+++ b/packages/engine-mustache/package.json
@@ -1,11 +1,11 @@
{
"name": "@pattern-lab/engine-mustache",
"description": "The Mustache engine for Pattern Lab / Node",
- "version": "2.0.1-alpha.0",
+ "version": "6.1.0",
"main": "lib/engine_mustache.js",
"dependencies": {
- "fs-extra": "0.30.0",
- "mustache": "2.2.0"
+ "fs-extra": "10.0.0",
+ "mustache": "3.1.0"
},
"keywords": [
"Pattern Lab",
@@ -22,9 +22,10 @@
"license": "MIT",
"scripts": {},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/engine-nunjucks/.nvmrc b/packages/engine-nunjucks/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/engine-nunjucks/.nvmrc
+++ b/packages/engine-nunjucks/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/engine-nunjucks/CHANGELOG.md b/packages/engine-nunjucks/CHANGELOG.md
index 2a9fd1d57..a84b3b3ca 100644
--- a/packages/engine-nunjucks/CHANGELOG.md
+++ b/packages/engine-nunjucks/CHANGELOG.md
@@ -3,6 +3,124 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-nunjucks
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/issues/1192) ([374c103](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/374c103a59504ba239b16680f86a89b4d95e304f))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/issues/1192) ([48de8c2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/48de8c2e134a61c0b4440375254bc9590a3e2563))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/issues/1192) ([363f22c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/363f22c643239ef4ca48d6f5942111604fda5ead))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/issues/1192) ([487cc78](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/487cc783388043ec16ab1e54a3bfd8490038d058))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/issues/1192) ([571017f](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/571017ffafa2cf6e8fa01b7ea7effc88922b05d1))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* Rename Handlebars and Nunjucks extension setting to "extend" ([74e5af2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/74e5af28c4e714fdfc1db535b94c52f3dc14a3a4))
+
+
+### Features
+
+* **engine-nunjucks:** Configurable extension locations; Use usePatternlabConfig() ([e54e3b3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/e54e3b3d48f934d3a4d44b9f4ff262f742a4aaf9))
+* update Node to v12 ([fcbb970](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/fcbb970648cdd775c9a88078f14c1f24c5b62d73))
+
+
+
+
+
+
+# [0.2.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/@pattern-lab/engine-nunjucks@0.1.5-alpha.0...@pattern-lab/engine-nunjucks@0.2.0) (2019-08-23)
+
+
+### Bug Fixes
+
+* Rename Handlebars and Nunjucks extension setting to "extend" ([74e5af2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/74e5af2))
+
+
+### Features
+
+* **engine-nunjucks:** Configurable extension locations; Use usePatternlabConfig() ([e54e3b3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/commit/e54e3b3))
+
+
+
+
+
+
## [0.1.4-beta.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-nunjucks/compare/@pattern-lab/engine-nunjucks@0.1.4-beta.0...@pattern-lab/engine-nunjucks@0.1.4-beta.2) (2019-02-09)
diff --git a/packages/engine-nunjucks/LICENSE b/packages/engine-nunjucks/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/engine-nunjucks/LICENSE
+++ b/packages/engine-nunjucks/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-nunjucks/README.md b/packages/engine-nunjucks/README.md
index b85c5e5d7..283a3695c 100644
--- a/packages/engine-nunjucks/README.md
+++ b/packages/engine-nunjucks/README.md
@@ -5,28 +5,46 @@
To install the Nunjucks PatternEngine in your edition, run `npm install @pattern-lab/engine-nunjucks`.
## Supported features
-- [x] [Includes](http://patternlab.io/docs/pattern-including.html)
+- [x] [Includes](https://patternlab.io/docs/including-patterns/)
- [x] Lineage
-- [x] [Hidden Patterns](http://patternlab.io/docs/pattern-hiding.html)
-- [x] [Pseudo-Patterns](http://patternlab.io/docs/pattern-pseudo-patterns.html)
-- [x] [Pattern States](http://patternlab.io/docs/pattern-states.html)
-- [ ] [Pattern Parameters](http://patternlab.io/docs/pattern-parameters.html) (Accomplished instead using native Nunjucks variables)
-- [ ] [Style Modifiers](http://patternlab.io/docs/pattern-stylemodifier.html) (Accomplished instead using native Nunjucks variables)
+- [x] [Hidden Patterns](https://patternlab.io/docs/hiding-patterns-in-the-navigation/)
+- [x] [Pseudo-Patterns](https://patternlab.io/docs/using-pseudo-patterns/)
+- [x] [Pattern States](https://patternlab.io/docs/using-pattern-states/)
+- [ ] ~~[Pattern Parameters](https://patternlab.io/docs/using-pattern-parameters/)~~ (Accomplished instead using native Nunjucks variables)
+- [ ] ~~[Style Modifiers](https://github.com/pattern-lab/patternlab-node/issues/1177)~~ (Accomplished instead using native Nunjucks variables)
Level of Support is more or less full. Partial calls and lineage hunting are supported. Nunjucks does not support the mustache-specific syntax extensions, style modifiers and pattern parameters, because their use cases are addressed by the core Nunjucks feature set. Pattern Lab's listitems feature is still written in the mustache syntax.
## Extending the Nunjucks instance
-To add custom filters or make customizations to the nunjucks instance, create a file named `patternlab-nunjucks-config.js` in the root of your Pattern Lab project. `patternlab-nunjucks-config.js` should export a function with the Nunjucks environment as parameter.
+To add custom filters or make customizations to the nunjucks instance, add the following to `patternlab-config.json`:
+```json
+ {
+ ...
+ "engines": {
+ "nunjucks": {
+ "extend": [
+ "nunjucks-extensions/*.js"
+ ]
+ }
+ }
+ }
```
+
+...or use the default file name: `patternlab-nunjucks-config.js` (in the root of your Pattern Lab project).
+
+Each file providing extensions should export a function with the Nunjucks environment as parameter.
+
+```js
module.exports = function (env) {
[YOUR CUSTOM CODE HERE]
};
```
Example: `patternlab-nunjucks-config.js` file that uses lodash and adds three custom filters.
-```
+
+```js
var _shuffle = require('lodash/shuffle'),
_take = require('lodash/take');
diff --git a/packages/engine-nunjucks/_meta/_01-foot.njk b/packages/engine-nunjucks/_meta/_foot.njk
similarity index 100%
rename from packages/engine-nunjucks/_meta/_01-foot.njk
rename to packages/engine-nunjucks/_meta/_foot.njk
diff --git a/packages/engine-nunjucks/_meta/_00-head.njk b/packages/engine-nunjucks/_meta/_head.njk
similarity index 92%
rename from packages/engine-nunjucks/_meta/_00-head.njk
rename to packages/engine-nunjucks/_meta/_head.njk
index b69898755..0de971fd3 100644
--- a/packages/engine-nunjucks/_meta/_00-head.njk
+++ b/packages/engine-nunjucks/_meta/_head.njk
@@ -1,5 +1,5 @@
-
+
{{ title }}
diff --git a/packages/engine-nunjucks/lib/engine_nunjucks.js b/packages/engine-nunjucks/lib/engine_nunjucks.js
index 0153939ac..939e21adc 100644
--- a/packages/engine-nunjucks/lib/engine_nunjucks.js
+++ b/packages/engine-nunjucks/lib/engine_nunjucks.js
@@ -22,39 +22,10 @@
const fs = require('fs-extra');
const path = require('path');
-const plPath = process.cwd();
-const plConfig = require(path.join(plPath, 'patternlab-config.json'));
const nunjucks = require('nunjucks');
const partialRegistry = [];
-// Create Pattern Loader
-// Since Pattern Lab includes are not path based we need a custom loader for Nunjucks.
-function PatternLoader() {}
-
-PatternLoader.prototype.getSource = function(name) {
- const fullPath = path.resolve(
- plConfig.paths.source.patterns,
- partialRegistry[name]
- );
- return {
- src: fs.readFileSync(fullPath, 'utf-8'),
- path: fullPath,
- noCache: true,
- };
-};
-
-const env = new nunjucks.Environment(new PatternLoader());
-
-// Load any user Defined configurations
-try {
- const nunjucksConfig = require(path.join(
- plPath,
- 'patternlab-nunjucks-config.js'
- ));
- if (typeof nunjucksConfig === 'function') {
- nunjucksConfig(env);
- }
-} catch (err) {}
+let env;
// Nunjucks Engine
const engine_nunjucks = {
@@ -66,9 +37,11 @@ const engine_nunjucks = {
expandPartials: false,
// regexes, stored here so they're only compiled once
- findPartialsRE: /{%\s*(?:extends|include|import|from)\s+(?:'[^']+'|"[^"]+").*%}/g,
+ findPartialsRE:
+ /{%\s*(?:extends|include|import|from)\s+(?:'[^']+'|"[^"]+").*%}/g,
findPartialKeyRE: /{%\s*(?:extends|include|import|from)\s+('[^']+'|"[^"]+")/,
- findListItemsRE: /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, // still requires mustache style syntax because of how PL implements lists
+ findListItemsRE:
+ /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, // still requires mustache style syntax because of how PL implements lists
// render it
renderPattern: function renderPattern(pattern, data) {
@@ -88,7 +61,7 @@ const engine_nunjucks = {
},
// given a pattern, and a partial string, tease out the "pattern key" and return it.
- findPartial: function(partialString) {
+ findPartial: function (partialString) {
try {
let partial = partialString.match(this.findPartialKeyRE)[1];
partial = partial.replace(/["']/g, '');
@@ -101,7 +74,7 @@ const engine_nunjucks = {
},
// keep track of partials and their paths so we can replace the name with the path
- registerPartial: function(pattern) {
+ registerPartial: function (pattern) {
// only register each partial once. Otherwise we'll eat up a ton of memory.
if (partialRegistry.indexOf(pattern.patternPartial) === -1) {
partialRegistry[pattern.patternPartial] = pattern.relPath.replace(
@@ -112,22 +85,17 @@ const engine_nunjucks = {
},
// still requires the mustache syntax because of the way PL handles lists
- findListItems: function(pattern) {
+ findListItems: function (pattern) {
const matches = pattern.template.match(this.findListItemsRE);
return matches;
},
// handled by nunjucks. This is here to keep PL from erroring
- findPartialsWithStyleModifiers: function() {
- return null;
- },
-
- // handled by nunjucks. This is here to keep PL from erroring
- findPartialsWithPatternParameters: function() {
+ findPartialsWithPatternParameters: function () {
return null;
},
- spawnFile: function(config, fileName) {
+ spawnFile: function (config, fileName) {
const paths = config.paths;
const metaFilePath = path.resolve(paths.source.meta, fileName);
try {
@@ -149,9 +117,75 @@ const engine_nunjucks = {
* @param {object} config - the global config object from core, since we won't
* assume it's already present
*/
- spawnMeta: function(config) {
- this.spawnFile(config, '_00-head.njk');
- this.spawnFile(config, '_01-foot.njk');
+ spawnMeta: function (config) {
+ this.spawnFile(config, '_head.njk');
+ this.spawnFile(config, '_foot.njk');
+ },
+
+ /**
+ * Accept a Pattern Lab config object from the core and use the settings to
+ * load helpers.
+ *
+ * @param {object} config - the global config object from core
+ */
+ usePatternLabConfig: function (config) {
+ // Create Pattern Loader
+ // Since Pattern Lab includes are not path based we need a custom loader for Nunjucks.
+ function PatternLoader() {}
+
+ PatternLoader.prototype.getSource = function (name) {
+ const fullPath = path.resolve(
+ config.paths.source.patterns,
+ partialRegistry[name]
+ );
+ return {
+ src: fs.readFileSync(fullPath, 'utf-8'),
+ path: fullPath,
+ noCache: true,
+ };
+ };
+
+ env = new nunjucks.Environment(new PatternLoader());
+
+ let extensions;
+
+ try {
+ // Look for helpers in the config
+ extensions = config.engines.nunjucks.extend;
+
+ if (typeof extensions === 'string') {
+ extensions = [extensions];
+ }
+ } catch (error) {
+ // No defined path(s) found, look in default location
+
+ const configPath = 'patternlab-nunjucks-config.js';
+ if (fs.existsSync(path.join(process.cwd(), configPath))) {
+ extensions = [configPath];
+ }
+ }
+
+ if (extensions) {
+ extensions.forEach((extensionPath) => {
+ // Load any user Defined configurations
+ const nunjucksConfigPath = path.join(process.cwd(), extensionPath);
+
+ try {
+ const nunjucksConfig = require(nunjucksConfigPath);
+ if (typeof nunjucksConfig === 'function') {
+ nunjucksConfig(env);
+ } else {
+ console.error(
+ `Failed to load Nunjucks extension: Expected ${extensionPath} to export a function.`
+ );
+ }
+ } catch (err) {
+ console.error(
+ `Failed to load Nunjucks extension ${nunjucksConfigPath}.`
+ );
+ }
+ });
+ }
},
};
diff --git a/packages/engine-nunjucks/package.json b/packages/engine-nunjucks/package.json
index 33913af77..83bb934e6 100644
--- a/packages/engine-nunjucks/package.json
+++ b/packages/engine-nunjucks/package.json
@@ -7,11 +7,11 @@
"deprecated": false,
"description": "The nunjucks PatternEngine for Pattern Lab / Node",
"dependencies": {
- "fs-extra": "7.0.0",
- "nunjucks": "3.1.3"
+ "fs-extra": "10.0.0",
+ "nunjucks": "^3.2.3"
},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"keywords": [
"Pattern Lab",
@@ -26,8 +26,9 @@
"main": "lib/engine_nunjucks.js",
"name": "@pattern-lab/engine-nunjucks",
"scripts": {},
- "version": "0.1.5-alpha.0",
+ "version": "6.1.0",
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/engine-react/.gitignore b/packages/engine-react/.gitignore
index 5148e527a..7d7d9a692 100644
--- a/packages/engine-react/.gitignore
+++ b/packages/engine-react/.gitignore
@@ -17,13 +17,13 @@ coverage
# nyc test coverage
.nyc_output
-# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# node-waf configuration
.lock-wscript
-# Compiled binary addons (http://nodejs.org/api/addons.html)
+# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
diff --git a/packages/engine-react/.nvmrc b/packages/engine-react/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/engine-react/.nvmrc
+++ b/packages/engine-react/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/engine-react/CHANGELOG.md b/packages/engine-react/CHANGELOG.md
index bc201eb4f..6f4c3ef02 100644
--- a/packages/engine-react/CHANGELOG.md
+++ b/packages/engine-react/CHANGELOG.md
@@ -3,6 +3,84 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-react
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/engine-react
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-react
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-react
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-react
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-react
+
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/issues/1192) ([374c103](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/commit/374c103a59504ba239b16680f86a89b4d95e304f))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/issues/1192) ([48de8c2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/commit/48de8c2e134a61c0b4440375254bc9590a3e2563))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/issues/1192) ([363f22c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/commit/363f22c643239ef4ca48d6f5942111604fda5ead))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/issues/1192) ([487cc78](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/commit/487cc783388043ec16ab1e54a3bfd8490038d058))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/issues/1192) ([571017f](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/commit/571017ffafa2cf6e8fa01b7ea7effc88922b05d1))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Features
+
+* **engine-react:** set package to private ([3aea881](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/commit/3aea8815f19df5b527cdda0b75cf99a9a8c3bc1e))
+
+
+
+
+
+
## [0.2.1-beta.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-react/compare/@pattern-lab/engine-react@0.2.1-beta.0...@pattern-lab/engine-react@0.2.1-beta.1) (2019-02-09)
**Note:** Version bump only for package @pattern-lab/engine-react
diff --git a/packages/engine-react/LICENSE b/packages/engine-react/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/engine-react/LICENSE
+++ b/packages/engine-react/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-react/README.md b/packages/engine-react/README.md
index 028006981..f1fb383a1 100644
--- a/packages/engine-react/README.md
+++ b/packages/engine-react/README.md
@@ -14,13 +14,13 @@ To install the React PatternEngine in your edition, `npm install @pattern-lab/en
## Supported features
-* [x] [Includes](http://patternlab.io/docs/pattern-including.html)
+* [x] [Includes](https://patternlab.io/docs/including-patterns/)
* [x] Data inheritance: This can be achieved by combining react `props` & `defaultProps`
-* [x] [Hidden Patterns](http://patternlab.io/docs/pattern-hiding.html)
-* [x] [Pseudo-Patterns](http://patternlab.io/docs/pattern-pseudo-patterns.html)
-* [x] [Pattern States](http://patternlab.io/docs/pattern-states.html#node)
-* [x] [Pattern Parameters](http://patternlab.io/docs/pattern-parameters.html): With react props
-* [x] [Style Modifiers](http://patternlab.io/docs/pattern-stylemodifier.html): With react props
+* [x] [Hidden Patterns](https://patternlab.io/docs/hiding-patterns-in-the-navigation/)
+* [x] [Pseudo-Patterns](https://patternlab.io/docs/using-pseudo-patterns/)
+* [x] [Pattern States](https://patternlab.io/docs/using-pattern-states/)
+* [x] [Pattern Parameters](https://patternlab.io/docs/using-pattern-parameters/): With react props
+* [x] [Style Modifiers](https://github.com/pattern-lab/patternlab-node/issues/1177): With react props
* [x] Lineage
* [x] Incremental builds
diff --git a/packages/engine-react/lib/engine_react.js b/packages/engine-react/lib/engine_react.js
index b0f01cdd2..a27f0c432 100644
--- a/packages/engine-react/lib/engine_react.js
+++ b/packages/engine-react/lib/engine_react.js
@@ -14,7 +14,7 @@ const path = require('path');
const React = require('react');
const ReactDOMServer = require('react-dom/server');
const Babel = require('babel-core');
-const Hogan = require('hogan');
+const Handlebars = require('handlebars');
const beautify = require('js-beautify');
const cheerio = require('cheerio');
const _require = require;
@@ -44,8 +44,8 @@ let patternLabConfig = {};
let enableRuntimeCode = true;
-const outputTemplate = Hogan.compile(
- fs.readFileSync(path.join(__dirname, './outputTemplate.mustache'), 'utf8')
+const outputTemplate = Handlebars.compile(
+ fs.readFileSync(path.join(__dirname, './outputTemplate.hbs'), 'utf8')
);
let registeredComponents = {
@@ -64,7 +64,7 @@ function babelTransform(pattern) {
// eval() module code in this little scope that injects our
// custom wrap of require();
- (require => {
+ ((require) => {
/* eslint-disable no-eval */
transpiledModule = eval(transpiledModule.code);
})(customRequire);
@@ -106,11 +106,11 @@ var engine_react = {
React.createFactory(transpiledModule)(data)
);
- renderedHTML = outputTemplate.render({
+ renderedHTML = outputTemplate({
htmlOutput: staticMarkup,
});
- return Promise.resolve(renderedHTML).catch(e => {
+ return Promise.resolve(renderedHTML).catch((e) => {
var errorMessage = `Error rendering React pattern "${
pattern.patternName
}" (${pattern.relPath}): [${e.toString()}]`;
@@ -161,7 +161,7 @@ var engine_react = {
}
// Remove unregistered imports from the matches
- matches.map(m => {
+ matches.map((m) => {
const key = self.findPartial(m);
if (!registeredComponents.byPatternPartial[key]) {
const i = matches.indexOf(m);
@@ -174,10 +174,6 @@ var engine_react = {
return matches;
},
- findPartialsWithStyleModifiers(pattern) {
- return [];
- },
-
// returns any patterns that match {{> value(foo:'bar') }} or {{>
// value:mod(foo:'bar') }} within the pattern
findPartialsWithPatternParameters(pattern) {
@@ -224,7 +220,7 @@ var engine_react = {
*
* @param {object} config - the global config object from core
*/
- usePatternLabConfig: function(config) {
+ usePatternLabConfig: function (config) {
patternLabConfig = config;
try {
diff --git a/packages/engine-react/lib/outputTemplate.hbs b/packages/engine-react/lib/outputTemplate.hbs
new file mode 100644
index 000000000..f7708f62c
--- /dev/null
+++ b/packages/engine-react/lib/outputTemplate.hbs
@@ -0,0 +1 @@
+{{{htmlOutput}}}
\ No newline at end of file
diff --git a/packages/engine-react/lib/outputTemplate.mustache b/packages/engine-react/lib/outputTemplate.mustache
deleted file mode 100644
index 0153d9810..000000000
--- a/packages/engine-react/lib/outputTemplate.mustache
+++ /dev/null
@@ -1 +0,0 @@
-{{{htmlOutput}}}
diff --git a/packages/engine-react/package.json b/packages/engine-react/package.json
index e3ca7ae04..569cb9bd3 100644
--- a/packages/engine-react/package.json
+++ b/packages/engine-react/package.json
@@ -1,15 +1,16 @@
{
"name": "@pattern-lab/engine-react",
"description": "The React engine for Pattern Lab / Node",
- "version": "0.2.1-beta.1",
+ "version": "6.1.0",
+ "private": true,
"main": "lib/engine_react.js",
"dependencies": {
"babel-core": "6.17.0",
"babel-plugin-transform-es2015-modules-commonjs": "6.16.0",
"babel-preset-react": "6.16.0",
"cheerio": "0.22.0",
- "hogan": "1.0.2",
- "js-beautify": "1.6.4",
+ "handlebars": "4.7.7",
+ "js-beautify": "1.13.5",
"react": "15.3.2",
"react-dom": "15.3.2"
},
@@ -30,7 +31,7 @@
"license": "MIT",
"scripts": {},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
diff --git a/packages/engine-twig-php/CHANGELOG.md b/packages/engine-twig-php/CHANGELOG.md
index 420e6f23d..f2da46cd2 100644
--- a/packages/engine-twig-php/CHANGELOG.md
+++ b/packages/engine-twig-php/CHANGELOG.md
@@ -1 +1,366 @@
+# Change Log
+
+All notable changes to this project will be documented in this file.
+See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+
+### Features
+
+* **engine-twig-php:** update @basalt/twig-renderer to v3.0.1 using Twig v3.7.1 ([#1499](https://github.com/pattern-lab/patternlab-node/issues/1499)) ([2e5c9e1](https://github.com/pattern-lab/patternlab-node/commit/2e5c9e1c6a3318ba1cd3765d448c181e4a3a9a27)), closes [#1496](https://github.com/pattern-lab/patternlab-node/issues/1496) [#1496](https://github.com/pattern-lab/patternlab-node/issues/1496)
+
+
+
+
+
+## [6.0.1](https://github.com/pattern-lab/patternlab-node/compare/v6.0.0...v6.0.1) (2023-02-01)
+
+
+### Bug Fixes
+
+* **twig engine:** startup and running problems ([#1478](https://github.com/pattern-lab/patternlab-node/issues/1478)) ([e5a1904](https://github.com/pattern-lab/patternlab-node/commit/e5a19049f083315939406677b1c0480f4b420569))
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+
+### Bug Fixes
+
+* **engine-twig-php:** twig include function syntax not matched by findPartials ([#1472](https://github.com/pattern-lab/patternlab-node/issues/1472)) ([3677539](https://github.com/pattern-lab/patternlab-node/commit/3677539409ac41dfee71d90cc429be5c92890838)), closes [#1471](https://github.com/pattern-lab/patternlab-node/issues/1471)
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.16.2](https://github.com/pattern-lab/patternlab-node/compare/v5.16.1...v5.16.2) (2022-02-07)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.15.5](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.5) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.15.4](https://github.com/pattern-lab/patternlab-node/compare/v5.15.3...v5.15.4) (2021-12-06)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.15.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.15.1...v5.15.2) (2021-11-03)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.15.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.14.3...v5.15.0) (2021-07-01)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.14.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.14.1...v5.14.2) (2021-03-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.14.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.14.0...v5.14.1) (2021-02-19)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.13.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.13.2...v5.13.3) (2020-12-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.13.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.13.1...v5.13.2) (2020-11-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.13.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.13.0...v5.13.1) (2020-09-06)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.13.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.12.0...v5.13.0) (2020-08-26)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.12.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.11.1...v5.12.0) (2020-08-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.11.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.10.2...v5.11.1) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.11.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.10.2...v5.11.0) (2020-06-28)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.9.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.8.0...v5.9.0) (2020-04-24)
+
+
+### Bug Fixes
+
+* actually exit build when Twig render fails ([5d28a24](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/5d28a24a53011396289c1e29e0a715cd82470185))
+* Update packages/engine-twig-php/lib/engine_twig_php.js ([c67d50e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/c67d50ebb5d69816b7514e85f129f8ecde984ad3))
+
+
+
+
+
+## [5.7.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.7.0...v5.7.1) (2020-02-24)
+
+
+### Bug Fixes
+
+* update twig-renderer ([46f53b7](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/46f53b79f8bb0bb64a9c55fd32f29459cea6e28c))
+
+
+
+
+
+# [5.7.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.6.0...v5.7.0) (2020-02-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.6.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.5.0...v5.6.0) (2020-01-18)
+
+
+### Features
+
+* pass additional configuration into twig-php engine ([dff5a78](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/dff5a7830918fa46e2692d9f9daed4121f803461))
+
+
+
+
+
+
+# [5.5.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.4.2...v5.5.0) (2019-12-19)
+
+
+### Features
+
+* upgrade Twig to use new filter, map, reduce ([4218a5a](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/4218a5a04b06027548afd9f417486297dd25fef8))
+
+
+
+
+
+# [5.4.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.3.3...v5.4.0) (2019-11-26)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.3.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.2.0...v5.3.0) (2019-11-13)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.2.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.1.0...v5.2.0) (2019-11-12)
+
+
+### Bug Fixes
+
+* **engine_twig_php:** Allow additional flexibility with twig namespaces. ([07bfaa3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/07bfaa35a00ff62fd2016cc9f34e09cf5af36559))
+
+
+
+
+
+
+# [5.1.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v5.0.2...v5.1.0) (2019-10-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+
+### Bug Fixes
+
+* **engine_twig_php:** Pseudo patterns Twig PHP ([226aa8b](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/226aa8bbaaf5e418530ccf54a28f6c5657ee6dea)), closes [#1045](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/issues/1045)
+* **engine_twig_php:** Twig incremental rebuilds ([5d33f24](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/5d33f24f156ebe50900701513a855de7de608dcf)), closes [#1015](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/issues/1015)
+* **engine_twig_php:** Twig incremental rebuilds ([1ade945](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/1ade9451840b2645706a0b01129e2b697dc22d4b)), closes [#1015](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/issues/1015)
+
+
+
+
+
+
+## [3.0.5](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/@pattern-lab/engine-twig-php@3.0.4...@pattern-lab/engine-twig-php@3.0.5) (2019-10-14)
+
+
+### Bug Fixes
+
+* **engine_twig_php:** Pseudo patterns Twig PHP ([226aa8b](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/226aa8bbaaf5e418530ccf54a28f6c5657ee6dea)), closes [#1045](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/issues/1045)
+* **engine_twig_php:** Twig incremental rebuilds ([5d33f24](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/5d33f24f156ebe50900701513a855de7de608dcf)), closes [#1015](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/issues/1015)
+* **engine_twig_php:** Twig incremental rebuilds ([1ade945](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/commit/1ade9451840b2645706a0b01129e2b697dc22d4b)), closes [#1015](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/issues/1015)
+
+
+
+
+
+
+## [3.0.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/@pattern-lab/engine-twig-php@3.0.1...@pattern-lab/engine-twig-php@3.0.2) (2019-08-23)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
+
+## [3.0.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig-php/compare/@pattern-lab/engine-twig-php@3.0.0...@pattern-lab/engine-twig-php@3.0.1) (2019-05-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig-php
+
+
+
+
+
# Change Log
diff --git a/packages/engine-twig-php/LICENSE b/packages/engine-twig-php/LICENSE
index 8d83dd7de..e65009972 100644
--- a/packages/engine-twig-php/LICENSE
+++ b/packages/engine-twig-php/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Evan Lovely, http://evanlovely.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Evan Lovely, https://www.evanlovely.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-twig-php/_meta/_01-foot.twig b/packages/engine-twig-php/_meta/_foot.twig
similarity index 100%
rename from packages/engine-twig-php/_meta/_01-foot.twig
rename to packages/engine-twig-php/_meta/_foot.twig
diff --git a/packages/engine-twig-php/_meta/_00-head.twig b/packages/engine-twig-php/_meta/_head.twig
similarity index 87%
rename from packages/engine-twig-php/_meta/_00-head.twig
rename to packages/engine-twig-php/_meta/_head.twig
index 4b49c63b7..5087213d9 100644
--- a/packages/engine-twig-php/_meta/_00-head.twig
+++ b/packages/engine-twig-php/_meta/_head.twig
@@ -1,8 +1,8 @@
-
+
{{ title }}
-
+
diff --git a/packages/engine-twig-php/lib/engine_twig_php.js b/packages/engine-twig-php/lib/engine_twig_php.js
index 461a10dbd..0f728dc6b 100644
--- a/packages/engine-twig-php/lib/engine_twig_php.js
+++ b/packages/engine-twig-php/lib/engine_twig_php.js
@@ -17,6 +17,7 @@
const TwigRenderer = require('@basalt/twig-renderer');
const fs = require('fs-extra');
const path = require('path');
+const chalk = require('chalk');
let twigRenderer;
let patternLabConfig = {};
@@ -26,10 +27,9 @@ const engine_twig_php = {
engineName: 'twig-php',
engineFileExtension: '.twig',
expandPartials: false,
-
- // @todo Evaluate RegExs
- // findPartialsRE: /{%\s*(?:extends|include|embed)\s+('[^']+'|"[^"]+").*?%}/g,
- // findPartialKeyRE: /"((?:\\.|[^"\\])*)"/,
+ findPartialsRE:
+ /{[%{]\s*.*?(?:extends|include|embed|from|import|use)\(?\s*['"](.+?)['"][\s\S]*?\)?\s*[%}]}/g,
+ namespaces: [],
/**
* Accept a Pattern Lab config object from the core and put it in
@@ -37,15 +37,20 @@ const engine_twig_php = {
*
* @param {object} config - the global config object from core
*/
- usePatternLabConfig: function(config) {
+ usePatternLabConfig: function (config) {
patternLabConfig = config;
- if (!config.engines.twig) {
+ if (!config.engines['twig-php']) {
console.error('Missing "twig" in Pattern Lab config file; exiting...');
process.exit(1);
}
- const { namespaces, alterTwigEnv, relativeFrom } = config.engines.twig;
+ const { namespaces, alterTwigEnv, relativeFrom, ...rest } =
+ config.engines['twig-php'];
+
+ // since package is a reserved word in node, we need to delete it from the config object like this
+ delete rest.package;
+ delete rest.fileExtensions;
// Schema on config object being passed in:
// https://github.com/basaltinc/twig-renderer/blob/master/config.schema.json
@@ -56,16 +61,26 @@ const engine_twig_php = {
},
relativeFrom,
alterTwigEnv,
+ ...rest,
});
+
+ // Preserve the namespaces (after recursively adding nested folders) from the config so we can use them later to evaluate partials.
+ this.namespaces = twigRenderer.config.src.namespaces;
},
renderPattern(pattern, data) {
return new Promise((resolve, reject) => {
- const patternPath = path.isAbsolute(pattern.relPath)
- ? path.relative(patternLabConfig.paths.source.root, pattern.relPath)
+ // If this is a pseudo pattern the relPath will be incorrect.
+ // i.e. /path/to/pattern.json
+ // Twig can't render that file so we need to use the base patterns
+ // relPath instead.
+ const relPath = pattern.isPseudoPattern
+ ? pattern.basePattern.relPath
: pattern.relPath;
- // console.log(patternPath);
+ const patternPath = path.isAbsolute(relPath)
+ ? path.relative(patternLabConfig.paths.source.root, relPath)
+ : relPath;
let details = '';
if (patternLabConfig.logLevel === 'debug') {
details = `${JSON.stringify(
@@ -77,14 +92,23 @@ const engine_twig_php = {
twigRenderer
.render(patternPath, data)
- .then(results => {
+ .then((results) => {
if (results.ok) {
resolve(results.html + details);
} else {
- reject(results.message);
+ // make Twig rendering errors more noticeable + exit when not in dev mode (or running the `patternlab serve` command)
+ if (
+ process.argv.slice(1).includes('serve') ||
+ process.env.NODE_ENV === 'development'
+ ) {
+ reject(chalk.red(results.message));
+ } else {
+ console.log(chalk.red(results.message));
+ process.exit(1);
+ }
}
})
- .catch(error => {
+ .catch((error) => {
reject(error);
});
});
@@ -99,7 +123,7 @@ const engine_twig_php = {
*/
spawnMeta(config) {
const { paths } = config;
- ['_00-head.twig', '_01-foot.twig'].forEach(fileName => {
+ ['_head.twig', '_foot.twig'].forEach((fileName) => {
const metaFilePath = path.resolve(paths.source.meta, fileName);
try {
fs.statSync(metaFilePath);
@@ -118,12 +142,29 @@ const engine_twig_php = {
// @todo Add all functions that get called even if disabled to ease implementing engine further
// Currently all of them return `null` as I'm not totally sure there absence will be ok. Additionally, future improvements may be implemented in this functions.
- findPartials(pattern) {
- return null;
- },
-
- findPartialsWithStyleModifiers(pattern) {
- return null;
+ // Find and return any {% extends|include|embed 'template-name' %} within pattern.
+ // The regex should match the following examples:
+ // {%
+ // include '@molecules/teaser-card/teaser-card.twig' with {
+ // teaser_card: card
+ // } only
+ // %}
+ // OR
+ // {% include '@molecules/teaser-card/teaser-card.twig' %}
+ // OR
+ // {%
+ // include '@molecules/teaser-card/teaser-card.twig'
+ // %}
+ findPartials: function (pattern) {
+ const matches = pattern.template.match(this.findPartialsRE);
+ const filteredMatches =
+ matches &&
+ matches.filter((match) => {
+ // Filter out programmatically created includes.
+ // i.e. {% include '@namespace/icons/assets/' ~ name ~ '.svg' %}
+ return match.indexOf('~') === -1;
+ });
+ return filteredMatches;
},
findPartialsWithPatternParameters(pattern) {
@@ -138,8 +179,81 @@ const engine_twig_php = {
return null;
},
- findPartial(partialString) {
- return null;
+ // Given a pattern, and a partial string, tease out the "pattern key" and
+ // return it.
+ findPartial: function (partialString) {
+ try {
+ const partial = partialString.replace(this.findPartialsRE, '$1');
+
+ // Check if namespaces is not empty.
+ const selectedNamespace = this.namespaces.filter((namespace) => {
+ // Check to see if this partial contains within the namespace id.
+ return partial.indexOf(`@${namespace.id}`) !== -1;
+ });
+
+ let namespaceResolvedPartial = '';
+
+ if (selectedNamespace.length > 0) {
+ // Loop through all namespaces and try to resolve the namespace to a file path.
+ for (
+ let index = 0;
+ index < selectedNamespace[0].paths.length;
+ index++
+ ) {
+ const patternPath = path.isAbsolute(selectedNamespace[0].paths[index])
+ ? path.relative(
+ patternLabConfig.paths.source.root,
+ selectedNamespace[0].paths[index]
+ )
+ : selectedNamespace[0].paths[index];
+
+ // Replace the name space with the actual path.
+ // i.e. @atoms -> source/_patterns/atoms
+ const tempPartial = path.join(
+ process.cwd(),
+ partial.replace(`@${selectedNamespace[0].id}`, patternPath)
+ );
+
+ try {
+ // Check to see if the file actually exists.
+ if (fs.existsSync(tempPartial)) {
+ // get the path to the top-level folder of this pattern
+ // ex. /Users/bradfrost/sites/pattern-lab/packages/edition-twig/source/_patterns/atoms
+ const fullFolderPath = `${
+ tempPartial.split(selectedNamespace[0].paths[index])[0]
+ }${selectedNamespace[0].paths[index]}`;
+
+ // then tease out the folder name itself (including the # prefix)
+ // ex. atoms
+ const folderName = path.parse(fullFolderPath).base;
+
+ // finally, return the Twig path we created from the full file path
+ // ex. atoms/buttons/button.twig
+ const fullIncludePath = tempPartial.replace(
+ tempPartial.split(
+ `${folderName}${tempPartial.split(folderName)[1]}`
+ )[0],
+ ''
+ );
+
+ namespaceResolvedPartial = fullIncludePath;
+
+ // After it matches one time, set the resolved partial and exit the loop.
+ break;
+ }
+ } catch (err) {
+ console.error(err);
+ }
+ }
+ }
+ // Return the path with the namespace resolved OR the regex'd partial.
+ return namespaceResolvedPartial || partial;
+ } catch (err) {
+ console.error(
+ 'Error occured when trying to find partial name in: ' + partialString
+ );
+ return null;
+ }
},
patternMatcher(pattern, regex) {
diff --git a/packages/engine-twig-php/package.json b/packages/engine-twig-php/package.json
index 1247028e1..28e806163 100644
--- a/packages/engine-twig-php/package.json
+++ b/packages/engine-twig-php/package.json
@@ -1,12 +1,13 @@
{
"name": "@pattern-lab/engine-twig-php",
"description": "The Twig PHP engine for Pattern Lab Node",
- "version": "3.0.0",
+ "version": "6.1.0",
"main": "lib/engine_twig_php.js",
"dependencies": {
- "@basalt/twig-renderer": "0.12.0",
- "@pattern-lab/core": "^3.0.1-alpha.0",
- "fs-extra": "0.30.0"
+ "@basalt/twig-renderer": "^3.0.1",
+ "@pattern-lab/core": "^6.1.0",
+ "chalk": "^4.1.0",
+ "fs-extra": "10.0.0"
},
"keywords": [
"Pattern Lab",
@@ -17,7 +18,7 @@
"bugs": "https://github.com/pattern-lab/patternlab-node/issues",
"author": {
"name": "Evan Lovely",
- "url": "http://evanlovely.com"
+ "url": "https://www.evanlovely.com"
},
"maintainers": [
{
@@ -27,9 +28,10 @@
"license": "MIT",
"scripts": {},
"engines": {
- "node": ">=8.9"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/engine-twig/.nvmrc b/packages/engine-twig/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/engine-twig/.nvmrc
+++ b/packages/engine-twig/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/engine-twig/CHANGELOG.md b/packages/engine-twig/CHANGELOG.md
index eedf33dc3..3f96a1670 100644
--- a/packages/engine-twig/CHANGELOG.md
+++ b/packages/engine-twig/CHANGELOG.md
@@ -3,6 +3,156 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+
+### Bug Fixes
+
+* **engine-twig:** twig include function syntax not matched by findPartials ([#1473](https://github.com/pattern-lab/patternlab-node/issues/1473)) ([cfa792b](https://github.com/pattern-lab/patternlab-node/commit/cfa792b2753d9f9f1840e08d55983c6c051b01fd)), closes [#1471](https://github.com/pattern-lab/patternlab-node/issues/1471)
+
+
+
+
+
+# [5.17.0](https://github.com/pattern-lab/patternlab-node/compare/v5.16.4...v5.17.0) (2022-09-25)
+
+
+### Features
+
+* **engine-twig:** add custom twing extensions ([#1435](https://github.com/pattern-lab/patternlab-node/issues/1435)) ([c32a45c](https://github.com/pattern-lab/patternlab-node/commit/c32a45c02e3b71bb841e7ea15cae000a68857df3)), closes [#1230](https://github.com/pattern-lab/patternlab-node/issues/1230) [#1230](https://github.com/pattern-lab/patternlab-node/issues/1230)
+
+
+
+
+
+## [5.16.4](https://github.com/pattern-lab/patternlab-node/compare/v5.16.2...v5.16.4) (2022-09-23)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+## [5.15.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.15.2...v5.15.3) (2021-11-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+
+### Bug Fixes
+
+* **pseudopatterns:** use the template instead of the pseudo data file for template rendering [#1308](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/issues/1308) ([#1312](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/issues/1312)) ([7ecca69](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/commit/7ecca69bcfed4060d17390b76562e5f468b4a897))
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+## [5.10.2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.10.1...v5.10.2) (2020-05-24)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+## [5.9.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.9.2...v5.9.3) (2020-05-01)
+
+
+### Bug Fixes
+
+* Update dependency on twing JS engine ([cfe88c6](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/commit/cfe88c6cdbf2219b9955eaa0ffcfc0e4a7683511))
+
+
+
+
+
+# [5.8.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v5.7.2...v5.8.0) (2020-04-03)
+
+
+### Bug Fixes
+
+* Updated the README to reflect which issues are resolved. ([d90c3c4](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/commit/d90c3c4605f9a5bcd1153996e3f4d1a17d58bd92))
+
+
+### Features
+
+* switch engine-twig to use twing rather than node-twig ([daca95c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/commit/daca95c4ffa48916fb6c67c5184bde9b624acd76))
+
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+**Note:** Version bump only for package @pattern-lab/engine-twig
+
+
+
+
+
+
## [0.2.1-beta.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-twig/compare/@pattern-lab/engine-twig@0.2.1-beta.0...@pattern-lab/engine-twig@0.2.1-beta.1) (2019-02-09)
**Note:** Version bump only for package @pattern-lab/engine-twig
diff --git a/packages/engine-twig/LICENSE b/packages/engine-twig/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/engine-twig/LICENSE
+++ b/packages/engine-twig/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-twig/README.md b/packages/engine-twig/README.md
index 194f92e49..91d78cc3c 100644
--- a/packages/engine-twig/README.md
+++ b/packages/engine-twig/README.md
@@ -1,14 +1,57 @@
## The Twig PatternEngine for Pattern Lab / Node
-To install the Twig engine in your edition, `npm install @pattern-lab/engine-twig` should do the trick.
+To install the Twig engine in your edition, `npm install @pattern-lab/engine-twig` should do the trick. This pattern engine uses the [`twing`](https://www.npmjs.com/package/twing) library.
## Supported features
-Level of support is more or less full. Partial calls and lineage hunting are supported. Twig does not support the mustache-specific syntax extensions, style modifiers and pattern parameters, because their use cases are addressed by the core Twig feature set.
+Level of support for Twig constructs is on the level that the `twing` library supports. The following partial resolution schemes (`includes`, `extends`, `import`) are supported:
-We are looking for help with the following issues:
+* relative file paths: standard by `twing` libary
+* namespaces: standard by `twing` library, `engine-twig` only passes the configuration from `patternlab-config.json`
+* Patternlab pattern names: integration between Patternlab and `twing` implemented by a custom [`loader`](https://nightlycommit.github.io/twing/api.html#create-your-own-loader)
+
+Now that this engine uses a better Twig Javascript library, the following issues are resolved:
* [Pattern Lab does not support twig extends](https://github.com/pattern-lab/patternlab-node/issues/554)
* [Verify maturity of Twig engine](https://github.com/pattern-lab/patternlab-node/issues/285)
See https://github.com/pattern-lab/the-spec/issues/37 for more info.
+
+## Adding Custom Extensions
+
+Create a JS file in Pattern Lab root directory (e.g. `twingExtensions.js`) and set
+```javascript
+"engine": {
+ "twig": {
+ "loadExtensionFile": "twingExtensions.js"
+ }
+}
+```
+in `patternlab-config.json`. See [Editing the Configuration Options](https://patternlab.io/docs/editing-the-configuration-options/#heading-loadextensionfile) for more info.
+
+- this JS file must export a Map for `TwingEnvironment.addExtensions(extensions: Map)`
+- Map will be added to the TwingEnvironment on startup
+
+### Example
+
+```javascript
+// twingExtensions.js
+const { TwingExtension, TwingFunction } = require('twing');
+
+const extensionsMap = new Map();
+
+class TestTwingExtension extends TwingExtension {
+ getFunctions() {
+ return [
+ new TwingFunction('foobar', function (foo) {
+ return Promise.resolve(`function foobar called with param "${foo}"`);
+ }),
+ ];
+ }
+}
+extensionsMap.set('TestTwingExtension', new TestTwingExtension());
+
+module.exports = extensionsMap;
+```
+
+See https://nightlycommit.github.io/twing/advanced.html#creating-an-extension for more details on how to create extensions
diff --git a/packages/engine-twig/_meta/_01-foot.twig b/packages/engine-twig/_meta/_foot.twig
similarity index 100%
rename from packages/engine-twig/_meta/_01-foot.twig
rename to packages/engine-twig/_meta/_foot.twig
diff --git a/packages/engine-twig/_meta/_00-head.twig b/packages/engine-twig/_meta/_head.twig
similarity index 87%
rename from packages/engine-twig/_meta/_00-head.twig
rename to packages/engine-twig/_meta/_head.twig
index 4b49c63b7..5087213d9 100644
--- a/packages/engine-twig/_meta/_00-head.twig
+++ b/packages/engine-twig/_meta/_head.twig
@@ -1,8 +1,8 @@
-
+
{{ title }}
-
+
diff --git a/packages/engine-twig/lib/engine_twig.js b/packages/engine-twig/lib/engine_twig.js
index 898a21450..efaa5416a 100644
--- a/packages/engine-twig/lib/engine_twig.js
+++ b/packages/engine-twig/lib/engine_twig.js
@@ -22,80 +22,239 @@
const fs = require('fs-extra');
const path = require('path');
-const process = require('process');
-const Twig = require('node-twig');
-const twig = Twig.renderFile;
+const {
+ TwingEnvironment,
+ TwingLoaderFilesystem,
+ TwingLoaderChain,
+ TwingSource,
+} = require('twing');
-var engine_twig = {
- engine: Twig,
+class TwingLoaderPatternLab {
+ patterns = new Map();
+
+ constuctor() {}
+
+ registerPartial(pattern) {
+ if (pattern.patternPartial) {
+ this.patterns.set(pattern.patternPartial, pattern);
+ }
+ }
+
+ /**
+ * Returns the source context for a given template logical name.
+ *
+ * @param {string} name The template logical name
+ * @param {TwingSource} from The source that initiated the template loading
+ *
+ * @returns {Promise}
+ *
+ * @throws TwingErrorLoader When name is not found
+ */
+ getSourceContext(name, from) {
+ const pattern = this.patterns.get(name);
+ return Promise.resolve(
+ new TwingSource(pattern.extendedTemplate, name, pattern.relPath)
+ );
+ }
+
+ /**
+ * Gets the cache key to use for the cache for a given template name.
+ *
+ * @param {string} name The name of the template to load
+ * @param {TwingSource} from The source that initiated the template loading
+ *
+ * @returns {Promise} The cache key
+ *
+ * @throws TwingErrorLoader When name is not found
+ */
+ getCacheKey(name, from) {
+ return Promise.resolve(name);
+ }
+
+ /**
+ * Returns true if the template is still fresh.
+ *l
+ * @param {string} name The template name
+ * @param {number} time Timestamp of the last modification time of the cached template
+ * @param {TwingSource} from The source that initiated the template loading
+ *
+ * @returns {Promise} true if the template is fresh, false otherwise
+ *
+ * @throws TwingErrorLoader When name is not found
+ */
+ isFresh(name, time, from) {
+ return Promise.resolve(this.patterns.has(name) ? true : false);
+ }
+
+ /**
+ * Check if we have the source code of a template, given its name.
+ *
+ * @param {string} name The name of the template to check if we can load
+ * @param {TwingSource} from The source that initiated the template loading
+ *
+ * @returns {Promise} If the template source code is handled by this loader or not
+ */
+ exists(name, from) {
+ return Promise.resolve(this.patterns.has(name) ? true : false);
+ }
+
+ /**
+ * Resolve the path of a template, given its name, whatever it means in the context of the loader.
+ *
+ * @param {string} name The name of the template to resolve
+ * @param {TwingSource} from The source that initiated the template loading
+ *
+ * @returns {Promise} The resolved path of the template
+ */
+ resolve(name, from) {
+ pattern = this.patterns.get(name);
+ return null;
+ }
+}
+
+const fileSystemLoader = new TwingLoaderFilesystem();
+const patternLabLoader = new TwingLoaderPatternLab();
+const chainLoader = new TwingLoaderChain([fileSystemLoader, patternLabLoader]);
+const twing = new TwingEnvironment(chainLoader);
+let metaPath;
+let patternLabConfig = {};
+
+const engine_twig = {
+ engine: twing,
engineName: 'twig',
engineFileExtension: '.twig',
- //Important! Needed for Twig compilation. Can't resolve paths otherwise.
- expandPartials: true,
-
// regexes, stored here so they're only compiled once
- findPartialsRE: /{%\s*(?:extends|include|embed)\s+('[^']+'|"[^"]+").*?%}/g,
- findPartialKeyRE: /"((?:\\.|[^"\\])*)"/,
- findListItemsRE: /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, // TODO
+ findPartialsRE:
+ /{[%{]\s*.*?(?:extends|include|embed|from|import|use)\(?\s*['"](.+?)['"][\s\S]*?\)?\s*[%}]}/g,
+ findListItemsRE:
+ /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, // TODO
// render it
- renderPattern: function renderPattern(pattern, data) {
- return Promise.resolve(
- twig(
- pattern.relPath,
- {
- root: path.relative(
- __dirname,
- path.resolve(process.cwd(), 'source', '_patterns')
- ),
- context: data,
- },
- (error, template) => {
- if (error) {
- console.log(error);
- }
- console.log(template);
- return template;
- }
- )
+ renderPattern: function renderPattern(pattern, data, partials) {
+ let patternPath = pattern.basePattern
+ ? pattern.basePattern.relPath
+ : pattern.relPath;
+ if (patternPath.lastIndexOf(metaPath) === 0) {
+ patternPath = patternPath.substring(metaPath.length + 1);
+ }
+ return Promise.resolve(twing.render(patternPath, data));
+ },
+
+ registerPartial: function registerPartial(pattern) {
+ console.log(
+ `registerPartial(${pattern.name} - ${pattern.patternPartial} - ${pattern.patternPath} - ${pattern.relPath})`
);
+ patternLabLoader.registerPartial(pattern);
},
// find and return any {% include 'template-name' %} within pattern
findPartials: function findPartials(pattern) {
- var matches = pattern.template.match(this.findPartialsRE);
- return matches;
- },
- findPartialsWithStyleModifiers: function() {
- // TODO: make the call to this from oPattern objects conditional on their
- // being implemented here.
- return [];
+ const matches = pattern.template.match(this.findPartialsRE);
+ const filteredMatches =
+ matches &&
+ matches.filter((match) => {
+ // Filter out programmatically created includes.
+ // i.e. {% include '@namespace/icons/assets/' ~ name ~ '.svg' %}
+ return match.indexOf('~') === -1;
+ });
+ return filteredMatches;
},
// returns any patterns that match {{> value(foo:"bar") }} or {{>
// value:mod(foo:"bar") }} within the pattern
- findPartialsWithPatternParameters: function() {
+ findPartialsWithPatternParameters: function () {
// TODO: make the call to this from oPattern objects conditional on their
// being implemented here.
return [];
},
- findListItems: function(pattern) {
- var matches = pattern.template.match(this.findListItemsRE);
+
+ findListItems: function (pattern) {
+ const matches = pattern.template.match(this.findListItemsRE);
return matches;
},
// given a pattern, and a partial string, tease out the "pattern key" and
// return it.
- findPartial: function(partialString) {
- //var partialKey = partialString.replace(this.findPartialsRE, '$1');
- var partial = partialString.match(this.findPartialKeyRE)[0];
- partial = partial.replace(/"/g, '');
+ findPartial: function (partialString) {
+ try {
+ const partial = partialString.replace(this.findPartialsRE, '$1');
+
+ // Check if namespaces is not empty.
+ const [selectedNamespace] = fileSystemLoader
+ .getNamespaces()
+ .filter((namespace) => {
+ // Check to see if this partial contains within the namespace id.
+ return partial.indexOf(`@${namespace}`) !== -1;
+ });
+
+ let namespaceResolvedPartial = '';
+
+ if (selectedNamespace.length > 0) {
+ // Loop through all namespaces and try to resolve the namespace to a file path.
+ const namespacePaths = fileSystemLoader.getPaths(selectedNamespace);
+
+ for (let index = 0; index < namespacePaths.length; index++) {
+ const patternPath = path.isAbsolute(namespacePaths[index])
+ ? path.relative(
+ patternLabConfig.paths.source.root,
+ namespacePaths[index]
+ )
+ : namespacePaths[index];
+
+ // Replace the name space with the actual path.
+ // i.e. @atoms -> source/_patterns/atoms
+ const tempPartial = path.join(
+ process.cwd(),
+ partial.replace(`@${selectedNamespace}`, patternPath)
+ );
+
+ try {
+ // Check to see if the file actually exists.
+ if (fs.existsSync(tempPartial)) {
+ // get the path to the top-level folder of this pattern
+ // ex. /Users/bradfrost/sites/pattern-lab/packages/edition-twig/source/_patterns/atoms
+ const fullFolderPath = `${
+ tempPartial.split(namespacePaths[index])[0]
+ }${namespacePaths[index]}`;
- return partial;
+ // then tease out the folder name itself (including the # prefix)
+ // ex. atoms
+ const folderName = fullFolderPath.substring(
+ fullFolderPath.lastIndexOf('/') + 1,
+ fullFolderPath.length
+ );
+
+ // finally, return the Twig path we created from the full file path
+ // ex. atoms/buttons/button.twig
+ const fullIncludePath = tempPartial.replace(
+ tempPartial.split(
+ `${folderName}${tempPartial.split(folderName)[1]}`
+ )[0],
+ ''
+ );
+
+ namespaceResolvedPartial = fullIncludePath;
+
+ // After it matches one time, set the resolved partial and exit the loop.
+ break;
+ }
+ } catch (err) {
+ console.error(err);
+ }
+ }
+ }
+ // Return the path with the namespace resolved OR the regex'd partial.
+ return namespaceResolvedPartial || partial;
+ } catch (err) {
+ console.error(
+ 'Error occurred when trying to find partial name in: ' + partialString
+ );
+ return null;
+ }
},
- spawnFile: function(config, fileName) {
+ spawnFile: function (config, fileName) {
const paths = config.paths;
const metaFilePath = path.resolve(paths.source.meta, fileName);
try {
@@ -117,9 +276,54 @@ var engine_twig = {
* @param {object} config - the global config object from core, since we won't
* assume it's already present
*/
- spawnMeta: function(config) {
- this.spawnFile(config, '_00-head.twig');
- this.spawnFile(config, '_01-foot.twig');
+ spawnMeta: function (config) {
+ this.spawnFile(config, '_head.twig');
+ this.spawnFile(config, '_foot.twig');
+ },
+
+ /**
+ * Accept a Pattern Lab config object from the core and use the settings to
+ * load helpers.
+ *
+ * @param {object} config - the global config object from core
+ */
+ usePatternLabConfig: function (config) {
+ patternLabConfig = config;
+ metaPath = path.resolve(config.paths.source.meta);
+ // Global paths
+ fileSystemLoader.addPath(config.paths.source.meta);
+ fileSystemLoader.addPath(config.paths.source.patterns);
+ // Namespaced paths
+ if (
+ config.engines &&
+ config.engines.twig &&
+ config.engines.twig.namespaces
+ ) {
+ const namespaces = config.engines.twig.namespaces;
+ Object.keys(namespaces).forEach(function (key, index) {
+ fileSystemLoader.addPath(namespaces[key], key);
+ });
+ }
+
+ // add twing extensions
+ if (
+ config.engines &&
+ config.engines.twig &&
+ config.engines.twig.loadExtensionsFile
+ ) {
+ const extensionsFile = path.resolve(
+ './',
+ config.engines.twig.loadExtensionsFile
+ );
+ if (fs.pathExistsSync(extensionsFile)) {
+ try {
+ const extensionsMap = require(extensionsFile);
+ twing.addExtensions(extensionsMap);
+ } catch (e) {
+ console.error(e);
+ }
+ }
+ }
},
};
diff --git a/packages/engine-twig/package.json b/packages/engine-twig/package.json
index 9ce29cf27..00ba42c3a 100644
--- a/packages/engine-twig/package.json
+++ b/packages/engine-twig/package.json
@@ -1,11 +1,11 @@
{
"name": "@pattern-lab/engine-twig",
"description": "The Twig engine for Pattern Lab / Node",
- "version": "0.2.1-beta.1",
+ "version": "6.1.0",
"main": "lib/engine_twig.js",
"dependencies": {
- "fs-extra": "0.30.0",
- "node-twig": "1.1.0"
+ "fs-extra": "10.0.0",
+ "twing": "^5.0.2"
},
"keywords": [
"Pattern Lab",
@@ -22,9 +22,10 @@
"license": "MIT",
"scripts": {},
"engines": {
- "node": ">=10.0"
+ "node": ">=16.20.0"
},
"publishConfig": {
"access": "public"
- }
+ },
+ "gitHead": "80f62be442223e09bafb30d0529cbd768e03f2ac"
}
diff --git a/packages/engine-underscore/.nvmrc b/packages/engine-underscore/.nvmrc
index 95c4e8d27..59ea99ee6 100644
--- a/packages/engine-underscore/.nvmrc
+++ b/packages/engine-underscore/.nvmrc
@@ -1 +1 @@
-10.0.0
\ No newline at end of file
+16.20
diff --git a/packages/engine-underscore/CHANGELOG.md b/packages/engine-underscore/CHANGELOG.md
index 76d22e011..d42c4f81d 100644
--- a/packages/engine-underscore/CHANGELOG.md
+++ b/packages/engine-underscore/CHANGELOG.md
@@ -3,6 +3,98 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+# [6.1.0](https://github.com/pattern-lab/patternlab-node/compare/v6.0.3...v6.1.0) (2023-12-21)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+# [6.0.0](https://github.com/pattern-lab/patternlab-node/compare/v5.17.0...v6.0.0) (2023-01-31)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+## [5.16.1](https://github.com/pattern-lab/patternlab-node/compare/v5.16.0...v5.16.1) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+# [5.16.0](https://github.com/pattern-lab/patternlab-node/compare/v5.15.7...v5.16.0) (2022-01-29)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+## [5.15.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/compare/v5.15.0...v5.15.1) (2021-10-16)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+
+## [5.14.3](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/compare/v5.14.2...v5.14.3) (2021-05-17)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+
+# [5.14.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/compare/v5.13.3...v5.14.0) (2021-01-12)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+
+## [5.10.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/compare/v5.10.0...v5.10.1) (2020-05-09)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+# [5.10.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/compare/v5.9.3...v5.10.0) (2020-05-09)
+
+
+### Bug Fixes
+
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/issues/1192) ([374c103](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/commit/374c103a59504ba239b16680f86a89b4d95e304f))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/issues/1192) ([48de8c2](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/commit/48de8c2e134a61c0b4440375254bc9590a3e2563))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/issues/1192) ([363f22c](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/commit/363f22c643239ef4ca48d6f5942111604fda5ead))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/issues/1192) ([487cc78](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/commit/487cc783388043ec16ab1e54a3bfd8490038d058))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/issues/1192) ([571017f](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/commit/571017ffafa2cf6e8fa01b7ea7effc88922b05d1))
+* **docs:** resolving broken links in new docs site [#1192](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/issues/1192) ([b4eb12e](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/commit/b4eb12e68ceb402964a7e303610e5b0c008876ba))
+
+
+
+
+
+# [5.0.0](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/compare/v3.0.0-beta.3...v5.0.0) (2019-10-25)
+
+**Note:** Version bump only for package @pattern-lab/engine-underscore
+
+
+
+
+
+
# [2.0.0-beta.1](https://github.com/pattern-lab/patternlab-node/tree/master/packages/engine-underscore/compare/@pattern-lab/engine-underscore@2.0.0-beta.0...@pattern-lab/engine-underscore@2.0.0-beta.1) (2019-02-09)
**Note:** Version bump only for package @pattern-lab/engine-underscore
diff --git a/packages/engine-underscore/LICENSE b/packages/engine-underscore/LICENSE
index c9b8c1daa..3bb526cd2 100644
--- a/packages/engine-underscore/LICENSE
+++ b/packages/engine-underscore/LICENSE
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2018 Brian Muenzenmeyer, http://brianmuenzenmeyer.com & Brad Frost, http://bradfrostweb.com
+Copyright (c) 2018 Brian Muenzenmeyer, https://brianmuenzenmeyer.com & Brad Frost, https://bradfrost.com
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
diff --git a/packages/engine-underscore/README.md b/packages/engine-underscore/README.md
index 59796d51f..c9580ecac 100644
--- a/packages/engine-underscore/README.md
+++ b/packages/engine-underscore/README.md
@@ -6,13 +6,13 @@ To install the Underscore PatternEngine in your edition, `npm install @pattern-l
## Supported features
-* [x] [Includes](http://patternlab.io/docs/pattern-including.html) (Accomplished using the included [`_.renderNamedPartial()`](https://github.com/pattern-lab/patternlab-node/blob/master/packages/engine-underscore/lib/engine_underscore.js#L54-L60))
+* [x] [Includes](https://patternlab.io/docs/including-patterns/) (Accomplished using the included [`_.renderNamedPartial()`](https://github.com/pattern-lab/patternlab-node/blob/master/packages/engine-underscore/lib/engine_underscore.js#L54-L60))
* [x] Lineage
-* [x] [Hidden Patterns](http://patternlab.io/docs/pattern-hiding.html)
-* [x] [Pseudo-Patterns](http://patternlab.io/docs/pattern-pseudo-patterns.html)
-* [x] [Pattern States](http://patternlab.io/docs/pattern-states.html)
-* [ ] [Pattern Parameters](http://patternlab.io/docs/pattern-parameters.html) (Accomplished instead using parameter object passed to the included [`_.renderNamedPartial()`](https://github.com/pattern-lab/patternlab-node/blob/master/packages/engine-underscore/lib/engine_underscore.js#L54-L60) mixin function)
-* [ ] [Style Modifiers](http://patternlab.io/docs/pattern-stylemodifier.html) (Accomplished instead using parameter object passed to the included [`_.renderNamedPartial()`](https://github.com/pattern-lab/patternlab-node/blob/master/packages/engine-underscore/lib/engine_underscore.js#L54-L60) mixin function)
+* [x] [Hidden Patterns](https://patternlab.io/docs/hiding-patterns-in-the-navigation/)
+* [x] [Pseudo-Patterns](https://patternlab.io/docs/using-pseudo-patterns/)
+* [x] [Pattern States](https://patternlab.io/docs/using-pattern-states/)
+* [ ] ~~[Pattern Parameters](https://patternlab.io/docs/using-pattern-parameters/)~~ (Accomplished instead using parameter object passed to the included [`_.renderNamedPartial()`](https://github.com/pattern-lab/patternlab-node/blob/master/packages/engine-underscore/lib/engine_underscore.js#L54-L60) mixin function)
+* [ ] ~~[Style Modifiers](https://github.com/pattern-lab/patternlab-node/issues/1177)~~ (Accomplished instead using parameter object passed to the included [`_.renderNamedPartial()`](https://github.com/pattern-lab/patternlab-node/blob/master/packages/engine-underscore/lib/engine_underscore.js#L54-L60) mixin function)
## Extensions to basic Underscore functionality
@@ -61,4 +61,4 @@ If you feed that template JSON that (for whatever reason) has `foo.bar` as `null
and know that the output will be more safely "To be, or, not to be, null" instead of just throwing an error and crashing the pattern. This is mainly useful for operationalized pattern templates that will be provided with JSON from services that you can't control in Pattern Lab.
-Note that `obj` is an Underscore pattern's current data context. See [Dr. Axel Rauschmeyer's article](http://www.2ality.com/2012/06/underscore-templates.html) for more.
+Note that `obj` is an Underscore pattern's current data context. See [Dr. Axel Rauschmeyer's article](https://2ality.com/2012/06/underscore-templates.html) for more.
diff --git a/packages/engine-underscore/_meta/_00-head.html b/packages/engine-underscore/_meta/_00-head.html
deleted file mode 100644
index b1f5c1ce0..000000000
--- a/packages/engine-underscore/_meta/_00-head.html
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- {{ title }}
-
-
-
-
-
-
-
- {{{ patternLabHead }}}
-
-
-
-
diff --git a/packages/development-edition-engine-react/source/_meta/_01-foot.hbs b/packages/engine-underscore/_meta/_foot.html
similarity index 91%
rename from packages/development-edition-engine-react/source/_meta/_01-foot.hbs
rename to packages/engine-underscore/_meta/_foot.html
index 2feb91336..797d9418d 100644
--- a/packages/development-edition-engine-react/source/_meta/_01-foot.hbs
+++ b/packages/engine-underscore/_meta/_foot.html
@@ -1,6 +1,6 @@
-
-
-{{{ patternLabFoot }}}
-
-
-
+
+
+{{{ patternLabFoot }}}
+
+
+
diff --git a/packages/engine-underscore/_meta/_head.html b/packages/engine-underscore/_meta/_head.html
new file mode 100644
index 000000000..9e3094352
--- /dev/null
+++ b/packages/engine-underscore/_meta/_head.html
@@ -0,0 +1,23 @@
+
+
+
+ {{ title }}
+
+
+
+
+
+
+
+ {{{ patternLabHead }}}
+
+
+
diff --git a/packages/engine-underscore/lib/engine_underscore.js b/packages/engine-underscore/lib/engine_underscore.js
index 79fd9ef81..86b34c307 100644
--- a/packages/engine-underscore/lib/engine_underscore.js
+++ b/packages/engine-underscore/lib/engine_underscore.js
@@ -21,10 +21,10 @@
const fs = require('fs-extra');
const path = require('path');
-var _ = require('underscore');
+const _ = require('underscore');
-var partialRegistry = {};
-var errorStyling = `
+const partialRegistry = {};
+const errorStyling = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Pattern Lab is compiling for the first time.
+
+
+ <% for (var i = 0 ; i < progress.length ; i++) { %>
+
+
+
+
+
+ <%= Math.round(100 * progress[i][0]) %>%
+
+
+
+ <%
+ const capitalize = (str) => {
+ if (typeof str !== 'string') return '';
+ return str.replace(/(?:^|\s)\S/g, function(a) { return a.toUpperCase(); });
+ }
+
+ const message = progress[i][1] || '';
+ const result = message.includes('building') || message.includes('compiling')
+ ? 'Compiling'
+ : message.includes('optimization')
+ ? 'Optimizing'
+ : message.includes('emitting') || message.includes('seal')
+ ? 'Wrapping up'
+ : progress[i][1];
+ %>
+
<%= capitalize(result) %>. . .
+
+
+ <% } %>
+
+
+
+
+
+
diff --git a/packages/uikit-workshop/build/webpack-server.js b/packages/uikit-workshop/build/webpack-server.js
new file mode 100644
index 000000000..0f8913f39
--- /dev/null
+++ b/packages/uikit-workshop/build/webpack-server.js
@@ -0,0 +1,146 @@
+const webpack = require('webpack');
+const express = require('express');
+const browserSync = require('browser-sync').create();
+const webpackDevMiddleware = require('webpack-dev-middleware');
+const opn = require('better-opn');
+const path = require('path');
+const hasha = require('hasha');
+const webpackDevServerWaitpage = require('./webpack-dev-server-waitpage');
+const webpackConfig = require('../webpack.config');
+const app = express();
+const portfinder = require('portfinder');
+
+const fileHashes = {};
+
+async function serve(patternlab, configPath, buildDir = 'public') {
+ // @todo: move these configs + make customizable?
+ const root = path.resolve(__dirname, `${buildDir}`);
+ const preferredPort = 3000;
+ portfinder.basePort = preferredPort;
+
+ const webpackConfigs = await webpackConfig({
+ watch: true,
+ prod: false,
+ buildDir: root,
+ rootDir: process.cwd(),
+ });
+
+ const port = await portfinder
+ .getPortPromise()
+ .then((portNo) => {
+ return portNo;
+ })
+ .catch((err) => {
+ console.log(err);
+ return 3000;
+ });
+
+ // customize bs reload behavior based on the type of asset that's changed
+ const filesToWatch = [
+ {
+ match: [`${process.cwd()}/patternlab-config.json`],
+ fn: async function () {
+ // when the main PL config changes, clear Node's cache (so the JSON config is re-read) and trigger another PL build
+ // this allows config changes to show up without restarting the build!
+ Object.keys(require.cache).forEach(function (key) {
+ delete require.cache[key];
+ });
+
+ const config = require(configPath);
+ const pl = require('@pattern-lab/core')(config);
+
+ pl.build({
+ watch: false,
+ cleanPublic: true,
+ });
+ },
+ },
+ `${root}/**/*.css`,
+ `${root}/**/*.js`,
+ {
+ match: [`${root}/**/*.svg`, `${root}/**/*.png`, `${root}/**/*.jpg`],
+ fn: async function () {
+ browserSync.reload();
+ },
+ },
+ // only reload the Webpack-generated HTML files when the contents have changed
+ {
+ match: [
+ path.join(process.cwd(), `${root}/*.html`),
+ path.join(process.cwd(), `${root}/styleguide/html/*.html`),
+ ],
+ fn: async function (event, filePath) {
+ let updatedHash = false;
+
+ const hash = await hasha.fromFile(
+ path.resolve(__dirname, `../${filePath}`),
+ { algorithm: 'md5' }
+ );
+
+ if (!fileHashes[filePath] || fileHashes[filePath] !== hash) {
+ fileHashes[filePath] = hash;
+ updatedHash = true;
+ }
+
+ if (updatedHash && !patternlab.isBusy()) {
+ browserSync.reload(filePath);
+ }
+ },
+ },
+ ];
+
+ browserSync.init(
+ {
+ proxy: `127.0.0.1:${port}`,
+ logLevel: 'info',
+ ui: false,
+ notify: false,
+ open: false,
+ tunnel: false,
+ port,
+ logFileChanges: false,
+ reloadOnRestart: true,
+ watchOptions: {
+ ignoreInitial: true,
+ },
+ files: filesToWatch,
+ },
+ function (err, bs) {
+ // assigned port from browsersync based on what's available
+ const assignedPort = bs.options.get('port');
+ opn(`http://localhost:${assignedPort}`);
+ const compiler = webpack(webpackConfigs);
+
+ app.use(
+ webpackDevServerWaitpage(compiler, {
+ proxyHeader: 'browsersync-proxy',
+ redirectPath: `http://localhost:${assignedPort}`,
+ })
+ );
+
+ app.use(
+ webpackDevMiddleware(compiler, {
+ stats: 'errors-warnings',
+ writeToDisk: true,
+ })
+ );
+
+ app.use(express.static(root));
+
+ app.listen(assignedPort, '127.0.0.1', function onStart(error) {
+ if (error) {
+ console.log(error);
+ }
+ });
+ }
+ );
+
+ // auto-reload the page when PL finishes compiling
+ patternlab.events.on('patternlab-build-end', () => {
+ browserSync.reload();
+ });
+}
+
+module.exports = {
+ serve,
+};
diff --git a/packages/uikit-workshop/dist/index.html b/packages/uikit-workshop/dist/index.html
deleted file mode 100644
index 908d91800..000000000
--- a/packages/uikit-workshop/dist/index.html
+++ /dev/null
@@ -1,411 +0,0 @@
-
-
-
-
- Pattern Lab
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/packages/uikit-workshop/dist/styleguide/css/pattern-lab.css b/packages/uikit-workshop/dist/styleguide/css/pattern-lab.css
deleted file mode 100644
index cf3e50682..000000000
--- a/packages/uikit-workshop/dist/styleguide/css/pattern-lab.css
+++ /dev/null
@@ -1 +0,0 @@
-.pl-c-body *{-webkit-box-sizing:border-box;box-sizing:border-box}button{font-size:inherit;background-color:transparent}.pl-c-html{min-height:100%}.pl-c-body{margin:0;padding:0;-webkit-text-size-adjust:100%;display:-webkit-box;display:-ms-flexbox;display:flex}code[class*=language-],pre[class*=language-]{color:#000;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono',monospace;direction:ltr;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;line-height:1.5;word-wrap:normal;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background-color:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background-color:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#a67f59;background-color:rgba(255,255,255,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}pre.line-numbers{position:relative;padding-left:3.8em;counter-reset:linenumber}pre.line-numbers>code{position:relative}.line-numbers .line-numbers-rows{position:absolute;pointer-events:none;top:0;font-size:100%;left:-3.8em;width:3em;letter-spacing:-1px;border-right:1px solid #999;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.line-numbers-rows>span{pointer-events:none;display:block;counter-increment:linenumber}.line-numbers-rows>span:before{content:counter(linenumber);color:#999;display:block;padding-right:.8em;text-align:right}.token a{color:inherit}pl-search{background-color:inherit;-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2;top:0;z-index:10;-ms-flex-negative:0;flex-shrink:0;padding:.3rem .5rem;display:inline-block}@media screen and (min-width:42em){pl-search{margin-left:1rem;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-negative:1;flex-shrink:1}.pl-c-body--theme-sidebar pl-search{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;margin-left:0;padding-left:0;padding-right:0;width:100%}}.pl-c-typeahead{width:100%;background-color:inherit;-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2;display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;z-index:10;text-transform:capitalize;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;color:#fafafa;position:relative}.pl-c-body--theme-light .pl-c-typeahead{color:#222}@media screen and (min-width:42em){.pl-c-typeahead{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.pl-c-body--theme-sidebar .pl-c-typeahead{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}}.pl-c-typeahead__hint{top:0;left:0;right:0;width:100%}.pl-c-typeahead__hint,.pl-c-typeahead__input{text-transform:capitalize;background-color:#222;color:#fff;border-color:#090909;text-overflow:ellipsis;border-width:1px;border-style:solid;-webkit-transition:all .1s ease;transition:all .1s ease;max-width:100%;padding:.31rem .5rem;font-size:16px;width:100%;outline-offset:-3px;outline-width:2px;-webkit-appearance:none}@media all and (min-width:900px){.pl-c-typeahead__hint,.pl-c-typeahead__input{font-size:inherit}}.pl-c-typeahead__hint::-ms-clear,.pl-c-typeahead__input::-ms-clear{display:none}.pl-c-body--theme-sidebar .pl-c-typeahead__hint,.pl-c-body--theme-sidebar .pl-c-typeahead__input{border-radius:0}.pl-c-typeahead__input-wrapper--with-clear-button .pl-c-typeahead__hint,.pl-c-typeahead__input-wrapper--with-clear-button .pl-c-typeahead__input{padding-right:1.7rem}@media all and (min-width:42em){.pl-c-typeahead__input-wrapper--with-clear-button .pl-c-typeahead__hint,.pl-c-typeahead__input-wrapper--with-clear-button .pl-c-typeahead__input{padding-right:1.4rem}}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-typeahead__hint,.pl-c-body--theme-sidebar .pl-c-typeahead__input{max-width:none}}.pl-c-body--theme-light .pl-c-typeahead__hint,.pl-c-body--theme-light .pl-c-typeahead__input{background-color:#eee;color:#4d4c4c!important;border-color:#ddd!important}.pl-c-typeahead__hint::-moz-input-placeholder,.pl-c-typeahead__hint::-webkit-input-placeholder,.pl-c-typeahead__input::-moz-input-placeholder,.pl-c-typeahead__input::-webkit-input-placeholder{color:#fff!important;-webkit-transition:all .1s ease;transition:all .1s ease}.pl-c-typeahead__hint:focus,.pl-c-typeahead__hint:hover,.pl-c-typeahead__input:focus,.pl-c-typeahead__input:hover{color:#fff;background-color:#1d1d1d!important}.pl-c-body--theme-light .pl-c-typeahead__hint:focus,.pl-c-body--theme-light .pl-c-typeahead__hint:hover,.pl-c-body--theme-light .pl-c-typeahead__input:focus,.pl-c-body--theme-light .pl-c-typeahead__input:hover{color:#222!important;background-color:#ddd!important;border-color:#ccc!important}.pl-c-typeahead__hint:focus::-moz-input-placeholder,.pl-c-typeahead__hint:focus::-webkit-input-placeholder,.pl-c-typeahead__hint:hover::-moz-input-placeholder,.pl-c-typeahead__hint:hover::-webkit-input-placeholder,.pl-c-typeahead__input:focus::-moz-input-placeholder,.pl-c-typeahead__input:focus::-webkit-input-placeholder,.pl-c-typeahead__input:hover::-moz-input-placeholder,.pl-c-typeahead__input:hover::-webkit-input-placeholder{color:#fff!important}.pl-c-body--theme-light .pl-c-typeahead__hint:focus::-moz-input-placeholder,.pl-c-body--theme-light .pl-c-typeahead__hint:focus::-webkit-input-placeholder,.pl-c-body--theme-light .pl-c-typeahead__hint:hover::-moz-input-placeholder,.pl-c-body--theme-light .pl-c-typeahead__hint:hover::-webkit-input-placeholder,.pl-c-body--theme-light .pl-c-typeahead__input:focus::-moz-input-placeholder,.pl-c-body--theme-light .pl-c-typeahead__input:focus::-webkit-input-placeholder,.pl-c-body--theme-light .pl-c-typeahead__input:hover::-moz-input-placeholder,.pl-c-body--theme-light .pl-c-typeahead__input:hover::-webkit-input-placeholder{color:#222!important}.pl-c-typeahead__menu{overflow:hidden;max-height:0;-webkit-transition:max-height .1s ease-out;transition:max-height .1s ease-out;background-color:#222;text-transform:capitalize;position:absolute;min-width:100%;width:100%;overflow:hidden;top:100%;right:0;max-height:0;display:block!important;-webkit-transition:max-height .3s ease,opacity .3s ease;transition:max-height .3s ease,opacity .3s ease;opacity:0}.pl-c-typeahead__menu.pl-is-active{max-height:calc(100vh - 2rem - 1rem);max-height:calc(var(--pl-viewport-height,calc(100vh - 2rem)) - 1rem);overflow:auto;-webkit-overflow-scrolling:touch}@media all and (min-width:42em){.pl-c-typeahead__menu{border-bottom-right-radius:6px;border-bottom-left-radius:6px}}.pl-c-body--theme-light .pl-c-typeahead__menu{background-color:#fafafa}.pl-c-typeahead__menu.pl-is-open{max-height:120rem;max-height:calc(var(--viewport-height) - 4rem);opacity:1}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-typeahead__menu{position:relative!important;border-radius:0}}@media all and (max-width:41em){.pl-c-typeahead__menu{position:relative!important}}.pl-c-typeahead__results{list-style:none;margin:0;padding:0;background-color:inherit;border-color:transparent;border-width:1px;border-style:solid;overflow:hidden;border-color:#151515}@media all and (min-width:42em){.pl-c-typeahead__results{border-bottom-right-radius:6px;border-bottom-left-radius:6px}}.pl-c-typeahead__results:empty{border-width:0;max-height:0}.pl-c-body--theme-light .pl-c-typeahead__results{border-color:#ccc}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-typeahead__results{border-radius:0}}.pl-c-typeahead__result{-webkit-transition:all .3s ease;transition:all .3s ease;background-color:inherit;padding:.8em;cursor:pointer;overflow:hidden}.pl-c-typeahead__result:last-child{border-bottom-right-radius:6px;border-bottom-left-radius:6px}.pl-c-body--theme-sidebar .pl-c-typeahead__result:last-child{border-radius:0}.pl-c-typeahead__result:hover{background-color:rgba(255,255,255,.15)}.pl-c-body--theme-light .pl-c-typeahead__result:hover{background-color:#eee}.pl-c-typeahead__result:active,.pl-c-typeahead__result:focus{background-color:rgba(255,255,255,.18)}.pl-c-body--theme-light .pl-c-typeahead__result:active,.pl-c-body--theme-light .pl-c-typeahead__result:focus{background-color:#ddd}.pl-c-typeahead__result.pl-has-cursor{color:#fff;background-color:rgba(255,255,255,.25)}.pl-c-body--theme-light .pl-c-typeahead__result.pl-has-cursor{color:#000;background-color:#ddd}.pl-c-typeahead__input-wrapper{position:relative}.pl-c-typeahead__clear-button{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;height:1.7rem;width:1.7rem;background-color:transparent;border-radius:20rem;overflow:hidden;position:absolute;right:0;top:50%;-webkit-transform:translateY(-50%);-ms-transform:translateY(-50%);transform:translateY(-50%);z-index:100;cursor:pointer;border:0;-webkit-transition:opacity .1s ease;transition:opacity .1s ease;opacity:0;visibility:hidden}.pl-c-typeahead__clear-button:hover{color:#fff;background-color:#222}.pl-c-typeahead__clear-button.pl-is-active,.pl-c-typeahead__clear-button:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-typeahead__clear-button{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-typeahead__clear-button:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-typeahead__clear-button:active,.pl-c-body--theme-light .pl-c-typeahead__clear-button:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-typeahead__clear-button{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-typeahead__clear-button{font-size:.85rem;padding:1.5rem 1rem}.pl-c-typeahead__clear-button:active,.pl-c-typeahead__clear-button:hover{background-color:transparent}@media all and (min-width:42em){.pl-c-typeahead__clear-button{height:1.4rem;width:1.4rem}}.pl-c-body--theme-light .pl-c-typeahead__clear-button{background-color:transparent}.pl-c-body--theme-light .pl-c-typeahead__clear-button:active,.pl-c-body--theme-light .pl-c-typeahead__clear-button:hover{background-color:transparent}.pl-c-typeahead__clear-button.pl-is-visible{opacity:1;visibility:visible}.pl-c-typeahead__clear-button-icon{fill:currentColor;line-height:0;font-size:0;position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}pl-layout{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;min-height:100vh;max-width:100vw;background-color:#ddd}@media all and (-ms-high-contrast:none),(-ms-high-contrast:active){pl-layout{overflow:hidden}}@media all and (min-width:42em){pl-layout.pl-c-body--theme-sidebar{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}}pl-layout.pl-c-body--theme-light{background-color:#fff}.pl-c-header{position:fixed;position:-webkit-sticky;position:sticky;top:0;left:0;z-index:4;display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;background-color:#000;color:grey;font-family:HelveticaNeue,Helvetica,Arial,sans-serif;font-size:.7rem;min-height:30px}@supports (padding:0px){.pl-c-header{padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}}.pl-c-header__nav-toggle{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;border:0}.pl-c-header__nav-toggle:hover{color:#fff;background-color:#222}.pl-c-header__nav-toggle.pl-is-active,.pl-c-header__nav-toggle:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-header__nav-toggle{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-header__nav-toggle:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-header__nav-toggle:active,.pl-c-body--theme-light .pl-c-header__nav-toggle:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-header__nav-toggle{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-header__nav-toggle{font-size:.85rem;padding:1.5rem 1rem}@media all and (min-width:42em){.pl-c-header__nav-toggle{display:none}}.pl-c-logo{max-width:2rem;margin:0 1rem;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.pl-c-logo:focus{outline:1px dotted grey;outline-offset:-1px}.pl-c-logo__img{display:block;max-width:100%;height:auto}.pl-c-nav{overflow:hidden;max-height:0;-webkit-transition:max-height .1s ease-out;transition:max-height .1s ease-out;background-color:inherit;position:absolute;left:0;top:100%;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;transition:max-height .1s ease-out}.pl-c-nav.pl-is-active{max-height:calc(100vh - 2rem - 1rem);max-height:calc(var(--pl-viewport-height,calc(100vh - 2rem)) - 1rem);overflow:auto;-webkit-overflow-scrolling:touch}@media all and (min-width:42em){.pl-c-nav{overflow:visible;max-height:none}}.pl-c-nav.pl-is-active{-webkit-box-shadow:0 1px 1px #000;box-shadow:0 1px 1px #000}.pl-c-body--theme-light .pl-c-nav.pl-is-active{-webkit-box-shadow:0 1px 1px #a6a6a6;box-shadow:0 1px 1px #a6a6a6}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-nav.pl-is-active{-webkit-box-shadow:none;box-shadow:none}}@media all and (min-width:42em){.pl-c-nav.pl-is-active{overflow:visible;max-height:none}}@media all and (min-width:42em){.pl-c-nav{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;position:relative;top:auto;width:auto;-webkit-box-shadow:none;box-shadow:none}}.pl-c-nav__list{z-index:1;margin:0;padding:0;list-style:none;-ms-flex-negative:0;flex-shrink:0;-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2;background-color:inherit}@media all and (min-width:42em){.pl-c-nav__list{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.pl-c-body--theme-sidebar .pl-c-nav__list{display:block}}.pl-c-nav__item{background-color:inherit;-webkit-transform:translateZ(0);transform:translateZ(0);cursor:pointer;position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.pl-c-body--theme-sidebar .pl-c-nav__item{display:block}@media all and (min-width:42em){.pl-c-nav__sublist>.pl-c-nav__item:last-child{overflow:hidden;border-bottom-left-radius:6px;border-bottom-right-radius:6px}}.pl-c-nav__link{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin:0}.pl-c-nav__link:hover{color:#fff;background-color:#222}.pl-c-nav__link.pl-is-active,.pl-c-nav__link:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-nav__link{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-nav__link:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-nav__link:active,.pl-c-body--theme-light .pl-c-nav__link:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-nav__link{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-nav__link{font-size:.85rem;padding:1.5rem 1rem}.pl-c-body--theme-sidebar .pl-c-nav__link{width:100%}.pl-c-nav__link--sublink{text-transform:none;padding-left:.5rem}.pl-c-nav__link--dropdown{-webkit-appearance:none;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.pl-c-nav__link--dropdown:after{content:'\25BC';color:rgba(255,255,255,.25);display:inline-block;font-size:7px;position:relative;top:1px;right:-2px;-webkit-transition:all .1s ease-out;transition:all .1s ease-out}.pl-c-nav__link--dropdown:focus:after,.pl-c-nav__link--dropdown:hover:after{color:grey}.pl-c-nav__link--dropdown.pl-is-active{color:#fff;background-color:#222}.pl-c-nav__link--dropdown.pl-is-active:after{color:grey;-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.pl-c-nav__sublist{background-color:inherit;list-style:none;margin:0;padding:0}@media all and (min-width:42em){.pl-c-nav__sublist{position:absolute;top:100%;left:0;min-width:10rem;border-bottom-left-radius:6px;border-bottom-right-radius:6px}}.pl-c-nav__sublist--dropdown,.pl-c-nav__subsublist--dropdown{list-style:none;margin:0;padding:0;overflow:hidden;max-height:0;-webkit-transition:max-height .1s ease-out;transition:max-height .1s ease-out;visibility:hidden}.pl-c-nav__sublist--dropdown.pl-is-active,.pl-c-nav__subsublist--dropdown.pl-is-active{max-height:calc(100vh - 2rem - 1rem);max-height:calc(var(--pl-viewport-height,calc(100vh - 2rem)) - 1rem);overflow:auto;-webkit-overflow-scrolling:touch}.pl-c-nav__sublist--dropdown.pl-is-active,.pl-c-nav__subsublist--dropdown.pl-is-active{margin-left:.5rem;visibility:visible;max-height:none}@media all and (min-width:42em){.pl-c-nav__sublist--dropdown.pl-is-active,.pl-c-nav__subsublist--dropdown.pl-is-active{height:auto;max-height:calc(100vh - 2rem - 1rem)}}.pl-c-body--theme-sidebar .pl-c-nav__sublist--dropdown.pl-is-active,.pl-c-body--theme-sidebar .pl-c-nav__subsublist--dropdown.pl-is-active{max-height:none}@media all and (min-width:42em){.pl-c-nav__sublist--dropdown.pl-is-active{margin-left:0;border-width:1px;border-style:solid;border-color:#000}.pl-c-body--theme-light .pl-c-nav__sublist--dropdown.pl-is-active{border-color:#ccc}}.pl-c-nav__subsublist{list-style:none;margin:0;padding:0}.pl-c-viewport-size{margin:0;border:0;padding:.3rem .5rem .4rem;line-height:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.pl-c-viewport-size__input{padding:.1rem;margin:0;border:0;border-radius:3px;background-color:transparent;font-size:inherit;color:grey;width:35px;text-align:right;-webkit-transition:all .1s ease-out;transition:all .1s ease-out}.pl-c-viewport-size__input::-moz-focus-inner{padding:0;border:0}.pl-c-viewport-size__input:hover{color:#fff;background-color:#222}.pl-c-viewport-size__input:active,.pl-c-viewport-size__input:focus{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-viewport-size__label{display:block;margin:0;padding:0}.pl-c-size-list{display:none;list-style:none;margin:0;padding:0;overflow-x:auto;padding:0 .25rem}@media all and (min-width:42em){.pl-c-size-list{-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-overflow-scrolling:touch}}@media all and (min-width:53em){.pl-c-size-list{display:block;display:-webkit-box;display:-ms-flexbox;display:flex}}.pl-c-size-list__action{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px}.pl-c-size-list__action:hover{color:#fff;background-color:#222}.pl-c-size-list__action.pl-is-active,.pl-c-size-list__action:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-size-list__action{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-size-list__action:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-size-list__action:active,.pl-c-body--theme-light .pl-c-size-list__action:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-size-list__action{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-size-list__action{font-size:.85rem;padding:1.5rem 1rem}.pl-c-size-list__item:first-child{margin-left:auto}.pl-c-size-list__item:last-child{margin-right:auto}.pl-c-controls{margin-left:auto;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-controls{display:block}}.pl-c-controls__list{list-style:none;margin:0;padding:0;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:nowrap;flex-wrap:nowrap}.pl-c-tools{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex}.pl-c-tools__toggle{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;margin:0;padding-top:.6rem;padding-bottom:.5rem;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;position:relative;min-width:30px}.pl-c-tools__toggle:hover{color:#fff;background-color:#222}.pl-c-tools__toggle.pl-is-active,.pl-c-tools__toggle:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-tools__toggle{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-tools__toggle:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-tools__toggle:active,.pl-c-body--theme-light .pl-c-tools__toggle:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-tools__toggle{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-tools__toggle{font-size:.85rem;padding:1.5rem 1rem}.pl-c-tools__toggle-icon{-webkit-transition:inherit;transition:inherit}.pl-c-tools__list{list-style:none;margin:0;padding:0;overflow:hidden;max-height:0;-webkit-transition:max-height .1s ease-out;transition:max-height .1s ease-out;position:absolute;top:100%;right:0;z-index:10;width:10rem;border-bottom-left-radius:6px;border-bottom-right-radius:6px}.pl-c-tools__list.pl-is-active{max-height:calc(100vh - 2rem - 1rem);max-height:calc(var(--pl-viewport-height,calc(100vh - 2rem)) - 1rem);overflow:auto;-webkit-overflow-scrolling:touch}.pl-c-tools__action{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;margin:0}.pl-c-tools__action:hover{color:#fff;background-color:#222}.pl-c-tools__action.pl-is-active,.pl-c-tools__action:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-tools__action{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-tools__action:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-tools__action:active,.pl-c-body--theme-light .pl-c-tools__action:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-tools__action{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-tools__action{font-size:.85rem;padding:1.5rem 1rem}.pl-c-tools__action-icon{margin-left:auto}.pl-c-viewport{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%;position:relative;top:2rem;bottom:0;left:0;right:0;z-index:0;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-webkit-transition:height .3s ease;transition:height .3s ease}@supports ((position: -webkit-sticky) or (position: sticky)){.pl-c-viewport{top:0}}.pl-c-body--theme-sidebar .pl-c-viewport{top:0}.pl-c-viewport__cover{width:100%;height:100%;display:none;position:fixed;top:0;left:0;z-index:200;cursor:move;pointer-events:auto}.pl-c-viewport__iframe-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;max-width:100vw;width:100%;position:relative;margin:0 auto;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-overflow-scrolling:touch;width:100%}.pl-c-viewport__iframe-wrapper.hay-mode{-webkit-transition:all 40s linear;transition:all 40s linear}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-viewport__iframe-wrapper{max-width:calc(100vw - 14rem)}}.pl-c-viewport__iframe{min-height:calc(100vh - 35.5px);-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;width:100%;border:0;padding:0;margin:0;top:0;bottom:0;left:0;right:0;background-color:#fff;max-width:100vw}.pl-c-viewport__iframe.is-ready{min-height:0}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-viewport__iframe{max-width:calc(100vw - 14rem)}}.pl-c-viewport__iframe.hay-mode{-webkit-transition:all 40s linear;transition:all 40s linear}.pl-c-viewport__resizer{position:absolute;right:0;top:0;bottom:0;width:14px;margin:0;height:100%;cursor:ew-resize}.pl-c-viewport__resizer-handle{margin:0;width:100%;height:100%;background-color:#ccc;-webkit-transition:background-color .1s ease-out;transition:background-color .1s ease-out}.pl-c-viewport__resizer-handle:hover{background-color:grey}.pl-c-viewport__resizer-handle:active{cursor:move;background-color:#4d4c4c}.vp-animate{-webkit-transition:width .8s ease-out;transition:width .8s ease-out}.pl-c-viewport-modal-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;max-width:100vw;position:relative}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-viewport-modal-wrapper{max-width:calc(100vw - 14rem)}}@media all and (min-width:42em) and (-ms-high-contrast:none),all and (min-width:42em) and (-ms-high-contrast:active){.pl-c-body--theme-sidebar .pl-c-viewport-modal-wrapper{margin-left:14rem}}.pl-c-pattern{margin-bottom:2rem;position:relative;clear:both}.pl-c-pattern__header{position:relative;padding:.5rem 0 0;line-height:1.3;font-size:90%;color:grey}.pl-c-pattern__header:empty{padding:0}.pl-c-pattern__title{font-family:HelveticaNeue,Helvetica,Arial,sans-serif!important;font-size:.85rem!important;line-height:1!important;font-weight:400!important;margin:0!important;padding:0!important;text-transform:capitalize!important}.pl-c-pattern__title-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start;padding:1rem 0 .3rem;color:grey!important;text-decoration:none;cursor:pointer}.pl-c-pattern__title-link:focus,.pl-c-pattern__title-link:hover{color:#000!important}.pl-c-pattern__extra-toggle{font-size:9px;position:absolute;bottom:-1px;right:0;z-index:1;padding:.65em .65em .5em;line-height:1;color:grey;background-color:transparent;font-weight:400;border:1px solid #ddd;border-top-left-radius:6px;border-top-right-radius:6px;-webkit-transition:background-color .1s ease-out;transition:background-color .1s ease-out}.pl-c-pattern__extra-toggle .pl-c-pattern__toggle-icon{display:inline-block}.pl-c-pattern__extra-toggle.pl-is-active,.pl-c-pattern__extra-toggle:focus,.pl-c-pattern__extra-toggle:hover{background-color:#fafafa;color:#000}.pl-c-pattern__extra-toggle:focus{outline:1px dotted #4d4c4c}.pl-c-pattern__extra-toggle.pl-is-active{border-bottom-color:#fafafa}.pl-c-pattern__extra-toggle.pl-is-active .pl-c-pattern__toggle-icon{-webkit-transform:rotate(180deg);-ms-transform:rotate(180deg);transform:rotate(180deg)}.pl-c-pattern__extra{background-color:#fafafa;border-top:1px solid #ddd;margin-bottom:1rem;overflow:hidden;max-height:1px;position:relative;-webkit-transition:all .1s ease-out;transition:all .1s ease-out}.pl-c-pattern__extra.pl-is-active{border:1px solid #ddd;border-radius:6px;border-top-right-radius:0;max-height:150rem}.pl-c-category{margin-top:6rem;font:HelveticaNeue,Helvetica,Arial,sans-serif!important}.pl-c-category:first-of-type{margin-top:2rem}.pl-c-category__title{font-size:1.4rem!important;color:#222!important;margin:0 0 .2rem;text-transform:capitalize}.pl-c-category__title-link{-webkit-transition:color .1s ease-out;transition:color .1s ease-out}.pl-c-category__description{font-size:.85rem;line-height:1.5;max-width:30rem}.pl-c-category__description:empty{display:none}.pl-c-pattern-info{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-flow:row wrap;flex-flow:row wrap;width:100%;overflow:auto;-webkit-overflow-scrolling:touch}.pl-c-pattern .pl-c-pattern-info{max-height:20rem;min-height:18rem;overflow:scroll;-ms-overflow-style:-ms-autohiding-scrollbar;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-overflow-scrolling:touch}.pl-c-pattern .pl-c-pattern-info::-webkit-scrollbar{width:0!important}@media all and (min-width:53em){.pl-c-pattern .pl-c-pattern-info{max-height:none;height:18rem;overflow:visible}}.pl-c-pattern-info__panel{-ms-flex-preferred-size:40%;flex-basis:40%;padding-top:1rem;padding-right:1rem;padding-bottom:0;padding-left:1rem;margin-bottom:1rem;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;max-width:100%;min-width:300px;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;overflow:auto;-webkit-overflow-scrolling:touch}.pl-c-pattern-info__header{margin-bottom:.5rem}.pl-c-pattern-info__title{font-size:1.4rem!important;font-weight:400;margin-top:0;margin-bottom:0;color:inherit;text-transform:capitalize;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.pl-c-pattern-info__description{border-bottom-color:grey}.pl-c-annotations{border-top-color:grey}.pl-c-pattern-state{display:inline-block;width:5px;height:5px;margin-left:10px;position:relative;top:5px;left:0;border-radius:50%;background-color:#02a4d5;line-height:4px;text-indent:10px}.pl-c-pattern-state--complete{background-color:#03790f}.pl-c-pattern-state--inreview{background-color:#c7a118}.pl-c-pattern-state--deprecated{background-color:#b00b02}.complete:before{color:#03790f!important}.pl-c-lineage{font-size:.85rem;line-height:1.7;margin-top:0}.pl-c-lineage__link{font-style:italic;color:grey;text-decoration:underline;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .1s ease;transition:opacity .1s ease}.pl-c-lineage__link:focus,.pl-c-lineage__link:hover{opacity:.8}.pl-c-breadcrumb{list-style:none;margin:0;padding:0;margin-bottom:.5rem;display:-webkit-box;display:-ms-flexbox;display:flex;font-size:.7rem;color:grey;text-transform:capitalize}.pl-c-breadcrumb__item:after{content:'\25B6';opacity:.4;font-size:6px;display:inline-block;margin:0 .2rem;position:relative;top:-1px}.pl-c-tabs{padding:0 .5rem .5rem;background-color:#fff;border:1px solid #ddd;border-radius:6px;font-family:HelveticaNeue,Helvetica,Arial,sans-serif;position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;overflow:hidden;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.pl-c-tabs__list{display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;list-style:none;margin:0;padding:.5rem 0;background-color:#fff}.pl-c-tabs__link{display:block;line-height:1;padding:.2rem .4rem;border:1px solid transparent;border-radius:6px;color:grey;background-color:#fff;cursor:pointer;text-decoration:none;text-transform:lowercase;-webkit-transition:all .1s ease-out;transition:all .1s ease-out}.pl-c-tabs__link:hover{color:#222}.pl-c-tabs__link.pl-is-active-tab{color:#222;background-color:#eee;border:1px solid #ddd}.pl-c-tabs__content{overflow:auto;-webkit-overflow-scrolling:touch;padding-top:.5rem}.pl-c-tabs__panel{display:none}.pl-c-tabs__panel.pl-is-active-tab{display:block}.pl-c-tabs__panel :not(pre)>code[class*=language-],.pl-c-tabs__panel pre[class*=language-]{background-color:transparent;margin:0;padding:0;border:0;display:block}.pl-c-tabs__panel code[class*=language-]{background-color:transparent;margin:0}.pl-c-tools{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex}.pl-c-tools__toggle{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;margin:0;padding-top:.6rem;padding-bottom:.5rem;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;position:relative;min-width:30px}.pl-c-tools__toggle:hover{color:#fff;background-color:#222}.pl-c-tools__toggle.pl-is-active,.pl-c-tools__toggle:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-tools__toggle{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-tools__toggle:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-tools__toggle:active,.pl-c-body--theme-light .pl-c-tools__toggle:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-tools__toggle{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-tools__toggle{font-size:.85rem;padding:1.5rem 1rem}.pl-c-tools__toggle-icon{-webkit-transition:inherit;transition:inherit}.pl-c-tools__list{list-style:none;margin:0;padding:0;overflow:hidden;max-height:0;-webkit-transition:max-height .1s ease-out;transition:max-height .1s ease-out;position:absolute;top:100%;right:0;z-index:10;width:10rem;border-bottom-left-radius:6px;border-bottom-right-radius:6px}.pl-c-tools__list.pl-is-active{max-height:calc(100vh - 2rem - 1rem);max-height:calc(var(--pl-viewport-height,calc(100vh - 2rem)) - 1rem);overflow:auto;-webkit-overflow-scrolling:touch}.pl-c-tools__action{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:100%;margin:0}.pl-c-tools__action:hover{color:#fff;background-color:#222}.pl-c-tools__action.pl-is-active,.pl-c-tools__action:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-tools__action{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-tools__action:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-tools__action:active,.pl-c-body--theme-light .pl-c-tools__action:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-tools__action{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-tools__action{font-size:.85rem;padding:1.5rem 1rem}.pl-c-tools__action-icon{margin-left:auto}.pl-has-annotation{cursor:help!important;outline:1px dotted grey;outline-offset:-4px;-webkit-transition:-webkit-box-shadow .1s ease;transition:-webkit-box-shadow .1s ease;transition:box-shadow .1s ease;transition:box-shadow .1s ease, -webkit-box-shadow .1s ease}.pl-has-annotation a,.pl-has-annotation input{cursor:help!important}.pl-has-annotation:hover{-webkit-box-shadow:0 0 3px grey;box-shadow:0 0 3px grey}.pl-has-annotation.active{-webkit-box-shadow:inset 0 0 6px #4d4c4c;box-shadow:inset 0 0 6px #4d4c4c;outline:1px dotted grey;outline-offset:-1px}.pl-c-annotation-tip{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:24px!important;height:24px!important;margin-top:6px!important;margin-left:6px!important;border-radius:50%!important;background-color:#222!important;color:#fff!important;font-size:16px!important;position:absolute;z-index:100}.pl-c-annotations{margin:1rem 0}.pl-c-annotations__title{font-size:1.2rem!important;margin:0 0 .5rem}.pl-c-annotations .pl-c-annotations__list{counter-reset:the-count;padding:0;margin:0;list-style:none}.pl-c-annotations__item{position:relative;padding-left:1.5rem;margin-bottom:1rem;border-radius:6px;-webkit-transition:background-color .1s ease;transition:background-color .1s ease}.pl-c-annotations__item:before{content:counter(the-count);counter-increment:the-count;font-size:85%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;width:14px;height:14px;border-radius:50%;padding:2px;text-align:center;background-color:grey;color:#fff;position:absolute;top:4px;left:0}.pl-c-annotations__item.pl-is-active{outline:1px dotted grey;outline-offset:-1px}.pl-c-annotations .pl-c-annotations__item-title{margin-bottom:0}pl-modal{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;position:relative;position:-webkit-sticky;position:sticky;z-index:20;max-height:100vh;-webkit-box-shadow:0 0 2px 0 #4d4c4c;box-shadow:0 0 2px 0 #4d4c4c;overflow:visible}.pl-c-modal{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;font-family:HelveticaNeue,Helvetica,Arial,sans-serif;background-color:#222;color:#ccc;position:-webkit-sticky;position:sticky;top:auto;bottom:0;left:0;right:0;z-index:5;width:100%;height:0;-webkit-transition:height .3s ease,-webkit-transform .3s ease;transition:height .3s ease,-webkit-transform .3s ease;transition:transform .3s ease,height .3s ease;transition:transform .3s ease,height .3s ease,-webkit-transform .3s ease;-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);pointer-events:none;will-change:height,transform;overflow:hidden;max-width:100vw;-webkit-box-shadow:0 -1px 2px rgba(77,76,76,.1);box-shadow:0 -1px 2px rgba(77,76,76,.1)}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-modal{max-width:calc(100vw - 14rem)}}.pl-c-modal.pl-is-active{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);height:40vh;-webkit-transition:-webkit-transform .3s ease;transition:-webkit-transform .3s ease;transition:transform .3s ease;transition:transform .3s ease, -webkit-transform .3s ease;pointer-events:auto}.pl-c-modal__wrapper{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.pl-c-modal__wrapper>*{height:100%}.pl-c-modal__content{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;width:100%;overflow:hidden}.pl-c-modal__toolbar{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-ms-flex-negative:0;flex-shrink:0}.pl-c-modal__content-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;overflow:hidden}.pl-c-modal__toolbar-controls{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-ms-flex-item-align:end;align-self:flex-end;position:relative;z-index:10;-ms-flex-negative:0;flex-shrink:0}.pl-c-modal__close-btn{background-color:#000;color:grey;text-decoration:none;line-height:1;padding:.7rem .5rem;border:0;text-align:left;-webkit-transition:background-color .1s ease-out,color .1s ease-out;transition:background-color .1s ease-out,color .1s ease-out;cursor:pointer;outline-offset:-3px;outline-width:2px;margin:0;-webkit-appearance:none;-ms-flex-negative:0;flex-shrink:0;z-index:2;opacity:.85;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.pl-c-modal__close-btn:hover{color:#fff;background-color:#222}.pl-c-modal__close-btn.pl-is-active,.pl-c-modal__close-btn:active{color:#fff;background-color:#222;outline:1px dotted grey;outline-offset:-1px}.pl-c-body--theme-light .pl-c-modal__close-btn{background-color:#fff;color:#4d4c4c}.pl-c-body--theme-light .pl-c-modal__close-btn:hover{background-color:#eee}.pl-c-body--theme-light .pl-c-modal__close-btn:active,.pl-c-body--theme-light .pl-c-modal__close-btn:focus{background-color:#ddd}.pl-c-body--theme-density-cozy .pl-c-modal__close-btn{font-size:.85rem;padding:1.2rem .8rem}.pl-c-body--theme-density-comfortable .pl-c-modal__close-btn{font-size:.85rem;padding:1.5rem 1rem}@media all and (max-width:41em){.pl-c-modal__close-btn{border-radius:20rem;padding-top:.5rem;padding-bottom:.5rem}}.pl-c-modal__close-btn:focus,.pl-c-modal__close-btn:hover{opacity:1}.pl-c-modal__close-btn:active,.pl-c-modal__close-btn:focus{opacity:1}.pl-c-modal__cover{width:100%;height:100%;display:none;position:absolute;z-index:20;cursor:move}.pl-c-modal__resizer{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;top:0;left:0;right:0;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;left:0;height:14px;width:100%;background-color:inherit;z-index:2;cursor:ns-resize}.pl-c-modal__resizer:after{content:'';height:3px;width:50px;border-top:1px solid currentColor;border-bottom:1px solid currentColor;-webkit-transition:opacity .3s ease-out;transition:opacity .3s ease-out;opacity:.5;background-color:currentColor;border-radius:3px;display:block}.pl-c-modal__resizer:hover:after{opacity:.8}.pl-c-modal__resizer:active:after,.pl-c-modal__resizer:focus:after{opacity:.95}.pl-c-modal__close-btn-icon{width:12px;height:12px;color:currentColor;fill:currentColor;-webkit-transition:fill .1s ease-out;transition:fill .1s ease-out;-ms-flex-negative:0;flex-shrink:0;-ms-flex-item-align:center;align-self:center}.pl-c-code-copy-btn{display:inline-block;position:absolute;top:.5rem;right:.5rem;padding:.2rem .4rem;background-color:#eee;color:#222;border:1px solid #ddd;border-radius:6px;font-family:HelveticaNeue,Helvetica,Arial,sans-serif;font-size:1rem;text-transform:lowercase;line-height:1;cursor:pointer;z-index:2;-webkit-transition:background-color .1s ease-out;transition:background-color .1s ease-out}.pl-c-code-copy-btn:focus,.pl-c-code-copy-btn:hover{background-color:#ccc}.pl-c-text-passage{font-size:.85rem;line-height:1.7}.pl-c-text-passage p{margin-top:0;margin-bottom:1rem}.pl-c-text-passage a{color:grey;text-decoration:underline;-webkit-transition:opacity .1s ease;transition:opacity .1s ease}.pl-c-text-passage a:focus,.pl-c-text-passage a:hover{opacity:.8}.pl-c-text-passage code[class*=language-],.pl-c-text-passage pre[class*=language-]{color:inherit}.pl-c-text-passage blockquote{padding-left:.8rem;border-left:3px solid inherit}.pl-c-text-passage hr{height:1px;background-color:grey;margin:2rem 0;border:0}.pl-c-text-passage h1{margin-bottom:1rem;font-weight:400}.pl-c-text-passage h2{margin:1rem 0 1rem;font-weight:400}.pl-c-text-passage h3{margin:1rem 0 1rem;font-weight:400}.pl-c-text-passage h4{margin:1rem 0 1rem;font-weight:400}.pl-c-text-passage h5{margin:1rem 0 1rem;font-weight:400}.pl-c-text-passage h6{margin:1rem 0 1rem;font-weight:400}.pl-c-text-passage ul{list-style:square;margin-left:.9rem;margin-bottom:1rem}.pl-c-text-passage ul li:last-child{margin-bottom:0}.pl-c-text-passage ol{list-style:decimal;margin-left:.9rem;margin-bottom:1rem}.pl-c-text-passage ol li:last-child{margin-bottom:0}.pl-c-text-passage li{margin-bottom:.5rem}.pl-c-body--theme-light .pl-c-header{background-color:#fff;border-bottom:1px solid #ccc}@media all and (max-width:41em){.pl-c-body--theme-light .pl-c-tools__list.pl-is-active{border-bottom:1px solid #ccc;border-left:1px solid #ccc}}.pl-c-body--theme-light:not(.pl-c-body--theme-sidebar) .pl-c-tools__list.pl-is-active{border-bottom:1px solid #ccc;border-left:1px solid #ccc}.pl-c-body--theme-light .pl-c-nav__link--dropdown{color:#4d4c4c;background-color:#fff}.pl-c-body--theme-light .pl-c-nav__link--dropdown:after{color:#ccc}@media all and (min-width:42em){.pl-c-body--theme-light .pl-c-nav__sublist>.pl-c-nav__item:last-child .pl-c-nav__link{border-bottom-left-radius:6px;border-bottom-right-radius:6px}}.pl-c-body--theme-light .pl-c-viewport-size__input{color:#4d4c4c}.pl-c-body--theme-light .pl-c-viewport-size__input:focus,.pl-c-body--theme-light .pl-c-viewport-size__input:hover{background-color:#ddd}.pl-c-body--theme-light .typeahead{background-color:#ddd!important}.pl-c-body--theme-light .tt-input{background-color:#eee!important;color:#4d4c4c!important}.pl-c-body--theme-light .tt-input:hover{color:#222;background-color:#ddd!important}.pl-c-body--theme-light .tt-input:hover::-webkit-input-placeholder{color:#222}.pl-c-body--theme-light .tt-input:hover::-moz-input-placeholder{color:#222}.pl-c-body--theme-light .pl-c-modal{background-color:#fff;color:#4d4c4c;border-top:1px solid #ccc}.pl-c-body--theme-light .pl-c-modal__close-btn,.pl-c-body--theme-light .pl-c-tools__action{background-color:#fff}.pl-c-body--theme-light .pl-c-modal__close-btn:focus,.pl-c-body--theme-light .pl-c-modal__close-btn:hover,.pl-c-body--theme-light .pl-c-tools__action:focus,.pl-c-body--theme-light .pl-c-tools__action:hover{background-color:#eee;color:#4d4c4c}.pl-c-body--theme-density-cozy .pl-c-header{font-size:.85rem}.pl-c-body--theme-density-cozy .pl-c-viewport-size__input{width:44px}.pl-c-body--theme-density-cozy .pl-c-typeahead{padding:.9rem .8rem}@media all and (max-width:78em){.pl-c-body--theme-density-cozy .pl-c-size-list{display:none}}@media all and (max-width:78em){.pl-c-body--theme-density-cozy .pl-c-viewport-size{display:none}}.pl-c-body--theme-density-cozy .pl-c-tools__toggle{min-width:44px}.pl-c-body--theme-density-cozy .pl-c-viewport{top:3.28rem}.pl-c-body--theme-density-comfortable .pl-c-header{font-size:.85rem}.pl-c-body--theme-density-comfortable .pl-c-logo{max-width:4rem}.pl-c-body--theme-density-comfortable .pl-c-header .tt-suggestion{padding:1.5rem 1rem}.pl-c-body--theme-density-comfortable .pl-c-viewport-size__input{width:44px}.pl-c-body--theme-density-comfortable .pl-c-typeahead{padding:.9rem 1rem}@media all and (max-width:78em){.pl-c-body--theme-density-comfortable .pl-c-size-list{display:none}}@media all and (max-width:78em){.pl-c-body--theme-density-comfortable .pl-c-viewport-size{display:none}}.pl-c-body--theme-density-comfortable .pl-c-tools__toggle{min-width:44px}.pl-c-body--theme-density-comfortable .pl-c-viewport{top:3.8rem}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-header{width:14rem;height:100vh;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;border-bottom:0;padding:1rem;overflow:auto;-webkit-overflow-scrolling:touch;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.pl-c-body--theme-sidebar.pl-c-body--theme-light .pl-c-header{border-right:1px solid #ccc}.pl-c-body--theme-sidebar .pl-c-logo{max-width:7rem;margin:0 auto 1rem}.pl-c-body--theme-sidebar .pl-c-nav{display:block;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.pl-c-body--theme-sidebar .pl-c-nav__list{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.pl-c-body--theme-sidebar .pl-c-nav__sublist{position:relative;border-radius:0}.pl-c-body--theme-sidebar .pl-c-nav__sublist .pl-c-nav__link{padding-left:1rem}.pl-c-body--theme-sidebar .pl-c-nav__sublist--dropdown.pl-is-active{border:0;border-left:1px solid #4d4c4c}.pl-c-body--theme-sidebar.pl-c-body--theme-light .pl-c-nav__sublist--dropdown.pl-is-active{border-left-color:#eee}.pl-c-body--theme-sidebar .pl-c-nav__subsublist{border-left:1px solid #4d4c4c;margin-left:1rem}.pl-c-body--theme-sidebar.pl-c-body--theme-light .pl-c-nav__subsublist{border-left-color:#eee}.pl-c-body--theme-sidebar .pl-c-nav__sublist .pl-c-nav__link{border-left:0;border-right:0}}@media all and (min-width:42em) and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-nav__sublist>.pl-c-nav__item:last-child .pl-c-nav__link{border-bottom-left-radius:0;border-bottom-right-radius:0;border-bottom:0}}@media all and (min-width:42em){.pl-c-body--theme-sidebar .pl-c-controls{display:block;justify-self:flex-end;margin-left:0}.pl-c-body--theme-sidebar .pl-c-viewport-size{display:none}.pl-c-body--theme-sidebar .pl-c-tools__toggle{display:none}.pl-c-body--theme-sidebar .pl-c-tools__list{max-height:none;overflow:visible;position:relative;border-radius:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;width:100%}.pl-c-body--theme-sidebar .pl-c-modal{right:0;width:auto}}.is-vishidden{position:absolute!important;overflow:hidden;width:1px;height:1px;padding:0;border:0;clip:rect(1px,1px,1px,1px)}
diff --git a/packages/uikit-workshop/dist/styleguide/js/0-chunk-bfab2102075df63da231.js b/packages/uikit-workshop/dist/styleguide/js/0-chunk-bfab2102075df63da231.js
deleted file mode 100644
index 3b55ef3c4..000000000
--- a/packages/uikit-workshop/dist/styleguide/js/0-chunk-bfab2102075df63da231.js
+++ /dev/null
@@ -1,15 +0,0 @@
-(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[0],{
-
-/***/ "./node_modules/@webcomponents/shadydom/src/shadydom.js":
-/*!***************************************************************************!*\
- !*** ./node_modules/@webcomponents/shadydom/src/shadydom.js + 28 modules ***!
- \***************************************************************************/
-/*! no exports provided */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-eval("\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/shady-data.js\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nvar ShadyData =\n/*#__PURE__*/\nfunction () {\n function ShadyData() {\n _classCallCheck(this, ShadyData);\n\n /** @type {ShadowRoot} */\n this.root = null;\n /** @type {ShadowRoot} */\n\n this.publicRoot = null;\n this.dirty = false;\n this.observer = null;\n /** @type {Array} */\n\n this.assignedNodes = null;\n /** @type {Element} */\n\n this.assignedSlot = null;\n /** @type {Array} */\n\n this._previouslyAssignedNodes = null;\n /** @type {Element} */\n\n this._prevAssignedSlot = null;\n /** @type {Array} */\n\n this.flattenedNodes = null;\n this.ownerShadyRoot = undefined;\n /** @type {Node|undefined} */\n\n this.parentNode = undefined;\n /** @type {Node|undefined} */\n\n this.firstChild = undefined;\n /** @type {Node|undefined} */\n\n this.lastChild = undefined;\n /** @type {Node|undefined} */\n\n this.previousSibling = undefined;\n /** @type {Node|undefined} */\n\n this.nextSibling = undefined;\n /** @type {Array|undefined} */\n\n this.childNodes = undefined;\n this.__outsideAccessors = false;\n this.__insideAccessors = false;\n this.__onCallbackListeners = {};\n }\n /** @override */\n\n\n _createClass(ShadyData, [{\n key: \"toJSON\",\n value: function toJSON() {\n return {};\n }\n }]);\n\n return ShadyData;\n}();\nfunction ensureShadyDataForNode(node) {\n if (!node.__shady) {\n node.__shady = new ShadyData();\n }\n\n return node.__shady;\n}\nfunction shadyDataForNode(node) {\n return node && node.__shady;\n}\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/utils.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/** @type {!Object} */\n\nvar settings = window['ShadyDOM'] || {};\nsettings.hasNativeShadowDOM = Boolean(Element.prototype.attachShadow && Node.prototype.getRootNode);\nvar desc = Object.getOwnPropertyDescriptor(Node.prototype, 'firstChild');\nsettings.hasDescriptors = Boolean(desc && desc.configurable && desc.get);\nsettings.inUse = settings['force'] || !settings.hasNativeShadowDOM;\nsettings.noPatch = settings['noPatch'] || false;\nsettings.preferPerformance = settings['preferPerformance'];\nvar utils_isTrackingLogicalChildNodes = function isTrackingLogicalChildNodes(node) {\n var nodeData = shadyDataForNode(node);\n return nodeData && nodeData.firstChild !== undefined;\n};\nvar utils_isShadyRoot = function isShadyRoot(obj) {\n return Boolean(obj._localName === 'ShadyRoot');\n};\nvar utils_hasShadowRootWithSlot = function hasShadowRootWithSlot(node) {\n var nodeData = shadyDataForNode(node);\n var root = nodeData && nodeData.root;\n return root && root._hasInsertionPoint();\n};\nvar utils_p = Element.prototype;\nvar matches = utils_p.matches || utils_p.matchesSelector || utils_p.mozMatchesSelector || utils_p.msMatchesSelector || utils_p.oMatchesSelector || utils_p.webkitMatchesSelector;\nvar matchesSelector = function matchesSelector(element, selector) {\n return matches.call(element, selector);\n};\nvar mixin = function mixin(target, source) {\n for (var i in source) {\n target[i] = source[i];\n }\n\n return target;\n}; // NOTE, prefer MutationObserver over Promise for microtask timing\n// for consistency x-platform.\n\nvar twiddle = document.createTextNode('');\nvar utils_content = 0;\nvar queue = [];\nnew MutationObserver(function () {\n while (queue.length) {\n // catch errors in user code...\n try {\n queue.shift()();\n } catch (e) {\n // enqueue another record and throw\n twiddle.textContent = utils_content++;\n throw e;\n }\n }\n}).observe(twiddle, {\n characterData: true\n}); // use MutationObserver to get microtask async timing.\n\nvar microtask = function microtask(callback) {\n queue.push(callback);\n twiddle.textContent = utils_content++;\n};\nvar hasDocumentContains = Boolean(document.contains);\nvar utils_contains = function contains(container, node) {\n while (node) {\n if (node == container) {\n return true;\n }\n\n node = node[SHADY_PREFIX + 'parentNode'];\n }\n\n return false;\n};\n\nvar getNodeHTMLCollectionName = function getNodeHTMLCollectionName(node) {\n return node.getAttribute('id') || node.getAttribute('name');\n};\n\nvar isValidHTMLCollectionName = function isValidHTMLCollectionName(name) {\n return name !== 'length' && isNaN(name);\n};\n\nvar createPolyfilledHTMLCollection = function createPolyfilledHTMLCollection(nodes) {\n // Note: loop in reverse so that the first named item matches the named property\n for (var l = nodes.length - 1; l >= 0; l--) {\n var node = nodes[l];\n var name = getNodeHTMLCollectionName(node);\n\n if (name && isValidHTMLCollectionName(name)) {\n nodes[name] = node;\n }\n }\n\n nodes.item = function (index) {\n return nodes[index];\n };\n\n nodes.namedItem = function (name) {\n if (isValidHTMLCollectionName(name) && nodes[name]) {\n return nodes[name];\n }\n\n var _iteratorNormalCompletion = true;\n var _didIteratorError = false;\n var _iteratorError = undefined;\n\n try {\n for (var _iterator = nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {\n var _node = _step.value;\n var nodeName = getNodeHTMLCollectionName(_node);\n\n if (nodeName == name) {\n return _node;\n }\n }\n } catch (err) {\n _didIteratorError = true;\n _iteratorError = err;\n } finally {\n try {\n if (!_iteratorNormalCompletion && _iterator.return != null) {\n _iterator.return();\n }\n } finally {\n if (_didIteratorError) {\n throw _iteratorError;\n }\n }\n }\n\n return null;\n };\n\n return nodes;\n};\nvar NATIVE_PREFIX = '__shady_native_';\nvar SHADY_PREFIX = '__shady_';\n/**\n * Patch a group of accessors on an object only if it exists or if the `force`\n * argument is true.\n * @param {!Object} proto\n * @param {!Object} descriptors\n * @param {string=} prefix\n * @param {Array=} disallowedPatches\n */\n\nvar patchProperties = function patchProperties(proto, descriptors) {\n var prefix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : '';\n var disallowedPatches = arguments.length > 3 ? arguments[3] : undefined;\n\n for (var _p in descriptors) {\n var newDescriptor = descriptors[_p];\n\n if (disallowedPatches && disallowedPatches.indexOf(_p) >= 0) {\n continue;\n }\n\n newDescriptor.configurable = true;\n var name = prefix + _p; // NOTE: we prefer writing directly because some browsers\n // have descriptors that are writable but not configurable (e.g.\n // `appendChild` on older browsers)\n\n if (newDescriptor.value) {\n proto[name] = newDescriptor.value;\n } else {\n // NOTE: this can throw if 'force' is used so catch the error.\n try {\n Object.defineProperty(proto, name, newDescriptor);\n } catch (e) {// this error is harmless so we just trap it.\n }\n }\n }\n};\n/** @type {!function(new:HTMLElement)} */\n\nvar NativeHTMLElement = window['customElements'] && window['customElements']['nativeHTMLElement'] || HTMLElement; // note, this is not a perfect polyfill since it doesn't include symbols\n\n/** @return {!Object} */\n\nvar getOwnPropertyDescriptors = function getOwnPropertyDescriptors(obj) {\n var descriptors = {};\n Object.getOwnPropertyNames(obj).forEach(function (name) {\n descriptors[name] = Object.getOwnPropertyDescriptor(obj, name);\n });\n return descriptors;\n};\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/flush.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n // render enqueuer/flusher\n\nvar flushList = [];\nvar scheduled;\nfunction enqueue(callback) {\n if (!scheduled) {\n scheduled = true;\n microtask(flush);\n }\n\n flushList.push(callback);\n}\nfunction flush() {\n scheduled = false;\n var didFlush = Boolean(flushList.length);\n\n while (flushList.length) {\n flushList.shift()();\n }\n\n return didFlush;\n}\nflush['list'] = flushList;\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/observe-changes.js\nfunction observe_changes_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction observe_changes_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction observe_changes_createClass(Constructor, protoProps, staticProps) { if (protoProps) observe_changes_defineProperties(Constructor.prototype, protoProps); if (staticProps) observe_changes_defineProperties(Constructor, staticProps); return Constructor; }\n\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\nvar observe_changes_AsyncObserver =\n/*#__PURE__*/\nfunction () {\n function AsyncObserver() {\n observe_changes_classCallCheck(this, AsyncObserver);\n\n this._scheduled = false;\n this.addedNodes = [];\n this.removedNodes = [];\n this.callbacks = new Set();\n }\n\n observe_changes_createClass(AsyncObserver, [{\n key: \"schedule\",\n value: function schedule() {\n var _this = this;\n\n if (!this._scheduled) {\n this._scheduled = true;\n microtask(function () {\n _this.flush();\n });\n }\n }\n }, {\n key: \"flush\",\n value: function flush() {\n if (this._scheduled) {\n this._scheduled = false;\n var mutations = this.takeRecords();\n\n if (mutations.length) {\n this.callbacks.forEach(function (cb) {\n cb(mutations);\n });\n }\n }\n }\n }, {\n key: \"takeRecords\",\n value: function takeRecords() {\n if (this.addedNodes.length || this.removedNodes.length) {\n var mutations = [{\n addedNodes: this.addedNodes,\n removedNodes: this.removedNodes\n }];\n this.addedNodes = [];\n this.removedNodes = [];\n return mutations;\n }\n\n return [];\n }\n }]);\n\n return AsyncObserver;\n}(); // TODO(sorvell): consider instead polyfilling MutationObserver\n// directly so that users do not have to fork their code.\n// Supporting the entire api may be challenging: e.g. filtering out\n// removed nodes in the wrong scope and seeing non-distributing\n// subtree child mutations.\n\n\nvar observe_changes_observeChildren = function observeChildren(node, callback) {\n var sd = ensureShadyDataForNode(node);\n\n if (!sd.observer) {\n sd.observer = new observe_changes_AsyncObserver();\n }\n\n sd.observer.callbacks.add(callback);\n var observer = sd.observer;\n return {\n _callback: callback,\n _observer: observer,\n _node: node,\n takeRecords: function takeRecords() {\n return observer.takeRecords();\n }\n };\n};\nvar observe_changes_unobserveChildren = function unobserveChildren(handle) {\n var observer = handle && handle._observer;\n\n if (observer) {\n observer.callbacks.delete(handle._callback);\n\n if (!observer.callbacks.size) {\n ensureShadyDataForNode(handle._node).observer = null;\n }\n }\n};\nfunction filterMutations(mutations, target) {\n /** @const {Node} */\n var targetRootNode = target.getRootNode();\n return mutations.map(function (mutation) {\n /** @const {boolean} */\n var mutationInScope = targetRootNode === mutation.target.getRootNode();\n\n if (mutationInScope && mutation.addedNodes) {\n var nodes = Array.from(mutation.addedNodes).filter(function (n) {\n return targetRootNode === n.getRootNode();\n });\n\n if (nodes.length) {\n mutation = Object.create(mutation);\n Object.defineProperty(mutation, 'addedNodes', {\n value: nodes,\n configurable: true\n });\n return mutation;\n }\n } else if (mutationInScope) {\n return mutation;\n }\n }).filter(function (m) {\n return m;\n });\n}\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/innerHTML.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n// Cribbed from ShadowDOM polyfill\n// https://github.com/webcomponents/webcomponentsjs/blob/master/src/ShadowDOM/wrappers/HTMLElement.js#L28\n/////////////////////////////////////////////////////////////////////////////\n// innerHTML and outerHTML\n// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#escapingString\nvar escapeAttrRegExp = /[&\\u00A0\"]/g;\nvar escapeDataRegExp = /[&\\u00A0<>]/g;\n\nfunction escapeReplace(c) {\n switch (c) {\n case '&':\n return '&';\n\n case '<':\n return '<';\n\n case '>':\n return '>';\n\n case '\"':\n return '"';\n\n case \"\\xA0\":\n return ' ';\n }\n}\n\nfunction escapeAttr(s) {\n return s.replace(escapeAttrRegExp, escapeReplace);\n}\n\nfunction escapeData(s) {\n return s.replace(escapeDataRegExp, escapeReplace);\n}\n\nfunction makeSet(arr) {\n var set = {};\n\n for (var i = 0; i < arr.length; i++) {\n set[arr[i]] = true;\n }\n\n return set;\n} // http://www.whatwg.org/specs/web-apps/current-work/#void-elements\n\n\nvar voidElements = makeSet(['area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'keygen', 'link', 'meta', 'param', 'source', 'track', 'wbr']);\nvar plaintextParents = makeSet(['style', 'script', 'xmp', 'iframe', 'noembed', 'noframes', 'plaintext', 'noscript']);\n/**\n * @param {Node} node\n * @param {Node} parentNode\n * @param {Function=} callback\n */\n\nfunction getOuterHTML(node, parentNode, callback) {\n switch (node.nodeType) {\n case Node.ELEMENT_NODE:\n {\n var tagName = node.localName;\n var s = '<' + tagName;\n var attrs = node.attributes;\n\n for (var i = 0, attr; attr = attrs[i]; i++) {\n s += ' ' + attr.name + '=\"' + escapeAttr(attr.value) + '\"';\n }\n\n s += '>';\n\n if (voidElements[tagName]) {\n return s;\n }\n\n return s + getInnerHTML(node, callback) + '' + tagName + '>';\n }\n\n case Node.TEXT_NODE:\n {\n var data =\n /** @type {Text} */\n node.data;\n\n if (parentNode && plaintextParents[parentNode.localName]) {\n return data;\n }\n\n return escapeData(data);\n }\n\n case Node.COMMENT_NODE:\n {\n return '';\n }\n\n default:\n {\n window.console.error(node);\n throw new Error('not implemented');\n }\n }\n}\n/**\n * @param {Node} node\n * @param {Function=} callback\n */\n\nfunction getInnerHTML(node, callback) {\n if (node.localName === 'template') {\n node =\n /** @type {HTMLTemplateElement} */\n node.content;\n }\n\n var s = '';\n var c$ = callback ? callback(node) : node.childNodes;\n\n for (var i = 0, l = c$.length, child; i < l && (child = c$[i]); i++) {\n s += getOuterHTML(child, node, callback);\n }\n\n return s;\n}\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patch-native.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\nvar hasDescriptors = settings.hasDescriptors;\nvar patch_native_NATIVE_PREFIX = NATIVE_PREFIX; // Object on which raw native methods are stored.\n// e.g. `nativeMethods.querySelector.call(node, selector)`\n// same as `node.querySelector(selector)`\n\nvar nativeMethods = {\n /** @this {Element} */\n querySelector: function querySelector(selector) {\n return this[patch_native_NATIVE_PREFIX + 'querySelector'](selector);\n },\n\n /** @this {Element} */\n querySelectorAll: function querySelectorAll(selector) {\n return this[patch_native_NATIVE_PREFIX + 'querySelectorAll'](selector);\n }\n}; // Object on which raw native accessors are available via `accessorName(node)`.\n// e.g. `nativeTree.firstChild(node)`\n// same as `node.firstChild`\n\nvar nativeTree = {};\n\nvar installNativeAccessor = function installNativeAccessor(name) {\n nativeTree[name] = function (node) {\n return node[patch_native_NATIVE_PREFIX + name];\n };\n};\n\nvar installNativeMethod = function installNativeMethod(name, fn) {\n if (!nativeMethods[name]) {\n nativeMethods[name] = fn;\n }\n};\n\nvar patch_native_defineNativeAccessors = function defineNativeAccessors(proto, descriptors) {\n patchProperties(proto, descriptors, patch_native_NATIVE_PREFIX); // make native accessors available to users\n\n for (var prop in descriptors) {\n installNativeAccessor(prop);\n }\n};\n\nvar copyProperties = function copyProperties(proto) {\n var list = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];\n\n for (var i = 0; i < list.length; i++) {\n var name = list[i];\n var descriptor = Object.getOwnPropertyDescriptor(proto, name);\n\n if (descriptor) {\n Object.defineProperty(proto, patch_native_NATIVE_PREFIX + name, descriptor); // make native methods/accessors available to users\n\n if (descriptor.value) {\n installNativeMethod(name, descriptor.value);\n } else {\n installNativeAccessor(name);\n }\n }\n }\n};\n/** @type {!TreeWalker} */\n\n\nvar nodeWalker = document.createTreeWalker(document, NodeFilter.SHOW_ALL, null, false);\n/** @type {!TreeWalker} */\n\nvar elementWalker = document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, null, false);\n/** @type {!Document} */\n\nvar inertDoc = document.implementation.createHTMLDocument('inert');\n\nvar clearNode = function clearNode(node) {\n var firstChild;\n\n while (firstChild = node[patch_native_NATIVE_PREFIX + 'firstChild']) {\n node[patch_native_NATIVE_PREFIX + 'removeChild'](firstChild);\n }\n};\n\nvar ParentNodeAccessors = ['firstElementChild', 'lastElementChild', 'children', 'childElementCount'];\nvar ParentNodeMethods = ['querySelector', 'querySelectorAll' // 'append', 'prepend'\n];\nvar patch_native_addNativePrefixedProperties = function addNativePrefixedProperties() {\n // EventTarget\n var eventProps = ['dispatchEvent', 'addEventListener', 'removeEventListener'];\n\n if (window.EventTarget) {\n copyProperties(window.EventTarget.prototype, eventProps);\n } else {\n copyProperties(Node.prototype, eventProps);\n copyProperties(Window.prototype, eventProps);\n } // Node\n\n\n if (hasDescriptors) {\n copyProperties(Node.prototype, ['parentNode', 'firstChild', 'lastChild', 'previousSibling', 'nextSibling', 'childNodes', 'parentElement', 'textContent']);\n } else {\n patch_native_defineNativeAccessors(Node.prototype, {\n parentNode: {\n /** @this {Node} */\n get: function get() {\n nodeWalker.currentNode = this;\n return nodeWalker.parentNode();\n }\n },\n firstChild: {\n /** @this {Node} */\n get: function get() {\n nodeWalker.currentNode = this;\n return nodeWalker.firstChild();\n }\n },\n lastChild: {\n /** @this {Node} */\n get: function get() {\n nodeWalker.currentNode = this;\n return nodeWalker.lastChild();\n }\n },\n previousSibling: {\n /** @this {Node} */\n get: function get() {\n nodeWalker.currentNode = this;\n return nodeWalker.previousSibling();\n }\n },\n nextSibling: {\n /** @this {Node} */\n get: function get() {\n nodeWalker.currentNode = this;\n return nodeWalker.nextSibling();\n }\n },\n // TODO(sorvell): make this a NodeList or whatever\n childNodes: {\n /** @this {Node} */\n get: function get() {\n var nodes = [];\n nodeWalker.currentNode = this;\n var n = nodeWalker.firstChild();\n\n while (n) {\n nodes.push(n);\n n = nodeWalker.nextSibling();\n }\n\n return nodes;\n }\n },\n parentElement: {\n /** @this {Node} */\n get: function get() {\n elementWalker.currentNode = this;\n return elementWalker.parentNode();\n }\n },\n textContent: {\n /** @this {Node} */\n get: function get() {\n /* eslint-disable no-case-declarations */\n switch (this.nodeType) {\n case Node.ELEMENT_NODE:\n case Node.DOCUMENT_FRAGMENT_NODE:\n // TODO(sorvell): This cannot be a single TreeWalker that's reused\n // at least for Safari 9, but it's unclear why.\n var textWalker = document.createTreeWalker(this, NodeFilter.SHOW_TEXT, null, false);\n var content = '',\n n;\n\n while (n = textWalker.nextNode()) {\n // TODO(sorvell): can't use textContent since we patch it on Node.prototype!\n // However, should probably patch it only on element.\n content += n.nodeValue;\n }\n\n return content;\n\n default:\n return this.nodeValue;\n }\n },\n // Needed on browsers that do not proper accessors (e.g. old versions of Chrome)\n\n /** @this {Node} */\n set: function set(value) {\n if (typeof value === 'undefined' || value === null) {\n value = '';\n }\n\n switch (this.nodeType) {\n case Node.ELEMENT_NODE:\n case Node.DOCUMENT_FRAGMENT_NODE:\n clearNode(this); // Document fragments must have no childnodes if setting a blank string\n\n if (value.length > 0 || this.nodeType === Node.ELEMENT_NODE) {\n // Note: old Chrome versions require 2nd argument here\n this[patch_native_NATIVE_PREFIX + 'insertBefore'](document.createTextNode(value), undefined);\n }\n\n break;\n\n default:\n // TODO(sorvell): can't do this if patch nodeValue.\n this.nodeValue = value;\n break;\n }\n }\n }\n });\n }\n\n copyProperties(Node.prototype, ['appendChild', 'insertBefore', 'removeChild', 'replaceChild', 'cloneNode', 'contains']);\n var ParentNodeWalkerDescriptors = {\n firstElementChild: {\n /** @this {ParentNode} */\n get: function get() {\n elementWalker.currentNode = this;\n return elementWalker.firstChild();\n }\n },\n lastElementChild: {\n /** @this {ParentNode} */\n get: function get() {\n elementWalker.currentNode = this;\n return elementWalker.lastChild();\n }\n },\n children: {\n /** @this {ParentNode} */\n get: function get() {\n var nodes = [];\n elementWalker.currentNode = this;\n var n = elementWalker.firstChild();\n\n while (n) {\n nodes.push(n);\n n = elementWalker.nextSibling();\n }\n\n return createPolyfilledHTMLCollection(nodes);\n }\n },\n childElementCount: {\n /** @this {ParentNode} */\n get: function get() {\n if (this.children) {\n return this.children.length;\n }\n\n return 0;\n }\n }\n }; // Element\n\n if (hasDescriptors) {\n copyProperties(Element.prototype, ParentNodeAccessors);\n copyProperties(Element.prototype, ['previousElementSibling', 'nextElementSibling', 'innerHTML']); // NOTE, on IE 11 / Edge 15 children and/or innerHTML are on HTMLElement instead of Element\n\n if (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children')) {\n copyProperties(HTMLElement.prototype, ['children']);\n }\n\n if (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'innerHTML')) {\n copyProperties(HTMLElement.prototype, ['innerHTML']);\n }\n } else {\n patch_native_defineNativeAccessors(Element.prototype, ParentNodeWalkerDescriptors);\n patch_native_defineNativeAccessors(Element.prototype, {\n previousElementSibling: {\n /** @this {Element} */\n get: function get() {\n elementWalker.currentNode = this;\n return elementWalker.previousSibling();\n }\n },\n nextElementSibling: {\n /** @this {Element} */\n get: function get() {\n elementWalker.currentNode = this;\n return elementWalker.nextSibling();\n }\n },\n innerHTML: {\n /** @this {Element} */\n get: function get() {\n return getInnerHTML(this, function (n) {\n return n[patch_native_NATIVE_PREFIX + 'childNodes'];\n });\n },\n // Needed on browsers that do not proper accessors (e.g. old versions of Chrome)\n\n /** @this {Element} */\n set: function set(value) {\n var content = this.localName === 'template' ?\n /** @type {HTMLTemplateElement} */\n this.content : this;\n clearNode(content);\n var containerName = this.localName || 'div';\n var htmlContainer;\n\n if (!this.namespaceURI || this.namespaceURI === inertDoc.namespaceURI) {\n htmlContainer = inertDoc.createElement(containerName);\n } else {\n htmlContainer = inertDoc.createElementNS(this.namespaceURI, containerName);\n }\n\n htmlContainer.innerHTML = value;\n var newContent = this.localName === 'template' ?\n /** @type {HTMLTemplateElement} */\n htmlContainer.content : htmlContainer;\n var firstChild;\n\n while (firstChild = newContent[patch_native_NATIVE_PREFIX + 'firstChild']) {\n // Note: old Chrome versions require 2nd argument here\n content[patch_native_NATIVE_PREFIX + 'insertBefore'](firstChild, undefined);\n }\n }\n }\n });\n }\n\n copyProperties(Element.prototype, ['setAttribute', 'getAttribute', 'hasAttribute', 'removeAttribute', // on older Safari, these are on Element.\n 'focus', 'blur']);\n copyProperties(Element.prototype, ParentNodeMethods); // HTMLElement\n\n copyProperties(HTMLElement.prototype, ['focus', 'blur', // On IE these are on HTMLElement\n 'contains']);\n\n if (hasDescriptors) {\n copyProperties(HTMLElement.prototype, ['parentElement', 'children', 'innerHTML']);\n } // HTMLTemplateElement\n\n\n if (window.HTMLTemplateElement) {\n copyProperties(window.HTMLTemplateElement.prototype, ['innerHTML']);\n } // DocumentFragment\n\n\n if (hasDescriptors) {\n // NOTE, IE 11 does not have on DocumentFragment\n // firstElementChild\n // lastElementChild\n copyProperties(DocumentFragment.prototype, ParentNodeAccessors);\n } else {\n patch_native_defineNativeAccessors(DocumentFragment.prototype, ParentNodeWalkerDescriptors);\n }\n\n copyProperties(DocumentFragment.prototype, ParentNodeMethods); // Document\n\n if (hasDescriptors) {\n copyProperties(Document.prototype, ParentNodeAccessors);\n copyProperties(Document.prototype, ['activeElement']);\n } else {\n patch_native_defineNativeAccessors(Document.prototype, ParentNodeWalkerDescriptors);\n }\n\n copyProperties(Document.prototype, ['importNode', 'getElementById']);\n copyProperties(Document.prototype, ParentNodeMethods);\n};\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patch-instances.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\nvar InsideDescriptors = getOwnPropertyDescriptors({\n /** @this {Node} */\n get childNodes() {\n return this[SHADY_PREFIX + 'childNodes'];\n },\n\n /** @this {Node} */\n get firstChild() {\n return this[SHADY_PREFIX + 'firstChild'];\n },\n\n /** @this {Node} */\n get lastChild() {\n return this[SHADY_PREFIX + 'lastChild'];\n },\n\n /** @this {Node} */\n get textContent() {\n return this[SHADY_PREFIX + 'textContent'];\n },\n\n /** @this {Node} */\n set textContent(value) {\n this[SHADY_PREFIX + 'textContent'] = value;\n },\n\n /** @this {Node} */\n get childElementCount() {\n return this[SHADY_PREFIX + 'childElementCount'];\n },\n\n /** @this {Node} */\n get children() {\n return this[SHADY_PREFIX + 'children'];\n },\n\n /** @this {Node} */\n get firstElementChild() {\n return this[SHADY_PREFIX + 'firstElementChild'];\n },\n\n /** @this {Node} */\n get lastElementChild() {\n return this[SHADY_PREFIX + 'lastElementChild'];\n },\n\n /** @this {Node} */\n get innerHTML() {\n return this[SHADY_PREFIX + 'innerHTML'];\n },\n\n /** @this {Node} */\n set innerHTML(value) {\n return this[SHADY_PREFIX + 'innerHTML'] = value;\n },\n\n /** @this {Node} */\n get shadowRoot() {\n return this[SHADY_PREFIX + 'shadowRoot'];\n }\n\n});\nvar OutsideDescriptors = getOwnPropertyDescriptors({\n /** @this {Node} */\n get parentElement() {\n return this[SHADY_PREFIX + 'parentElement'];\n },\n\n /** @this {Node} */\n get parentNode() {\n return this[SHADY_PREFIX + 'parentNode'];\n },\n\n /** @this {Node} */\n get nextSibling() {\n return this[SHADY_PREFIX + 'nextSibling'];\n },\n\n /** @this {Node} */\n get previousSibling() {\n return this[SHADY_PREFIX + 'previousSibling'];\n },\n\n /** @this {Node} */\n get nextElementSibling() {\n return this[SHADY_PREFIX + 'nextElementSibling'];\n },\n\n /** @this {Node} */\n get previousElementSibling() {\n return this[SHADY_PREFIX + 'previousElementSibling'];\n },\n\n /** @this {Node} */\n get className() {\n return this[SHADY_PREFIX + 'className'];\n },\n\n /** @this {Node} */\n set className(value) {\n return this[SHADY_PREFIX + 'className'] = value;\n }\n\n});\n\nfor (var patch_instances_prop in InsideDescriptors) {\n InsideDescriptors[patch_instances_prop].enumerable = false;\n}\n\nfor (var _prop in OutsideDescriptors) {\n OutsideDescriptors[_prop].enumerable = false;\n}\n\nvar noInstancePatching = settings.hasDescriptors || settings.noPatch; // ensure an element has patched \"outside\" accessors; no-op when not needed\n\nvar patchOutsideElementAccessors = noInstancePatching ? function () {} : function (element) {\n var sd = ensureShadyDataForNode(element);\n\n if (!sd.__outsideAccessors) {\n sd.__outsideAccessors = true;\n patchProperties(element, OutsideDescriptors);\n }\n}; // ensure an element has patched \"inside\" accessors; no-op when not needed\n\nvar patchInsideElementAccessors = noInstancePatching ? function () {} : function (element) {\n var sd = ensureShadyDataForNode(element);\n\n if (!sd.__insideAccessors) {\n sd.__insideAccessors = true;\n patchProperties(element, InsideDescriptors);\n }\n};\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patch-events.js\nfunction _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n/*\nMake this name unique so it is unlikely to conflict with properties on objects passed to `addEventListener`\nhttps://github.com/webcomponents/shadydom/issues/173\n*/\n\nvar\n/** string */\neventWrappersName = \"__eventWrappers\".concat(Date.now());\n/** @type {?function(!Event): boolean} */\n\nvar composedGetter = function () {\n var composedProp = Object.getOwnPropertyDescriptor(Event.prototype, 'composed');\n return composedProp ? function (ev) {\n return composedProp.get.call(ev);\n } : null;\n}(); // https://github.com/w3c/webcomponents/issues/513#issuecomment-224183937\n\n\nvar alwaysComposed = {\n 'blur': true,\n 'focus': true,\n 'focusin': true,\n 'focusout': true,\n 'click': true,\n 'dblclick': true,\n 'mousedown': true,\n 'mouseenter': true,\n 'mouseleave': true,\n 'mousemove': true,\n 'mouseout': true,\n 'mouseover': true,\n 'mouseup': true,\n 'wheel': true,\n 'beforeinput': true,\n 'input': true,\n 'keydown': true,\n 'keyup': true,\n 'compositionstart': true,\n 'compositionupdate': true,\n 'compositionend': true,\n 'touchstart': true,\n 'touchend': true,\n 'touchmove': true,\n 'touchcancel': true,\n 'pointerover': true,\n 'pointerenter': true,\n 'pointerdown': true,\n 'pointermove': true,\n 'pointerup': true,\n 'pointercancel': true,\n 'pointerout': true,\n 'pointerleave': true,\n 'gotpointercapture': true,\n 'lostpointercapture': true,\n 'dragstart': true,\n 'drag': true,\n 'dragenter': true,\n 'dragleave': true,\n 'dragover': true,\n 'drop': true,\n 'dragend': true,\n 'DOMActivate': true,\n 'DOMFocusIn': true,\n 'DOMFocusOut': true,\n 'keypress': true\n};\nvar unpatchedEvents = {\n 'DOMAttrModified': true,\n 'DOMAttributeNameChanged': true,\n 'DOMCharacterDataModified': true,\n 'DOMElementNameChanged': true,\n 'DOMNodeInserted': true,\n 'DOMNodeInsertedIntoDocument': true,\n 'DOMNodeRemoved': true,\n 'DOMNodeRemovedFromDocument': true,\n 'DOMSubtreeModified': true\n /**\n * Some EventTarget subclasses are not Node subclasses, and you cannot call\n * `getRootNode()` on them.\n *\n * @param {!(Node|EventTarget)} eventTarget\n * @return {!(Node|EventTarget)}\n */\n\n};\n\nfunction getRootNodeWithFallback(eventTarget) {\n if (eventTarget instanceof Node) {\n return eventTarget[SHADY_PREFIX + 'getRootNode']();\n } else {\n return eventTarget;\n }\n}\n\nfunction pathComposer(startNode, composed) {\n var composedPath = [];\n var current = startNode;\n var startRoot = getRootNodeWithFallback(startNode);\n\n while (current) {\n composedPath.push(current);\n\n if (current[SHADY_PREFIX + 'assignedSlot']) {\n current = current[SHADY_PREFIX + 'assignedSlot'];\n } else if (current.nodeType === Node.DOCUMENT_FRAGMENT_NODE && current.host && (composed || current !== startRoot)) {\n current = current.host;\n } else {\n current = current[SHADY_PREFIX + 'parentNode'];\n }\n } // event composedPath includes window when startNode's ownerRoot is document\n\n\n if (composedPath[composedPath.length - 1] === document) {\n composedPath.push(window);\n }\n\n return composedPath;\n}\n\nvar patch_events_composedPath = function composedPath(event) {\n if (!event.__composedPath) {\n event.__composedPath = pathComposer(event.target, true);\n }\n\n return event.__composedPath;\n};\n\nfunction retarget(refNode, path) {\n if (!utils_isShadyRoot) {\n return refNode;\n } // If ANCESTOR's root is not a shadow root or ANCESTOR's root is BASE's\n // shadow-including inclusive ancestor, return ANCESTOR.\n\n\n var refNodePath = pathComposer(refNode, true);\n var p$ = path;\n\n for (var i = 0, ancestor, lastRoot, root, rootIdx; i < p$.length; i++) {\n ancestor = p$[i];\n root = getRootNodeWithFallback(ancestor);\n\n if (root !== lastRoot) {\n rootIdx = refNodePath.indexOf(root);\n lastRoot = root;\n }\n\n if (!utils_isShadyRoot(root) || rootIdx > -1) {\n return ancestor;\n }\n }\n}\n\nvar EventPatches = {\n /**\n * @this {Event}\n */\n get composed() {\n if (this.__composed === undefined) {\n // if there's an original `composed` getter on the Event prototype, use that\n if (composedGetter) {\n // TODO(web-padawan): see https://github.com/webcomponents/shadydom/issues/275\n this.__composed = this.type === 'focusin' || this.type === 'focusout' || composedGetter(this); // If the event is trusted, or `isTrusted` is not supported, check the list of always composed events\n } else if (this.isTrusted !== false) {\n this.__composed = alwaysComposed[this.type];\n }\n }\n\n return (\n /** @type {!Event} */\n this.__composed || false\n );\n },\n\n /**\n * @this {Event}\n */\n composedPath: function composedPath() {\n if (!this.__composedPath) {\n this.__composedPath = pathComposer(this['__target'], this.composed);\n }\n\n return (\n /** @type {!Event} */\n this.__composedPath\n );\n },\n\n /**\n * @this {Event}\n */\n get target() {\n return retarget(this.currentTarget || this['__previousCurrentTarget'], this.composedPath());\n },\n\n // http://w3c.github.io/webcomponents/spec/shadow/#event-relatedtarget-retargeting\n\n /**\n * @this {Event}\n */\n get relatedTarget() {\n if (!this.__relatedTarget) {\n return null;\n }\n\n if (!this.__relatedTargetComposedPath) {\n this.__relatedTargetComposedPath = pathComposer(this.__relatedTarget, true);\n } // find the deepest node in relatedTarget composed path that is in the same root with the currentTarget\n\n\n return retarget(this.currentTarget || this['__previousCurrentTarget'],\n /** @type {!Event} */\n this.__relatedTargetComposedPath);\n },\n\n /**\n * @this {Event}\n */\n stopPropagation: function stopPropagation() {\n Event.prototype.stopPropagation.call(this);\n this.__propagationStopped = true;\n },\n\n /**\n * @this {Event}\n */\n stopImmediatePropagation: function stopImmediatePropagation() {\n Event.prototype.stopImmediatePropagation.call(this);\n this.__immediatePropagationStopped = true;\n this.__propagationStopped = true;\n }\n};\n\nfunction mixinComposedFlag(Base) {\n // NOTE: avoiding use of `class` here so that transpiled output does not\n // try to do `Base.call` with a dom construtor.\n var klazz = function klazz(type, options) {\n var event = new Base(type, options);\n event.__composed = options && Boolean(options['composed']);\n return event;\n }; // put constructor properties on subclass\n\n\n klazz.__proto__ = Base;\n klazz.prototype = Base.prototype;\n return klazz;\n}\n\nvar nonBubblingEventsToRetarget = {\n 'focus': true,\n 'blur': true\n};\n/**\n * Check if the event has been retargeted by comparing original `target`, and calculated `target`\n * @param {Event} event\n * @return {boolean} True if the original target and calculated target are the same\n */\n\nfunction hasRetargeted(event) {\n return event['__target'] !== event.target || event.__relatedTarget !== event.relatedTarget;\n}\n/**\n *\n * @param {Event} event\n * @param {Node} node\n * @param {string} phase\n */\n\n\nfunction fireHandlers(event, node, phase) {\n var hs = node.__handlers && node.__handlers[event.type] && node.__handlers[event.type][phase];\n\n if (hs) {\n for (var i = 0, fn; fn = hs[i]; i++) {\n if (hasRetargeted(event) && event.target === event.relatedTarget) {\n return;\n }\n\n fn.call(node, event);\n\n if (event.__immediatePropagationStopped) {\n return;\n }\n }\n }\n}\n\nfunction retargetNonBubblingEvent(e) {\n var path = e.composedPath();\n var node; // override `currentTarget` to let patched `target` calculate correctly\n\n Object.defineProperty(e, 'currentTarget', {\n get: function get() {\n return node;\n },\n configurable: true\n });\n\n for (var i = path.length - 1; i >= 0; i--) {\n node = path[i]; // capture phase fires all capture handlers\n\n fireHandlers(e, node, 'capture');\n\n if (e.__propagationStopped) {\n return;\n }\n } // set the event phase to `AT_TARGET` as in spec\n\n\n Object.defineProperty(e, 'eventPhase', {\n get: function get() {\n return Event.AT_TARGET;\n }\n }); // the event only needs to be fired when owner roots change when iterating the event path\n // keep track of the last seen owner root\n\n var lastFiredRoot;\n\n for (var _i = 0; _i < path.length; _i++) {\n node = path[_i];\n var nodeData = shadyDataForNode(node);\n var root = nodeData && nodeData.root;\n\n if (_i === 0 || root && root === lastFiredRoot) {\n fireHandlers(e, node, 'bubble'); // don't bother with window, it doesn't have `getRootNode` and will be last in the path anyway\n\n if (node !== window) {\n lastFiredRoot = node[SHADY_PREFIX + 'getRootNode']();\n }\n\n if (e.__propagationStopped) {\n return;\n }\n }\n }\n}\n\nfunction listenerSettingsEqual(savedListener, node, type, capture, once, passive) {\n var savedNode = savedListener.node,\n savedType = savedListener.type,\n savedCapture = savedListener.capture,\n savedOnce = savedListener.once,\n savedPassive = savedListener.passive;\n return node === savedNode && type === savedType && capture === savedCapture && once === savedOnce && passive === savedPassive;\n}\n\nfunction findListener(wrappers, node, type, capture, once, passive) {\n for (var i = 0; i < wrappers.length; i++) {\n if (listenerSettingsEqual(wrappers[i], node, type, capture, once, passive)) {\n return i;\n }\n }\n\n return -1;\n}\n/**\n * Firefox can throw on accessing eventWrappers inside of `removeEventListener` during a selenium run\n * Try/Catch accessing eventWrappers to work around\n * https://bugzilla.mozilla.org/show_bug.cgi?id=1353074\n */\n\nfunction getEventWrappers(eventLike) {\n var wrappers = null;\n\n try {\n wrappers = eventLike[eventWrappersName];\n } catch (e) {} // eslint-disable-line no-empty\n\n\n return wrappers;\n}\n/**\n * @this {EventTarget}\n */\n\n\nfunction patch_events_addEventListener(type, fnOrObj, optionsOrCapture) {\n if (!fnOrObj) {\n return;\n }\n\n var handlerType = _typeof(fnOrObj); // bail if `fnOrObj` is not a function, not an object\n\n\n if (handlerType !== 'function' && handlerType !== 'object') {\n return;\n } // bail if `fnOrObj` is an object without a `handleEvent` method\n\n\n if (handlerType === 'object' && (!fnOrObj.handleEvent || typeof fnOrObj.handleEvent !== 'function')) {\n return;\n }\n\n if (unpatchedEvents[type]) {\n return this[NATIVE_PREFIX + 'addEventListener'](type, fnOrObj, optionsOrCapture);\n } // The callback `fn` might be used for multiple nodes/events. Since we generate\n // a wrapper function, we need to keep track of it when we remove the listener.\n // It's more efficient to store the node/type/options information as Array in\n // `fn` itself rather than the node (we assume that the same callback is used\n // for few nodes at most, whereas a node will likely have many event listeners).\n // NOTE(valdrin) invoking external functions is costly, inline has better perf.\n\n\n var capture, once, passive;\n\n if (optionsOrCapture && _typeof(optionsOrCapture) === 'object') {\n capture = Boolean(optionsOrCapture.capture);\n once = Boolean(optionsOrCapture.once);\n passive = Boolean(optionsOrCapture.passive);\n } else {\n capture = Boolean(optionsOrCapture);\n once = false;\n passive = false;\n } // hack to let ShadyRoots have event listeners\n // event listener will be on host, but `currentTarget`\n // will be set to shadyroot for event listener\n\n\n var target = optionsOrCapture && optionsOrCapture.__shadyTarget || this;\n var wrappers = fnOrObj[eventWrappersName];\n\n if (wrappers) {\n // Stop if the wrapper function has already been created.\n if (findListener(wrappers, target, type, capture, once, passive) > -1) {\n return;\n }\n } else {\n fnOrObj[eventWrappersName] = [];\n }\n /**\n * @this {HTMLElement}\n * @param {Event} e\n */\n\n\n var wrapperFn = function wrapperFn(e) {\n // Support `once` option.\n if (once) {\n this[SHADY_PREFIX + 'removeEventListener'](type, fnOrObj, optionsOrCapture);\n }\n\n if (!e['__target']) {\n patchEvent(e);\n }\n\n var lastCurrentTargetDesc;\n\n if (target !== this) {\n // replace `currentTarget` to make `target` and `relatedTarget` correct for inside the shadowroot\n lastCurrentTargetDesc = Object.getOwnPropertyDescriptor(e, 'currentTarget');\n Object.defineProperty(e, 'currentTarget', {\n get: function get() {\n return target;\n },\n configurable: true\n });\n }\n\n e['__previousCurrentTarget'] = e['currentTarget']; // Always check if a shadowRoot is in the current event path.\n // If it is not, the event was generated on either the host of the shadowRoot\n // or a children of the host.\n\n if (utils_isShadyRoot(target) && e.composedPath().indexOf(target) == -1) {\n return;\n } // There are two critera that should stop events from firing on this node\n // 1. the event is not composed and the current node is not in the same root as the target\n // 2. when bubbling, if after retargeting, relatedTarget and target point to the same node\n\n\n if (e.composed || e.composedPath().indexOf(target) > -1) {\n if (hasRetargeted(e) && e.target === e.relatedTarget) {\n if (e.eventPhase === Event.BUBBLING_PHASE) {\n e.stopImmediatePropagation();\n }\n\n return;\n } // prevent non-bubbling events from triggering bubbling handlers on shadowroot, but only if not in capture phase\n\n\n if (e.eventPhase !== Event.CAPTURING_PHASE && !e.bubbles && e.target !== target && !(target instanceof Window)) {\n return;\n }\n\n var ret = handlerType === 'function' ? fnOrObj.call(target, e) : fnOrObj.handleEvent && fnOrObj.handleEvent(e);\n\n if (target !== this) {\n // replace the \"correct\" `currentTarget`\n if (lastCurrentTargetDesc) {\n Object.defineProperty(e, 'currentTarget', lastCurrentTargetDesc);\n lastCurrentTargetDesc = null;\n } else {\n delete e['currentTarget'];\n }\n }\n\n return ret;\n }\n }; // Store the wrapper information.\n\n\n fnOrObj[eventWrappersName].push({\n // note: use target here which is either a shadowRoot\n // (when the host element is proxy'ing the event) or this element\n node: target,\n type: type,\n capture: capture,\n once: once,\n passive: passive,\n wrapperFn: wrapperFn\n });\n\n if (nonBubblingEventsToRetarget[type]) {\n this.__handlers = this.__handlers || {};\n this.__handlers[type] = this.__handlers[type] || {\n 'capture': [],\n 'bubble': []\n };\n\n this.__handlers[type][capture ? 'capture' : 'bubble'].push(wrapperFn);\n } else {\n this[NATIVE_PREFIX + 'addEventListener'](type, wrapperFn, optionsOrCapture);\n }\n}\n/**\n * @this {EventTarget}\n */\n\nfunction patch_events_removeEventListener(type, fnOrObj, optionsOrCapture) {\n if (!fnOrObj) {\n return;\n }\n\n if (unpatchedEvents[type]) {\n return this[NATIVE_PREFIX + 'removeEventListener'](type, fnOrObj, optionsOrCapture);\n } // NOTE(valdrin) invoking external functions is costly, inline has better perf.\n\n\n var capture, once, passive;\n\n if (optionsOrCapture && _typeof(optionsOrCapture) === 'object') {\n capture = Boolean(optionsOrCapture.capture);\n once = Boolean(optionsOrCapture.once);\n passive = Boolean(optionsOrCapture.passive);\n } else {\n capture = Boolean(optionsOrCapture);\n once = false;\n passive = false;\n }\n\n var target = optionsOrCapture && optionsOrCapture.__shadyTarget || this; // Search the wrapped function.\n\n var wrapperFn = undefined;\n var wrappers = getEventWrappers(fnOrObj);\n\n if (wrappers) {\n var idx = findListener(wrappers, target, type, capture, once, passive);\n\n if (idx > -1) {\n wrapperFn = wrappers.splice(idx, 1)[0].wrapperFn; // Cleanup.\n\n if (!wrappers.length) {\n fnOrObj[eventWrappersName] = undefined;\n }\n }\n }\n\n this[NATIVE_PREFIX + 'removeEventListener'](type, wrapperFn || fnOrObj, optionsOrCapture);\n\n if (wrapperFn && nonBubblingEventsToRetarget[type] && this.__handlers && this.__handlers[type]) {\n var arr = this.__handlers[type][capture ? 'capture' : 'bubble'];\n\n var _idx = arr.indexOf(wrapperFn);\n\n if (_idx > -1) {\n arr.splice(_idx, 1);\n }\n }\n}\n\nfunction activateFocusEventOverrides() {\n for (var ev in nonBubblingEventsToRetarget) {\n window[NATIVE_PREFIX + 'addEventListener'](ev, function (e) {\n if (!e['__target']) {\n patchEvent(e);\n retargetNonBubblingEvent(e);\n }\n }, true);\n }\n}\n\nvar EventPatchesDescriptors = getOwnPropertyDescriptors(EventPatches);\nvar SHADY_PROTO = '__shady_patchedProto';\nvar SHADY_SOURCE_PROTO = '__shady_sourceProto';\n\nfunction patchEvent(event) {\n event['__target'] = event.target;\n event.__relatedTarget = event.relatedTarget; // attempt to patch prototype (via cache)\n\n if (settings.hasDescriptors) {\n var proto = Object.getPrototypeOf(event);\n\n if (!Object.hasOwnProperty(proto, SHADY_PROTO)) {\n var patchedProto = Object.create(proto);\n patchedProto[SHADY_SOURCE_PROTO] = proto;\n patchProperties(patchedProto, EventPatchesDescriptors);\n proto[SHADY_PROTO] = patchedProto;\n }\n\n event.__proto__ = proto[SHADY_PROTO]; // and fallback to patching instance\n } else {\n patchProperties(event, EventPatchesDescriptors);\n }\n}\n\nvar PatchedEvent = mixinComposedFlag(Event);\nvar PatchedCustomEvent = mixinComposedFlag(CustomEvent);\nvar PatchedMouseEvent = mixinComposedFlag(MouseEvent);\nfunction patchEvents() {\n activateFocusEventOverrides();\n window.Event = PatchedEvent;\n window.CustomEvent = PatchedCustomEvent;\n window.MouseEvent = PatchedMouseEvent;\n}\nfunction patchClick() {\n // Fix up `Element.prototype.click()` if `isTrusted` is supported, but `composed` isn't\n if (!composedGetter && Object.getOwnPropertyDescriptor(Event.prototype, 'isTrusted')) {\n /** @this {Element} */\n var composedClickFn = function composedClickFn() {\n var ev = new MouseEvent('click', {\n bubbles: true,\n cancelable: true,\n composed: true\n });\n this[SHADY_PREFIX + 'dispatchEvent'](ev);\n };\n\n if (Element.prototype.click) {\n Element.prototype.click = composedClickFn;\n } else if (HTMLElement.prototype.click) {\n HTMLElement.prototype.click = composedClickFn;\n }\n }\n}\nvar eventPropertyNames = Object.getOwnPropertyNames(Document.prototype).filter(function (name) {\n return name.substring(0, 2) === 'on';\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/array-splice.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\nfunction newSplice(index, removed, addedCount) {\n return {\n index: index,\n removed: removed,\n addedCount: addedCount\n };\n}\n\nvar EDIT_LEAVE = 0;\nvar EDIT_UPDATE = 1;\nvar EDIT_ADD = 2;\nvar EDIT_DELETE = 3; // Note: This function is *based* on the computation of the Levenshtein\n// \"edit\" distance. The one change is that \"updates\" are treated as two\n// edits - not one. With Array splices, an update is really a delete\n// followed by an add. By retaining this, we optimize for \"keeping\" the\n// maximum array items in the original array. For example:\n//\n// 'xxxx123' -> '123yyyy'\n//\n// With 1-edit updates, the shortest path would be just to update all seven\n// characters. With 2-edit updates, we delete 4, leave 3, and add 4. This\n// leaves the substring '123' intact.\n\nfunction calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd) {\n // \"Deletion\" columns\n var rowCount = oldEnd - oldStart + 1;\n var columnCount = currentEnd - currentStart + 1;\n var distances = new Array(rowCount); // \"Addition\" rows. Initialize null column.\n\n for (var i = 0; i < rowCount; i++) {\n distances[i] = new Array(columnCount);\n distances[i][0] = i;\n } // Initialize null row\n\n\n for (var j = 0; j < columnCount; j++) {\n distances[0][j] = j;\n }\n\n for (var _i = 1; _i < rowCount; _i++) {\n for (var _j = 1; _j < columnCount; _j++) {\n if (equals(current[currentStart + _j - 1], old[oldStart + _i - 1])) distances[_i][_j] = distances[_i - 1][_j - 1];else {\n var north = distances[_i - 1][_j] + 1;\n var west = distances[_i][_j - 1] + 1;\n distances[_i][_j] = north < west ? north : west;\n }\n }\n }\n\n return distances;\n} // This starts at the final weight, and walks \"backward\" by finding\n// the minimum previous weight recursively until the origin of the weight\n// matrix.\n\n\nfunction spliceOperationsFromEditDistances(distances) {\n var i = distances.length - 1;\n var j = distances[0].length - 1;\n var current = distances[i][j];\n var edits = [];\n\n while (i > 0 || j > 0) {\n if (i == 0) {\n edits.push(EDIT_ADD);\n j--;\n continue;\n }\n\n if (j == 0) {\n edits.push(EDIT_DELETE);\n i--;\n continue;\n }\n\n var northWest = distances[i - 1][j - 1];\n var west = distances[i - 1][j];\n var north = distances[i][j - 1];\n var min = void 0;\n if (west < north) min = west < northWest ? west : northWest;else min = north < northWest ? north : northWest;\n\n if (min == northWest) {\n if (northWest == current) {\n edits.push(EDIT_LEAVE);\n } else {\n edits.push(EDIT_UPDATE);\n current = northWest;\n }\n\n i--;\n j--;\n } else if (min == west) {\n edits.push(EDIT_DELETE);\n i--;\n current = west;\n } else {\n edits.push(EDIT_ADD);\n j--;\n current = north;\n }\n }\n\n edits.reverse();\n return edits;\n}\n/**\n * Splice Projection functions:\n *\n * A splice map is a representation of how a previous array of items\n * was transformed into a new array of items. Conceptually it is a list of\n * tuples of\n *\n * \n *\n * which are kept in ascending index order of. The tuple represents that at\n * the |index|, |removed| sequence of items were removed, and counting forward\n * from |index|, |addedCount| items were added.\n */\n\n/**\n * Lacking individual splice mutation information, the minimal set of\n * splices can be synthesized given the previous state and final state of an\n * array. The basic approach is to calculate the edit distance matrix and\n * choose the shortest path through it.\n *\n * Complexity: O(l * p)\n * l: The length of the current array\n * p: The length of the old array\n */\n\n\nfunction calcSplices(current, currentStart, currentEnd, old, oldStart, oldEnd) {\n var prefixCount = 0;\n var suffixCount = 0;\n var splice;\n var minLength = Math.min(currentEnd - currentStart, oldEnd - oldStart);\n if (currentStart == 0 && oldStart == 0) prefixCount = sharedPrefix(current, old, minLength);\n if (currentEnd == current.length && oldEnd == old.length) suffixCount = sharedSuffix(current, old, minLength - prefixCount);\n currentStart += prefixCount;\n oldStart += prefixCount;\n currentEnd -= suffixCount;\n oldEnd -= suffixCount;\n if (currentEnd - currentStart == 0 && oldEnd - oldStart == 0) return [];\n\n if (currentStart == currentEnd) {\n splice = newSplice(currentStart, [], 0);\n\n while (oldStart < oldEnd) {\n splice.removed.push(old[oldStart++]);\n }\n\n return [splice];\n } else if (oldStart == oldEnd) return [newSplice(currentStart, [], currentEnd - currentStart)];\n\n var ops = spliceOperationsFromEditDistances(calcEditDistances(current, currentStart, currentEnd, old, oldStart, oldEnd));\n splice = undefined;\n var splices = [];\n var index = currentStart;\n var oldIndex = oldStart;\n\n for (var i = 0; i < ops.length; i++) {\n switch (ops[i]) {\n case EDIT_LEAVE:\n if (splice) {\n splices.push(splice);\n splice = undefined;\n }\n\n index++;\n oldIndex++;\n break;\n\n case EDIT_UPDATE:\n if (!splice) splice = newSplice(index, [], 0);\n splice.addedCount++;\n index++;\n splice.removed.push(old[oldIndex]);\n oldIndex++;\n break;\n\n case EDIT_ADD:\n if (!splice) splice = newSplice(index, [], 0);\n splice.addedCount++;\n index++;\n break;\n\n case EDIT_DELETE:\n if (!splice) splice = newSplice(index, [], 0);\n splice.removed.push(old[oldIndex]);\n oldIndex++;\n break;\n }\n }\n\n if (splice) {\n splices.push(splice);\n }\n\n return splices;\n}\n\nfunction sharedPrefix(current, old, searchLength) {\n for (var i = 0; i < searchLength; i++) {\n if (!equals(current[i], old[i])) return i;\n }\n\n return searchLength;\n}\n\nfunction sharedSuffix(current, old, searchLength) {\n var index1 = current.length;\n var index2 = old.length;\n var count = 0;\n\n while (count < searchLength && equals(current[--index1], old[--index2])) {\n count++;\n }\n\n return count;\n}\n\nfunction equals(currentValue, previousValue) {\n return currentValue === previousValue;\n}\n\nfunction calculateSplices(current, previous) {\n return calcSplices(current, 0, current.length, previous, 0, previous.length);\n}\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/link-nodes.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\n\nfunction linkNode(node, container, ref_node) {\n patchOutsideElementAccessors(node);\n ref_node = ref_node || null;\n var nodeData = ensureShadyDataForNode(node);\n var containerData = ensureShadyDataForNode(container);\n var ref_nodeData = ref_node ? ensureShadyDataForNode(ref_node) : null; // update ref_node.previousSibling <-> node\n\n nodeData.previousSibling = ref_node ? ref_nodeData.previousSibling : container[SHADY_PREFIX + 'lastChild'];\n var psd = shadyDataForNode(nodeData.previousSibling);\n\n if (psd) {\n psd.nextSibling = node;\n } // update node <-> ref_node\n\n\n var nsd = shadyDataForNode(nodeData.nextSibling = ref_node);\n\n if (nsd) {\n nsd.previousSibling = node;\n } // update node <-> container\n\n\n nodeData.parentNode = container;\n\n if (ref_node) {\n if (ref_node === containerData.firstChild) {\n containerData.firstChild = node;\n }\n } else {\n containerData.lastChild = node;\n\n if (!containerData.firstChild) {\n containerData.firstChild = node;\n }\n } // remove caching of childNodes\n\n\n containerData.childNodes = null;\n}\n\nvar link_nodes_recordInsertBefore = function recordInsertBefore(node, container, ref_node) {\n patchInsideElementAccessors(container);\n var containerData = ensureShadyDataForNode(container);\n\n if (containerData.firstChild !== undefined) {\n containerData.childNodes = null;\n } // handle document fragments\n\n\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n var c$ = node[SHADY_PREFIX + 'childNodes'];\n\n for (var i = 0; i < c$.length; i++) {\n linkNode(c$[i], container, ref_node);\n } // cleanup logical dom in doc fragment.\n\n\n var nodeData = ensureShadyDataForNode(node);\n var resetTo = nodeData.firstChild !== undefined ? null : undefined;\n nodeData.firstChild = nodeData.lastChild = resetTo;\n nodeData.childNodes = resetTo;\n } else {\n linkNode(node, container, ref_node);\n }\n};\nvar link_nodes_recordRemoveChild = function recordRemoveChild(node, container) {\n var nodeData = ensureShadyDataForNode(node);\n var containerData = ensureShadyDataForNode(container);\n\n if (node === containerData.firstChild) {\n containerData.firstChild = nodeData.nextSibling;\n }\n\n if (node === containerData.lastChild) {\n containerData.lastChild = nodeData.previousSibling;\n }\n\n var p = nodeData.previousSibling;\n var n = nodeData.nextSibling;\n\n if (p) {\n ensureShadyDataForNode(p).nextSibling = n;\n }\n\n if (n) {\n ensureShadyDataForNode(n).previousSibling = p;\n } // When an element is removed, logical data is no longer tracked.\n // Explicitly set `undefined` here to indicate this. This is disginguished\n // from `null` which is set if info is null.\n\n\n nodeData.parentNode = nodeData.previousSibling = nodeData.nextSibling = undefined;\n\n if (containerData.childNodes !== undefined) {\n // remove caching of childNodes\n containerData.childNodes = null;\n }\n};\n/**\n * @param {!Node} node\n */\n\nvar link_nodes_recordChildNodes = function recordChildNodes(node) {\n var nodeData = ensureShadyDataForNode(node);\n\n if (nodeData.firstChild === undefined) {\n // remove caching of childNodes\n nodeData.childNodes = null;\n var first = nodeData.firstChild = node[NATIVE_PREFIX + 'firstChild'] || null;\n nodeData.lastChild = node[NATIVE_PREFIX + 'lastChild'] || null;\n patchInsideElementAccessors(node);\n\n for (var n = first, previous; n; n = n[NATIVE_PREFIX + 'nextSibling']) {\n var sd = ensureShadyDataForNode(n);\n sd.parentNode = node;\n sd.nextSibling = n[NATIVE_PREFIX + 'nextSibling'] || null;\n sd.previousSibling = previous || null;\n previous = n;\n patchOutsideElementAccessors(n);\n }\n }\n};\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/style-scoping.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nvar style_scoping_scopingShim = null;\nfunction getScopingShim() {\n if (!style_scoping_scopingShim) {\n style_scoping_scopingShim = window['ShadyCSS'] && window['ShadyCSS']['ScopingShim'];\n }\n\n return style_scoping_scopingShim || null;\n}\n/**\n * @param {!Node} node\n * @param {string} attr\n * @param {string} value\n */\n\nfunction scopeClassAttribute(node, attr, value) {\n var scopingShim = getScopingShim();\n\n if (scopingShim && attr === 'class') {\n scopingShim['setElementClass'](node, value);\n return true;\n }\n\n return false;\n}\n/**\n * @param {!Node} node\n * @param {string} newScopeName\n */\n\nfunction addShadyScoping(node, newScopeName) {\n var scopingShim = getScopingShim();\n\n if (!scopingShim) {\n return;\n }\n\n scopingShim['scopeNode'](node, newScopeName);\n}\n/**\n * @param {!Node} node\n * @param {string} currentScopeName\n */\n\nfunction removeShadyScoping(node, currentScopeName) {\n var scopingShim = getScopingShim();\n\n if (!scopingShim) {\n return;\n }\n\n scopingShim['unscopeNode'](node, currentScopeName);\n}\n/**\n * @param {!Node} node\n * @param {string} newScopeName\n * @param {string} oldScopeName\n */\n\nfunction replaceShadyScoping(node, newScopeName, oldScopeName) {\n var scopingShim = getScopingShim();\n\n if (!scopingShim) {\n return;\n }\n\n if (oldScopeName) {\n removeShadyScoping(node, oldScopeName);\n }\n\n addShadyScoping(node, newScopeName);\n}\n/**\n * @param {!Node} node\n * @param {string} newScopeName\n * @return {boolean}\n */\n\nfunction currentScopeIsCorrect(node, newScopeName) {\n var scopingShim = getScopingShim();\n\n if (!scopingShim) {\n return true;\n }\n\n if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {\n // NOTE: as an optimization, only check that all the top-level children\n // have the correct scope.\n var correctScope = true;\n var childNodes = node[SHADY_PREFIX + 'childNodes'];\n\n for (var idx = 0; correctScope && idx < childNodes.length; idx++) {\n correctScope = correctScope && currentScopeIsCorrect(childNodes[idx], newScopeName);\n }\n\n return correctScope;\n }\n\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return true;\n }\n\n var currentScope = scopingShim['currentScopeForNode'](node);\n return currentScope === newScopeName;\n}\n/**\n * @param {!Node} node\n * @return {string}\n */\n\nfunction currentScopeForNode(node) {\n if (node.nodeType !== Node.ELEMENT_NODE) {\n return '';\n }\n\n var scopingShim = getScopingShim();\n\n if (!scopingShim) {\n return '';\n }\n\n return scopingShim['currentScopeForNode'](node);\n}\n/**\n * Walk over a node's tree and apply visitorFn to each element node\n *\n * @param {Node} node\n * @param {function(!Node):void} visitorFn\n */\n\nfunction treeVisitor(node, visitorFn) {\n if (!node) {\n return;\n } // this check is necessary if `node` is a Document Fragment\n\n\n if (node.nodeType === Node.ELEMENT_NODE) {\n visitorFn(node);\n }\n\n var childNodes = node[SHADY_PREFIX + 'childNodes'];\n\n for (var idx = 0, n; idx < childNodes.length; idx++) {\n n = childNodes[idx];\n\n if (n.nodeType === Node.ELEMENT_NODE) {\n treeVisitor(n, visitorFn);\n }\n }\n}\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/Node.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\n\n\nvar doc = window.document;\nvar preferPerformance = settings.preferPerformance;\nvar nativeIsConnectedAccessors =\n/** @type {ObjectPropertyDescriptor} */\nObject.getOwnPropertyDescriptor(Node.prototype, 'isConnected');\nvar nativeIsConnected = nativeIsConnectedAccessors && nativeIsConnectedAccessors.get;\nfunction Node_clearNode(node) {\n var firstChild;\n\n while (firstChild = node[SHADY_PREFIX + 'firstChild']) {\n node[SHADY_PREFIX + 'removeChild'](firstChild);\n }\n}\n\nfunction removeOwnerShadyRoot(node) {\n // optimization: only reset the tree if node is actually in a root\n if (hasCachedOwnerRoot(node)) {\n var c$ = node[SHADY_PREFIX + 'childNodes'];\n\n for (var i = 0, l = c$.length, n; i < l && (n = c$[i]); i++) {\n removeOwnerShadyRoot(n);\n }\n }\n\n var nodeData = shadyDataForNode(node);\n\n if (nodeData) {\n nodeData.ownerShadyRoot = undefined;\n }\n}\n\nfunction hasCachedOwnerRoot(node) {\n var nodeData = shadyDataForNode(node);\n return Boolean(nodeData && nodeData.ownerShadyRoot !== undefined);\n}\n/**\n * Finds the first flattened node that is composed in the node's parent.\n * If the given node is a slot, then the first flattened node is returned\n * if it exists, otherwise advance to the node's nextSibling.\n * @param {Node} node within which to find first composed node\n * @returns {Node} first composed node\n */\n\n\nfunction firstComposedNode(node) {\n var composed = node;\n\n if (node && node.localName === 'slot') {\n var nodeData = shadyDataForNode(node);\n var flattened = nodeData && nodeData.flattenedNodes;\n composed = flattened && flattened.length ? flattened[0] : firstComposedNode(node[SHADY_PREFIX + 'nextSibling']);\n }\n\n return composed;\n}\n/**\n * @param {Node} node\n * @param {Node=} addedNode\n * @param {Node=} removedNode\n */\n\n\nfunction scheduleObserver(node, addedNode, removedNode) {\n var nodeData = shadyDataForNode(node);\n var observer = nodeData && nodeData.observer;\n\n if (observer) {\n if (addedNode) {\n observer.addedNodes.push(addedNode);\n }\n\n if (removedNode) {\n observer.removedNodes.push(removedNode);\n }\n\n observer.schedule();\n }\n}\n\nvar NodePatches = getOwnPropertyDescriptors({\n /** @this {Node} */\n get parentNode() {\n var nodeData = shadyDataForNode(this);\n var l = nodeData && nodeData.parentNode;\n return l !== undefined ? l : this[NATIVE_PREFIX + 'parentNode'];\n },\n\n /** @this {Node} */\n get firstChild() {\n var nodeData = shadyDataForNode(this);\n var l = nodeData && nodeData.firstChild;\n return l !== undefined ? l : this[NATIVE_PREFIX + 'firstChild'];\n },\n\n /** @this {Node} */\n get lastChild() {\n var nodeData = shadyDataForNode(this);\n var l = nodeData && nodeData.lastChild;\n return l !== undefined ? l : this[NATIVE_PREFIX + 'lastChild'];\n },\n\n /** @this {Node} */\n get nextSibling() {\n var nodeData = shadyDataForNode(this);\n var l = nodeData && nodeData.nextSibling;\n return l !== undefined ? l : this[NATIVE_PREFIX + 'nextSibling'];\n },\n\n /** @this {Node} */\n get previousSibling() {\n var nodeData = shadyDataForNode(this);\n var l = nodeData && nodeData.previousSibling;\n return l !== undefined ? l : this[NATIVE_PREFIX + 'previousSibling'];\n },\n\n /** @this {Node} */\n get childNodes() {\n var childNodes;\n\n if (utils_isTrackingLogicalChildNodes(this)) {\n var nodeData = shadyDataForNode(this);\n\n if (!nodeData.childNodes) {\n nodeData.childNodes = [];\n\n for (var n = this[SHADY_PREFIX + 'firstChild']; n; n = n[SHADY_PREFIX + 'nextSibling']) {\n nodeData.childNodes.push(n);\n }\n }\n\n childNodes = nodeData.childNodes;\n } else {\n childNodes = this[NATIVE_PREFIX + 'childNodes'];\n }\n\n childNodes.item = function (index) {\n return childNodes[index];\n };\n\n return childNodes;\n },\n\n /** @this {Node} */\n get parentElement() {\n var nodeData = shadyDataForNode(this);\n var l = nodeData && nodeData.parentNode;\n\n if (l && l.nodeType !== Node.ELEMENT_NODE) {\n l = null;\n }\n\n return l !== undefined ? l : this[NATIVE_PREFIX + 'parentElement'];\n },\n\n /** @this {Node} */\n get isConnected() {\n if (nativeIsConnected && nativeIsConnected.call(this)) {\n return true;\n }\n\n if (this.nodeType == Node.DOCUMENT_FRAGMENT_NODE) {\n return false;\n } // Fast path for distributed nodes.\n\n\n var ownerDocument = this.ownerDocument;\n\n if (hasDocumentContains) {\n if (ownerDocument[NATIVE_PREFIX + 'contains'](this)) {\n return true;\n }\n } else if (ownerDocument.documentElement && ownerDocument.documentElement[NATIVE_PREFIX + 'contains'](this)) {\n return true;\n } // Slow path for non-distributed nodes.\n\n\n var node = this;\n\n while (node && !(node instanceof Document)) {\n node = node[SHADY_PREFIX + 'parentNode'] || (utils_isShadyRoot(node) ?\n /** @type {ShadowRoot} */\n node.host : undefined);\n }\n\n return !!(node && node instanceof Document);\n },\n\n /** @this {Node} */\n get textContent() {\n if (utils_isTrackingLogicalChildNodes(this)) {\n var tc = [];\n\n for (var i = 0, cn = this[SHADY_PREFIX + 'childNodes'], c; c = cn[i]; i++) {\n if (c.nodeType !== Node.COMMENT_NODE) {\n tc.push(c[SHADY_PREFIX + 'textContent']);\n }\n }\n\n return tc.join('');\n } else {\n return this[NATIVE_PREFIX + 'textContent'];\n }\n },\n\n /**\n * @this {Node}\n * @param {string} value\n */\n set textContent(value) {\n if (typeof value === 'undefined' || value === null) {\n value = '';\n }\n\n switch (this.nodeType) {\n case Node.ELEMENT_NODE:\n case Node.DOCUMENT_FRAGMENT_NODE:\n if (!utils_isTrackingLogicalChildNodes(this) && settings.hasDescriptors) {\n // may be removing a nested slot but fast path if we know we are not.\n var firstChild = this[SHADY_PREFIX + 'firstChild'];\n\n if (firstChild != this[SHADY_PREFIX + 'lastChild'] || firstChild && firstChild.nodeType != Node.TEXT_NODE) {\n Node_clearNode(this);\n }\n\n this[NATIVE_PREFIX + 'textContent'] = value;\n } else {\n Node_clearNode(this); // Document fragments must have no childNodes if setting a blank string\n\n if (value.length > 0 || this.nodeType === Node.ELEMENT_NODE) {\n this[SHADY_PREFIX + 'insertBefore'](document.createTextNode(value));\n }\n }\n\n break;\n\n default:\n // Note, be wary of patching `nodeValue`.\n this.nodeValue = value;\n break;\n }\n },\n\n // Patched `insertBefore`. Note that all mutations that add nodes are routed\n // here. When a is added or a node is added to a host with a shadowRoot\n // with a slot, a standard dom `insert` call is aborted and `_asyncRender`\n // is called on the relevant shadowRoot. In all other cases, a standard dom\n // `insert` can be made, but the location and ref_node may need to be changed.\n\n /**\n * @this {Node}\n * @param {Node} node\n * @param {Node=} ref_node\n */\n insertBefore: function insertBefore(node, ref_node) {\n // optimization: assume native insertBefore is ok if the nodes are not in the document.\n if (this.ownerDocument !== doc && node.ownerDocument !== doc) {\n this[NATIVE_PREFIX + 'insertBefore'](node, ref_node);\n return node;\n }\n\n if (node === this) {\n throw Error(\"Failed to execute 'appendChild' on 'Node': The new child element contains the parent.\");\n }\n\n if (ref_node) {\n var refData = shadyDataForNode(ref_node);\n var p = refData && refData.parentNode;\n\n if (p !== undefined && p !== this || p === undefined && ref_node[NATIVE_PREFIX + 'parentNode'] !== this) {\n throw Error(\"Failed to execute 'insertBefore' on 'Node': The node \" + \"before which the new node is to be inserted is not a child of this node.\");\n }\n }\n\n if (ref_node === node) {\n return node;\n }\n /** @type {!Array} */\n\n\n var slotsAdded = [];\n var ownerRoot = attach_shadow_ownerShadyRootForNode(this);\n /** @type {string} */\n\n var newScopeName = ownerRoot ? ownerRoot.host.localName : currentScopeForNode(this);\n /** @type {string} */\n\n var oldScopeName; // remove from existing location\n\n var parentNode = node[SHADY_PREFIX + 'parentNode'];\n\n if (parentNode) {\n oldScopeName = currentScopeForNode(node);\n parentNode[SHADY_PREFIX + 'removeChild'](node, Boolean(ownerRoot) || !attach_shadow_ownerShadyRootForNode(node));\n } // add to new parent\n\n\n var allowNativeInsert = true;\n var needsScoping = (!preferPerformance || node['__noInsertionPoint'] === undefined) && !currentScopeIsCorrect(node, newScopeName);\n var needsSlotFinding = ownerRoot && !node['__noInsertionPoint'] && (!preferPerformance || node.nodeType === Node.DOCUMENT_FRAGMENT_NODE);\n\n if (needsSlotFinding || needsScoping) {\n // NOTE: avoid node.removeChild as this *can* trigger another patched\n // method (e.g. custom elements) and we want only the shady method to run.\n // The following table describes what style scoping actions should happen as a result of this insertion.\n // document -> shadowRoot: replace\n // shadowRoot -> shadowRoot: replace\n // shadowRoot -> shadowRoot of same type: do nothing\n // shadowRoot -> document: allow unscoping\n // document -> document: do nothing\n // The \"same type of shadowRoot\" and \"document to document cases rely on `currentScopeIsCorrect` returning true\n if (needsScoping) {\n // in a document or disconnected tree, replace scoping if necessary\n oldScopeName = oldScopeName || currentScopeForNode(node);\n }\n\n treeVisitor(node, function (node) {\n if (needsSlotFinding && node.localName === 'slot') {\n slotsAdded.push(\n /** @type {!HTMLSlotElement} */\n node);\n }\n\n if (needsScoping) {\n replaceShadyScoping(node, newScopeName, oldScopeName);\n }\n });\n } // if a slot is added, must render containing root.\n\n\n if (this.localName === 'slot' || slotsAdded.length) {\n if (slotsAdded.length) {\n ownerRoot._addSlots(slotsAdded);\n }\n\n if (ownerRoot) {\n ownerRoot._asyncRender();\n }\n }\n\n if (utils_isTrackingLogicalChildNodes(this)) {\n link_nodes_recordInsertBefore(node, this, ref_node); // when inserting into a host with a shadowRoot with slot, use\n // `shadowRoot._asyncRender()` via `attach-shadow` module\n\n var parentData = shadyDataForNode(this);\n\n if (utils_hasShadowRootWithSlot(this)) {\n parentData.root._asyncRender();\n\n allowNativeInsert = false; // when inserting into a host with shadowRoot with NO slot, do nothing\n // as the node should not be added to composed dome anywhere.\n } else if (parentData.root) {\n allowNativeInsert = false;\n }\n }\n\n if (allowNativeInsert) {\n // if adding to a shadyRoot, add to host instead\n var container = utils_isShadyRoot(this) ?\n /** @type {ShadowRoot} */\n this.host : this; // if ref_node, get the ref_node that's actually in composed dom.\n\n if (ref_node) {\n ref_node = firstComposedNode(ref_node);\n container[NATIVE_PREFIX + 'insertBefore'](node, ref_node);\n } else {\n container[NATIVE_PREFIX + 'appendChild'](node);\n } // Since ownerDocument is not patched, it can be incorrect after this call\n // if the node is physically appended via distribution. This can result\n // in the custom elements polyfill not upgrading the node if it's in an inert doc.\n // We correct this by calling `adoptNode`.\n\n } else if (node.ownerDocument !== this.ownerDocument) {\n this.ownerDocument.adoptNode(node);\n }\n\n scheduleObserver(this, node);\n return node;\n },\n\n /**\n * @this {Node}\n * @param {Node} node\n */\n appendChild: function appendChild(node) {\n return this[SHADY_PREFIX + 'insertBefore'](node);\n },\n\n /**\n * Patched `removeChild`. Note that all dom \"removals\" are routed here.\n * Removes the given `node` from the element's `children`.\n * This method also performs dom composition.\n * @this {Node}\n * @param {Node} node\n * @param {boolean=} skipUnscoping\n */\n removeChild: function removeChild(node) {\n var skipUnscoping = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;\n\n if (this.ownerDocument !== doc) {\n return this[NATIVE_PREFIX + 'removeChild'](node);\n }\n\n if (node[SHADY_PREFIX + 'parentNode'] !== this) {\n throw Error('The node to be removed is not a child of this node: ' + node);\n }\n\n var preventNativeRemove;\n var ownerRoot = attach_shadow_ownerShadyRootForNode(node);\n\n var removingInsertionPoint = ownerRoot && ownerRoot._removeContainedSlots(node);\n\n var parentData = shadyDataForNode(this);\n\n if (utils_isTrackingLogicalChildNodes(this)) {\n link_nodes_recordRemoveChild(node, this);\n\n if (utils_hasShadowRootWithSlot(this)) {\n parentData.root._asyncRender();\n\n preventNativeRemove = true;\n }\n } // unscope a node leaving a ShadowRoot if ShadyCSS is present, and this node\n // is not going to be rescoped in `insertBefore`\n\n\n if (getScopingShim() && !skipUnscoping && ownerRoot) {\n var oldScopeName = currentScopeForNode(node);\n treeVisitor(node, function (node) {\n removeShadyScoping(node, oldScopeName);\n });\n }\n\n removeOwnerShadyRoot(node); // if removing slot, must render containing root\n\n if (ownerRoot) {\n var changeSlotContent = this && this.localName === 'slot';\n\n if (changeSlotContent) {\n preventNativeRemove = true;\n }\n\n if (removingInsertionPoint || changeSlotContent) {\n ownerRoot._asyncRender();\n }\n }\n\n if (!preventNativeRemove) {\n // if removing from a shadyRoot, remove from host instead\n var container = utils_isShadyRoot(this) ?\n /** @type {ShadowRoot} */\n this.host : this; // not guaranteed to physically be in container; e.g.\n // (1) if parent has a shadyRoot, element may or may not at distributed\n // location (could be undistributed)\n // (2) if parent is a slot, element may not ben in composed dom\n\n if (!(parentData.root || node.localName === 'slot') || container === node[NATIVE_PREFIX + 'parentNode']) {\n container[NATIVE_PREFIX + 'removeChild'](node);\n }\n }\n\n scheduleObserver(this, null, node);\n return node;\n },\n\n /**\n * @this {Node}\n * @param {Node} node\n * @param {Node=} ref_node\n */\n replaceChild: function replaceChild(node, ref_node) {\n this[SHADY_PREFIX + 'insertBefore'](node, ref_node);\n this[SHADY_PREFIX + 'removeChild'](ref_node);\n return node;\n },\n\n /**\n * @this {Node}\n * @param {boolean=} deep\n */\n cloneNode: function cloneNode(deep) {\n if (this.localName == 'template') {\n return this[NATIVE_PREFIX + 'cloneNode'](deep);\n } else {\n var n = this[NATIVE_PREFIX + 'cloneNode'](false); // Attribute nodes historically had childNodes, but they have later\n // been removed from the spec.\n // Make sure we do not do a deep clone on them for old browsers (IE11)\n\n if (deep && n.nodeType !== Node.ATTRIBUTE_NODE) {\n var c$ = this[SHADY_PREFIX + 'childNodes'];\n\n for (var i = 0, nc; i < c$.length; i++) {\n nc = c$[i][SHADY_PREFIX + 'cloneNode'](true);\n n[SHADY_PREFIX + 'appendChild'](nc);\n }\n }\n\n return n;\n }\n },\n\n /**\n * @this {Node}\n * @param {Object=} options\n */\n // TODO(sorvell): implement `options` e.g. `{ composed: boolean }`\n getRootNode: function getRootNode(options) {\n // eslint-disable-line no-unused-vars\n if (!this || !this.nodeType) {\n return;\n }\n\n var nodeData = ensureShadyDataForNode(this);\n var root = nodeData.ownerShadyRoot;\n\n if (root === undefined) {\n if (utils_isShadyRoot(this)) {\n root = this;\n nodeData.ownerShadyRoot = root;\n } else {\n var parent = this[SHADY_PREFIX + 'parentNode'];\n root = parent ? parent[SHADY_PREFIX + 'getRootNode'](options) : this; // memo-ize result for performance but only memo-ize\n // result if node is in the document. This avoids a problem where a root\n // can be cached while an element is inside a fragment.\n // If this happens and we cache the result, the value can become stale\n // because for perf we avoid processing the subtree of added fragments.\n\n if (document.documentElement[NATIVE_PREFIX + 'contains'](this)) {\n nodeData.ownerShadyRoot = root;\n }\n }\n }\n\n return root;\n },\n\n /** @this {Node} */\n contains: function contains(node) {\n return utils_contains(this, node);\n }\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/ParentNode.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n/**\n * @param {Node} node\n * @param {Function} matcher\n * @param {Function=} halter\n */\n\nfunction query(node, matcher, halter) {\n var list = [];\n queryElements(node[SHADY_PREFIX + 'childNodes'], matcher, halter, list);\n return list;\n}\n\nfunction queryElements(elements, matcher, halter, list) {\n for (var i = 0, l = elements.length, c; i < l && (c = elements[i]); i++) {\n if (c.nodeType === Node.ELEMENT_NODE && queryElement(c, matcher, halter, list)) {\n return true;\n }\n }\n}\n\nfunction queryElement(node, matcher, halter, list) {\n var result = matcher(node);\n\n if (result) {\n list.push(node);\n }\n\n if (halter && halter(result)) {\n return result;\n }\n\n queryElements(node[SHADY_PREFIX + 'childNodes'], matcher, halter, list);\n} // Needed on Element, DocumentFragment, Document\n\n\nvar ParentNodePatches = getOwnPropertyDescriptors({\n /** @this {Element} */\n get firstElementChild() {\n var nodeData = shadyDataForNode(this);\n\n if (nodeData && nodeData.firstChild !== undefined) {\n var n = this[SHADY_PREFIX + 'firstChild'];\n\n while (n && n.nodeType !== Node.ELEMENT_NODE) {\n n = n[SHADY_PREFIX + 'nextSibling'];\n }\n\n return n;\n } else {\n return this[NATIVE_PREFIX + 'firstElementChild'];\n }\n },\n\n /** @this {Element} */\n get lastElementChild() {\n var nodeData = shadyDataForNode(this);\n\n if (nodeData && nodeData.lastChild !== undefined) {\n var n = this[SHADY_PREFIX + 'lastChild'];\n\n while (n && n.nodeType !== Node.ELEMENT_NODE) {\n n = n[SHADY_PREFIX + 'previousSibling'];\n }\n\n return n;\n } else {\n return this[NATIVE_PREFIX + 'lastElementChild'];\n }\n },\n\n /** @this {Element} */\n get children() {\n if (!utils_isTrackingLogicalChildNodes(this)) {\n return this[NATIVE_PREFIX + 'children'];\n }\n\n return createPolyfilledHTMLCollection(Array.prototype.filter.call(this[SHADY_PREFIX + 'childNodes'], function (n) {\n return n.nodeType === Node.ELEMENT_NODE;\n }));\n },\n\n /** @this {Element} */\n get childElementCount() {\n var children = this[SHADY_PREFIX + 'children'];\n\n if (children) {\n return children.length;\n }\n\n return 0;\n }\n\n});\nvar QueryPatches = getOwnPropertyDescriptors({\n // TODO(sorvell): consider doing native QSA and filtering results.\n\n /**\n * @this {Element}\n * @param {string} selector\n */\n querySelector: function querySelector(selector) {\n // match selector and halt on first result.\n var result = query(this, function (n) {\n return matchesSelector(n, selector);\n }, function (n) {\n return Boolean(n);\n })[0];\n return result || null;\n },\n\n /**\n * @this {Element}\n * @param {string} selector\n * @param {boolean} useNative\n */\n // TODO(sorvell): `useNative` option relies on native querySelectorAll and\n // misses distributed nodes, see\n // https://github.com/webcomponents/shadydom/pull/210#issuecomment-361435503\n querySelectorAll: function querySelectorAll(selector, useNative) {\n if (useNative) {\n var o = Array.prototype.slice.call(this[NATIVE_PREFIX + 'querySelectorAll'](selector));\n var root = this[SHADY_PREFIX + 'getRootNode']();\n return o.filter(function (e) {\n return e[SHADY_PREFIX + 'getRootNode']() == root;\n });\n }\n\n return query(this, function (n) {\n return matchesSelector(n, selector);\n });\n }\n}); // Create a custom `ParentNodeDocumentOrFragment` that optionally does not\n// mixin querySelector/All; this is a performance optimization.\n\nvar ParentNodeDocumentOrFragmentPatches = settings.preferPerformance ? Object.assign({}, ParentNodePatches) : ParentNodePatches;\nObject.assign(ParentNodePatches, QueryPatches);\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/DocumentOrFragment.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\nvar DocumentOrFragmentPatches = getOwnPropertyDescriptors({\n /**\n * @this {Element}\n * @param {string} id\n */\n getElementById: function getElementById(id) {\n if (id === '') {\n return null;\n }\n\n var result = query(this, function (n) {\n return n.id == id;\n }, function (n) {\n return Boolean(n);\n })[0];\n return result || null;\n }\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/DocumentOrShadowRoot.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\nfunction getDocumentActiveElement() {\n if (settings.hasDescriptors) {\n return document[NATIVE_PREFIX + 'activeElement'];\n } else {\n return document.activeElement;\n }\n}\n\nvar DocumentOrShadowRootPatches = getOwnPropertyDescriptors({\n /** @this {Document|ShadowRoot} */\n get activeElement() {\n var active = getDocumentActiveElement(); // In IE11, activeElement might be an empty object if the document is\n // contained in an iframe.\n // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10998788/\n\n if (!active || !active.nodeType) {\n return null;\n }\n\n var isShadyRoot = !!utils_isShadyRoot(this);\n\n if (this !== document) {\n // If this node isn't a document or shady root, then it doesn't have\n // an active element.\n if (!isShadyRoot) {\n return null;\n } // If this shady root's host is the active element or the active\n // element is not a descendant of the host (in the composed tree),\n // then it doesn't have an active element.\n\n\n if (this.host === active || !this.host[NATIVE_PREFIX + 'contains'](active)) {\n return null;\n }\n } // This node is either the document or a shady root of which the active\n // element is a (composed) descendant of its host; iterate upwards to\n // find the active element's most shallow host within it.\n\n\n var activeRoot = attach_shadow_ownerShadyRootForNode(active);\n\n while (activeRoot && activeRoot !== this) {\n active = activeRoot.host;\n activeRoot = attach_shadow_ownerShadyRootForNode(active);\n }\n\n if (this === document) {\n // This node is the document, so activeRoot should be null.\n return activeRoot ? null : active;\n } else {\n // This node is a non-document shady root, and it should be\n // activeRoot.\n return activeRoot === this ? active : null;\n }\n }\n\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/ElementOrShadowRoot.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\n/** @type {!Document} */\n\nvar ElementOrShadowRoot_inertDoc = document.implementation.createHTMLDocument('inert');\nvar ElementOrShadowRootPatches = getOwnPropertyDescriptors({\n /** @this {Element} */\n get innerHTML() {\n if (utils_isTrackingLogicalChildNodes(this)) {\n var content = this.localName === 'template' ?\n /** @type {HTMLTemplateElement} */\n this.content : this;\n return getInnerHTML(content, function (e) {\n return e[SHADY_PREFIX + 'childNodes'];\n });\n } else {\n return this[NATIVE_PREFIX + 'innerHTML'];\n }\n },\n\n /**\n * @this {Element}\n * @param {string} value\n */\n set innerHTML(value) {\n if (this.localName === 'template') {\n this[NATIVE_PREFIX + 'innerHTML'] = value;\n } else {\n Node_clearNode(this);\n var containerName = this.localName || 'div';\n var htmlContainer;\n\n if (!this.namespaceURI || this.namespaceURI === ElementOrShadowRoot_inertDoc.namespaceURI) {\n htmlContainer = ElementOrShadowRoot_inertDoc.createElement(containerName);\n } else {\n htmlContainer = ElementOrShadowRoot_inertDoc.createElementNS(this.namespaceURI, containerName);\n }\n\n if (settings.hasDescriptors) {\n htmlContainer[NATIVE_PREFIX + 'innerHTML'] = value;\n } else {\n htmlContainer.innerHTML = value;\n }\n\n var firstChild;\n\n while (firstChild = htmlContainer[SHADY_PREFIX + 'firstChild']) {\n this[SHADY_PREFIX + 'insertBefore'](firstChild);\n }\n }\n }\n\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/ShadowRoot.js\nfunction ShadowRoot_typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { ShadowRoot_typeof = function _typeof(obj) { return typeof obj; }; } else { ShadowRoot_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return ShadowRoot_typeof(obj); }\n\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nvar ShadowRootPatches = getOwnPropertyDescriptors({\n /**\n * @this {ShadowRoot}\n * @param {string} type\n * @param {Function} fn\n * @param {Object|boolean=} optionsOrCapture\n */\n addEventListener: function addEventListener(type, fn, optionsOrCapture) {\n if (ShadowRoot_typeof(optionsOrCapture) !== 'object') {\n optionsOrCapture = {\n capture: Boolean(optionsOrCapture)\n };\n }\n\n optionsOrCapture.__shadyTarget = this;\n this.host[SHADY_PREFIX + 'addEventListener'](type, fn, optionsOrCapture);\n },\n\n /**\n * @this {ShadowRoot}\n * @param {string} type\n * @param {Function} fn\n * @param {Object|boolean=} optionsOrCapture\n */\n removeEventListener: function removeEventListener(type, fn, optionsOrCapture) {\n if (ShadowRoot_typeof(optionsOrCapture) !== 'object') {\n optionsOrCapture = {\n capture: Boolean(optionsOrCapture)\n };\n }\n\n optionsOrCapture.__shadyTarget = this;\n this.host[SHADY_PREFIX + 'removeEventListener'](type, fn, optionsOrCapture);\n }\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patch-shadyRoot.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\n\n\n\n\n\n/**\n * @param {!Object} proto\n * @param {string=} prefix\n */\n\nvar patch_shadyRoot_patchShadyAccessors = function patchShadyAccessors(proto, prefix) {\n patchProperties(proto, ShadowRootPatches, prefix);\n patchProperties(proto, DocumentOrShadowRootPatches, prefix);\n patchProperties(proto, ElementOrShadowRootPatches, prefix); // We ensure ParentNode accessors since these do not exist in Edge/IE on DocumentFragments.\n\n patchProperties(proto, ParentNodePatches, prefix); // Ensure `shadowRoot` has basic descriptors when we cannot rely\n // on them coming from DocumentFragment.\n //\n // Case 1, noPatching: Because we want noPatch ShadyRoots to have native property\n // names so that they do not have to be wrapped...\n // When we do *not* patch Node/DocumentFragment.prototype\n // we must manually install those properties on ShadyRoot's prototype.\n // Note, it's important to only install these in this mode so as not to stomp\n // over CustomElements polyfill's patches on Node/DocumentFragment methods.\n\n if (settings.noPatch && !prefix) {\n patchProperties(proto, NodePatches, prefix);\n patchProperties(proto, DocumentOrFragmentPatches, prefix); // Case 2, bad descriptors: Ensure accessors are on ShadowRoot.\n // These descriptors are normally used for instance patching but because\n // ShadyRoot can always be patched, just do it to the prototype.\n } else if (!settings.hasDescriptors) {\n patchProperties(proto, OutsideDescriptors);\n patchProperties(proto, InsideDescriptors);\n }\n};\n\nvar patch_shadyRoot_patchShadyRoot = function patchShadyRoot(proto) {\n proto.__proto__ = DocumentFragment.prototype; // patch both prefixed and not, even when noPatch == true.\n\n patch_shadyRoot_patchShadyAccessors(proto, SHADY_PREFIX);\n patch_shadyRoot_patchShadyAccessors(proto); // Ensure native properties are all safely wrapped since ShadowRoot is not an\n // actual DocumentFragment instance.\n\n Object.defineProperties(proto, {\n nodeType: {\n value: Node.DOCUMENT_FRAGMENT_NODE,\n configurable: true\n },\n nodeName: {\n value: '#document-fragment',\n configurable: true\n },\n nodeValue: {\n value: null,\n configurable: true\n }\n }); // make undefined\n\n ['localName', 'namespaceURI', 'prefix'].forEach(function (prop) {\n Object.defineProperty(proto, prop, {\n value: undefined,\n configurable: true\n });\n }); // defer properties to host\n\n ['ownerDocument', 'baseURI', 'isConnected'].forEach(function (prop) {\n Object.defineProperty(proto, prop, {\n /** @this {ShadowRoot} */\n get: function get() {\n return this.host[prop];\n },\n configurable: true\n });\n });\n};\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/attach-shadow.js\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _nonIterableSpread(); }\n\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance\"); }\n\nfunction _iterableToArray(iter) { if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === \"[object Arguments]\") return Array.from(iter); }\n\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } }\n\nfunction attach_shadow_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction attach_shadow_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction attach_shadow_createClass(Constructor, protoProps, staticProps) { if (protoProps) attach_shadow_defineProperties(Constructor.prototype, protoProps); if (staticProps) attach_shadow_defineProperties(Constructor, staticProps); return Constructor; }\n\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\n\n\n // Do not export this object. It must be passed as the first argument to the\n// ShadyRoot constructor in `attachShadow` to prevent the constructor from\n// throwing. This prevents the user from being able to manually construct a\n// ShadyRoot (i.e. `new ShadowRoot()`).\n\nvar ShadyRootConstructionToken = {};\nvar CATCHALL_NAME = '__catchall';\nvar SHADYROOT_NAME = 'ShadyRoot';\nvar MODE_CLOSED = 'closed';\nvar isRendering = settings['deferConnectionCallbacks'] && document.readyState === 'loading';\nvar rootRendered;\n\nfunction ancestorList(node) {\n var ancestors = [];\n\n do {\n ancestors.unshift(node);\n } while (node = node[SHADY_PREFIX + 'parentNode']);\n\n return ancestors;\n}\n/**\n * @extends {ShadowRoot}\n */\n\n\nvar attach_shadow_ShadyRoot =\n/*#__PURE__*/\nfunction () {\n function ShadyRoot(token, host, options) {\n attach_shadow_classCallCheck(this, ShadyRoot);\n\n if (token !== ShadyRootConstructionToken) {\n throw new TypeError('Illegal constructor');\n } // NOTE: set a fake local name so this element can be\n // distinguished from a DocumentFragment when patching.\n // FF doesn't allow this to be `localName`\n\n\n this._localName = SHADYROOT_NAME; // root <=> host\n\n this.host = host;\n /** @type {!string|undefined} */\n\n this.mode = options && options.mode;\n link_nodes_recordChildNodes(host);\n var hostData = ensureShadyDataForNode(host);\n /** @type {!ShadyRoot} */\n\n hostData.root = this;\n hostData.publicRoot = this.mode !== MODE_CLOSED ? this : null; // setup root\n\n var rootData = ensureShadyDataForNode(this);\n rootData.firstChild = rootData.lastChild = rootData.parentNode = rootData.nextSibling = rootData.previousSibling = null;\n rootData.childNodes = []; // state flags\n\n this._renderPending = false;\n this._hasRendered = false; // marsalled lazily\n\n this._slotList = null;\n /** @type {Object>} */\n\n this._slotMap = null;\n this._pendingSlots = null; // NOTE: optimization flag, only require an asynchronous render\n // to record parsed children if flag is not set.\n\n if (settings['preferPerformance']) {\n var n;\n\n while (n = host[NATIVE_PREFIX + 'firstChild']) {\n host[NATIVE_PREFIX + 'removeChild'](n);\n }\n } else {\n this._asyncRender();\n }\n }\n\n attach_shadow_createClass(ShadyRoot, [{\n key: \"_asyncRender\",\n value: function _asyncRender() {\n var _this = this;\n\n if (!this._renderPending) {\n this._renderPending = true;\n enqueue(function () {\n return _this._render();\n });\n }\n } // returns the oldest renderPending ancestor root.\n\n }, {\n key: \"_getPendingDistributionRoot\",\n value: function _getPendingDistributionRoot() {\n var renderRoot;\n var root = this;\n\n while (root) {\n if (root._renderPending) {\n renderRoot = root;\n }\n\n root = root._getDistributionParent();\n }\n\n return renderRoot;\n } // Returns the shadyRoot `this.host` if `this.host`\n // has children that require distribution.\n\n }, {\n key: \"_getDistributionParent\",\n value: function _getDistributionParent() {\n var root = this.host[SHADY_PREFIX + 'getRootNode']();\n\n if (!utils_isShadyRoot(root)) {\n return;\n }\n\n var nodeData = shadyDataForNode(this.host);\n\n if (nodeData && nodeData.__childSlotCount > 0) {\n return root;\n }\n } // Renders the top most render pending shadowRoot in the distribution tree.\n // This is safe because when a distribution parent renders, all children render.\n\n }, {\n key: \"_render\",\n value: function _render() {\n // If this root is not pending, it needs no rendering work. Any pending\n // parent that needs to render wll cause this root to render.\n var root = this._renderPending && this._getPendingDistributionRoot();\n\n if (root) {\n root._renderSelf();\n }\n }\n }, {\n key: \"_flushInitial\",\n value: function _flushInitial() {\n if (!this._hasRendered && this._renderPending) {\n this._render();\n }\n }\n /** @override */\n\n }, {\n key: \"_renderSelf\",\n value: function _renderSelf() {\n // track rendering state.\n var wasRendering = isRendering;\n isRendering = true;\n this._renderPending = false;\n\n if (this._slotList) {\n this._distribute();\n\n this._compose();\n } // NOTE: optimization flag, only process parsed children\n // if optimization flag is not set.\n // on initial render remove any undistributed children.\n\n\n if (!settings['preferPerformance'] && !this._hasRendered) {\n var c$ = this.host[SHADY_PREFIX + 'childNodes'];\n\n for (var i = 0, l = c$.length; i < l; i++) {\n var child = c$[i];\n var data = shadyDataForNode(child);\n\n if (child[NATIVE_PREFIX + 'parentNode'] === this.host && (child.localName === 'slot' || !data.assignedSlot)) {\n this.host[NATIVE_PREFIX + 'removeChild'](child);\n }\n }\n }\n\n this._hasRendered = true;\n isRendering = wasRendering;\n\n if (rootRendered) {\n rootRendered();\n }\n }\n }, {\n key: \"_distribute\",\n value: function _distribute() {\n this._validateSlots(); // capture # of previously assigned nodes to help determine if dirty.\n\n\n for (var i = 0, slot; i < this._slotList.length; i++) {\n slot = this._slotList[i];\n\n this._clearSlotAssignedNodes(slot);\n } // distribute host children.\n\n\n for (var n = this.host[SHADY_PREFIX + 'firstChild']; n; n = n[SHADY_PREFIX + 'nextSibling']) {\n this._distributeNodeToSlot(n);\n } // fallback content, slotchange, and dirty roots\n\n\n for (var _i = 0; _i < this._slotList.length; _i++) {\n var _slot = this._slotList[_i];\n var slotData = shadyDataForNode(_slot); // distribute fallback content\n\n if (!slotData.assignedNodes.length) {\n for (var _n = _slot[SHADY_PREFIX + 'firstChild']; _n; _n = _n[SHADY_PREFIX + 'nextSibling']) {\n this._distributeNodeToSlot(_n, _slot);\n }\n }\n\n var slotParentData = shadyDataForNode(_slot[SHADY_PREFIX + 'parentNode']);\n var slotParentRoot = slotParentData && slotParentData.root;\n\n if (slotParentRoot && (slotParentRoot._hasInsertionPoint() || slotParentRoot._renderPending)) {\n slotParentRoot._renderSelf();\n }\n\n this._addAssignedToFlattenedNodes(slotData.flattenedNodes, slotData.assignedNodes);\n\n var prevAssignedNodes = slotData._previouslyAssignedNodes;\n\n if (prevAssignedNodes) {\n for (var _i2 = 0; _i2 < prevAssignedNodes.length; _i2++) {\n shadyDataForNode(prevAssignedNodes[_i2])._prevAssignedSlot = null;\n }\n\n slotData._previouslyAssignedNodes = null; // dirty if previously less assigned nodes than previously assigned.\n\n if (prevAssignedNodes.length > slotData.assignedNodes.length) {\n slotData.dirty = true;\n }\n }\n /* Note: A slot is marked dirty whenever a node is newly assigned to it\n or a node is assigned to a different slot (done in `_distributeNodeToSlot`)\n or if the number of nodes assigned to the slot has decreased (done above);\n */\n\n\n if (slotData.dirty) {\n slotData.dirty = false;\n\n this._fireSlotChange(_slot);\n }\n }\n }\n /**\n * Distributes given `node` to the appropriate slot based on its `slot`\n * attribute. If `forcedSlot` is given, then the node is distributed to the\n * `forcedSlot`.\n * Note: slot to which the node is assigned will be marked dirty for firing\n * `slotchange`.\n * @param {Node} node\n * @param {Node=} forcedSlot\n *\n */\n\n }, {\n key: \"_distributeNodeToSlot\",\n value: function _distributeNodeToSlot(node, forcedSlot) {\n var nodeData = ensureShadyDataForNode(node);\n var oldSlot = nodeData._prevAssignedSlot;\n nodeData._prevAssignedSlot = null;\n var slot = forcedSlot;\n\n if (!slot) {\n var name = node[SHADY_PREFIX + 'slot'] || CATCHALL_NAME;\n var list = this._slotMap[name];\n slot = list && list[0];\n }\n\n if (slot) {\n var slotData = ensureShadyDataForNode(slot);\n slotData.assignedNodes.push(node);\n nodeData.assignedSlot = slot;\n } else {\n nodeData.assignedSlot = undefined;\n }\n\n if (oldSlot !== nodeData.assignedSlot) {\n if (nodeData.assignedSlot) {\n ensureShadyDataForNode(nodeData.assignedSlot).dirty = true;\n }\n }\n }\n /**\n * Clears the assignedNodes tracking data for a given `slot`. Note, the current\n * assigned node data is tracked (via _previouslyAssignedNodes and\n * _prevAssignedSlot) to see if `slotchange` should fire. This data may be out\n * of date at this time because the assigned nodes may have already been\n * distributed to another root. This is ok since this data is only used to\n * track changes.\n * @param {HTMLSlotElement} slot\n */\n\n }, {\n key: \"_clearSlotAssignedNodes\",\n value: function _clearSlotAssignedNodes(slot) {\n var slotData = shadyDataForNode(slot);\n var n$ = slotData.assignedNodes;\n slotData.assignedNodes = [];\n slotData.flattenedNodes = [];\n slotData._previouslyAssignedNodes = n$;\n\n if (n$) {\n for (var i = 0; i < n$.length; i++) {\n var n = shadyDataForNode(n$[i]);\n n._prevAssignedSlot = n.assignedSlot; // only clear if it was previously set to this slot;\n // this helps ensure that if the node has otherwise been distributed\n // ignore it.\n\n if (n.assignedSlot === slot) {\n n.assignedSlot = null;\n }\n }\n }\n }\n }, {\n key: \"_addAssignedToFlattenedNodes\",\n value: function _addAssignedToFlattenedNodes(flattened, assigned) {\n for (var i = 0, n; i < assigned.length && (n = assigned[i]); i++) {\n if (n.localName == 'slot') {\n var nestedAssigned = shadyDataForNode(n).assignedNodes;\n\n if (nestedAssigned && nestedAssigned.length) {\n this._addAssignedToFlattenedNodes(flattened, nestedAssigned);\n }\n } else {\n flattened.push(assigned[i]);\n }\n }\n }\n }, {\n key: \"_fireSlotChange\",\n value: function _fireSlotChange(slot) {\n // NOTE: cannot bubble correctly here so not setting bubbles: true\n // Safari tech preview does not bubble but chrome does\n // Spec says it bubbles (https://dom.spec.whatwg.org/#mutation-observers)\n slot[NATIVE_PREFIX + 'dispatchEvent'](new Event('slotchange'));\n var slotData = shadyDataForNode(slot);\n\n if (slotData.assignedSlot) {\n this._fireSlotChange(slotData.assignedSlot);\n }\n } // Reify dom such that it is at its correct rendering position\n // based on logical distribution.\n // NOTE: here we only compose parents of elements and not the\n // shadowRoot into the host. The latter is performend via a fast path\n // in the `logical-mutation`.insertBefore.\n\n }, {\n key: \"_compose\",\n value: function _compose() {\n var slots = this._slotList;\n var composeList = [];\n\n for (var i = 0; i < slots.length; i++) {\n var parent = slots[i][SHADY_PREFIX + 'parentNode'];\n /* compose node only if:\n (1) parent does not have a shadowRoot since shadowRoot has already\n composed into the host\n (2) we're not already composing it\n [consider (n^2) but rare better than Set]\n */\n\n var parentData = shadyDataForNode(parent);\n\n if (!(parentData && parentData.root) && composeList.indexOf(parent) < 0) {\n composeList.push(parent);\n }\n }\n\n for (var _i3 = 0; _i3 < composeList.length; _i3++) {\n var node = composeList[_i3];\n var targetNode = node === this ? this.host : node;\n\n this._updateChildNodes(targetNode, this._composeNode(node));\n }\n } // Returns the list of nodes which should be rendered inside `node`.\n\n }, {\n key: \"_composeNode\",\n value: function _composeNode(node) {\n var children = [];\n var c$ = node[SHADY_PREFIX + 'childNodes'];\n\n for (var i = 0; i < c$.length; i++) {\n var child = c$[i]; // Note: if we see a slot here, the nodes are guaranteed to need to be\n // composed here. This is because if there is redistribution, it has\n // already been handled by this point.\n\n if (this._isInsertionPoint(child)) {\n var flattenedNodes = shadyDataForNode(child).flattenedNodes;\n\n for (var j = 0; j < flattenedNodes.length; j++) {\n var distributedNode = flattenedNodes[j];\n children.push(distributedNode);\n }\n } else {\n children.push(child);\n }\n }\n\n return children;\n }\n }, {\n key: \"_isInsertionPoint\",\n value: function _isInsertionPoint(node) {\n return node.localName == 'slot';\n } // Ensures that the rendered node list inside `container` is `children`.\n\n }, {\n key: \"_updateChildNodes\",\n value: function _updateChildNodes(container, children) {\n var composed = Array.prototype.slice.call(container[NATIVE_PREFIX + 'childNodes']);\n var splices = calculateSplices(children, composed); // process removals\n\n for (var i = 0, d = 0, s; i < splices.length && (s = splices[i]); i++) {\n for (var j = 0, n; j < s.removed.length && (n = s.removed[j]); j++) {\n // check if the node is still where we expect it is before trying\n // to remove it; this can happen if we move a node and\n // then schedule its previous host for distribution resulting in\n // the node being removed here.\n if (n[NATIVE_PREFIX + 'parentNode'] === container) {\n container[NATIVE_PREFIX + 'removeChild'](n);\n } // TODO(sorvell): avoid the need for splicing here.\n\n\n composed.splice(s.index + d, 1);\n }\n\n d -= s.addedCount;\n } // process adds\n\n\n for (var _i4 = 0, _s, next; _i4 < splices.length && (_s = splices[_i4]); _i4++) {\n //eslint-disable-line no-redeclare\n next = composed[_s.index];\n\n for (var _j = _s.index, _n2; _j < _s.index + _s.addedCount; _j++) {\n _n2 = children[_j];\n container[NATIVE_PREFIX + 'insertBefore'](_n2, next);\n composed.splice(_j, 0, _n2);\n }\n }\n }\n }, {\n key: \"_ensureSlotData\",\n value: function _ensureSlotData() {\n this._pendingSlots = this._pendingSlots || [];\n this._slotList = this._slotList || [];\n this._slotMap = this._slotMap || {};\n }\n }, {\n key: \"_addSlots\",\n value: function _addSlots(slots) {\n var _this$_pendingSlots;\n\n this._ensureSlotData();\n\n (_this$_pendingSlots = this._pendingSlots).push.apply(_this$_pendingSlots, _toConsumableArray(slots));\n }\n }, {\n key: \"_validateSlots\",\n value: function _validateSlots() {\n if (this._pendingSlots && this._pendingSlots.length) {\n this._mapSlots(this._pendingSlots);\n\n this._pendingSlots = [];\n }\n }\n /**\n * Adds the given slots. Slots are maintained in an dom-ordered list.\n * In addition a map of name to slot is updated.\n */\n\n }, {\n key: \"_mapSlots\",\n value: function _mapSlots(slots) {\n var slotNamesToSort;\n\n for (var i = 0; i < slots.length; i++) {\n var slot = slots[i]; // ensure insertionPoints's and their parents have logical dom info.\n // save logical tree info\n // a. for shadyRoot\n // b. for insertion points (fallback)\n // c. for parents of insertion points\n\n link_nodes_recordChildNodes(slot);\n var slotParent = slot[SHADY_PREFIX + 'parentNode'];\n link_nodes_recordChildNodes(slotParent);\n var slotParentData = shadyDataForNode(slotParent);\n slotParentData.__childSlotCount = (slotParentData.__childSlotCount || 0) + 1;\n\n var name = this._nameForSlot(slot);\n\n if (this._slotMap[name]) {\n slotNamesToSort = slotNamesToSort || {};\n slotNamesToSort[name] = true;\n\n this._slotMap[name].push(slot);\n } else {\n this._slotMap[name] = [slot];\n }\n\n this._slotList.push(slot);\n }\n\n if (slotNamesToSort) {\n for (var n in slotNamesToSort) {\n this._slotMap[n] = this._sortSlots(this._slotMap[n]);\n }\n }\n }\n }, {\n key: \"_nameForSlot\",\n value: function _nameForSlot(slot) {\n var name = slot['name'] || slot.getAttribute('name') || CATCHALL_NAME;\n slot.__slotName = name;\n return name;\n }\n /**\n * Slots are kept in an ordered list. Slots with the same name\n * are sorted here by tree order.\n */\n\n }, {\n key: \"_sortSlots\",\n value: function _sortSlots(slots) {\n // NOTE: Cannot use `compareDocumentPosition` because it's not polyfilled,\n // but the code here could be used to polyfill the preceeding/following info\n // in `compareDocumentPosition`.\n return slots.sort(function (a, b) {\n var listA = ancestorList(a);\n var listB = ancestorList(b);\n\n for (var i = 0; i < listA.length; i++) {\n var nA = listA[i];\n var nB = listB[i];\n\n if (nA !== nB) {\n var c$ = Array.from(nA[SHADY_PREFIX + 'parentNode'][SHADY_PREFIX + 'childNodes']);\n return c$.indexOf(nA) - c$.indexOf(nB);\n }\n }\n });\n }\n /**\n * Removes from tracked slot data any slots contained within `container` and\n * then updates the tracked data (_slotList and _slotMap).\n * Any removed slots also have their `assignedNodes` removed from comopsed dom.\n */\n\n }, {\n key: \"_removeContainedSlots\",\n value: function _removeContainedSlots(container) {\n if (!this._slotList) {\n return;\n }\n\n this._validateSlots();\n\n var didRemove;\n var map = this._slotMap;\n\n for (var n in map) {\n var slots = map[n];\n\n for (var i = 0; i < slots.length; i++) {\n var slot = slots[i];\n\n if (utils_contains(container, slot)) {\n slots.splice(i, 1);\n\n var x = this._slotList.indexOf(slot);\n\n if (x >= 0) {\n this._slotList.splice(x, 1);\n\n var slotParentData = shadyDataForNode(slot[SHADY_PREFIX + 'parentNode']);\n\n if (slotParentData && slotParentData.__childSlotCount) {\n slotParentData.__childSlotCount--;\n }\n }\n\n i--;\n\n this._removeFlattenedNodes(slot);\n\n didRemove = true;\n }\n }\n }\n\n return didRemove;\n }\n }, {\n key: \"_updateSlotName\",\n value: function _updateSlotName(slot) {\n if (!this._slotList) {\n return;\n } // make sure slotMap is initialized with this slot\n\n\n this._validateSlots();\n\n var oldName = slot.__slotName;\n\n var name = this._nameForSlot(slot);\n\n if (name === oldName) {\n return;\n } // remove from existing tracking\n\n\n var slots = this._slotMap[oldName];\n var i = slots.indexOf(slot);\n\n if (i >= 0) {\n slots.splice(i, 1);\n } // add to new location and sort if nedessary\n\n\n var list = this._slotMap[name] || (this._slotMap[name] = []);\n list.push(slot);\n\n if (list.length > 1) {\n this._slotMap[name] = this._sortSlots(list);\n }\n }\n }, {\n key: \"_removeFlattenedNodes\",\n value: function _removeFlattenedNodes(slot) {\n var data = shadyDataForNode(slot);\n var n$ = data.flattenedNodes;\n\n if (n$) {\n for (var i = 0; i < n$.length; i++) {\n var node = n$[i];\n var parent = node[NATIVE_PREFIX + 'parentNode'];\n\n if (parent) {\n parent[NATIVE_PREFIX + 'removeChild'](node);\n }\n }\n }\n\n data.flattenedNodes = [];\n data.assignedNodes = [];\n }\n }, {\n key: \"_hasInsertionPoint\",\n value: function _hasInsertionPoint() {\n this._validateSlots();\n\n return Boolean(this._slotList && this._slotList.length);\n }\n }]);\n\n return ShadyRoot;\n}();\n\npatch_shadyRoot_patchShadyRoot(attach_shadow_ShadyRoot.prototype);\n\n/**\n Implements a pared down version of ShadowDOM's scoping, which is easy to\n polyfill across browsers.\n*/\n\nvar attach_shadow_attachShadow = function attachShadow(host, options) {\n if (!host) {\n throw new Error('Must provide a host.');\n }\n\n if (!options) {\n throw new Error('Not enough arguments.');\n }\n\n return new attach_shadow_ShadyRoot(ShadyRootConstructionToken, host, options);\n}; // Mitigate connect/disconnect spam by wrapping custom element classes.\n\nif (window['customElements'] && settings.inUse && !settings['preferPerformance']) {\n // process connect/disconnect after roots have rendered to avoid\n // issues with reaction stack.\n var connectMap = new Map();\n\n rootRendered = function rootRendered() {\n // allow elements to connect\n // save map state (without needing polyfills on IE11)\n var r = [];\n connectMap.forEach(function (v, k) {\n r.push([k, v]);\n });\n connectMap.clear();\n\n for (var i = 0; i < r.length; i++) {\n var e = r[i][0],\n value = r[i][1];\n\n if (value) {\n e.__shadydom_connectedCallback();\n } else {\n e.__shadydom_disconnectedCallback();\n }\n }\n }; // Document is in loading state and flag is set (deferConnectionCallbacks)\n // so process connection stack when `readystatechange` fires.\n\n\n if (isRendering) {\n document.addEventListener('readystatechange', function () {\n isRendering = false;\n rootRendered();\n }, {\n once: true\n });\n }\n /*\n * (1) elements can only be connected/disconnected if they are in the expected\n * state.\n * (2) never run connect/disconnect during rendering to avoid reaction stack issues.\n */\n\n\n var ManageConnect = function ManageConnect(base, connected, disconnected) {\n var counter = 0;\n var connectFlag = \"__isConnected\".concat(counter++);\n\n if (connected || disconnected) {\n /** @this {!HTMLElement} */\n base.prototype.connectedCallback = base.prototype.__shadydom_connectedCallback = function () {\n // if rendering defer connected\n // otherwise connect only if we haven't already\n if (isRendering) {\n connectMap.set(this, true);\n } else if (!this[connectFlag]) {\n this[connectFlag] = true;\n\n if (connected) {\n connected.call(this);\n }\n }\n };\n /** @this {!HTMLElement} */\n\n\n base.prototype.disconnectedCallback = base.prototype.__shadydom_disconnectedCallback = function () {\n // if rendering, cancel a pending connection and queue disconnect,\n // otherwise disconnect only if a connection has been allowed\n if (isRendering) {\n // This is necessary only because calling removeChild\n // on a node that requires distribution leaves it in the DOM tree\n // until distribution.\n // NOTE: remember this is checking the patched isConnected to determine\n // if the node is in the logical tree.\n if (!this.isConnected) {\n connectMap.set(this, false);\n }\n } else if (this[connectFlag]) {\n this[connectFlag] = false;\n\n if (disconnected) {\n disconnected.call(this);\n }\n }\n };\n }\n\n return base;\n };\n\n var define = window['customElements']['define']; // NOTE: Instead of patching customElements.define,\n // re-define on the CustomElementRegistry.prototype.define\n // for Safari 10 compatibility (it's flakey otherwise).\n\n Object.defineProperty(window['CustomElementRegistry'].prototype, 'define', {\n value: function value(name, constructor) {\n var connected = constructor.prototype.connectedCallback;\n var disconnected = constructor.prototype.disconnectedCallback;\n define.call(window['customElements'], name, ManageConnect(constructor, connected, disconnected)); // unpatch connected/disconnected on class; custom elements tears this off\n // so the patch is maintained, but if the user calls these methods for\n // e.g. testing, they will be as expected.\n\n constructor.prototype.connectedCallback = connected;\n constructor.prototype.disconnectedCallback = disconnected;\n }\n });\n}\n/** @return {!ShadyRoot|undefined} */\n\n\nvar attach_shadow_ownerShadyRootForNode = function ownerShadyRootForNode(node) {\n var root = node[SHADY_PREFIX + 'getRootNode']();\n\n if (utils_isShadyRoot(root)) {\n return root;\n }\n};\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/wrapper.js\nfunction wrapper_classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction wrapper_defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction wrapper_createClass(Constructor, protoProps, staticProps) { if (protoProps) wrapper_defineProperties(Constructor.prototype, protoProps); if (staticProps) wrapper_defineProperties(Constructor, staticProps); return Constructor; }\n\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n/** @implements {IWrapper} */\n\nvar wrapper_Wrapper =\n/*#__PURE__*/\nfunction () {\n /** @param {!Node} node */\n function Wrapper(node) {\n wrapper_classCallCheck(this, Wrapper);\n\n this.node = node;\n } // node\n\n\n wrapper_createClass(Wrapper, [{\n key: \"addEventListener\",\n value: function addEventListener(name, fn, options) {\n return this.node[SHADY_PREFIX + 'addEventListener'](name, fn, options);\n }\n }, {\n key: \"removeEventListener\",\n value: function removeEventListener(name, fn, options) {\n return this.node[SHADY_PREFIX + 'removeEventListener'](name, fn, options);\n }\n }, {\n key: \"appendChild\",\n value: function appendChild(node) {\n return this.node[SHADY_PREFIX + 'appendChild'](node);\n }\n }, {\n key: \"insertBefore\",\n value: function insertBefore(node, ref_node) {\n return this.node[SHADY_PREFIX + 'insertBefore'](node, ref_node);\n }\n }, {\n key: \"removeChild\",\n value: function removeChild(node) {\n return this.node[SHADY_PREFIX + 'removeChild'](node);\n }\n }, {\n key: \"replaceChild\",\n value: function replaceChild(node, ref_node) {\n return this.node[SHADY_PREFIX + 'replaceChild'](node, ref_node);\n }\n }, {\n key: \"cloneNode\",\n value: function cloneNode(deep) {\n return this.node[SHADY_PREFIX + 'cloneNode'](deep);\n }\n }, {\n key: \"getRootNode\",\n value: function getRootNode(options) {\n return this.node[SHADY_PREFIX + 'getRootNode'](options);\n }\n }, {\n key: \"contains\",\n value: function contains(node) {\n return this.node[SHADY_PREFIX + 'contains'](node);\n }\n }, {\n key: \"dispatchEvent\",\n value: function dispatchEvent(event) {\n return this.node[SHADY_PREFIX + 'dispatchEvent'](event);\n } // element\n\n }, {\n key: \"setAttribute\",\n value: function setAttribute(name, value) {\n this.node[SHADY_PREFIX + 'setAttribute'](name, value);\n } // NOTE: not needed, just here for balance\n\n }, {\n key: \"getAttribute\",\n value: function getAttribute(name) {\n return this.node[NATIVE_PREFIX + 'getAttribute'](name);\n } // NOTE: not needed, just here for balance\n\n }, {\n key: \"hasAttribute\",\n value: function hasAttribute(name) {\n return this.node[NATIVE_PREFIX + 'hasAttribute'](name);\n }\n }, {\n key: \"removeAttribute\",\n value: function removeAttribute(name) {\n this.node[SHADY_PREFIX + 'removeAttribute'](name);\n }\n }, {\n key: \"attachShadow\",\n value: function attachShadow(options) {\n return this.node[SHADY_PREFIX + 'attachShadow'](options);\n }\n /** @return {!Node|undefined} */\n\n }, {\n key: \"focus\",\n // NOTE: not needed, just here for balance\n\n /** @override */\n value: function focus() {\n this.node[NATIVE_PREFIX + 'focus']();\n }\n }, {\n key: \"blur\",\n value: function blur() {\n this.node[SHADY_PREFIX + 'blur']();\n } // document\n\n }, {\n key: \"importNode\",\n value: function importNode(node, deep) {\n if (this.node.nodeType === Node.DOCUMENT_NODE) {\n return this.node[SHADY_PREFIX + 'importNode'](node, deep);\n }\n }\n }, {\n key: \"getElementById\",\n value: function getElementById(id) {\n if (this.node.nodeType === Node.DOCUMENT_NODE) {\n return this.node[SHADY_PREFIX + 'getElementById'](id);\n }\n } // query\n\n }, {\n key: \"querySelector\",\n value: function querySelector(selector) {\n return this.node[SHADY_PREFIX + 'querySelector'](selector);\n }\n }, {\n key: \"querySelectorAll\",\n value: function querySelectorAll(selector, useNative) {\n return this.node[SHADY_PREFIX + 'querySelectorAll'](selector, useNative);\n } // slot\n\n }, {\n key: \"assignedNodes\",\n value: function assignedNodes(options) {\n if (this.node.localName === 'slot') {\n return this.node[SHADY_PREFIX + 'assignedNodes'](options);\n }\n }\n }, {\n key: \"activeElement\",\n get: function get() {\n if (utils_isShadyRoot(this.node) || this.node.nodeType === Node.DOCUMENT_NODE) {\n var e = this.node[SHADY_PREFIX + 'activeElement'];\n return e;\n }\n }\n /**\n * Installed for compatibility with browsers (older Chrome/Safari) that do\n * not have a configurable `activeElement` accessor. Enables noPatch and\n * patch mode both to consistently use ShadyDOM.wrap(document)._activeElement.\n * @override\n * @return {!Node|undefined}\n */\n\n }, {\n key: \"_activeElement\",\n get: function get() {\n return this.activeElement;\n }\n }, {\n key: \"host\",\n get: function get() {\n if (utils_isShadyRoot(this.node)) {\n return (\n /** @type {!ShadowRoot} */\n this.node.host\n );\n }\n }\n }, {\n key: \"parentNode\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'parentNode'];\n }\n }, {\n key: \"firstChild\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'firstChild'];\n }\n }, {\n key: \"lastChild\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'lastChild'];\n }\n }, {\n key: \"nextSibling\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'nextSibling'];\n }\n }, {\n key: \"previousSibling\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'previousSibling'];\n }\n }, {\n key: \"childNodes\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'childNodes'];\n }\n }, {\n key: \"parentElement\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'parentElement'];\n }\n }, {\n key: \"firstElementChild\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'firstElementChild'];\n }\n }, {\n key: \"lastElementChild\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'lastElementChild'];\n }\n }, {\n key: \"nextElementSibling\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'nextElementSibling'];\n }\n }, {\n key: \"previousElementSibling\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'previousElementSibling'];\n }\n }, {\n key: \"children\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'children'];\n }\n }, {\n key: \"childElementCount\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'childElementCount'];\n }\n }, {\n key: \"shadowRoot\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'shadowRoot'];\n }\n }, {\n key: \"assignedSlot\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'assignedSlot'];\n }\n }, {\n key: \"isConnected\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'isConnected'];\n }\n }, {\n key: \"innerHTML\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'innerHTML'];\n },\n set: function set(value) {\n this.node[SHADY_PREFIX + 'innerHTML'] = value;\n }\n }, {\n key: \"textContent\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'textContent'];\n },\n set: function set(value) {\n this.node[SHADY_PREFIX + 'textContent'] = value;\n }\n }, {\n key: \"slot\",\n get: function get() {\n return this.node[SHADY_PREFIX + 'slot'];\n },\n set: function set(value) {\n this.node[SHADY_PREFIX + 'slot'] = value;\n }\n }]);\n\n return Wrapper;\n}();\n\neventPropertyNames.forEach(function (name) {\n Object.defineProperty(wrapper_Wrapper.prototype, name, {\n /** @this {Wrapper} */\n get: function get() {\n return this.node[SHADY_PREFIX + name];\n },\n\n /** @this {Wrapper} */\n set: function set(value) {\n this.node[SHADY_PREFIX + name] = value;\n },\n configurable: true\n });\n});\n\nvar wrapperMap = new WeakMap();\nfunction wrap(obj) {\n if (utils_isShadyRoot(obj) || obj instanceof wrapper_Wrapper) {\n return obj;\n }\n\n var wrapper = wrapperMap.get(obj);\n\n if (!wrapper) {\n wrapper = new wrapper_Wrapper(obj);\n wrapperMap.set(obj, wrapper);\n }\n\n return wrapper;\n}\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/EventTarget.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\nvar EventTargetPatches = getOwnPropertyDescriptors({\n /** @this {Node} */\n dispatchEvent: function dispatchEvent(event) {\n flush();\n return this[NATIVE_PREFIX + 'dispatchEvent'](event);\n },\n addEventListener: patch_events_addEventListener,\n removeEventListener: patch_events_removeEventListener\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/Slotable.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\nvar SlotablePatches = getOwnPropertyDescriptors({\n /** @this {Node} */\n get assignedSlot() {\n // Force any parent's shadowRoot to flush so that distribution occurs\n // and this node has an assignedSlot.\n var parent = this[SHADY_PREFIX + 'parentNode'];\n var ownerRoot = parent && parent[SHADY_PREFIX + 'shadowRoot'];\n\n if (ownerRoot) {\n ownerRoot._render();\n }\n\n var nodeData = shadyDataForNode(this);\n return nodeData && nodeData.assignedSlot || null;\n }\n\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/Element.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\n\nvar Element_doc = window.document;\n/**\n * Should be called whenever an attribute changes. If the `slot` attribute\n * changes, provokes rendering if necessary. If a `` element's `name`\n * attribute changes, updates the root's slot map and renders.\n * @param {Node} node\n * @param {string} name\n */\n\nfunction distributeAttributeChange(node, name) {\n if (name === 'slot') {\n var parent = node[SHADY_PREFIX + 'parentNode'];\n\n if (utils_hasShadowRootWithSlot(parent)) {\n shadyDataForNode(parent).root._asyncRender();\n }\n } else if (node.localName === 'slot' && name === 'name') {\n var root = attach_shadow_ownerShadyRootForNode(node);\n\n if (root) {\n root._updateSlotName(node);\n\n root._asyncRender();\n }\n }\n}\n\nvar ElementPatches = getOwnPropertyDescriptors({\n /** @this {Element} */\n get previousElementSibling() {\n var nodeData = shadyDataForNode(this);\n\n if (nodeData && nodeData.previousSibling !== undefined) {\n var n = this[SHADY_PREFIX + 'previousSibling'];\n\n while (n && n.nodeType !== Node.ELEMENT_NODE) {\n n = n[SHADY_PREFIX + 'previousSibling'];\n }\n\n return n;\n } else {\n return this[NATIVE_PREFIX + 'previousElementSibling'];\n }\n },\n\n /** @this {Element} */\n get nextElementSibling() {\n var nodeData = shadyDataForNode(this);\n\n if (nodeData && nodeData.nextSibling !== undefined) {\n var n = this[SHADY_PREFIX + 'nextSibling'];\n\n while (n && n.nodeType !== Node.ELEMENT_NODE) {\n n = n[SHADY_PREFIX + 'nextSibling'];\n }\n\n return n;\n } else {\n return this[NATIVE_PREFIX + 'nextElementSibling'];\n }\n },\n\n /** @this {Element} */\n get slot() {\n return this.getAttribute('slot');\n },\n\n /** @this {Element} */\n set slot(value) {\n this[SHADY_PREFIX + 'setAttribute']('slot', value);\n },\n\n // Note: Can be patched on element prototype on all browsers.\n // Must be patched on instance on browsers that support native Shadow DOM\n // but do not have builtin accessors (old Chrome).\n\n /** @this {Element} */\n get shadowRoot() {\n var nodeData = shadyDataForNode(this);\n return nodeData && nodeData.publicRoot || null;\n },\n\n /** @this {Element} */\n get className() {\n return this.getAttribute('class') || '';\n },\n\n /**\n * @this {Element}\n * @param {string} value\n */\n set className(value) {\n this[SHADY_PREFIX + 'setAttribute']('class', value);\n },\n\n /**\n * @this {Element}\n * @param {string} attr\n * @param {string} value\n */\n setAttribute: function setAttribute(attr, value) {\n if (this.ownerDocument !== Element_doc) {\n this[NATIVE_PREFIX + 'setAttribute'](attr, value);\n } else if (!scopeClassAttribute(this, attr, value)) {\n this[NATIVE_PREFIX + 'setAttribute'](attr, value);\n distributeAttributeChange(this, attr);\n }\n },\n\n /**\n * @this {Element}\n * @param {string} attr\n */\n removeAttribute: function removeAttribute(attr) {\n this[NATIVE_PREFIX + 'removeAttribute'](attr);\n distributeAttributeChange(this, attr);\n },\n\n /**\n * @this {Element}\n * @param {!{mode: string}} options\n */\n attachShadow: function attachShadow(options) {\n return attach_shadow_attachShadow(this, options);\n }\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/HTMLElement.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\nvar HTMLElementPatches = getOwnPropertyDescriptors({\n /** @this {HTMLElement} */\n blur: function blur() {\n var nodeData = shadyDataForNode(this);\n var root = nodeData && nodeData.root;\n var shadowActive = root && root.activeElement;\n\n if (shadowActive) {\n shadowActive[SHADY_PREFIX + 'blur']();\n } else {\n this[NATIVE_PREFIX + 'blur']();\n }\n }\n});\neventPropertyNames.forEach(function (property) {\n HTMLElementPatches[property] = {\n /** @this {HTMLElement} */\n set: function set(fn) {\n var shadyData = ensureShadyDataForNode(this);\n var eventName = property.substring(2);\n shadyData.__onCallbackListeners[property] && this.removeEventListener(eventName, shadyData.__onCallbackListeners[property]);\n this[SHADY_PREFIX + 'addEventListener'](eventName, fn);\n shadyData.__onCallbackListeners[property] = fn;\n },\n\n /** @this {HTMLElement} */\n get: function get() {\n var shadyData = shadyDataForNode(this);\n return shadyData && shadyData.__onCallbackListeners[property];\n },\n configurable: true\n };\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/Slot.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\nvar SlotPatches = getOwnPropertyDescriptors({\n /**\n * @this {HTMLSlotElement}\n * @param {Object=} options\n */\n assignedNodes: function assignedNodes(options) {\n if (this.localName === 'slot') {\n // Force any containing shadowRoot to flush so that distribution occurs\n // and this node has assignedNodes.\n var root = this[SHADY_PREFIX + 'getRootNode']();\n\n if (root && utils_isShadyRoot(root)) {\n root._render();\n }\n\n var nodeData = shadyDataForNode(this);\n return nodeData ? (options && options.flatten ? nodeData.flattenedNodes : nodeData.assignedNodes) || [] : [];\n }\n }\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/Document.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\nvar Document_doc = window.document;\nvar DocumentPatches = getOwnPropertyDescriptors({\n // note: Though not technically correct, we fast path `importNode`\n // when called on a node not owned by the main document.\n // This allows, for example, elements that cannot\n // contain custom elements and are therefore not likely to contain shadowRoots\n // to cloned natively. This is a fairly significant performance win.\n\n /**\n * @this {Document}\n * @param {Node} node\n * @param {boolean} deep\n */\n importNode: function importNode(node, deep) {\n // A template element normally has no children with shadowRoots, so make\n // sure we always make a deep copy to correctly construct the template.content\n if (node.ownerDocument !== Document_doc || node.localName === 'template') {\n return this[NATIVE_PREFIX + 'importNode'](node, deep);\n }\n\n var n = this[NATIVE_PREFIX + 'importNode'](node, false);\n\n if (deep) {\n var c$ = node[SHADY_PREFIX + 'childNodes'];\n\n for (var i = 0, nc; i < c$.length; i++) {\n nc = this[SHADY_PREFIX + 'importNode'](c$[i], true);\n n[SHADY_PREFIX + 'appendChild'](nc);\n }\n }\n\n return n;\n }\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patches/Window.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\nvar WindowPatches = getOwnPropertyDescriptors({\n // NOTE: ensure these methods are bound to `window` so that `this` is correct\n // when called directly from global context without a receiver; e.g.\n // `addEventListener(...)`.\n addEventListener: patch_events_addEventListener.bind(window),\n removeEventListener: patch_events_removeEventListener.bind(window)\n});\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/patch-prototypes.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n\n\n\n\n\n\n\n\n\n\n\n // Some browsers (IE/Edge) have non-standard HTMLElement accessors.\n\nvar NonStandardHTMLElement = {};\n\nif (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'parentElement')) {\n NonStandardHTMLElement.parentElement = NodePatches.parentElement;\n}\n\nif (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'contains')) {\n NonStandardHTMLElement.contains = NodePatches.contains;\n}\n\nif (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'children')) {\n NonStandardHTMLElement.children = ParentNodePatches.children;\n}\n\nif (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'innerHTML')) {\n NonStandardHTMLElement.innerHTML = ElementOrShadowRootPatches.innerHTML;\n}\n\nif (Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'className')) {\n NonStandardHTMLElement.className = ElementPatches.className;\n} // Avoid patching `innerHTML` if it does not exist on Element (IE)\n// and we can patch accessors (hasDescriptors).\n\n\nvar ElementShouldHaveInnerHTML = !settings.hasDescriptors || 'innerHTML' in Element.prototype; // setup patching\n\nvar patchMap = {\n EventTarget: [EventTargetPatches],\n Node: [NodePatches, !window.EventTarget ? EventTargetPatches : null],\n Text: [SlotablePatches],\n Element: [ElementPatches, ParentNodePatches, SlotablePatches, ElementShouldHaveInnerHTML ? ElementOrShadowRootPatches : null, !window.HTMLSlotElement ? SlotPatches : null],\n HTMLElement: [HTMLElementPatches, NonStandardHTMLElement],\n HTMLSlotElement: [SlotPatches],\n DocumentFragment: [ParentNodeDocumentOrFragmentPatches, DocumentOrFragmentPatches],\n Document: [DocumentPatches, ParentNodeDocumentOrFragmentPatches, DocumentOrFragmentPatches, DocumentOrShadowRootPatches],\n Window: [WindowPatches]\n};\n\nvar getPatchPrototype = function getPatchPrototype(name) {\n return window[name] && window[name].prototype;\n}; // Note, must avoid patching accessors on prototypes when descriptors are not correct\n// because the CustomElements polyfill checks if these exist before patching instances.\n// CustomElements polyfill *only* cares about these accessors.\n\n\nvar disallowedNativePatches = settings.hasDescriptors ? null : ['innerHTML', 'textContent'];\n/** @param {string=} prefix */\n\nvar patch_prototypes_applyPatches = function applyPatches(prefix) {\n var disallowed = prefix ? null : disallowedNativePatches;\n\n var _loop = function _loop(p) {\n var proto = getPatchPrototype(p);\n patchMap[p].forEach(function (patch) {\n return proto && patch && patchProperties(proto, patch, prefix, disallowed);\n });\n };\n\n for (var p in patchMap) {\n _loop(p);\n }\n};\nvar patch_prototypes_addShadyPrefixedProperties = function addShadyPrefixedProperties() {\n // perform shady patches\n patch_prototypes_applyPatches(SHADY_PREFIX); // install `_activeElement` because some browsers (older Chrome/Safari) do not have\n // a 'configurable' `activeElement` accesssor.\n\n var descriptor = DocumentOrShadowRootPatches.activeElement;\n Object.defineProperty(document, '_activeElement', descriptor); // On Window, we're patching `addEventListener` which is a weird auto-bound\n // property that is not directly on the Window prototype.\n\n patchProperties(Window.prototype, WindowPatches, SHADY_PREFIX);\n};\n// CONCATENATED MODULE: ./node_modules/@webcomponents/shadydom/src/shadydom.js\n/**\n@license\nCopyright (c) 2016 The Polymer Project Authors. All rights reserved.\nThis code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\nThe complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\nThe complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\nCode distributed by Google as part of the polymer project is also\nsubject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n*/\n\n/**\n * Patches elements that interacts with ShadyDOM\n * such that tree traversal and mutation apis act like they would under\n * ShadowDOM.\n *\n * This import enables seemless interaction with ShadyDOM powered\n * custom elements, enabling better interoperation with 3rd party code,\n * libraries, and frameworks that use DOM tree manipulation apis.\n */\n\n\n\n\n\n\n\n\n\n\nif (settings.inUse) {\n var ShadyDOM = {\n // TODO(sorvell): remove when Polymer does not depend on this.\n 'inUse': settings.inUse,\n // NOTE: old browsers without prototype accessors (very old Chrome\n // and Safari) need manually patched accessors to properly set\n // `innerHTML` and `textContent` when an element is:\n // (1) inside a shadowRoot\n // (2) does not have special (slot) children itself\n // (3) and setting the property needs to provoke distribution (because\n // a nested slot is added/removed)\n 'patch': function patch(node) {\n patchInsideElementAccessors(node);\n patchOutsideElementAccessors(node);\n return node;\n },\n 'isShadyRoot': utils_isShadyRoot,\n 'enqueue': enqueue,\n 'flush': flush,\n 'flushInitial': function flushInitial(root) {\n root._flushInitial();\n },\n 'settings': settings,\n 'filterMutations': filterMutations,\n 'observeChildren': observe_changes_observeChildren,\n 'unobserveChildren': observe_changes_unobserveChildren,\n // Set to true to defer native custom elements connection until the\n // document has fully parsed. This enables custom elements that create\n // shadowRoots to be defined while the document is loading. Elements\n // customized as they are created by the parser will successfully\n // render with this flag on.\n 'deferConnectionCallbacks': settings['deferConnectionCallbacks'],\n // Set to true to speed up the polyfill slightly at the cost of correctness\n // * does not patch querySelector/All on Document or DocumentFragment\n // * does not wrap connected/disconnected callbacks to de-dup these\n // when using native customElements\n // * does not wait to process children of elements with shadowRoots\n // meaning shadowRoots should not be created while an element is parsing\n // (e.g. if a custom element that creates a shadowRoot is defined before\n // a candidate element in the document below it.\n 'preferPerformance': settings['preferPerformance'],\n // Integration point with ShadyCSS to disable styling MutationObserver,\n // as ShadyDOM will now handle dynamic scoping.\n 'handlesDynamicScoping': true,\n 'wrap': settings.noPatch ? wrap : function (n) {\n return n;\n },\n 'Wrapper': wrapper_Wrapper,\n 'composedPath': patch_events_composedPath,\n // Set to true to avoid patching regular platform property names. When set,\n // Shadow DOM compatible behavior is only available when accessing DOM\n // API using `ShadyDOM.wrap`, e.g. `ShadyDOM.wrap(element).shadowRoot`.\n // This setting provides a small performance boost, but requires all DOM API\n // access that requires Shadow DOM behavior to be proxied via `ShadyDOM.wrap`.\n 'noPatch': settings.noPatch,\n 'nativeMethods': nativeMethods,\n 'nativeTree': nativeTree\n };\n window['ShadyDOM'] = ShadyDOM; // Modifies native prototypes for Node, Element, etc. to\n // make native platform behavior available at prefixed names, e.g.\n // `utils.NATIVE_PREFIX + 'firstChild'` or `__shady_native_firstChild`.\n // This allows the standard names to be safely patched while retaining the\n // ability for native behavior to be used. This polyfill manipulates DOM\n // by using this saved native behavior.\n // Note, some browsers do not have proper element descriptors for\n // accessors; in this case, native behavior for these accessors is simulated\n // via a TreeWalker.\n\n patch_native_addNativePrefixedProperties(); // Modifies native prototypes for Node, Element, etc. to make ShadowDOM\n // behavior available at prefixed names, e.g.\n // `utils.SHADY_PREFIX + 'firstChild` or `__shady_firstChild`. This is done\n // so this polyfill can perform Shadow DOM style DOM manipulation.\n // Because patching normal platform property names is optional, these prefixed\n // names are used internally.\n\n patch_prototypes_addShadyPrefixedProperties(); // Modifies native prototypes for Node, Element, etc. to patch\n // regular platform property names to have Shadow DOM compatible API behavior.\n // This applies the utils.SHADY_PREFIX behavior to normal names. For example,\n // if `noPatch` is not set, then `el.__shady_firstChild` is equivalent to\n // `el.firstChild`.\n // NOTE, on older browsers (old Chrome/Safari) native accessors cannot be\n // patched on prototypes (e.g. Node.prototype.firstChild cannot be modified).\n // On these browsers, instance level patching is performed where needed; this\n // instance patching is only done when `noPatch` is *not* set.\n\n if (!settings.noPatch) {\n patch_prototypes_applyPatches(); // Patch click event behavior only if we're patching\n\n patchClick();\n } // For simplicity, patch events unconditionally.\n // Patches the event system to have Shadow DOM compatible behavior (e.g.\n // event retargeting). When `noPatch` is set, retargeting is only available\n // when adding event listeners and dispatching events via `ShadyDOM.wrap`\n // (e.g. `ShadyDOM.wrap(element).addEventListener(...)`).\n\n\n patchEvents();\n window.ShadowRoot =\n /** @type {function(new:ShadowRoot)} */\n attach_shadow_ShadyRoot;\n}\n\n//# sourceURL=webpack:///./node_modules/@webcomponents/shadydom/src/shadydom.js_+_28_modules?");
-
-/***/ })
-
-}]);
\ No newline at end of file
diff --git a/packages/uikit-workshop/dist/styleguide/js/1-chunk-861f2bf3817d7850085a.js b/packages/uikit-workshop/dist/styleguide/js/1-chunk-861f2bf3817d7850085a.js
deleted file mode 100644
index 73c9dde7c..000000000
--- a/packages/uikit-workshop/dist/styleguide/js/1-chunk-861f2bf3817d7850085a.js
+++ /dev/null
@@ -1,15 +0,0 @@
-(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[1],{
-
-/***/ "./node_modules/document-register-element/build/document-register-element.js":
-/*!***********************************************************************************!*\
- !*** ./node_modules/document-register-element/build/document-register-element.js ***!
- \***********************************************************************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports) {
-
-eval("function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n/*! (C) Andrea Giammarchi - @WebReflection - ISC Style License */\n!function (e, t) {\n \"use strict\";\n\n function n() {\n var e = A.splice(0, A.length);\n\n for (Ye = 0; e.length;) {\n e.shift().call(null, e.shift());\n }\n }\n\n function r(e, t) {\n for (var n = 0, r = e.length; n < r; n++) {\n T(e[n], t);\n }\n }\n\n function o(e) {\n for (var t, n = 0, r = e.length; n < r; n++) {\n t = e[n], V(t, le[a(t)]);\n }\n }\n\n function l(e) {\n return function (t) {\n ke(t) && (T(t, e), ae.length && r(t.querySelectorAll(ae), e));\n };\n }\n\n function a(e) {\n var t = Ze.call(e, \"is\"),\n n = e.nodeName.toUpperCase(),\n r = ue.call(oe, t ? te + t.toUpperCase() : ee + n);\n return t && -1 < r && !i(n, t) ? -1 : r;\n }\n\n function i(e, t) {\n return -1 < ae.indexOf(e + '[is=\"' + t + '\"]');\n }\n\n function u(e) {\n var t = e.currentTarget,\n n = e.attrChange,\n r = e.attrName,\n o = e.target,\n l = e[$] || 2,\n a = e[Q] || 3;\n !ot || o && o !== t || !t[Z] || \"style\" === r || e.prevValue === e.newValue && (\"\" !== e.newValue || n !== l && n !== a) || t[Z](r, n === l ? null : e.prevValue, n === a ? null : e.newValue);\n }\n\n function c(e) {\n var t = l(e);\n return function (e) {\n A.push(t, e.target), Ye && clearTimeout(Ye), Ye = setTimeout(n, 1);\n };\n }\n\n function s(e) {\n rt && (rt = !1, e.currentTarget.removeEventListener(Y, s)), ae.length && r((e.target || y).querySelectorAll(ae), e.detail === q ? q : _), Re && d();\n }\n\n function m(e, t) {\n var n = this;\n ze.call(n, e, t), O.call(n, {\n target: n\n });\n }\n\n function f(e, t, n) {\n var r = t.apply(e, n),\n l = a(r);\n return -1 < l && V(r, le[l]), n.pop() && ae.length && o(r.querySelectorAll(ae)), r;\n }\n\n function p(e, t) {\n Fe(e, t), I ? I.observe(e, Qe) : (nt && (e.setAttribute = m, e[U] = D(e), e[k](J, O)), e[k](W, u)), e[K] && ot && (e.created = !0, e[K](), e.created = !1);\n }\n\n function d() {\n for (var e, t = 0, n = _e.length; t < n; t++) {\n e = _e[t], ie.contains(e) || (n--, _e.splice(t--, 1), T(e, q));\n }\n }\n\n function h(e) {\n throw new Error(\"A \" + e + \" type is already registered\");\n }\n\n function T(e, t) {\n var n,\n r,\n o = a(e);\n -1 < o && (S(e, le[o]), o = 0, t !== _ || e[_] ? t !== q || e[q] || (e[_] = !1, e[q] = !0, r = \"disconnected\", o = 1) : (e[q] = !1, e[_] = !0, r = \"connected\", o = 1, Re && ue.call(_e, e) < 0 && _e.push(e)), o && (n = e[t + x] || e[r + x]) && n.call(e));\n }\n\n function L() {}\n\n function M(e, t, n) {\n var r = n && n[B] || \"\",\n o = t.prototype,\n l = Ie(o),\n a = t.observedAttributes || pe,\n i = {\n prototype: l\n };\n Ue(l, K, {\n value: function value() {\n if (we) we = !1;else if (!this[ve]) {\n this[ve] = !0, new t(this), o[K] && o[K].call(this);\n var e = Ae[Ne.get(t)];\n (!ge || e.create.length > 1) && H(this);\n }\n }\n }), Ue(l, Z, {\n value: function value(e) {\n -1 < ue.call(a, e) && o[Z] && o[Z].apply(this, arguments);\n }\n }), o[G] && Ue(l, j, {\n value: o[G]\n }), o[z] && Ue(l, X, {\n value: o[z]\n }), r && (i[B] = r), e = e.toUpperCase(), Ae[e] = {\n constructor: t,\n create: r ? [r, De(e)] : [e]\n }, Ne.set(t, e), y[R](e.toLowerCase(), i), g(e), Oe[e].r();\n }\n\n function E(e) {\n var t = Ae[e.toUpperCase()];\n return t && t.constructor;\n }\n\n function v(e) {\n return \"string\" == typeof e ? e : e && e.is || \"\";\n }\n\n function H(e) {\n for (var t, n = e[Z], r = n ? e.attributes : pe, o = r.length; o--;) {\n t = r[o], n.call(e, t.name || t.nodeName, null, t.value || t.nodeValue);\n }\n }\n\n function g(e) {\n return e = e.toUpperCase(), e in Oe || (Oe[e] = {}, Oe[e].p = new Ce(function (t) {\n Oe[e].r = t;\n })), Oe[e].p;\n }\n\n function b() {\n He && delete e.customElements, fe(e, \"customElements\", {\n configurable: !0,\n value: new L()\n }), fe(e, \"CustomElementRegistry\", {\n configurable: !0,\n value: L\n });\n\n for (var t = w.get(/^HTML[A-Z]*[a-z]/), n = t.length; n--; function (t) {\n var n = e[t];\n\n if (n) {\n e[t] = function (e) {\n var t, r;\n return e || (e = this), e[ve] || (we = !0, t = Ae[Ne.get(e.constructor)], r = ge && 1 === t.create.length, e = r ? Reflect.construct(n, pe, t.constructor) : y.createElement.apply(y, t.create), e[ve] = !0, we = !1, r || H(e)), e;\n }, e[t].prototype = n.prototype;\n\n try {\n n.prototype.constructor = e[t];\n } catch (r) {\n Ee = !0, fe(n, ve, {\n value: e[t]\n });\n }\n }\n }(t[n])) {\n ;\n }\n\n y.createElement = function (e, t) {\n var n = v(t);\n return n ? $e.call(this, e, De(n)) : $e.call(this, e);\n }, Je || (tt = !0, y[R](\"\"));\n }\n\n var y = e.document,\n C = e.Object,\n w = function (e) {\n var t,\n n,\n r,\n o,\n l = /^[A-Z]+[a-z]/,\n a = function a(e) {\n var t,\n n = [];\n\n for (t in u) {\n e.test(t) && n.push(t);\n }\n\n return n;\n },\n i = function i(e, t) {\n (t = t.toLowerCase()) in u || (u[e] = (u[e] || []).concat(t), u[t] = u[t.toUpperCase()] = e);\n },\n u = (C.create || C)(null),\n c = {};\n\n for (n in e) {\n for (o in e[n]) {\n for (r = e[n][o], u[o] = r, t = 0; t < r.length; t++) {\n u[r[t].toLowerCase()] = u[r[t].toUpperCase()] = o;\n }\n }\n }\n\n return c.get = function (e) {\n return \"string\" == typeof e ? u[e] || (l.test(e) ? [] : \"\") : a(e);\n }, c.set = function (e, t) {\n return l.test(e) ? i(e, t) : i(t, e), c;\n }, c;\n }({\n collections: {\n HTMLAllCollection: [\"all\"],\n HTMLCollection: [\"forms\"],\n HTMLFormControlsCollection: [\"elements\"],\n HTMLOptionsCollection: [\"options\"]\n },\n elements: {\n Element: [\"element\"],\n HTMLAnchorElement: [\"a\"],\n HTMLAppletElement: [\"applet\"],\n HTMLAreaElement: [\"area\"],\n HTMLAttachmentElement: [\"attachment\"],\n HTMLAudioElement: [\"audio\"],\n HTMLBRElement: [\"br\"],\n HTMLBaseElement: [\"base\"],\n HTMLBodyElement: [\"body\"],\n HTMLButtonElement: [\"button\"],\n HTMLCanvasElement: [\"canvas\"],\n HTMLContentElement: [\"content\"],\n HTMLDListElement: [\"dl\"],\n HTMLDataElement: [\"data\"],\n HTMLDataListElement: [\"datalist\"],\n HTMLDetailsElement: [\"details\"],\n HTMLDialogElement: [\"dialog\"],\n HTMLDirectoryElement: [\"dir\"],\n HTMLDivElement: [\"div\"],\n HTMLDocument: [\"document\"],\n HTMLElement: [\"element\", \"abbr\", \"address\", \"article\", \"aside\", \"b\", \"bdi\", \"bdo\", \"cite\", \"code\", \"command\", \"dd\", \"dfn\", \"dt\", \"em\", \"figcaption\", \"figure\", \"footer\", \"header\", \"i\", \"kbd\", \"mark\", \"nav\", \"noscript\", \"rp\", \"rt\", \"ruby\", \"s\", \"samp\", \"section\", \"small\", \"strong\", \"sub\", \"summary\", \"sup\", \"u\", \"var\", \"wbr\"],\n HTMLEmbedElement: [\"embed\"],\n HTMLFieldSetElement: [\"fieldset\"],\n HTMLFontElement: [\"font\"],\n HTMLFormElement: [\"form\"],\n HTMLFrameElement: [\"frame\"],\n HTMLFrameSetElement: [\"frameset\"],\n HTMLHRElement: [\"hr\"],\n HTMLHeadElement: [\"head\"],\n HTMLHeadingElement: [\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\"],\n HTMLHtmlElement: [\"html\"],\n HTMLIFrameElement: [\"iframe\"],\n HTMLImageElement: [\"img\"],\n HTMLInputElement: [\"input\"],\n HTMLKeygenElement: [\"keygen\"],\n HTMLLIElement: [\"li\"],\n HTMLLabelElement: [\"label\"],\n HTMLLegendElement: [\"legend\"],\n HTMLLinkElement: [\"link\"],\n HTMLMapElement: [\"map\"],\n HTMLMarqueeElement: [\"marquee\"],\n HTMLMediaElement: [\"media\"],\n HTMLMenuElement: [\"menu\"],\n HTMLMenuItemElement: [\"menuitem\"],\n HTMLMetaElement: [\"meta\"],\n HTMLMeterElement: [\"meter\"],\n HTMLModElement: [\"del\", \"ins\"],\n HTMLOListElement: [\"ol\"],\n HTMLObjectElement: [\"object\"],\n HTMLOptGroupElement: [\"optgroup\"],\n HTMLOptionElement: [\"option\"],\n HTMLOutputElement: [\"output\"],\n HTMLParagraphElement: [\"p\"],\n HTMLParamElement: [\"param\"],\n HTMLPictureElement: [\"picture\"],\n HTMLPreElement: [\"pre\"],\n HTMLProgressElement: [\"progress\"],\n HTMLQuoteElement: [\"blockquote\", \"q\", \"quote\"],\n HTMLScriptElement: [\"script\"],\n HTMLSelectElement: [\"select\"],\n HTMLShadowElement: [\"shadow\"],\n HTMLSlotElement: [\"slot\"],\n HTMLSourceElement: [\"source\"],\n HTMLSpanElement: [\"span\"],\n HTMLStyleElement: [\"style\"],\n HTMLTableCaptionElement: [\"caption\"],\n HTMLTableCellElement: [\"td\", \"th\"],\n HTMLTableColElement: [\"col\", \"colgroup\"],\n HTMLTableElement: [\"table\"],\n HTMLTableRowElement: [\"tr\"],\n HTMLTableSectionElement: [\"thead\", \"tbody\", \"tfoot\"],\n HTMLTemplateElement: [\"template\"],\n HTMLTextAreaElement: [\"textarea\"],\n HTMLTimeElement: [\"time\"],\n HTMLTitleElement: [\"title\"],\n HTMLTrackElement: [\"track\"],\n HTMLUListElement: [\"ul\"],\n HTMLUnknownElement: [\"unknown\", \"vhgroupv\", \"vkeygen\"],\n HTMLVideoElement: [\"video\"]\n },\n nodes: {\n Attr: [\"node\"],\n Audio: [\"audio\"],\n CDATASection: [\"node\"],\n CharacterData: [\"node\"],\n Comment: [\"#comment\"],\n Document: [\"#document\"],\n DocumentFragment: [\"#document-fragment\"],\n DocumentType: [\"node\"],\n HTMLDocument: [\"#document\"],\n Image: [\"img\"],\n Option: [\"option\"],\n ProcessingInstruction: [\"node\"],\n ShadowRoot: [\"#shadow-root\"],\n Text: [\"#text\"],\n XMLDocument: [\"xml\"]\n }\n });\n\n \"object\" != _typeof(t) && (t = {\n type: t || \"auto\"\n });\n\n var A,\n O,\n N,\n D,\n I,\n F,\n S,\n V,\n P,\n R = \"registerElement\",\n U = \"__\" + R + (1e5 * e.Math.random() >> 0),\n k = \"addEventListener\",\n _ = \"attached\",\n x = \"Callback\",\n q = \"detached\",\n B = \"extends\",\n Z = \"attributeChanged\" + x,\n j = _ + x,\n G = \"connected\" + x,\n z = \"disconnected\" + x,\n K = \"created\" + x,\n X = q + x,\n $ = \"ADDITION\",\n Q = \"REMOVAL\",\n W = \"DOMAttrModified\",\n Y = \"DOMContentLoaded\",\n J = \"DOMSubtreeModified\",\n ee = \"<\",\n te = \"=\",\n ne = /^[A-Z][A-Z0-9]*(?:-[A-Z0-9]+)+$/,\n re = [\"ANNOTATION-XML\", \"COLOR-PROFILE\", \"FONT-FACE\", \"FONT-FACE-SRC\", \"FONT-FACE-URI\", \"FONT-FACE-FORMAT\", \"FONT-FACE-NAME\", \"MISSING-GLYPH\"],\n oe = [],\n le = [],\n ae = \"\",\n ie = y.documentElement,\n ue = oe.indexOf || function (e) {\n for (var t = this.length; t-- && this[t] !== e;) {\n ;\n }\n\n return t;\n },\n ce = C.prototype,\n se = ce.hasOwnProperty,\n me = ce.isPrototypeOf,\n fe = C.defineProperty,\n pe = [],\n de = C.getOwnPropertyDescriptor,\n he = C.getOwnPropertyNames,\n Te = C.getPrototypeOf,\n Le = C.setPrototypeOf,\n Me = !!C.__proto__,\n Ee = !1,\n ve = \"__dreCEv1\",\n He = e.customElements,\n ge = !/^force/.test(t.type) && !!(He && He.define && He.get && He.whenDefined),\n be = C.create || C,\n ye = e.Map || function () {\n var e,\n t = [],\n n = [];\n return {\n get: function get(e) {\n return n[ue.call(t, e)];\n },\n set: function set(r, o) {\n e = ue.call(t, r), e < 0 ? n[t.push(r) - 1] = o : n[e] = o;\n }\n };\n },\n Ce = e.Promise || function (e) {\n function t(e) {\n for (r = !0; n.length;) {\n n.shift()(e);\n }\n }\n\n var n = [],\n r = !1,\n o = {\n \"catch\": function _catch() {\n return o;\n },\n then: function then(e) {\n return n.push(e), r && setTimeout(t, 1), o;\n }\n };\n return e(t), o;\n },\n we = !1,\n Ae = be(null),\n Oe = be(null),\n Ne = new ye(),\n De = function De(e) {\n return e.toLowerCase();\n },\n Ie = C.create || function it(e) {\n return e ? (it.prototype = e, new it()) : this;\n },\n Fe = Le || (Me ? function (e, t) {\n return e.__proto__ = t, e;\n } : he && de ? function () {\n function e(e, t) {\n for (var n, r = he(t), o = 0, l = r.length; o < l; o++) {\n n = r[o], se.call(e, n) || fe(e, n, de(t, n));\n }\n }\n\n return function (t, n) {\n do {\n e(t, n);\n } while ((n = Te(n)) && !me.call(n, t));\n\n return t;\n };\n }() : function (e, t) {\n for (var n in t) {\n e[n] = t[n];\n }\n\n return e;\n }),\n Se = e.MutationObserver || e.WebKitMutationObserver,\n Ve = e.HTMLAnchorElement,\n Pe = (e.HTMLElement || e.Element || e.Node).prototype,\n Re = !me.call(Pe, ie),\n Ue = Re ? function (e, t, n) {\n return e[t] = n.value, e;\n } : fe,\n ke = Re ? function (e) {\n return 1 === e.nodeType;\n } : function (e) {\n return me.call(Pe, e);\n },\n _e = Re && [],\n xe = Pe.attachShadow,\n qe = Pe.cloneNode,\n Be = Pe.dispatchEvent,\n Ze = Pe.getAttribute,\n je = Pe.hasAttribute,\n Ge = Pe.removeAttribute,\n ze = Pe.setAttribute,\n Ke = y.createElement,\n Xe = y.importNode,\n $e = Ke,\n Qe = Se && {\n attributes: !0,\n characterData: !0,\n attributeOldValue: !0\n },\n We = Se || function (e) {\n nt = !1, ie.removeEventListener(W, We);\n },\n Ye = 0,\n Je = R in y && !/^force-all/.test(t.type),\n et = !0,\n tt = !1,\n nt = !0,\n rt = !0,\n ot = !0;\n\n if (Se && (P = y.createElement(\"div\"), P.innerHTML = \"\", new Se(function (e, t) {\n if (e[0] && \"childList\" == e[0].type && !e[0].removedNodes[0].childNodes.length) {\n P = de(Pe, \"innerHTML\");\n var n = P && P.set;\n n && fe(Pe, \"innerHTML\", {\n set: function set(e) {\n for (; this.lastChild;) {\n this.removeChild(this.lastChild);\n }\n\n n.call(this, e);\n }\n });\n }\n\n t.disconnect(), P = null;\n }).observe(P, {\n childList: !0,\n subtree: !0\n }), P.innerHTML = \"\"), Je || (Le || Me ? (S = function S(e, t) {\n me.call(t, e) || p(e, t);\n }, V = p) : (S = function S(e, t) {\n e[U] || (e[U] = C(!0), p(e, t));\n }, V = S), Re ? (nt = !1, function () {\n var e = de(Pe, k),\n t = e.value,\n n = function n(e) {\n var t = new CustomEvent(W, {\n bubbles: !0\n });\n t.attrName = e, t.prevValue = Ze.call(this, e), t.newValue = null, t[Q] = t.attrChange = 2, Ge.call(this, e), Be.call(this, t);\n },\n r = function r(e, t) {\n var n = je.call(this, e),\n r = n && Ze.call(this, e),\n o = new CustomEvent(W, {\n bubbles: !0\n });\n ze.call(this, e, t), o.attrName = e, o.prevValue = n ? r : null, o.newValue = t, n ? o.MODIFICATION = o.attrChange = 1 : o[$] = o.attrChange = 0, Be.call(this, o);\n },\n o = function o(e) {\n var t,\n n = e.currentTarget,\n r = n[U],\n o = e.propertyName;\n r.hasOwnProperty(o) && (r = r[o], t = new CustomEvent(W, {\n bubbles: !0\n }), t.attrName = r.name, t.prevValue = r.value || null, t.newValue = r.value = n[o] || null, null == t.prevValue ? t[$] = t.attrChange = 0 : t.MODIFICATION = t.attrChange = 1, Be.call(n, t));\n };\n\n e.value = function (e, l, a) {\n e === W && this[Z] && this.setAttribute !== r && (this[U] = {\n className: {\n name: \"class\",\n value: this.className\n }\n }, this.setAttribute = r, this.removeAttribute = n, t.call(this, \"propertychange\", o)), t.call(this, e, l, a);\n }, fe(Pe, k, e);\n }()) : Se || (ie[k](W, We), ie.setAttribute(U, 1), ie.removeAttribute(U), nt && (O = function O(e) {\n var t,\n n,\n r,\n o = this;\n\n if (o === e.target) {\n t = o[U], o[U] = n = D(o);\n\n for (r in n) {\n if (!(r in t)) return N(0, o, r, t[r], n[r], $);\n if (n[r] !== t[r]) return N(1, o, r, t[r], n[r], \"MODIFICATION\");\n }\n\n for (r in t) {\n if (!(r in n)) return N(2, o, r, t[r], n[r], Q);\n }\n }\n }, N = function N(e, t, n, r, o, l) {\n var a = {\n attrChange: e,\n currentTarget: t,\n attrName: n,\n prevValue: r,\n newValue: o\n };\n a[l] = e, u(a);\n }, D = function D(e) {\n for (var t, n, r = {}, o = e.attributes, l = 0, a = o.length; l < a; l++) {\n t = o[l], \"setAttribute\" !== (n = t.name) && (r[n] = t.value);\n }\n\n return r;\n })), y[R] = function (e, t) {\n if (n = e.toUpperCase(), et && (et = !1, Se ? (I = function (e, t) {\n function n(e, t) {\n for (var n = 0, r = e.length; n < r; t(e[n++])) {\n ;\n }\n }\n\n return new Se(function (r) {\n for (var o, l, a, i = 0, u = r.length; i < u; i++) {\n o = r[i], \"childList\" === o.type ? (n(o.addedNodes, e), n(o.removedNodes, t)) : (l = o.target, ot && l[Z] && \"style\" !== o.attributeName && (a = Ze.call(l, o.attributeName)) !== o.oldValue && l[Z](o.attributeName, o.oldValue, a));\n }\n });\n }(l(_), l(q)), F = function F(e) {\n return I.observe(e, {\n childList: !0,\n subtree: !0\n }), e;\n }, F(y), xe && (Pe.attachShadow = function () {\n return F(xe.apply(this, arguments));\n })) : (A = [], y[k](\"DOMNodeInserted\", c(_)), y[k](\"DOMNodeRemoved\", c(q))), y[k](Y, s), y[k](\"readystatechange\", s), y.importNode = function (e, t) {\n switch (e.nodeType) {\n case 1:\n return f(y, Xe, [e, !!t]);\n\n case 11:\n for (var n = y.createDocumentFragment(), r = e.childNodes, o = r.length, l = 0; l < o; l++) {\n n.appendChild(y.importNode(r[l], !!t));\n }\n\n return n;\n\n default:\n return qe.call(e, !!t);\n }\n }, Pe.cloneNode = function (e) {\n return f(this, qe, [!!e]);\n }), tt) return tt = !1;\n if (-2 < ue.call(oe, te + n) + ue.call(oe, ee + n) && h(e), !ne.test(n) || -1 < ue.call(re, n)) throw new Error(\"The type \" + e + \" is invalid\");\n\n var n,\n o,\n a = function a() {\n return u ? y.createElement(m, n) : y.createElement(m);\n },\n i = t || ce,\n u = se.call(i, B),\n m = u ? t[B].toUpperCase() : n;\n\n return u && -1 < ue.call(oe, ee + m) && h(m), o = oe.push((u ? te : ee) + n) - 1, ae = ae.concat(ae.length ? \",\" : \"\", u ? m + '[is=\"' + e.toLowerCase() + '\"]' : m), a.prototype = le[o] = se.call(i, \"prototype\") ? i.prototype : Ie(Pe), ae.length && r(y.querySelectorAll(ae), _), a;\n }, y.createElement = $e = function $e(e, t) {\n var n = v(t),\n r = n ? Ke.call(y, e, De(n)) : Ke.call(y, e),\n o = \"\" + e,\n l = ue.call(oe, (n ? te : ee) + (n || o).toUpperCase()),\n a = -1 < l;\n return n && (r.setAttribute(\"is\", n = n.toLowerCase()), a && (a = i(o.toUpperCase(), n))), ot = !y.createElement.innerHTMLHelper, a && V(r, le[l]), r;\n }), L.prototype = {\n constructor: L,\n define: ge ? function (e, t, n) {\n if (n) M(e, t, n);else {\n var r = e.toUpperCase();\n Ae[r] = {\n constructor: t,\n create: [r]\n }, Ne.set(t, r), He.define(e, t);\n }\n } : M,\n get: ge ? function (e) {\n return He.get(e) || E(e);\n } : E,\n whenDefined: ge ? function (e) {\n return Ce.race([He.whenDefined(e), g(e)]);\n } : g\n }, !He || /^force/.test(t.type)) b();else if (!t.noBuiltIn) try {\n !function (t, n, r) {\n var o = new RegExp(\"^ $\");\n if (n[B] = \"a\", t.prototype = Ie(Ve.prototype), t.prototype.constructor = t, e.customElements.define(r, t, n), !o.test(y.createElement(\"a\", {\n is: r\n }).outerHTML) || !o.test(new t().outerHTML)) throw n;\n }(function ut() {\n return Reflect.construct(Ve, [], ut);\n }, {}, \"document-register-element-a\");\n } catch (lt) {\n b();\n }\n if (!t.noBuiltIn) try {\n if (Ke.call(y, \"a\", \"a\").outerHTML.indexOf(\"is\") < 0) throw {};\n } catch (at) {\n De = function De(e) {\n return {\n is: e.toLowerCase()\n };\n };\n }\n}(window);\n\n//# sourceURL=webpack:///./node_modules/document-register-element/build/document-register-element.js?");
-
-/***/ })
-
-}]);
\ No newline at end of file
diff --git a/packages/uikit-workshop/dist/styleguide/js/2-chunk-e309c72e0e8f5783df94.js b/packages/uikit-workshop/dist/styleguide/js/2-chunk-e309c72e0e8f5783df94.js
deleted file mode 100644
index de9e8f130..000000000
--- a/packages/uikit-workshop/dist/styleguide/js/2-chunk-e309c72e0e8f5783df94.js
+++ /dev/null
@@ -1,15 +0,0 @@
-(window["webpackJsonp"] = window["webpackJsonp"] || []).push([[2],{
-
-/***/ "./node_modules/@webcomponents/custom-elements/src/native-shim.js":
-/*!************************************************************************!*\
- !*** ./node_modules/@webcomponents/custom-elements/src/native-shim.js ***!
- \************************************************************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports) {
-
-eval("/**\n * @license\n * Copyright (c) 2016 The Polymer Project Authors. All rights reserved.\n * This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt\n * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt\n * The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt\n * Code distributed by Google as part of the polymer project is also\n * subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt\n */\n\n/**\n * This shim allows elements written in, or compiled to, ES5 to work on native\n * implementations of Custom Elements v1. It sets new.target to the value of\n * this.constructor so that the native HTMLElement constructor can access the\n * current under-construction element's definition.\n */\n(function () {\n if ( // No Reflect, no classes, no need for shim because native custom elements\n // require ES2015 classes or Reflect.\n window.Reflect === undefined || window.customElements === undefined || // The webcomponentsjs custom elements polyfill doesn't require\n // ES2015-compatible construction (`super()` or `Reflect.construct`).\n window.customElements.hasOwnProperty('polyfillWrapFlushCallback')) {\n return;\n }\n\n var BuiltInHTMLElement = HTMLElement;\n\n window.HTMLElement = function HTMLElement() {\n return Reflect.construct(BuiltInHTMLElement, [], this.constructor);\n };\n\n HTMLElement.prototype = BuiltInHTMLElement.prototype;\n HTMLElement.prototype.constructor = HTMLElement;\n Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement);\n})();\n\n//# sourceURL=webpack:///./node_modules/@webcomponents/custom-elements/src/native-shim.js?");
-
-/***/ })
-
-}]);
\ No newline at end of file
diff --git a/packages/uikit-workshop/dist/styleguide/js/patternlab-pattern.js b/packages/uikit-workshop/dist/styleguide/js/patternlab-pattern.js
deleted file mode 100644
index 107d34080..000000000
--- a/packages/uikit-workshop/dist/styleguide/js/patternlab-pattern.js
+++ /dev/null
@@ -1,228 +0,0 @@
-/******/ (function(modules) { // webpackBootstrap
-/******/ // The module cache
-/******/ var 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)
-/******/ var 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;
-/******/
-/******/ // define getter function for harmony exports
-/******/ __webpack_require__.d = function(exports, name, getter) {
-/******/ if(!__webpack_require__.o(exports, name)) {
-/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
-/******/ }
-/******/ };
-/******/
-/******/ // define __esModule on exports
-/******/ __webpack_require__.r = function(exports) {
-/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
-/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
-/******/ }
-/******/ Object.defineProperty(exports, '__esModule', { value: true });
-/******/ };
-/******/
-/******/ // create a fake namespace object
-/******/ // mode & 1: value is a module id, require it
-/******/ // mode & 2: merge all properties of value into the ns
-/******/ // mode & 4: return value when already ns object
-/******/ // mode & 8|1: behave like require
-/******/ __webpack_require__.t = function(value, mode) {
-/******/ if(mode & 1) value = __webpack_require__(value);
-/******/ if(mode & 8) return value;
-/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
-/******/ var ns = Object.create(null);
-/******/ __webpack_require__.r(ns);
-/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
-/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
-/******/ return ns;
-/******/ };
-/******/
-/******/ // getDefaultExport function for compatibility with non-harmony modules
-/******/ __webpack_require__.n = function(module) {
-/******/ var 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 = "./styleguide/";
-/******/
-/******/
-/******/ // Load entry module and return exports
-/******/ return __webpack_require__(__webpack_require__.s = "./src/scripts/patternlab-pattern.js");
-/******/ })
-/************************************************************************/
-/******/ ({
-
-/***/ "./node_modules/clipboard/dist/clipboard.js":
-/*!**************************************************!*\
- !*** ./node_modules/clipboard/dist/clipboard.js ***!
- \**************************************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports, __webpack_require__) {
-
-eval("/* WEBPACK VAR INJECTION */(function(module) {var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;function _typeof2(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof2(obj); }\n\n/*!\n * clipboard.js v2.0.4\n * https://zenorocha.github.io/clipboard.js\n * \n * Licensed MIT © Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n if (( false ? undefined : _typeof2(exports)) === 'object' && ( false ? undefined : _typeof2(module)) === 'object') module.exports = factory();else if (true) !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));else {}\n})(this, function () {\n return (\n /******/\n function (modules) {\n // webpackBootstrap\n\n /******/\n // The module cache\n\n /******/\n var installedModules = {};\n /******/\n\n /******/\n // The require function\n\n /******/\n\n function __webpack_require__(moduleId) {\n /******/\n\n /******/\n // Check if module is in cache\n\n /******/\n if (installedModules[moduleId]) {\n /******/\n return installedModules[moduleId].exports;\n /******/\n }\n /******/\n // Create a new module (and put it into the cache)\n\n /******/\n\n\n var module = installedModules[moduleId] = {\n /******/\n i: moduleId,\n\n /******/\n l: false,\n\n /******/\n exports: {}\n /******/\n\n };\n /******/\n\n /******/\n // Execute the module function\n\n /******/\n\n modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n /******/\n\n /******/\n // Flag the module as loaded\n\n /******/\n\n module.l = true;\n /******/\n\n /******/\n // Return the exports of the module\n\n /******/\n\n return module.exports;\n /******/\n }\n /******/\n\n /******/\n\n /******/\n // expose the modules object (__webpack_modules__)\n\n /******/\n\n\n __webpack_require__.m = modules;\n /******/\n\n /******/\n // expose the module cache\n\n /******/\n\n __webpack_require__.c = installedModules;\n /******/\n\n /******/\n // define getter function for harmony exports\n\n /******/\n\n __webpack_require__.d = function (exports, name, getter) {\n /******/\n if (!__webpack_require__.o(exports, name)) {\n /******/\n Object.defineProperty(exports, name, {\n enumerable: true,\n get: getter\n });\n /******/\n }\n /******/\n\n };\n /******/\n\n /******/\n // define __esModule on exports\n\n /******/\n\n\n __webpack_require__.r = function (exports) {\n /******/\n if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n /******/\n Object.defineProperty(exports, Symbol.toStringTag, {\n value: 'Module'\n });\n /******/\n }\n /******/\n\n\n Object.defineProperty(exports, '__esModule', {\n value: true\n });\n /******/\n };\n /******/\n\n /******/\n // create a fake namespace object\n\n /******/\n // mode & 1: value is a module id, require it\n\n /******/\n // mode & 2: merge all properties of value into the ns\n\n /******/\n // mode & 4: return value when already ns object\n\n /******/\n // mode & 8|1: behave like require\n\n /******/\n\n\n __webpack_require__.t = function (value, mode) {\n /******/\n if (mode & 1) value = __webpack_require__(value);\n /******/\n\n if (mode & 8) return value;\n /******/\n\n if (mode & 4 && _typeof2(value) === 'object' && value && value.__esModule) return value;\n /******/\n\n var ns = Object.create(null);\n /******/\n\n __webpack_require__.r(ns);\n /******/\n\n\n Object.defineProperty(ns, 'default', {\n enumerable: true,\n value: value\n });\n /******/\n\n if (mode & 2 && typeof value != 'string') for (var key in value) {\n __webpack_require__.d(ns, key, function (key) {\n return value[key];\n }.bind(null, key));\n }\n /******/\n\n return ns;\n /******/\n };\n /******/\n\n /******/\n // getDefaultExport function for compatibility with non-harmony modules\n\n /******/\n\n\n __webpack_require__.n = function (module) {\n /******/\n var getter = module && module.__esModule ?\n /******/\n function getDefault() {\n return module['default'];\n } :\n /******/\n function getModuleExports() {\n return module;\n };\n /******/\n\n __webpack_require__.d(getter, 'a', getter);\n /******/\n\n\n return getter;\n /******/\n };\n /******/\n\n /******/\n // Object.prototype.hasOwnProperty.call\n\n /******/\n\n\n __webpack_require__.o = function (object, property) {\n return Object.prototype.hasOwnProperty.call(object, property);\n };\n /******/\n\n /******/\n // __webpack_public_path__\n\n /******/\n\n\n __webpack_require__.p = \"\";\n /******/\n\n /******/\n\n /******/\n // Load entry module and return exports\n\n /******/\n\n return __webpack_require__(__webpack_require__.s = 0);\n /******/\n }(\n /************************************************************************/\n\n /******/\n [\n /* 0 */\n\n /***/\n function (module, exports, __webpack_require__) {\n \"use strict\";\n\n var _typeof = typeof Symbol === \"function\" && _typeof2(Symbol.iterator) === \"symbol\" ? function (obj) {\n return _typeof2(obj);\n } : function (obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : _typeof2(obj);\n };\n\n var _createClass = function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n }();\n\n var _clipboardAction = __webpack_require__(1);\n\n var _clipboardAction2 = _interopRequireDefault(_clipboardAction);\n\n var _tinyEmitter = __webpack_require__(3);\n\n var _tinyEmitter2 = _interopRequireDefault(_tinyEmitter);\n\n var _goodListener = __webpack_require__(4);\n\n var _goodListener2 = _interopRequireDefault(_goodListener);\n\n function _interopRequireDefault(obj) {\n return obj && obj.__esModule ? obj : {\n default: obj\n };\n }\n\n function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n }\n\n function _possibleConstructorReturn(self, call) {\n if (!self) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return call && (_typeof2(call) === \"object\" || typeof call === \"function\") ? call : self;\n }\n\n function _inherits(subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function, not \" + _typeof2(superClass));\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n enumerable: false,\n writable: true,\n configurable: true\n }\n });\n if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;\n }\n /**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\n var Clipboard = function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n\n\n function Clipboard(trigger, options) {\n _classCallCheck(this, Clipboard);\n\n var _this = _possibleConstructorReturn(this, (Clipboard.__proto__ || Object.getPrototypeOf(Clipboard)).call(this));\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: 'resolveOptions',\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = _typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: 'listenClick',\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = (0, _goodListener2.default)(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: 'onClick',\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n\n if (this.clipboardAction) {\n this.clipboardAction = null;\n }\n\n this.clipboardAction = new _clipboardAction2.default({\n action: this.action(trigger),\n target: this.target(trigger),\n text: this.text(trigger),\n container: this.container,\n trigger: trigger,\n emitter: this\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: 'defaultAction',\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: 'defaultTarget',\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: 'defaultText',\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: 'destroy',\n value: function destroy() {\n this.listener.destroy();\n\n if (this.clipboardAction) {\n this.clipboardAction.destroy();\n this.clipboardAction = null;\n }\n }\n }], [{\n key: 'isSupported',\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n }(_tinyEmitter2.default);\n /**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\n\n function getAttributeValue(suffix, element) {\n var attribute = 'data-clipboard-' + suffix;\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n }\n\n module.exports = Clipboard;\n /***/\n },\n /* 1 */\n\n /***/\n function (module, exports, __webpack_require__) {\n \"use strict\";\n\n var _typeof = typeof Symbol === \"function\" && _typeof2(Symbol.iterator) === \"symbol\" ? function (obj) {\n return _typeof2(obj);\n } : function (obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : _typeof2(obj);\n };\n\n var _createClass = function () {\n function defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n }\n\n return function (Constructor, protoProps, staticProps) {\n if (protoProps) defineProperties(Constructor.prototype, protoProps);\n if (staticProps) defineProperties(Constructor, staticProps);\n return Constructor;\n };\n }();\n\n var _select = __webpack_require__(2);\n\n var _select2 = _interopRequireDefault(_select);\n\n function _interopRequireDefault(obj) {\n return obj && obj.__esModule ? obj : {\n default: obj\n };\n }\n\n function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n }\n /**\n * Inner class which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n */\n\n\n var ClipboardAction = function () {\n /**\n * @param {Object} options\n */\n function ClipboardAction(options) {\n _classCallCheck(this, ClipboardAction);\n\n this.resolveOptions(options);\n this.initSelection();\n }\n /**\n * Defines base properties passed from constructor.\n * @param {Object} options\n */\n\n\n _createClass(ClipboardAction, [{\n key: 'resolveOptions',\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = options.action;\n this.container = options.container;\n this.emitter = options.emitter;\n this.target = options.target;\n this.text = options.text;\n this.trigger = options.trigger;\n this.selectedText = '';\n }\n /**\n * Decides which selection strategy is going to be applied based\n * on the existence of `text` and `target` properties.\n */\n\n }, {\n key: 'initSelection',\n value: function initSelection() {\n if (this.text) {\n this.selectFake();\n } else if (this.target) {\n this.selectTarget();\n }\n }\n /**\n * Creates a fake textarea element, sets its value from `text` property,\n * and makes a selection on it.\n */\n\n }, {\n key: 'selectFake',\n value: function selectFake() {\n var _this = this;\n\n var isRTL = document.documentElement.getAttribute('dir') == 'rtl';\n this.removeFake();\n\n this.fakeHandlerCallback = function () {\n return _this.removeFake();\n };\n\n this.fakeHandler = this.container.addEventListener('click', this.fakeHandlerCallback) || true;\n this.fakeElem = document.createElement('textarea'); // Prevent zooming on iOS\n\n this.fakeElem.style.fontSize = '12pt'; // Reset box model\n\n this.fakeElem.style.border = '0';\n this.fakeElem.style.padding = '0';\n this.fakeElem.style.margin = '0'; // Move element out of screen horizontally\n\n this.fakeElem.style.position = 'absolute';\n this.fakeElem.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n this.fakeElem.style.top = yPosition + 'px';\n this.fakeElem.setAttribute('readonly', '');\n this.fakeElem.value = this.text;\n this.container.appendChild(this.fakeElem);\n this.selectedText = (0, _select2.default)(this.fakeElem);\n this.copyText();\n }\n /**\n * Only removes the fake element after another click event, that way\n * a user can hit `Ctrl+C` to copy because selection still exists.\n */\n\n }, {\n key: 'removeFake',\n value: function removeFake() {\n if (this.fakeHandler) {\n this.container.removeEventListener('click', this.fakeHandlerCallback);\n this.fakeHandler = null;\n this.fakeHandlerCallback = null;\n }\n\n if (this.fakeElem) {\n this.container.removeChild(this.fakeElem);\n this.fakeElem = null;\n }\n }\n /**\n * Selects the content from element passed on `target` property.\n */\n\n }, {\n key: 'selectTarget',\n value: function selectTarget() {\n this.selectedText = (0, _select2.default)(this.target);\n this.copyText();\n }\n /**\n * Executes the copy operation based on the current selection.\n */\n\n }, {\n key: 'copyText',\n value: function copyText() {\n var succeeded = void 0;\n\n try {\n succeeded = document.execCommand(this.action);\n } catch (err) {\n succeeded = false;\n }\n\n this.handleResult(succeeded);\n }\n /**\n * Fires an event based on the copy operation result.\n * @param {Boolean} succeeded\n */\n\n }, {\n key: 'handleResult',\n value: function handleResult(succeeded) {\n this.emitter.emit(succeeded ? 'success' : 'error', {\n action: this.action,\n text: this.selectedText,\n trigger: this.trigger,\n clearSelection: this.clearSelection.bind(this)\n });\n }\n /**\n * Moves focus away from `target` and back to the trigger, removes current selection.\n */\n\n }, {\n key: 'clearSelection',\n value: function clearSelection() {\n if (this.trigger) {\n this.trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n /**\n * Sets the `action` to be performed which can be either 'copy' or 'cut'.\n * @param {String} action\n */\n\n }, {\n key: 'destroy',\n\n /**\n * Destroy lifecycle.\n */\n value: function destroy() {\n this.removeFake();\n }\n }, {\n key: 'action',\n set: function set() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'copy';\n this._action = action;\n\n if (this._action !== 'copy' && this._action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n }\n }\n /**\n * Gets the `action` property.\n * @return {String}\n */\n ,\n get: function get() {\n return this._action;\n }\n /**\n * Sets the `target` property using an element\n * that will be have its content copied.\n * @param {Element} target\n */\n\n }, {\n key: 'target',\n set: function set(target) {\n if (target !== undefined) {\n if (target && (typeof target === 'undefined' ? 'undefined' : _typeof(target)) === 'object' && target.nodeType === 1) {\n if (this.action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (this.action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n\n this._target = target;\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n }\n }\n /**\n * Gets the `target` property.\n * @return {String|HTMLElement}\n */\n ,\n get: function get() {\n return this._target;\n }\n }]);\n\n return ClipboardAction;\n }();\n\n module.exports = ClipboardAction;\n /***/\n },\n /* 2 */\n\n /***/\n function (module, exports) {\n function select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n selectedText = element.value;\n } else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n } else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n selectedText = selection.toString();\n }\n\n return selectedText;\n }\n\n module.exports = select;\n /***/\n },\n /* 3 */\n\n /***/\n function (module, exports) {\n function E() {// Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n }\n\n E.prototype = {\n on: function on(name, callback, ctx) {\n var e = this.e || (this.e = {});\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n return this;\n },\n once: function once(name, callback, ctx) {\n var self = this;\n\n function listener() {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n }\n\n ;\n listener._ = callback;\n return this.on(name, listener, ctx);\n },\n emit: function emit(name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n off: function off(name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback) liveEvents.push(evts[i]);\n }\n } // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n\n liveEvents.length ? e[name] = liveEvents : delete e[name];\n return this;\n }\n };\n module.exports = E;\n /***/\n },\n /* 4 */\n\n /***/\n function (module, exports, __webpack_require__) {\n var is = __webpack_require__(5);\n\n var delegate = __webpack_require__(6);\n /**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\n\n\n function listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n } else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n } else if (is.string(target)) {\n return listenSelector(target, type, callback);\n } else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n }\n /**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\n\n\n function listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n return {\n destroy: function destroy() {\n node.removeEventListener(type, callback);\n }\n };\n }\n /**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\n\n\n function listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function (node) {\n node.addEventListener(type, callback);\n });\n return {\n destroy: function destroy() {\n Array.prototype.forEach.call(nodeList, function (node) {\n node.removeEventListener(type, callback);\n });\n }\n };\n }\n /**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\n\n\n function listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n }\n\n module.exports = listen;\n /***/\n },\n /* 5 */\n\n /***/\n function (module, exports) {\n /**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\n exports.node = function (value) {\n return value !== undefined && value instanceof HTMLElement && value.nodeType === 1;\n };\n /**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\n\n\n exports.nodeList = function (value) {\n var type = Object.prototype.toString.call(value);\n return value !== undefined && (type === '[object NodeList]' || type === '[object HTMLCollection]') && 'length' in value && (value.length === 0 || exports.node(value[0]));\n };\n /**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\n\n\n exports.string = function (value) {\n return typeof value === 'string' || value instanceof String;\n };\n /**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\n\n\n exports.fn = function (value) {\n var type = Object.prototype.toString.call(value);\n return type === '[object Function]';\n };\n /***/\n\n },\n /* 6 */\n\n /***/\n function (module, exports, __webpack_require__) {\n var closest = __webpack_require__(7);\n /**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\n\n\n function _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n element.addEventListener(type, listenerFn, useCapture);\n return {\n destroy: function destroy() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n };\n }\n /**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\n\n\n function delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n } // Handle Element-less usage, it defaults to global delegation\n\n\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n } // Handle Selector-based usage\n\n\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n } // Handle Array-like based usage\n\n\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n }\n /**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\n\n\n function listener(element, selector, type, callback) {\n return function (e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n };\n }\n\n module.exports = delegate;\n /***/\n },\n /* 7 */\n\n /***/\n function (module, exports) {\n var DOCUMENT_NODE_TYPE = 9;\n /**\n * A polyfill for Element.matches()\n */\n\n if (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n proto.matches = proto.matchesSelector || proto.mozMatchesSelector || proto.msMatchesSelector || proto.oMatchesSelector || proto.webkitMatchesSelector;\n }\n /**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\n\n\n function closest(element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' && element.matches(selector)) {\n return element;\n }\n\n element = element.parentNode;\n }\n }\n\n module.exports = closest;\n /***/\n }])\n );\n});\n/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(/*! ./../../webpack/buildin/module.js */ \"./node_modules/webpack/buildin/module.js\")(module)))\n\n//# sourceURL=webpack:///./node_modules/clipboard/dist/clipboard.js?");
-
-/***/ }),
-
-/***/ "./node_modules/iframe-resizer/js/iframeResizer.contentWindow.min.js":
-/*!***************************************************************************!*\
- !*** ./node_modules/iframe-resizer/js/iframeResizer.contentWindow.min.js ***!
- \***************************************************************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports) {
-
-eval("function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n/*! iFrame Resizer (iframeSizer.contentWindow.min.js) - v3.6.6 - 2019-02-26\n * Desc: Include this file in any page being loaded into an iframe\n * to force the iframe to resize to the content size.\n * Requires: iframeResizer.min.js on host page.\n * Copyright: (c) 2019 David J. Bradshaw - dave@bradshaw.net\n * License: MIT\n */\n!function (d) {\n \"use strict\";\n\n if (\"undefined\" != typeof window) {\n var n = !0,\n i = 10,\n o = \"\",\n r = 0,\n a = \"\",\n t = null,\n u = \"\",\n c = !1,\n s = {\n resize: 1,\n click: 1\n },\n l = 128,\n f = !0,\n m = 1,\n g = \"bodyOffset\",\n h = g,\n p = !0,\n v = \"\",\n y = {},\n w = 32,\n e = null,\n b = !1,\n T = \"[iFrameSizer]\",\n E = T.length,\n S = \"\",\n O = {\n max: 1,\n min: 1,\n bodyScroll: 1,\n documentElementScroll: 1\n },\n M = \"child\",\n I = !0,\n N = window.parent,\n C = \"*\",\n k = 0,\n A = !1,\n x = null,\n z = 16,\n L = 1,\n R = \"scroll\",\n F = R,\n P = window,\n D = function D() {\n ue(\"MessageCallback function not defined\");\n },\n q = function q() {},\n H = function H() {},\n W = {\n height: function height() {\n return ue(\"Custom height calculation function not defined\"), document.documentElement.offsetHeight;\n },\n width: function width() {\n return ue(\"Custom width calculation function not defined\"), document.body.scrollWidth;\n }\n },\n j = {},\n B = !1;\n\n try {\n var V = Object.create({}, {\n passive: {\n get: function get() {\n B = !0;\n }\n },\n once: {\n get: function get() {\n !0;\n }\n }\n });\n window.addEventListener(\"test\", te, V), window.removeEventListener(\"test\", te, V);\n } catch (e) {}\n\n var J,\n U,\n K,\n Q,\n X,\n Y,\n $,\n G = Date.now || function () {\n return new Date().getTime();\n },\n Z = {\n bodyOffset: function bodyOffset() {\n return document.body.offsetHeight + ye(\"marginTop\") + ye(\"marginBottom\");\n },\n offset: function offset() {\n return Z.bodyOffset();\n },\n bodyScroll: function bodyScroll() {\n return document.body.scrollHeight;\n },\n custom: function custom() {\n return W.height();\n },\n documentElementOffset: function documentElementOffset() {\n return document.documentElement.offsetHeight;\n },\n documentElementScroll: function documentElementScroll() {\n return document.documentElement.scrollHeight;\n },\n max: function max() {\n return Math.max.apply(null, be(Z));\n },\n min: function min() {\n return Math.min.apply(null, be(Z));\n },\n grow: function grow() {\n return Z.max();\n },\n lowestElement: function lowestElement() {\n return Math.max(Z.bodyOffset() || Z.documentElementOffset(), we(\"bottom\", Ee()));\n },\n taggedElement: function taggedElement() {\n return Te(\"bottom\", \"data-iframe-height\");\n }\n },\n _ = {\n bodyScroll: function bodyScroll() {\n return document.body.scrollWidth;\n },\n bodyOffset: function bodyOffset() {\n return document.body.offsetWidth;\n },\n custom: function custom() {\n return W.width();\n },\n documentElementScroll: function documentElementScroll() {\n return document.documentElement.scrollWidth;\n },\n documentElementOffset: function documentElementOffset() {\n return document.documentElement.offsetWidth;\n },\n scroll: function scroll() {\n return Math.max(_.bodyScroll(), _.documentElementScroll());\n },\n max: function max() {\n return Math.max.apply(null, be(_));\n },\n min: function min() {\n return Math.min.apply(null, be(_));\n },\n rightMostElement: function rightMostElement() {\n return we(\"right\", Ee());\n },\n taggedElement: function taggedElement() {\n return Te(\"right\", \"data-iframe-width\");\n }\n },\n ee = (J = Se, X = null, Y = 0, $ = function $() {\n Y = G(), X = null, Q = J.apply(U, K), X || (U = K = null);\n }, function () {\n var e = G();\n Y || (Y = e);\n var t = z - (e - Y);\n return U = this, K = arguments, t <= 0 || z < t ? (X && (clearTimeout(X), X = null), Y = e, Q = J.apply(U, K), X || (U = K = null)) : X || (X = setTimeout($, t)), Q;\n });\n\n ne(window, \"message\", ke), ne(window, \"readystatechange\", Ae), Ae();\n }\n\n function te() {}\n\n function ne(e, t, n, o) {\n \"addEventListener\" in window ? e.addEventListener(t, n, !!B && (o || {})) : \"attachEvent\" in window && e.attachEvent(\"on\" + t, n);\n }\n\n function oe(e, t, n) {\n \"removeEventListener\" in window ? e.removeEventListener(t, n, !1) : \"detachEvent\" in window && e.detachEvent(\"on\" + t, n);\n }\n\n function ie(e) {\n return e.charAt(0).toUpperCase() + e.slice(1);\n }\n\n function re(e) {\n return T + \"[\" + S + \"] \" + e;\n }\n\n function ae(e) {\n b && \"object\" == _typeof(window.console) && console.log(re(e));\n }\n\n function ue(e) {\n \"object\" == _typeof(window.console) && console.warn(re(e));\n }\n\n function ce() {\n var e;\n !function () {\n function e(e) {\n return \"true\" === e;\n }\n\n var t = v.substr(E).split(\":\");\n S = t[0], r = d !== t[1] ? Number(t[1]) : r, c = d !== t[2] ? e(t[2]) : c, b = d !== t[3] ? e(t[3]) : b, w = d !== t[4] ? Number(t[4]) : w, n = d !== t[6] ? e(t[6]) : n, a = t[7], h = d !== t[8] ? t[8] : h, o = t[9], u = t[10], k = d !== t[11] ? Number(t[11]) : k, y.enable = d !== t[12] && e(t[12]), M = d !== t[13] ? t[13] : M, F = d !== t[14] ? t[14] : F;\n }(), ae(\"Initialising iFrame (\" + location.href + \")\"), function () {\n function e(e, t) {\n return \"function\" == typeof e && (ae(\"Setup custom \" + t + \"CalcMethod\"), W[t] = e, e = \"custom\"), e;\n }\n\n \"iFrameResizer\" in window && Object === window.iFrameResizer.constructor && (t = window.iFrameResizer, ae(\"Reading data from page: \" + JSON.stringify(t)), D = \"messageCallback\" in t ? t.messageCallback : D, q = \"readyCallback\" in t ? t.readyCallback : q, C = \"targetOrigin\" in t ? t.targetOrigin : C, h = \"heightCalculationMethod\" in t ? t.heightCalculationMethod : h, F = \"widthCalculationMethod\" in t ? t.widthCalculationMethod : F, h = e(h, \"height\"), F = e(F, \"width\"));\n var t;\n ae(\"TargetOrigin for parent set to: \" + C);\n }(), function () {\n d === a && (a = r + \"px\");\n se(\"margin\", function (e, t) {\n -1 !== t.indexOf(\"-\") && (ue(\"Negative CSS value ignored for \" + e), t = \"\");\n return t;\n }(\"margin\", a));\n }(), se(\"background\", o), se(\"padding\", u), (e = document.createElement(\"div\")).style.clear = \"both\", e.style.display = \"block\", document.body.appendChild(e), me(), ge(), document.documentElement.style.height = \"\", document.body.style.height = \"\", ae('HTML & body height set to \"auto\"'), ae(\"Enable public methods\"), P.parentIFrame = {\n autoResize: function autoResize(e) {\n return !0 === e && !1 === n ? (n = !0, he()) : !1 === e && !0 === n && (n = !1, pe()), n;\n },\n close: function close() {\n Ce(0, 0, \"close\"), ae(\"Disable outgoing messages\"), I = !1, ae(\"Remove event listener: Message\"), oe(window, \"message\", ke), !0 === n && pe();\n },\n getId: function getId() {\n return S;\n },\n getPageInfo: function getPageInfo(e) {\n \"function\" == typeof e ? (H = e, Ce(0, 0, \"pageInfo\")) : (H = function H() {}, Ce(0, 0, \"pageInfoStop\"));\n },\n moveToAnchor: function moveToAnchor(e) {\n y.findTarget(e);\n },\n reset: function reset() {\n Ne(\"parentIFrame.reset\");\n },\n scrollTo: function scrollTo(e, t) {\n Ce(t, e, \"scrollTo\");\n },\n scrollToOffset: function scrollToOffset(e, t) {\n Ce(t, e, \"scrollToOffset\");\n },\n sendMessage: function sendMessage(e, t) {\n Ce(0, 0, \"message\", JSON.stringify(e), t);\n },\n setHeightCalculationMethod: function setHeightCalculationMethod(e) {\n h = e, me();\n },\n setWidthCalculationMethod: function setWidthCalculationMethod(e) {\n F = e, ge();\n },\n setTargetOrigin: function setTargetOrigin(e) {\n ae(\"Set targetOrigin: \" + e), C = e;\n },\n size: function size(e, t) {\n var n = (e || \"\") + (t ? \",\" + t : \"\");\n Oe(\"size\", \"parentIFrame.size(\" + n + \")\", e, t);\n }\n }, he(), y = function () {\n function r(e) {\n var t = e.getBoundingClientRect(),\n n = {\n x: window.pageXOffset !== d ? window.pageXOffset : document.documentElement.scrollLeft,\n y: window.pageYOffset !== d ? window.pageYOffset : document.documentElement.scrollTop\n };\n return {\n x: parseInt(t.left, 10) + parseInt(n.x, 10),\n y: parseInt(t.top, 10) + parseInt(n.y, 10)\n };\n }\n\n function n(e) {\n var t,\n n = e.split(\"#\")[1] || e,\n o = decodeURIComponent(n),\n i = document.getElementById(o) || document.getElementsByName(o)[0];\n d !== i ? (t = r(i), ae(\"Moving to in page link (#\" + n + \") at x: \" + t.x + \" y: \" + t.y), Ce(t.y, t.x, \"scrollToOffset\")) : (ae(\"In page link (#\" + n + \") not found in iFrame, so sending to parent\"), Ce(0, 0, \"inPageLink\", \"#\" + n));\n }\n\n function e() {\n \"\" !== location.hash && \"#\" !== location.hash && n(location.href);\n }\n\n function t() {\n Array.prototype.forEach.call(document.querySelectorAll('a[href^=\"#\"]'), function (e) {\n function t(e) {\n e.preventDefault(), n(this.getAttribute(\"href\"));\n }\n\n \"#\" !== e.getAttribute(\"href\") && ne(e, \"click\", t);\n });\n }\n\n y.enable ? Array.prototype.forEach && document.querySelectorAll ? (ae(\"Setting up location.hash handlers\"), t(), ne(window, \"hashchange\", e), setTimeout(e, l)) : ue(\"In page linking not fully supported in this browser! (See README.md for IE8 workaround)\") : ae(\"In page linking not enabled\");\n return {\n findTarget: n\n };\n }(), Oe(\"init\", \"Init message from host page\"), q();\n }\n\n function se(e, t) {\n d !== t && \"\" !== t && \"null\" !== t && ae(\"Body \" + e + ' set to \"' + (document.body.style[e] = t) + '\"');\n }\n\n function le(n) {\n var e = {\n add: function add(e) {\n function t() {\n Oe(n.eventName, n.eventType);\n }\n\n j[e] = t, ne(window, e, t, {\n passive: !0\n });\n },\n remove: function remove(e) {\n var t = j[e];\n delete j[e], oe(window, e, t);\n }\n };\n n.eventNames && Array.prototype.map ? (n.eventName = n.eventNames[0], n.eventNames.map(e[n.method])) : e[n.method](n.eventName), ae(ie(n.method) + \" event listener: \" + n.eventType);\n }\n\n function de(e) {\n le({\n method: e,\n eventType: \"Animation Start\",\n eventNames: [\"animationstart\", \"webkitAnimationStart\"]\n }), le({\n method: e,\n eventType: \"Animation Iteration\",\n eventNames: [\"animationiteration\", \"webkitAnimationIteration\"]\n }), le({\n method: e,\n eventType: \"Animation End\",\n eventNames: [\"animationend\", \"webkitAnimationEnd\"]\n }), le({\n method: e,\n eventType: \"Input\",\n eventName: \"input\"\n }), le({\n method: e,\n eventType: \"Mouse Up\",\n eventName: \"mouseup\"\n }), le({\n method: e,\n eventType: \"Mouse Down\",\n eventName: \"mousedown\"\n }), le({\n method: e,\n eventType: \"Orientation Change\",\n eventName: \"orientationchange\"\n }), le({\n method: e,\n eventType: \"Print\",\n eventName: [\"afterprint\", \"beforeprint\"]\n }), le({\n method: e,\n eventType: \"Ready State Change\",\n eventName: \"readystatechange\"\n }), le({\n method: e,\n eventType: \"Touch Start\",\n eventName: \"touchstart\"\n }), le({\n method: e,\n eventType: \"Touch End\",\n eventName: \"touchend\"\n }), le({\n method: e,\n eventType: \"Touch Cancel\",\n eventName: \"touchcancel\"\n }), le({\n method: e,\n eventType: \"Transition Start\",\n eventNames: [\"transitionstart\", \"webkitTransitionStart\", \"MSTransitionStart\", \"oTransitionStart\", \"otransitionstart\"]\n }), le({\n method: e,\n eventType: \"Transition Iteration\",\n eventNames: [\"transitioniteration\", \"webkitTransitionIteration\", \"MSTransitionIteration\", \"oTransitionIteration\", \"otransitioniteration\"]\n }), le({\n method: e,\n eventType: \"Transition End\",\n eventNames: [\"transitionend\", \"webkitTransitionEnd\", \"MSTransitionEnd\", \"oTransitionEnd\", \"otransitionend\"]\n }), \"child\" === M && le({\n method: e,\n eventType: \"IFrame Resized\",\n eventName: \"resize\"\n });\n }\n\n function fe(e, t, n, o) {\n return t !== e && (e in n || (ue(e + \" is not a valid option for \" + o + \"CalculationMethod.\"), e = t), ae(o + ' calculation method set to \"' + e + '\"')), e;\n }\n\n function me() {\n h = fe(h, g, Z, \"height\");\n }\n\n function ge() {\n F = fe(F, R, _, \"width\");\n }\n\n function he() {\n var e;\n !0 === n ? (de(\"add\"), e = w < 0, window.MutationObserver || window.WebKitMutationObserver ? e ? ve() : t = function () {\n function t(e) {\n function t(e) {\n !1 === e.complete && (ae(\"Attach listeners to \" + e.src), e.addEventListener(\"load\", i, !1), e.addEventListener(\"error\", r, !1), c.push(e));\n }\n\n \"attributes\" === e.type && \"src\" === e.attributeName ? t(e.target) : \"childList\" === e.type && Array.prototype.forEach.call(e.target.querySelectorAll(\"img\"), t);\n }\n\n function o(e) {\n var t;\n ae(\"Remove listeners from \" + e.src), e.removeEventListener(\"load\", i, !1), e.removeEventListener(\"error\", r, !1), t = e, c.splice(c.indexOf(t), 1);\n }\n\n function n(e, t, n) {\n o(e.target), Oe(t, n + \": \" + e.target.src, d, d);\n }\n\n function i(e) {\n n(e, \"imageLoad\", \"Image loaded\");\n }\n\n function r(e) {\n n(e, \"imageLoadFailed\", \"Image load failed\");\n }\n\n function e(e) {\n Oe(\"mutationObserver\", \"mutationObserver: \" + e[0].target + \" \" + e[0].type), e.forEach(t);\n }\n\n var a,\n u,\n c = [],\n s = window.MutationObserver || window.WebKitMutationObserver,\n l = (a = document.querySelector(\"body\"), u = {\n attributes: !0,\n attributeOldValue: !1,\n characterData: !0,\n characterDataOldValue: !1,\n childList: !0,\n subtree: !0\n }, l = new s(e), ae(\"Create body MutationObserver\"), l.observe(a, u), l);\n return {\n disconnect: function disconnect() {\n \"disconnect\" in l && (ae(\"Disconnect body MutationObserver\"), l.disconnect(), c.forEach(o));\n }\n };\n }() : (ae(\"MutationObserver not supported in this browser!\"), ve())) : ae(\"Auto Resize disabled\");\n }\n\n function pe() {\n de(\"remove\"), null !== t && t.disconnect(), clearInterval(e);\n }\n\n function ve() {\n 0 !== w && (ae(\"setInterval: \" + w + \"ms\"), e = setInterval(function () {\n Oe(\"interval\", \"setInterval: \" + w);\n }, Math.abs(w)));\n }\n\n function ye(e, o) {\n var t = 0;\n return o = o || document.body, t = \"defaultView\" in document && \"getComputedStyle\" in document.defaultView ? null !== (t = document.defaultView.getComputedStyle(o, null)) ? t[e] : 0 : function (e) {\n if (/^\\d+(px)?$/i.test(e)) return parseInt(e, i);\n var t = o.style.left,\n n = o.runtimeStyle.left;\n return o.runtimeStyle.left = o.currentStyle.left, o.style.left = e || 0, e = o.style.pixelLeft, o.style.left = t, o.runtimeStyle.left = n, e;\n }(o.currentStyle[e]), parseInt(t, i);\n }\n\n function we(e, t) {\n for (var n, o = t.length, i = 0, r = 0, a = ie(e), u = G(), c = 0; c < o; c++) {\n r < (i = t[c].getBoundingClientRect()[e] + ye(\"margin\" + a, t[c])) && (r = i);\n }\n\n return u = G() - u, ae(\"Parsed \" + o + \" HTML elements\"), ae(\"Element position calculated in \" + u + \"ms\"), z / 2 < (n = u) && ae(\"Event throttle increased to \" + (z = 2 * n) + \"ms\"), r;\n }\n\n function be(e) {\n return [e.bodyOffset(), e.bodyScroll(), e.documentElementOffset(), e.documentElementScroll()];\n }\n\n function Te(e, t) {\n var n = document.querySelectorAll(\"[\" + t + \"]\");\n return 0 === n.length && (ue(\"No tagged elements (\" + t + \") found on page\"), document.querySelectorAll(\"body *\")), we(e, n);\n }\n\n function Ee() {\n return document.querySelectorAll(\"body *\");\n }\n\n function Se(e, t, n, o) {\n var i, r;\n !function () {\n function e(e, t) {\n return !(Math.abs(e - t) <= k);\n }\n\n return i = d !== n ? n : Z[h](), r = d !== o ? o : _[F](), e(m, i) || c && e(L, r);\n }() && \"init\" !== e ? e in {\n init: 1,\n interval: 1,\n size: 1\n } || !(h in O || c && F in O) ? e in {\n interval: 1\n } || ae(\"No change in size detected\") : Ne(t) : (Me(), Ce(m = i, L = r, e));\n }\n\n function Oe(e, t, n, o) {\n A && e in s ? ae(\"Trigger event cancelled: \" + e) : (e in {\n reset: 1,\n resetPage: 1,\n init: 1\n } || ae(\"Trigger event: \" + t), \"init\" === e ? Se(e, t, n, o) : ee(e, t, n, o));\n }\n\n function Me() {\n A || (A = !0, ae(\"Trigger event lock on\")), clearTimeout(x), x = setTimeout(function () {\n A = !1, ae(\"Trigger event lock off\"), ae(\"--\");\n }, l);\n }\n\n function Ie(e) {\n m = Z[h](), L = _[F](), Ce(m, L, e);\n }\n\n function Ne(e) {\n var t = h;\n h = g, ae(\"Reset trigger event: \" + e), Me(), Ie(\"reset\"), h = t;\n }\n\n function Ce(e, t, n, o, i) {\n var r;\n !0 === I && (d === i ? i = C : ae(\"Message targetOrigin: \" + i), ae(\"Sending message to host page (\" + (r = S + \":\" + e + \":\" + t + \":\" + n + (d !== o ? \":\" + o : \"\")) + \")\"), N.postMessage(T + r, i));\n }\n\n function ke(t) {\n var n = {\n init: function init() {\n v = t.data, N = t.source, ce(), f = !1, setTimeout(function () {\n p = !1;\n }, l);\n },\n reset: function reset() {\n p ? ae(\"Page reset ignored by init\") : (ae(\"Page size reset by host page\"), Ie(\"resetPage\"));\n },\n resize: function resize() {\n Oe(\"resizeParent\", \"Parent window requested size check\");\n },\n moveToAnchor: function moveToAnchor() {\n y.findTarget(i());\n },\n inPageLink: function inPageLink() {\n this.moveToAnchor();\n },\n pageInfo: function pageInfo() {\n var e = i();\n ae(\"PageInfoFromParent called from parent: \" + e), H(JSON.parse(e)), ae(\" --\");\n },\n message: function message() {\n var e = i();\n ae(\"MessageCallback called from parent: \" + e), D(JSON.parse(e)), ae(\" --\");\n }\n };\n\n function o() {\n return t.data.split(\"]\")[1].split(\":\")[0];\n }\n\n function i() {\n return t.data.substr(t.data.indexOf(\":\") + 1);\n }\n\n function r() {\n return t.data.split(\":\")[2] in {\n true: 1,\n false: 1\n };\n }\n\n function e() {\n var e = o();\n e in n ? n[e]() : (\"undefined\" == typeof module || !module.exports) && \"iFrameResize\" in window || \"jQuery\" in window && \"iFrameResize\" in window.jQuery.prototype || r() || ue(\"Unexpected message (\" + t.data + \")\");\n }\n\n T === (\"\" + t.data).substr(0, E) && (!1 === f ? e() : r() ? n.init() : ae('Ignored message of type \"' + o() + '\". Received before initialization.'));\n }\n\n function Ae() {\n \"loading\" !== document.readyState && window.parent.postMessage(\"[iFrameResizerChild]Ready\", \"*\");\n }\n}();\n\n//# sourceURL=webpack:///./node_modules/iframe-resizer/js/iframeResizer.contentWindow.min.js?");
-
-/***/ }),
-
-/***/ "./node_modules/js-cookie/src/js.cookie.js":
-/*!*************************************************!*\
- !*** ./node_modules/js-cookie/src/js.cookie.js ***!
- \*************************************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports, __webpack_require__) {
-
-eval("var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_RESULT__;function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n/*!\n * JavaScript Cookie v2.2.0\n * https://github.com/js-cookie/js-cookie\n *\n * Copyright 2006, 2015 Klaus Hartl & Fagner Brack\n * Released under the MIT license\n */\n;\n\n(function (factory) {\n var registeredInModuleLoader = false;\n\n if (true) {\n !(__WEBPACK_AMD_DEFINE_FACTORY__ = (factory),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?\n\t\t\t\t(__WEBPACK_AMD_DEFINE_FACTORY__.call(exports, __webpack_require__, exports, module)) :\n\t\t\t\t__WEBPACK_AMD_DEFINE_FACTORY__),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n registeredInModuleLoader = true;\n }\n\n if (( false ? undefined : _typeof(exports)) === 'object') {\n module.exports = factory();\n registeredInModuleLoader = true;\n }\n\n if (!registeredInModuleLoader) {\n var OldCookies = window.Cookies;\n var api = window.Cookies = factory();\n\n api.noConflict = function () {\n window.Cookies = OldCookies;\n return api;\n };\n }\n})(function () {\n function extend() {\n var i = 0;\n var result = {};\n\n for (; i < arguments.length; i++) {\n var attributes = arguments[i];\n\n for (var key in attributes) {\n result[key] = attributes[key];\n }\n }\n\n return result;\n }\n\n function init(converter) {\n function api(key, value, attributes) {\n var result;\n\n if (typeof document === 'undefined') {\n return;\n } // Write\n\n\n if (arguments.length > 1) {\n attributes = extend({\n path: '/'\n }, api.defaults, attributes);\n\n if (typeof attributes.expires === 'number') {\n var expires = new Date();\n expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);\n attributes.expires = expires;\n } // We're using \"expires\" because \"max-age\" is not supported by IE\n\n\n attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';\n\n try {\n result = JSON.stringify(value);\n\n if (/^[\\{\\[]/.test(result)) {\n value = result;\n }\n } catch (e) {}\n\n if (!converter.write) {\n value = encodeURIComponent(String(value)).replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);\n } else {\n value = converter.write(value, key);\n }\n\n key = encodeURIComponent(String(key));\n key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);\n key = key.replace(/[\\(\\)]/g, escape);\n var stringifiedAttributes = '';\n\n for (var attributeName in attributes) {\n if (!attributes[attributeName]) {\n continue;\n }\n\n stringifiedAttributes += '; ' + attributeName;\n\n if (attributes[attributeName] === true) {\n continue;\n }\n\n stringifiedAttributes += '=' + attributes[attributeName];\n }\n\n return document.cookie = key + '=' + value + stringifiedAttributes;\n } // Read\n\n\n if (!key) {\n result = {};\n } // To prevent the for loop in the first place assign an empty array\n // in case there are no cookies at all. Also prevents odd result when\n // calling \"get()\"\n\n\n var cookies = document.cookie ? document.cookie.split('; ') : [];\n var rdecode = /(%[0-9A-Z]{2})+/g;\n var i = 0;\n\n for (; i < cookies.length; i++) {\n var parts = cookies[i].split('=');\n var cookie = parts.slice(1).join('=');\n\n if (!this.json && cookie.charAt(0) === '\"') {\n cookie = cookie.slice(1, -1);\n }\n\n try {\n var name = parts[0].replace(rdecode, decodeURIComponent);\n cookie = converter.read ? converter.read(cookie, name) : converter(cookie, name) || cookie.replace(rdecode, decodeURIComponent);\n\n if (this.json) {\n try {\n cookie = JSON.parse(cookie);\n } catch (e) {}\n }\n\n if (key === name) {\n result = cookie;\n break;\n }\n\n if (!key) {\n result[name] = cookie;\n }\n } catch (e) {}\n }\n\n return result;\n }\n\n api.set = api;\n\n api.get = function (key) {\n return api.call(api, key);\n };\n\n api.getJSON = function () {\n return api.apply({\n json: true\n }, [].slice.call(arguments));\n };\n\n api.defaults = {};\n\n api.remove = function (key, attributes) {\n api(key, '', extend(attributes, {\n expires: -1\n }));\n };\n\n api.withConverter = init;\n return api;\n }\n\n return init(function () {});\n});\n\n//# sourceURL=webpack:///./node_modules/js-cookie/src/js.cookie.js?");
-
-/***/ }),
-
-/***/ "./node_modules/mousetrap/mousetrap.js":
-/*!*********************************************!*\
- !*** ./node_modules/mousetrap/mousetrap.js ***!
- \*********************************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports, __webpack_require__) {
-
-eval("var __WEBPACK_AMD_DEFINE_RESULT__;/*global define:false */\n\n/**\n * Copyright 2012-2017 Craig Campbell\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Mousetrap is a simple keyboard shortcut library for Javascript with\n * no external dependencies\n *\n * @version 1.6.3\n * @url craig.is/killing/mice\n */\n(function (window, document, undefined) {\n // Check if mousetrap is used inside browser, if not, return\n if (!window) {\n return;\n }\n /**\n * mapping of special keycodes to their corresponding keys\n *\n * everything in this dictionary cannot use keypress events\n * so it has to be here to map to the correct keycodes for\n * keyup/keydown events\n *\n * @type {Object}\n */\n\n\n var _MAP = {\n 8: 'backspace',\n 9: 'tab',\n 13: 'enter',\n 16: 'shift',\n 17: 'ctrl',\n 18: 'alt',\n 20: 'capslock',\n 27: 'esc',\n 32: 'space',\n 33: 'pageup',\n 34: 'pagedown',\n 35: 'end',\n 36: 'home',\n 37: 'left',\n 38: 'up',\n 39: 'right',\n 40: 'down',\n 45: 'ins',\n 46: 'del',\n 91: 'meta',\n 93: 'meta',\n 224: 'meta'\n };\n /**\n * mapping for special characters so they can support\n *\n * this dictionary is only used incase you want to bind a\n * keyup or keydown event to one of these keys\n *\n * @type {Object}\n */\n\n var _KEYCODE_MAP = {\n 106: '*',\n 107: '+',\n 109: '-',\n 110: '.',\n 111: '/',\n 186: ';',\n 187: '=',\n 188: ',',\n 189: '-',\n 190: '.',\n 191: '/',\n 192: '`',\n 219: '[',\n 220: '\\\\',\n 221: ']',\n 222: '\\''\n };\n /**\n * this is a mapping of keys that require shift on a US keypad\n * back to the non shift equivelents\n *\n * this is so you can use keyup events with these keys\n *\n * note that this will only work reliably on US keyboards\n *\n * @type {Object}\n */\n\n var _SHIFT_MAP = {\n '~': '`',\n '!': '1',\n '@': '2',\n '#': '3',\n '$': '4',\n '%': '5',\n '^': '6',\n '&': '7',\n '*': '8',\n '(': '9',\n ')': '0',\n '_': '-',\n '+': '=',\n ':': ';',\n '\\\"': '\\'',\n '<': ',',\n '>': '.',\n '?': '/',\n '|': '\\\\'\n };\n /**\n * this is a list of special strings you can use to map\n * to modifier keys when you specify your keyboard shortcuts\n *\n * @type {Object}\n */\n\n var _SPECIAL_ALIASES = {\n 'option': 'alt',\n 'command': 'meta',\n 'return': 'enter',\n 'escape': 'esc',\n 'plus': '+',\n 'mod': /Mac|iPod|iPhone|iPad/.test(navigator.platform) ? 'meta' : 'ctrl'\n };\n /**\n * variable to store the flipped version of _MAP from above\n * needed to check if we should use keypress or not when no action\n * is specified\n *\n * @type {Object|undefined}\n */\n\n var _REVERSE_MAP;\n /**\n * loop through the f keys, f1 to f19 and add them to the map\n * programatically\n */\n\n\n for (var i = 1; i < 20; ++i) {\n _MAP[111 + i] = 'f' + i;\n }\n /**\n * loop through to map numbers on the numeric keypad\n */\n\n\n for (i = 0; i <= 9; ++i) {\n // This needs to use a string cause otherwise since 0 is falsey\n // mousetrap will never fire for numpad 0 pressed as part of a keydown\n // event.\n //\n // @see https://github.com/ccampbell/mousetrap/pull/258\n _MAP[i + 96] = i.toString();\n }\n /**\n * cross browser add event method\n *\n * @param {Element|HTMLDocument} object\n * @param {string} type\n * @param {Function} callback\n * @returns void\n */\n\n\n function _addEvent(object, type, callback) {\n if (object.addEventListener) {\n object.addEventListener(type, callback, false);\n return;\n }\n\n object.attachEvent('on' + type, callback);\n }\n /**\n * takes the event and returns the key character\n *\n * @param {Event} e\n * @return {string}\n */\n\n\n function _characterFromEvent(e) {\n // for keypress events we should return the character as is\n if (e.type == 'keypress') {\n var character = String.fromCharCode(e.which); // if the shift key is not pressed then it is safe to assume\n // that we want the character to be lowercase. this means if\n // you accidentally have caps lock on then your key bindings\n // will continue to work\n //\n // the only side effect that might not be desired is if you\n // bind something like 'A' cause you want to trigger an\n // event when capital A is pressed caps lock will no longer\n // trigger the event. shift+a will though.\n\n if (!e.shiftKey) {\n character = character.toLowerCase();\n }\n\n return character;\n } // for non keypress events the special maps are needed\n\n\n if (_MAP[e.which]) {\n return _MAP[e.which];\n }\n\n if (_KEYCODE_MAP[e.which]) {\n return _KEYCODE_MAP[e.which];\n } // if it is not in the special map\n // with keydown and keyup events the character seems to always\n // come in as an uppercase character whether you are pressing shift\n // or not. we should make sure it is always lowercase for comparisons\n\n\n return String.fromCharCode(e.which).toLowerCase();\n }\n /**\n * checks if two arrays are equal\n *\n * @param {Array} modifiers1\n * @param {Array} modifiers2\n * @returns {boolean}\n */\n\n\n function _modifiersMatch(modifiers1, modifiers2) {\n return modifiers1.sort().join(',') === modifiers2.sort().join(',');\n }\n /**\n * takes a key event and figures out what the modifiers are\n *\n * @param {Event} e\n * @returns {Array}\n */\n\n\n function _eventModifiers(e) {\n var modifiers = [];\n\n if (e.shiftKey) {\n modifiers.push('shift');\n }\n\n if (e.altKey) {\n modifiers.push('alt');\n }\n\n if (e.ctrlKey) {\n modifiers.push('ctrl');\n }\n\n if (e.metaKey) {\n modifiers.push('meta');\n }\n\n return modifiers;\n }\n /**\n * prevents default for this event\n *\n * @param {Event} e\n * @returns void\n */\n\n\n function _preventDefault(e) {\n if (e.preventDefault) {\n e.preventDefault();\n return;\n }\n\n e.returnValue = false;\n }\n /**\n * stops propogation for this event\n *\n * @param {Event} e\n * @returns void\n */\n\n\n function _stopPropagation(e) {\n if (e.stopPropagation) {\n e.stopPropagation();\n return;\n }\n\n e.cancelBubble = true;\n }\n /**\n * determines if the keycode specified is a modifier key or not\n *\n * @param {string} key\n * @returns {boolean}\n */\n\n\n function _isModifier(key) {\n return key == 'shift' || key == 'ctrl' || key == 'alt' || key == 'meta';\n }\n /**\n * reverses the map lookup so that we can look for specific keys\n * to see what can and can't use keypress\n *\n * @return {Object}\n */\n\n\n function _getReverseMap() {\n if (!_REVERSE_MAP) {\n _REVERSE_MAP = {};\n\n for (var key in _MAP) {\n // pull out the numeric keypad from here cause keypress should\n // be able to detect the keys from the character\n if (key > 95 && key < 112) {\n continue;\n }\n\n if (_MAP.hasOwnProperty(key)) {\n _REVERSE_MAP[_MAP[key]] = key;\n }\n }\n }\n\n return _REVERSE_MAP;\n }\n /**\n * picks the best action based on the key combination\n *\n * @param {string} key - character for key\n * @param {Array} modifiers\n * @param {string=} action passed in\n */\n\n\n function _pickBestAction(key, modifiers, action) {\n // if no action was picked in we should try to pick the one\n // that we think would work best for this key\n if (!action) {\n action = _getReverseMap()[key] ? 'keydown' : 'keypress';\n } // modifier keys don't work as expected with keypress,\n // switch to keydown\n\n\n if (action == 'keypress' && modifiers.length) {\n action = 'keydown';\n }\n\n return action;\n }\n /**\n * Converts from a string key combination to an array\n *\n * @param {string} combination like \"command+shift+l\"\n * @return {Array}\n */\n\n\n function _keysFromString(combination) {\n if (combination === '+') {\n return ['+'];\n }\n\n combination = combination.replace(/\\+{2}/g, '+plus');\n return combination.split('+');\n }\n /**\n * Gets info for a specific key combination\n *\n * @param {string} combination key combination (\"command+s\" or \"a\" or \"*\")\n * @param {string=} action\n * @returns {Object}\n */\n\n\n function _getKeyInfo(combination, action) {\n var keys;\n var key;\n var i;\n var modifiers = []; // take the keys from this pattern and figure out what the actual\n // pattern is all about\n\n keys = _keysFromString(combination);\n\n for (i = 0; i < keys.length; ++i) {\n key = keys[i]; // normalize key names\n\n if (_SPECIAL_ALIASES[key]) {\n key = _SPECIAL_ALIASES[key];\n } // if this is not a keypress event then we should\n // be smart about using shift keys\n // this will only work for US keyboards however\n\n\n if (action && action != 'keypress' && _SHIFT_MAP[key]) {\n key = _SHIFT_MAP[key];\n modifiers.push('shift');\n } // if this key is a modifier then add it to the list of modifiers\n\n\n if (_isModifier(key)) {\n modifiers.push(key);\n }\n } // depending on what the key combination is\n // we will try to pick the best event for it\n\n\n action = _pickBestAction(key, modifiers, action);\n return {\n key: key,\n modifiers: modifiers,\n action: action\n };\n }\n\n function _belongsTo(element, ancestor) {\n if (element === null || element === document) {\n return false;\n }\n\n if (element === ancestor) {\n return true;\n }\n\n return _belongsTo(element.parentNode, ancestor);\n }\n\n function Mousetrap(targetElement) {\n var self = this;\n targetElement = targetElement || document;\n\n if (!(self instanceof Mousetrap)) {\n return new Mousetrap(targetElement);\n }\n /**\n * element to attach key events to\n *\n * @type {Element}\n */\n\n\n self.target = targetElement;\n /**\n * a list of all the callbacks setup via Mousetrap.bind()\n *\n * @type {Object}\n */\n\n self._callbacks = {};\n /**\n * direct map of string combinations to callbacks used for trigger()\n *\n * @type {Object}\n */\n\n self._directMap = {};\n /**\n * keeps track of what level each sequence is at since multiple\n * sequences can start out with the same sequence\n *\n * @type {Object}\n */\n\n var _sequenceLevels = {};\n /**\n * variable to store the setTimeout call\n *\n * @type {null|number}\n */\n\n var _resetTimer;\n /**\n * temporary state where we will ignore the next keyup\n *\n * @type {boolean|string}\n */\n\n\n var _ignoreNextKeyup = false;\n /**\n * temporary state where we will ignore the next keypress\n *\n * @type {boolean}\n */\n\n var _ignoreNextKeypress = false;\n /**\n * are we currently inside of a sequence?\n * type of action (\"keyup\" or \"keydown\" or \"keypress\") or false\n *\n * @type {boolean|string}\n */\n\n var _nextExpectedAction = false;\n /**\n * resets all sequence counters except for the ones passed in\n *\n * @param {Object} doNotReset\n * @returns void\n */\n\n function _resetSequences(doNotReset) {\n doNotReset = doNotReset || {};\n var activeSequences = false,\n key;\n\n for (key in _sequenceLevels) {\n if (doNotReset[key]) {\n activeSequences = true;\n continue;\n }\n\n _sequenceLevels[key] = 0;\n }\n\n if (!activeSequences) {\n _nextExpectedAction = false;\n }\n }\n /**\n * finds all callbacks that match based on the keycode, modifiers,\n * and action\n *\n * @param {string} character\n * @param {Array} modifiers\n * @param {Event|Object} e\n * @param {string=} sequenceName - name of the sequence we are looking for\n * @param {string=} combination\n * @param {number=} level\n * @returns {Array}\n */\n\n\n function _getMatches(character, modifiers, e, sequenceName, combination, level) {\n var i;\n var callback;\n var matches = [];\n var action = e.type; // if there are no events related to this keycode\n\n if (!self._callbacks[character]) {\n return [];\n } // if a modifier key is coming up on its own we should allow it\n\n\n if (action == 'keyup' && _isModifier(character)) {\n modifiers = [character];\n } // loop through all callbacks for the key that was pressed\n // and see if any of them match\n\n\n for (i = 0; i < self._callbacks[character].length; ++i) {\n callback = self._callbacks[character][i]; // if a sequence name is not specified, but this is a sequence at\n // the wrong level then move onto the next match\n\n if (!sequenceName && callback.seq && _sequenceLevels[callback.seq] != callback.level) {\n continue;\n } // if the action we are looking for doesn't match the action we got\n // then we should keep going\n\n\n if (action != callback.action) {\n continue;\n } // if this is a keypress event and the meta key and control key\n // are not pressed that means that we need to only look at the\n // character, otherwise check the modifiers as well\n //\n // chrome will not fire a keypress if meta or control is down\n // safari will fire a keypress if meta or meta+shift is down\n // firefox will fire a keypress if meta or control is down\n\n\n if (action == 'keypress' && !e.metaKey && !e.ctrlKey || _modifiersMatch(modifiers, callback.modifiers)) {\n // when you bind a combination or sequence a second time it\n // should overwrite the first one. if a sequenceName or\n // combination is specified in this call it does just that\n //\n // @todo make deleting its own method?\n var deleteCombo = !sequenceName && callback.combo == combination;\n var deleteSequence = sequenceName && callback.seq == sequenceName && callback.level == level;\n\n if (deleteCombo || deleteSequence) {\n self._callbacks[character].splice(i, 1);\n }\n\n matches.push(callback);\n }\n }\n\n return matches;\n }\n /**\n * actually calls the callback function\n *\n * if your callback function returns false this will use the jquery\n * convention - prevent default and stop propogation on the event\n *\n * @param {Function} callback\n * @param {Event} e\n * @returns void\n */\n\n\n function _fireCallback(callback, e, combo, sequence) {\n // if this event should not happen stop here\n if (self.stopCallback(e, e.target || e.srcElement, combo, sequence)) {\n return;\n }\n\n if (callback(e, combo) === false) {\n _preventDefault(e);\n\n _stopPropagation(e);\n }\n }\n /**\n * handles a character key event\n *\n * @param {string} character\n * @param {Array} modifiers\n * @param {Event} e\n * @returns void\n */\n\n\n self._handleKey = function (character, modifiers, e) {\n var callbacks = _getMatches(character, modifiers, e);\n\n var i;\n var doNotReset = {};\n var maxLevel = 0;\n var processedSequenceCallback = false; // Calculate the maxLevel for sequences so we can only execute the longest callback sequence\n\n for (i = 0; i < callbacks.length; ++i) {\n if (callbacks[i].seq) {\n maxLevel = Math.max(maxLevel, callbacks[i].level);\n }\n } // loop through matching callbacks for this key event\n\n\n for (i = 0; i < callbacks.length; ++i) {\n // fire for all sequence callbacks\n // this is because if for example you have multiple sequences\n // bound such as \"g i\" and \"g t\" they both need to fire the\n // callback for matching g cause otherwise you can only ever\n // match the first one\n if (callbacks[i].seq) {\n // only fire callbacks for the maxLevel to prevent\n // subsequences from also firing\n //\n // for example 'a option b' should not cause 'option b' to fire\n // even though 'option b' is part of the other sequence\n //\n // any sequences that do not match here will be discarded\n // below by the _resetSequences call\n if (callbacks[i].level != maxLevel) {\n continue;\n }\n\n processedSequenceCallback = true; // keep a list of which sequences were matches for later\n\n doNotReset[callbacks[i].seq] = 1;\n\n _fireCallback(callbacks[i].callback, e, callbacks[i].combo, callbacks[i].seq);\n\n continue;\n } // if there were no sequence matches but we are still here\n // that means this is a regular match so we should fire that\n\n\n if (!processedSequenceCallback) {\n _fireCallback(callbacks[i].callback, e, callbacks[i].combo);\n }\n } // if the key you pressed matches the type of sequence without\n // being a modifier (ie \"keyup\" or \"keypress\") then we should\n // reset all sequences that were not matched by this event\n //\n // this is so, for example, if you have the sequence \"h a t\" and you\n // type \"h e a r t\" it does not match. in this case the \"e\" will\n // cause the sequence to reset\n //\n // modifier keys are ignored because you can have a sequence\n // that contains modifiers such as \"enter ctrl+space\" and in most\n // cases the modifier key will be pressed before the next key\n //\n // also if you have a sequence such as \"ctrl+b a\" then pressing the\n // \"b\" key will trigger a \"keypress\" and a \"keydown\"\n //\n // the \"keydown\" is expected when there is a modifier, but the\n // \"keypress\" ends up matching the _nextExpectedAction since it occurs\n // after and that causes the sequence to reset\n //\n // we ignore keypresses in a sequence that directly follow a keydown\n // for the same character\n\n\n var ignoreThisKeypress = e.type == 'keypress' && _ignoreNextKeypress;\n\n if (e.type == _nextExpectedAction && !_isModifier(character) && !ignoreThisKeypress) {\n _resetSequences(doNotReset);\n }\n\n _ignoreNextKeypress = processedSequenceCallback && e.type == 'keydown';\n };\n /**\n * handles a keydown event\n *\n * @param {Event} e\n * @returns void\n */\n\n\n function _handleKeyEvent(e) {\n // normalize e.which for key events\n // @see http://stackoverflow.com/questions/4285627/javascript-keycode-vs-charcode-utter-confusion\n if (typeof e.which !== 'number') {\n e.which = e.keyCode;\n }\n\n var character = _characterFromEvent(e); // no character found then stop\n\n\n if (!character) {\n return;\n } // need to use === for the character check because the character can be 0\n\n\n if (e.type == 'keyup' && _ignoreNextKeyup === character) {\n _ignoreNextKeyup = false;\n return;\n }\n\n self.handleKey(character, _eventModifiers(e), e);\n }\n /**\n * called to set a 1 second timeout on the specified sequence\n *\n * this is so after each key press in the sequence you have 1 second\n * to press the next key before you have to start over\n *\n * @returns void\n */\n\n\n function _resetSequenceTimer() {\n clearTimeout(_resetTimer);\n _resetTimer = setTimeout(_resetSequences, 1000);\n }\n /**\n * binds a key sequence to an event\n *\n * @param {string} combo - combo specified in bind call\n * @param {Array} keys\n * @param {Function} callback\n * @param {string=} action\n * @returns void\n */\n\n\n function _bindSequence(combo, keys, callback, action) {\n // start off by adding a sequence level record for this combination\n // and setting the level to 0\n _sequenceLevels[combo] = 0;\n /**\n * callback to increase the sequence level for this sequence and reset\n * all other sequences that were active\n *\n * @param {string} nextAction\n * @returns {Function}\n */\n\n function _increaseSequence(nextAction) {\n return function () {\n _nextExpectedAction = nextAction;\n ++_sequenceLevels[combo];\n\n _resetSequenceTimer();\n };\n }\n /**\n * wraps the specified callback inside of another function in order\n * to reset all sequence counters as soon as this sequence is done\n *\n * @param {Event} e\n * @returns void\n */\n\n\n function _callbackAndReset(e) {\n _fireCallback(callback, e, combo); // we should ignore the next key up if the action is key down\n // or keypress. this is so if you finish a sequence and\n // release the key the final key will not trigger a keyup\n\n\n if (action !== 'keyup') {\n _ignoreNextKeyup = _characterFromEvent(e);\n } // weird race condition if a sequence ends with the key\n // another sequence begins with\n\n\n setTimeout(_resetSequences, 10);\n } // loop through keys one at a time and bind the appropriate callback\n // function. for any key leading up to the final one it should\n // increase the sequence. after the final, it should reset all sequences\n //\n // if an action is specified in the original bind call then that will\n // be used throughout. otherwise we will pass the action that the\n // next key in the sequence should match. this allows a sequence\n // to mix and match keypress and keydown events depending on which\n // ones are better suited to the key provided\n\n\n for (var i = 0; i < keys.length; ++i) {\n var isFinal = i + 1 === keys.length;\n var wrappedCallback = isFinal ? _callbackAndReset : _increaseSequence(action || _getKeyInfo(keys[i + 1]).action);\n\n _bindSingle(keys[i], wrappedCallback, action, combo, i);\n }\n }\n /**\n * binds a single keyboard combination\n *\n * @param {string} combination\n * @param {Function} callback\n * @param {string=} action\n * @param {string=} sequenceName - name of sequence if part of sequence\n * @param {number=} level - what part of the sequence the command is\n * @returns void\n */\n\n\n function _bindSingle(combination, callback, action, sequenceName, level) {\n // store a direct mapped reference for use with Mousetrap.trigger\n self._directMap[combination + ':' + action] = callback; // make sure multiple spaces in a row become a single space\n\n combination = combination.replace(/\\s+/g, ' ');\n var sequence = combination.split(' ');\n var info; // if this pattern is a sequence of keys then run through this method\n // to reprocess each pattern one key at a time\n\n if (sequence.length > 1) {\n _bindSequence(combination, sequence, callback, action);\n\n return;\n }\n\n info = _getKeyInfo(combination, action); // make sure to initialize array if this is the first time\n // a callback is added for this key\n\n self._callbacks[info.key] = self._callbacks[info.key] || []; // remove an existing match if there is one\n\n _getMatches(info.key, info.modifiers, {\n type: info.action\n }, sequenceName, combination, level); // add this call back to the array\n // if it is a sequence put it at the beginning\n // if not put it at the end\n //\n // this is important because the way these are processed expects\n // the sequence ones to come first\n\n\n self._callbacks[info.key][sequenceName ? 'unshift' : 'push']({\n callback: callback,\n modifiers: info.modifiers,\n action: info.action,\n seq: sequenceName,\n level: level,\n combo: combination\n });\n }\n /**\n * binds multiple combinations to the same callback\n *\n * @param {Array} combinations\n * @param {Function} callback\n * @param {string|undefined} action\n * @returns void\n */\n\n\n self._bindMultiple = function (combinations, callback, action) {\n for (var i = 0; i < combinations.length; ++i) {\n _bindSingle(combinations[i], callback, action);\n }\n }; // start!\n\n\n _addEvent(targetElement, 'keypress', _handleKeyEvent);\n\n _addEvent(targetElement, 'keydown', _handleKeyEvent);\n\n _addEvent(targetElement, 'keyup', _handleKeyEvent);\n }\n /**\n * binds an event to mousetrap\n *\n * can be a single key, a combination of keys separated with +,\n * an array of keys, or a sequence of keys separated by spaces\n *\n * be sure to list the modifier keys first to make sure that the\n * correct key ends up getting bound (the last key in the pattern)\n *\n * @param {string|Array} keys\n * @param {Function} callback\n * @param {string=} action - 'keypress', 'keydown', or 'keyup'\n * @returns void\n */\n\n\n Mousetrap.prototype.bind = function (keys, callback, action) {\n var self = this;\n keys = keys instanceof Array ? keys : [keys];\n\n self._bindMultiple.call(self, keys, callback, action);\n\n return self;\n };\n /**\n * unbinds an event to mousetrap\n *\n * the unbinding sets the callback function of the specified key combo\n * to an empty function and deletes the corresponding key in the\n * _directMap dict.\n *\n * TODO: actually remove this from the _callbacks dictionary instead\n * of binding an empty function\n *\n * the keycombo+action has to be exactly the same as\n * it was defined in the bind method\n *\n * @param {string|Array} keys\n * @param {string} action\n * @returns void\n */\n\n\n Mousetrap.prototype.unbind = function (keys, action) {\n var self = this;\n return self.bind.call(self, keys, function () {}, action);\n };\n /**\n * triggers an event that has already been bound\n *\n * @param {string} keys\n * @param {string=} action\n * @returns void\n */\n\n\n Mousetrap.prototype.trigger = function (keys, action) {\n var self = this;\n\n if (self._directMap[keys + ':' + action]) {\n self._directMap[keys + ':' + action]({}, keys);\n }\n\n return self;\n };\n /**\n * resets the library back to its initial state. this is useful\n * if you want to clear out the current keyboard shortcuts and bind\n * new ones - for example if you switch to another page\n *\n * @returns void\n */\n\n\n Mousetrap.prototype.reset = function () {\n var self = this;\n self._callbacks = {};\n self._directMap = {};\n return self;\n };\n /**\n * should we stop this event before firing off callbacks\n *\n * @param {Event} e\n * @param {Element} element\n * @return {boolean}\n */\n\n\n Mousetrap.prototype.stopCallback = function (e, element) {\n var self = this; // if the element has the class \"mousetrap\" then no need to stop\n\n if ((' ' + element.className + ' ').indexOf(' mousetrap ') > -1) {\n return false;\n }\n\n if (_belongsTo(element, self.target)) {\n return false;\n } // Events originating from a shadow DOM are re-targetted and `e.target` is the shadow host,\n // not the initial event target in the shadow tree. Note that not all events cross the\n // shadow boundary.\n // For shadow trees with `mode: 'open'`, the initial event target is the first element in\n // the event’s composed path. For shadow trees with `mode: 'closed'`, the initial event\n // target cannot be obtained.\n\n\n if ('composedPath' in e && typeof e.composedPath === 'function') {\n // For open shadow trees, update `element` so that the following check works.\n var initialEventTarget = e.composedPath()[0];\n\n if (initialEventTarget !== e.target) {\n element = initialEventTarget;\n }\n } // stop for input, select, and textarea\n\n\n return element.tagName == 'INPUT' || element.tagName == 'SELECT' || element.tagName == 'TEXTAREA' || element.isContentEditable;\n };\n /**\n * exposes _handleKey publicly so it can be overwritten by extensions\n */\n\n\n Mousetrap.prototype.handleKey = function () {\n var self = this;\n return self._handleKey.apply(self, arguments);\n };\n /**\n * allow custom key mappings\n */\n\n\n Mousetrap.addKeycodes = function (object) {\n for (var key in object) {\n if (object.hasOwnProperty(key)) {\n _MAP[key] = object[key];\n }\n }\n\n _REVERSE_MAP = null;\n };\n /**\n * Init the global mousetrap functions\n *\n * This method is needed to allow the global mousetrap functions to work\n * now that mousetrap is a constructor function.\n */\n\n\n Mousetrap.init = function () {\n var documentMousetrap = Mousetrap(document);\n\n for (var method in documentMousetrap) {\n if (method.charAt(0) !== '_') {\n Mousetrap[method] = function (method) {\n return function () {\n return documentMousetrap[method].apply(documentMousetrap, arguments);\n };\n }(method);\n }\n }\n };\n\n Mousetrap.init(); // expose mousetrap to the global object\n\n window.Mousetrap = Mousetrap; // expose as a common js module\n\n if (typeof module !== 'undefined' && module.exports) {\n module.exports = Mousetrap;\n } // expose mousetrap as an AMD module\n\n\n if (true) {\n !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () {\n return Mousetrap;\n }).call(exports, __webpack_require__, exports, module),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n }\n})(typeof window !== 'undefined' ? window : null, typeof window !== 'undefined' ? document : null);\n\n//# sourceURL=webpack:///./node_modules/mousetrap/mousetrap.js?");
-
-/***/ }),
-
-/***/ "./node_modules/webpack/buildin/module.js":
-/*!***********************************!*\
- !*** (webpack)/buildin/module.js ***!
- \***********************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports) {
-
-eval("module.exports = function (module) {\n if (!module.webpackPolyfill) {\n module.deprecate = function () {};\n\n module.paths = []; // module.parent = undefined by default\n\n if (!module.children) module.children = [];\n Object.defineProperty(module, \"loaded\", {\n enumerable: true,\n get: function get() {\n return module.l;\n }\n });\n Object.defineProperty(module, \"id\", {\n enumerable: true,\n get: function get() {\n return module.i;\n }\n });\n module.webpackPolyfill = 1;\n }\n\n return module;\n};\n\n//# sourceURL=webpack:///(webpack)/buildin/module.js?");
-
-/***/ }),
-
-/***/ "./node_modules/wolfy87-eventemitter/EventEmitter.js":
-/*!***********************************************************!*\
- !*** ./node_modules/wolfy87-eventemitter/EventEmitter.js ***!
- \***********************************************************/
-/*! no static exports found */
-/*! ModuleConcatenation bailout: Module is not an ECMAScript module */
-/***/ (function(module, exports, __webpack_require__) {
-
-eval("var __WEBPACK_AMD_DEFINE_RESULT__;function _typeof(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n/*!\n * EventEmitter v5.2.6 - git.io/ee\n * Unlicense - http://unlicense.org/\n * Oliver Caldwell - https://oli.me.uk/\n * @preserve\n */\n;\n\n(function (exports) {\n 'use strict';\n /**\n * Class for managing events.\n * Can be extended to provide event functionality in other classes.\n *\n * @class EventEmitter Manages event registering and emitting.\n */\n\n function EventEmitter() {} // Shortcuts to improve speed and size\n\n\n var proto = EventEmitter.prototype;\n var originalGlobalValue = exports.EventEmitter;\n /**\n * Finds the index of the listener for the event in its storage array.\n *\n * @param {Function[]} listeners Array of listeners to search through.\n * @param {Function} listener Method to look for.\n * @return {Number} Index of the specified listener, -1 if not found\n * @api private\n */\n\n function indexOfListener(listeners, listener) {\n var i = listeners.length;\n\n while (i--) {\n if (listeners[i].listener === listener) {\n return i;\n }\n }\n\n return -1;\n }\n /**\n * Alias a method while keeping the context correct, to allow for overwriting of target method.\n *\n * @param {String} name The name of the target method.\n * @return {Function} The aliased method\n * @api private\n */\n\n\n function alias(name) {\n return function aliasClosure() {\n return this[name].apply(this, arguments);\n };\n }\n /**\n * Returns the listener array for the specified event.\n * Will initialise the event object and listener arrays if required.\n * Will return an object if you use a regex search. The object contains keys for each matched event. So /ba[rz]/ might return an object containing bar and baz. But only if you have either defined them with defineEvent or added some listeners to them.\n * Each property in the object response is an array of listener functions.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Function[]|Object} All listener functions for the event.\n */\n\n\n proto.getListeners = function getListeners(evt) {\n var events = this._getEvents();\n\n var response;\n var key; // Return a concatenated array of all matching events if\n // the selector is a regular expression.\n\n if (evt instanceof RegExp) {\n response = {};\n\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n response[key] = events[key];\n }\n }\n } else {\n response = events[evt] || (events[evt] = []);\n }\n\n return response;\n };\n /**\n * Takes a list of listener objects and flattens it into a list of listener functions.\n *\n * @param {Object[]} listeners Raw listener objects.\n * @return {Function[]} Just the listener functions.\n */\n\n\n proto.flattenListeners = function flattenListeners(listeners) {\n var flatListeners = [];\n var i;\n\n for (i = 0; i < listeners.length; i += 1) {\n flatListeners.push(listeners[i].listener);\n }\n\n return flatListeners;\n };\n /**\n * Fetches the requested listeners via getListeners but will always return the results inside an object. This is mainly for internal use but others may find it useful.\n *\n * @param {String|RegExp} evt Name of the event to return the listeners from.\n * @return {Object} All listener functions for an event in an object.\n */\n\n\n proto.getListenersAsObject = function getListenersAsObject(evt) {\n var listeners = this.getListeners(evt);\n var response;\n\n if (listeners instanceof Array) {\n response = {};\n response[evt] = listeners;\n }\n\n return response || listeners;\n };\n\n function isValidListener(listener) {\n if (typeof listener === 'function' || listener instanceof RegExp) {\n return true;\n } else if (listener && _typeof(listener) === 'object') {\n return isValidListener(listener.listener);\n } else {\n return false;\n }\n }\n /**\n * Adds a listener function to the specified event.\n * The listener will not be added if it is a duplicate.\n * If the listener returns true then it will be removed after it is called.\n * If you pass a regular expression as the event name then the listener will be added to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n\n proto.addListener = function addListener(evt, listener) {\n if (!isValidListener(listener)) {\n throw new TypeError('listener must be a function');\n }\n\n var listeners = this.getListenersAsObject(evt);\n var listenerIsWrapped = _typeof(listener) === 'object';\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key) && indexOfListener(listeners[key], listener) === -1) {\n listeners[key].push(listenerIsWrapped ? listener : {\n listener: listener,\n once: false\n });\n }\n }\n\n return this;\n };\n /**\n * Alias of addListener\n */\n\n\n proto.on = alias('addListener');\n /**\n * Semi-alias of addListener. It will add a listener that will be\n * automatically removed after its first execution.\n *\n * @param {String|RegExp} evt Name of the event to attach the listener to.\n * @param {Function} listener Method to be called when the event is emitted. If the function returns true then it will be removed after calling.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n proto.addOnceListener = function addOnceListener(evt, listener) {\n return this.addListener(evt, {\n listener: listener,\n once: true\n });\n };\n /**\n * Alias of addOnceListener.\n */\n\n\n proto.once = alias('addOnceListener');\n /**\n * Defines an event name. This is required if you want to use a regex to add a listener to multiple events at once. If you don't do this then how do you expect it to know what event to add to? Should it just add to every possible match for a regex? No. That is scary and bad.\n * You need to tell it what event names should be matched by a regex.\n *\n * @param {String} evt Name of the event to create.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n proto.defineEvent = function defineEvent(evt) {\n this.getListeners(evt);\n return this;\n };\n /**\n * Uses defineEvent to define multiple events.\n *\n * @param {String[]} evts An array of event names to define.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n\n proto.defineEvents = function defineEvents(evts) {\n for (var i = 0; i < evts.length; i += 1) {\n this.defineEvent(evts[i]);\n }\n\n return this;\n };\n /**\n * Removes a listener function from the specified event.\n * When passed a regular expression as the event name, it will remove the listener from all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to remove the listener from.\n * @param {Function} listener Method to remove from the event.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n\n proto.removeListener = function removeListener(evt, listener) {\n var listeners = this.getListenersAsObject(evt);\n var index;\n var key;\n\n for (key in listeners) {\n if (listeners.hasOwnProperty(key)) {\n index = indexOfListener(listeners[key], listener);\n\n if (index !== -1) {\n listeners[key].splice(index, 1);\n }\n }\n }\n\n return this;\n };\n /**\n * Alias of removeListener\n */\n\n\n proto.off = alias('removeListener');\n /**\n * Adds listeners in bulk using the manipulateListeners method.\n * If you pass an object as the first argument you can add to multiple events at once. The object should contain key value pairs of events and listeners or listener arrays. You can also pass it an event name and an array of listeners to be added.\n * You can also pass it a regular expression to add the array of listeners to all events that match it.\n * Yeah, this function does quite a bit. That's probably a bad thing.\n *\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add to multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to add.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n proto.addListeners = function addListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(false, evt, listeners);\n };\n /**\n * Removes listeners in bulk using the manipulateListeners method.\n * If you pass an object as the first argument you can remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.\n * You can also pass it an event name and an array of listeners to be removed.\n * You can also pass it a regular expression to remove the listeners from all events that match it.\n *\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to remove from multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n\n proto.removeListeners = function removeListeners(evt, listeners) {\n // Pass through to manipulateListeners\n return this.manipulateListeners(true, evt, listeners);\n };\n /**\n * Edits listeners in bulk. The addListeners and removeListeners methods both use this to do their job. You should really use those instead, this is a little lower level.\n * The first argument will determine if the listeners are removed (true) or added (false).\n * If you pass an object as the second argument you can add/remove from multiple events at once. The object should contain key value pairs of events and listeners or listener arrays.\n * You can also pass it an event name and an array of listeners to be added/removed.\n * You can also pass it a regular expression to manipulate the listeners of all events that match it.\n *\n * @param {Boolean} remove True if you want to remove listeners, false if you want to add.\n * @param {String|Object|RegExp} evt An event name if you will pass an array of listeners next. An object if you wish to add/remove from multiple events at once.\n * @param {Function[]} [listeners] An optional array of listener functions to add/remove.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n\n proto.manipulateListeners = function manipulateListeners(remove, evt, listeners) {\n var i;\n var value;\n var single = remove ? this.removeListener : this.addListener;\n var multiple = remove ? this.removeListeners : this.addListeners; // If evt is an object then pass each of its properties to this method\n\n if (_typeof(evt) === 'object' && !(evt instanceof RegExp)) {\n for (i in evt) {\n if (evt.hasOwnProperty(i) && (value = evt[i])) {\n // Pass the single listener straight through to the singular method\n if (typeof value === 'function') {\n single.call(this, i, value);\n } else {\n // Otherwise pass back to the multiple function\n multiple.call(this, i, value);\n }\n }\n }\n } else {\n // So evt must be a string\n // And listeners must be an array of listeners\n // Loop over it and pass each one to the multiple method\n i = listeners.length;\n\n while (i--) {\n single.call(this, evt, listeners[i]);\n }\n }\n\n return this;\n };\n /**\n * Removes all listeners from a specified event.\n * If you do not specify an event then all listeners will be removed.\n * That means every event will be emptied.\n * You can also pass a regex to remove all events that match it.\n *\n * @param {String|RegExp} [evt] Optional name of the event to remove all listeners for. Will remove from every event if not passed.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n\n proto.removeEvent = function removeEvent(evt) {\n var type = _typeof(evt);\n\n var events = this._getEvents();\n\n var key; // Remove different things depending on the state of evt\n\n if (type === 'string') {\n // Remove all listeners for the specified event\n delete events[evt];\n } else if (evt instanceof RegExp) {\n // Remove all events matching the regex.\n for (key in events) {\n if (events.hasOwnProperty(key) && evt.test(key)) {\n delete events[key];\n }\n }\n } else {\n // Remove all listeners in all events\n delete this._events;\n }\n\n return this;\n };\n /**\n * Alias of removeEvent.\n *\n * Added to mirror the node API.\n */\n\n\n proto.removeAllListeners = alias('removeEvent');\n /**\n * Emits an event of your choice.\n * When emitted, every listener attached to that event will be executed.\n * If you pass the optional argument array then those arguments will be passed to every listener upon execution.\n * Because it uses `apply`, your array of arguments will be passed as if you wrote them out separately.\n * So they will not arrive within the array on the other side, they will be separate.\n * You can also pass a regular expression to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {Array} [args] Optional array of arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n proto.emitEvent = function emitEvent(evt, args) {\n var listenersMap = this.getListenersAsObject(evt);\n var listeners;\n var listener;\n var i;\n var key;\n var response;\n\n for (key in listenersMap) {\n if (listenersMap.hasOwnProperty(key)) {\n listeners = listenersMap[key].slice(0);\n\n for (i = 0; i < listeners.length; i++) {\n // If the listener returns true then it shall be removed from the event\n // The function is executed either with a basic call or an apply if there is an args array\n listener = listeners[i];\n\n if (listener.once === true) {\n this.removeListener(evt, listener.listener);\n }\n\n response = listener.listener.apply(this, args || []);\n\n if (response === this._getOnceReturnValue()) {\n this.removeListener(evt, listener.listener);\n }\n }\n }\n }\n\n return this;\n };\n /**\n * Alias of emitEvent\n */\n\n\n proto.trigger = alias('emitEvent');\n /**\n * Subtly different from emitEvent in that it will pass its arguments on to the listeners, as opposed to taking a single array of arguments to pass on.\n * As with emitEvent, you can pass a regex in place of the event name to emit to all events that match it.\n *\n * @param {String|RegExp} evt Name of the event to emit and execute listeners for.\n * @param {...*} Optional additional arguments to be passed to each listener.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n proto.emit = function emit(evt) {\n var args = Array.prototype.slice.call(arguments, 1);\n return this.emitEvent(evt, args);\n };\n /**\n * Sets the current value to check against when executing listeners. If a\n * listeners return value matches the one set here then it will be removed\n * after execution. This value defaults to true.\n *\n * @param {*} value The new value to check for when executing listeners.\n * @return {Object} Current instance of EventEmitter for chaining.\n */\n\n\n proto.setOnceReturnValue = function setOnceReturnValue(value) {\n this._onceReturnValue = value;\n return this;\n };\n /**\n * Fetches the current value to check against when executing listeners. If\n * the listeners return value matches this one then it should be removed\n * automatically. It will return true by default.\n *\n * @return {*|Boolean} The current value to check for or the default, true.\n * @api private\n */\n\n\n proto._getOnceReturnValue = function _getOnceReturnValue() {\n if (this.hasOwnProperty('_onceReturnValue')) {\n return this._onceReturnValue;\n } else {\n return true;\n }\n };\n /**\n * Fetches the events object and creates one if required.\n *\n * @return {Object} The events storage object.\n * @api private\n */\n\n\n proto._getEvents = function _getEvents() {\n return this._events || (this._events = {});\n };\n /**\n * Reverts the global {@link EventEmitter} to its previous value and returns a reference to this version.\n *\n * @return {Function} Non conflicting EventEmitter class.\n */\n\n\n EventEmitter.noConflict = function noConflict() {\n exports.EventEmitter = originalGlobalValue;\n return EventEmitter;\n }; // Expose the class either via AMD, CommonJS or the global object\n\n\n if (true) {\n !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () {\n return EventEmitter;\n }).call(exports, __webpack_require__, exports, module),\n\t\t\t\t__WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));\n } else {}\n})(typeof window !== 'undefined' ? window : this || {});\n\n//# sourceURL=webpack:///./node_modules/wolfy87-eventemitter/EventEmitter.js?");
-
-/***/ }),
-
-/***/ "./src/scripts/components/copy-to-clipboard.js":
-/*!*****************************************************!*\
- !*** ./src/scripts/components/copy-to-clipboard.js ***!
- \*****************************************************/
-/*! no exports provided */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var clipboard__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! clipboard */ \"./node_modules/clipboard/dist/clipboard.js\");\n/* harmony import */ var clipboard__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(clipboard__WEBPACK_IMPORTED_MODULE_0__);\n/**\n * Copy to clipboard functionality for code snippet examples\n */\n\nvar clipboard = new clipboard__WEBPACK_IMPORTED_MODULE_0___default.a('.pl-js-code-copy-btn');\nclipboard.on('success', function (e) {\n var copyButton = document.querySelectorAll('.pl-js-code-copy-btn');\n\n for (var i = 0; i < copyButton.length; i++) {\n copyButton[i].innerText = 'Copy';\n }\n\n e.trigger.textContent = 'Copied';\n});\n\n//# sourceURL=webpack:///./src/scripts/components/copy-to-clipboard.js?");
-
-/***/ }),
-
-/***/ "./src/scripts/components/panels-util.js":
-/*!***********************************************!*\
- !*** ./src/scripts/components/panels-util.js ***!
- \***********************************************/
-/*! exports provided: panelsUtil */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"panelsUtil\", function() { return panelsUtil; });\n/**\n * Panels Util - for both styleguide and viewer\n */\nvar panelsUtil = {\n /**\n * Add click events to the template that was rendered\n * @param {String} the rendered template for the modal\n * @param {String} the pattern partial for the modal\n */\n addClickEvents: function addClickEvents(templateRendered, patternPartial) {\n var els = templateRendered.querySelectorAll('.pl-js-tab-link');\n\n for (var i = 0; i < els.length; ++i) {\n els[i].onclick = function (e) {\n e.preventDefault();\n var partial = this.getAttribute('data-patternpartial');\n var panelID = this.getAttribute('data-panelid');\n panelsUtil.show(partial, panelID);\n };\n }\n\n return templateRendered;\n },\n\n /**\n * Show a specific modal\n * @param {String} the pattern partial for the modal\n * @param {String} the ID of the panel to be shown\n */\n show: function show(patternPartial, panelID) {\n var activeTabClass = 'pl-is-active-tab'; // turn off all of the active tabs\n\n var allTabLinks = document.querySelectorAll(\".pl-js-tab-link\"); // hide all of the panels\n\n var allTabPanels = document.querySelectorAll(\".pl-js-tab-panel\"); // tabLink about to become active\n\n var activeTabLink = document.querySelector(\"#pl-\".concat(patternPartial, \"-\").concat(panelID, \"-tab\")); // tabPanelabout to become active\n\n var activeTabPanel = document.querySelector(\"#pl-\".concat(patternPartial, \"-\").concat(panelID, \"-panel\"));\n\n for (var i = 0; i < allTabLinks.length; ++i) {\n allTabLinks[i].classList.remove(activeTabClass);\n }\n\n for (var _i = 0; _i < allTabPanels.length; ++_i) {\n allTabPanels[_i].classList.remove(activeTabClass);\n }\n\n activeTabLink.classList.add(activeTabClass);\n activeTabPanel.classList.add(activeTabClass);\n }\n};\n\n//# sourceURL=webpack:///./src/scripts/components/panels-util.js?");
-
-/***/ }),
-
-/***/ "./src/scripts/patternlab-pattern.js":
-/*!*******************************************************!*\
- !*** ./src/scripts/patternlab-pattern.js + 2 modules ***!
- \*******************************************************/
-/*! no exports provided */
-/*! ModuleConcatenation bailout: Cannot concat with ./node_modules/mousetrap/mousetrap.js (<- Module is not an ECMAScript module) */
-/*! ModuleConcatenation bailout: Cannot concat with ./src/scripts/components/copy-to-clipboard.js */
-/*! ModuleConcatenation bailout: Cannot concat with ./src/scripts/components/panels-util.js */
-/*! ModuleConcatenation bailout: Cannot concat with ./src/scripts/utils/index.js */
-/***/ (function(module, __webpack_exports__, __webpack_require__) {
-
-"use strict";
-eval("\n// EXTERNAL MODULE: ./src/scripts/utils/postmessage.js\nvar postmessage = __webpack_require__(\"./src/scripts/utils/postmessage.js\");\n\n// EXTERNAL MODULE: ./src/scripts/components/panels-util.js\nvar panels_util = __webpack_require__(\"./src/scripts/components/panels-util.js\");\n\n// EXTERNAL MODULE: ./src/scripts/components/copy-to-clipboard.js\nvar copy_to_clipboard = __webpack_require__(\"./src/scripts/components/copy-to-clipboard.js\");\n\n// CONCATENATED MODULE: ./src/scripts/components/modal-styleguide.js\n/**\n * \"Modal\" (aka Panel UI) for the Styleguide Layer - for both annotations and code/info\n */\n\n\nvar modalStyleguide = {\n // set up some defaults\n active: [],\n targetOrigin: window.location.protocol === 'file:' ? '*' : window.location.protocol + '//' + window.location.host,\n\n /**\n * initialize the modal window\n */\n onReady: function onReady() {\n // go through the panel toggles and add click event to the pattern extra toggle button\n var els = document.querySelectorAll('.pl-js-pattern-extra-toggle');\n\n for (var i = 0; i < els.length; ++i) {\n els[i].onclick = function (e) {\n var patternPartial = this.getAttribute('data-patternpartial');\n modalStyleguide.toggle(patternPartial);\n };\n }\n },\n\n /**\n * toggle the modal window open and closed based on clicking the pip\n * @param {String} the patternPartial that identifies what needs to be toggled\n */\n toggle: function toggle(patternPartial) {\n if (modalStyleguide.active[patternPartial] === undefined || !modalStyleguide.active[patternPartial]) {\n var el = document.getElementById('pl-pattern-data-' + patternPartial);\n modalStyleguide.collectAndSend(el, true, false);\n } else {\n modalStyleguide.highlightsHide();\n modalStyleguide.close(patternPartial);\n }\n },\n\n /**\n * open the modal window for a view-all entry\n * @param {String} the patternPartial that identifies what needs to be opened\n * @param {String} the content that should be inserted\n */\n open: function open(patternPartial, content) {\n // make sure templateRendered is modified to be an HTML element\n var div = document.createElement('div');\n div.innerHTML = content;\n content = document.createElement('div').appendChild(div).querySelector('div'); // add click events\n\n content = panels_util[\"panelsUtil\"].addClickEvents(content, patternPartial); // make sure the modal viewer and other options are off just in case\n\n modalStyleguide.close(patternPartial); // note it's turned on in the viewer\n\n modalStyleguide.active[patternPartial] = true; // make sure there's no content\n\n div = document.getElementById('pl-pattern-extra-' + patternPartial);\n\n if (div.childNodes.length > 0) {\n div.removeChild(div.childNodes[0]);\n } // add the content\n\n\n document.getElementById('pl-pattern-extra-' + patternPartial).appendChild(content); // show the modal\n\n document.getElementById('pl-pattern-extra-toggle-' + patternPartial).classList.add('pl-is-active');\n document.getElementById('pl-pattern-extra-' + patternPartial).classList.add('pl-is-active');\n },\n\n /**\n * close the modal window for a view-all entry\n * @param {String} the patternPartial that identifies what needs to be closed\n */\n close: function close(patternPartial) {\n // note that the modal viewer is no longer active\n modalStyleguide.active[patternPartial] = false; // hide the modal, look at info-panel.js\n\n document.getElementById('pl-pattern-extra-toggle-' + patternPartial).classList.remove('pl-is-active');\n document.getElementById('pl-pattern-extra-' + patternPartial).classList.remove('pl-is-active');\n },\n\n /**\n * get the data that needs to be send to the viewer for rendering\n * @param {Element} the identifier for the element that needs to be collected\n * @param {Boolean} if the refresh is of a view-all view and the content should be sent back\n * @param {Boolean} if the text in the dropdown should be switched\n */\n collectAndSend: function collectAndSend(el, iframePassback, switchText) {\n /**\n * Verify
-
- ${require('./partials/header.html') }
+
+
+
+
+
+
+
+
+
-
-
- ${require('./partials/iframe.html') }
- ${require('./partials/modal.html') }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+
+
+
diff --git a/packages/uikit-workshop/src/html/partials/base-template.html b/packages/uikit-workshop/src/html/partials/base-template.html
old mode 100644
new mode 100755
index 025683798..fbf6ff782
--- a/packages/uikit-workshop/src/html/partials/base-template.html
+++ b/packages/uikit-workshop/src/html/partials/base-template.html
@@ -1,121 +1,175 @@
-{{# descBlockExists }}
-
-
-
- {{# isPatternView }}
-
-
- {{/ isPatternView }}
-
- {{# patternDescExists }}
-
- {{{ patternDesc }}} {{# patternDescAdditions }} {{{ patternDescAdditions }}} {{/ patternDescAdditions }}
-
- {{/ patternDescExists }}
-
- {{# lineageExists }}
-
- The {{ patternName }} pattern contains the following patterns:
- {{# lineage }}
-
- {{ lineagePattern }}
- {{# lineageState }} {{/ lineageState }}
-
- {{# hasComma }}, {{/ hasComma }}
- {{/ lineage }}
-
-
- {{/ lineageExists }}
-
- {{# lineageRExists }}
-
- The {{ patternName }} pattern is included in the following patterns:
- {{# lineageR }}
-
- {{ lineagePattern }}
- {{# lineageState }} {{/ lineageState }}
-
- {{# hasComma }}, {{/ hasComma }}
- {{/ lineageR }}
-
- {{/ lineageRExists }}
-
- {{# annotationExists }}
-
-
Annotations
-
-
- {{# annotations }}
-
-
- {{ title }}
-
-
- {{{ comment }}}
-
-
-
- {{/ annotations }}
-
-
-
-
- {{/ annotationExists }}
-
-
-{{/ descBlockExists }}
+{{#if descBlockExists }}
+
+
+ {{#if isPatternView }}
+
+
+
+ {{/if }} {{#if patternDescExists }}
+
+ {{{ patternDesc }}} {{#if patternDescAdditions }} {{{ patternDescAdditions
+ }}} {{/if }}
+
+
+ {{/if }} {{#if lineageExists }}
+
+ The
+ {{ patternName }}
+ pattern contains the following patterns: {{#each lineage }}
+
+ {{ lineagePattern }} {{#if lineageState }}
+ {{/if }}
+
+
+ {{#if hasComma }}, {{/if }} {{/each }}
+
+
+ {{/if }} {{#if lineageRExists }}
+
+ The
+ {{ patternName }}
+ pattern is included in the following patterns: {{#each lineageR }}
+
+ {{ lineagePattern }} {{#if lineageState }}
+ {{/if }}
+
+
+ {{#if hasComma }}, {{/if }} {{/each }}
+
+
+ {{/if }} {{#if annotationExists }}
+
+
Annotations
+
+ {{#each annotations }}
+
+ {{ title }}
+
+ {{{ comment }}}
+
+
+
+ {{/each }}
+
+
+
+
+ {{/if }}
+
+
+{{/if }}
-
-
-
-
-
-
- {{# panels }}
-
- Copy
-
- {{{ content }}}
-
- {{/ panels }}
-
-
-
-
-
-
+
+
+
+
+
+ {{#each panels }}
+
+
+ Copy
+
+ copy icon
+
+
+
+
+ clipboard
+
+
+
+
+ {{{ content }}}
+
+
+ {{/each }}
+
+
+
+
+
+
diff --git a/packages/uikit-workshop/src/html/partials/controls.html b/packages/uikit-workshop/src/html/partials/controls.html
deleted file mode 100644
index 533752058..000000000
--- a/packages/uikit-workshop/src/html/partials/controls.html
+++ /dev/null
@@ -1,87 +0,0 @@
-
-
-
-
- {{^ ishControlsHide.s }}
-
- S
-
- {{/ ishControlsHide.s }}
-
- {{^ ishControlsHide.m }}
-
- M
-
- {{/ ishControlsHide.m }}
-
- {{^ ishControlsHide.l }}
-
- L
-
- {{/ ishControlsHide.l }}
-
- {{^ ishControlsHide.full }}
-
- Full
-
- {{/ ishControlsHide.full }}
-
- {{^ ishControlsHide.random }}
-
- Rand
-
- {{/ ishControlsHide.random }}
-
- {{^ ishControlsHide.disco }}
-
- Disco
-
- {{/ ishControlsHide.disco }}
-
- {{^ ishControlsHide.hay }}
-
- Hay!
-
- {{/ ishControlsHide.hay }}
-
-
-{{^ ishControlsHide.tools-all }}
-
-{{/ ishControlsHide.tools-all }}
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/html/partials/header.html b/packages/uikit-workshop/src/html/partials/header.html
deleted file mode 100644
index da990cf32..000000000
--- a/packages/uikit-workshop/src/html/partials/header.html
+++ /dev/null
@@ -1,25 +0,0 @@
-
diff --git a/packages/uikit-workshop/src/html/partials/iframe-loader.html b/packages/uikit-workshop/src/html/partials/iframe-loader.html
deleted file mode 100644
index 40086f8aa..000000000
--- a/packages/uikit-workshop/src/html/partials/iframe-loader.html
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
Loading Pattern Lab
-
-
-
diff --git a/packages/uikit-workshop/src/html/partials/iframe.html b/packages/uikit-workshop/src/html/partials/iframe.html
deleted file mode 100644
index 0ae6a5752..000000000
--- a/packages/uikit-workshop/src/html/partials/iframe.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/html/partials/modal.html b/packages/uikit-workshop/src/html/partials/modal.html
deleted file mode 100644
index 724e6c667..000000000
--- a/packages/uikit-workshop/src/html/partials/modal.html
+++ /dev/null
@@ -1,20 +0,0 @@
-
-
diff --git a/packages/uikit-workshop/src/html/partials/pattern-nav.html b/packages/uikit-workshop/src/html/partials/pattern-nav.html
deleted file mode 100644
index a3b17fae2..000000000
--- a/packages/uikit-workshop/src/html/partials/pattern-nav.html
+++ /dev/null
@@ -1,59 +0,0 @@
-{{# patternTypes }}
-
-
- {{ patternTypeUC }}
-
-
-
- {{# patternTypeItems }}
-
-
- {{ patternSubtypeUC }}
-
-
-
- {{# patternSubtypeItems }}
-
-
-
- {{ patternName }}
-
- {{# patternState }}
-
- {{/ patternState }}
-
-
-
-
- {{/ patternSubtypeItems }}
-
-
-
-
- {{/ patternTypeItems }}
- {{# patternItems }}
-
-
-
- {{ patternName }}
-
- {{# patternState }}
-
- {{/ patternState }}
-
-
-
-
- {{/ patternItems }}
-
-
-
-
-{{/ patternTypes }}
-
-
-
- All
-
-
-
diff --git a/packages/uikit-workshop/src/icons/arrow-down.svg b/packages/uikit-workshop/src/icons/arrow-down.svg
new file mode 100644
index 000000000..510ce6bdc
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/arrow-down.svg
@@ -0,0 +1,5 @@
+
+
+arrow_drop_down
+
+
diff --git a/packages/uikit-workshop/src/icons/close.svg b/packages/uikit-workshop/src/icons/close.svg
new file mode 100644
index 000000000..efa3715ff
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/close.svg
@@ -0,0 +1,5 @@
+
+
+close
+
+
diff --git a/packages/uikit-workshop/src/icons/code-collapse.svg b/packages/uikit-workshop/src/icons/code-collapse.svg
new file mode 100644
index 000000000..10e66e73a
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/code-collapse.svg
@@ -0,0 +1,6 @@
+
+hide-code
+
+
+
+
diff --git a/packages/uikit-workshop/src/icons/code-expand.svg b/packages/uikit-workshop/src/icons/code-expand.svg
new file mode 100644
index 000000000..feb7446ce
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/code-expand.svg
@@ -0,0 +1,5 @@
+
+show-code
+
+
+
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/icons/copy.svg b/packages/uikit-workshop/src/icons/copy.svg
new file mode 100644
index 000000000..5354f8d85
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/copy.svg
@@ -0,0 +1,4 @@
+
+copy
+
+
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/icons/desktop.svg b/packages/uikit-workshop/src/icons/desktop.svg
new file mode 100644
index 000000000..48c9f6f11
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/desktop.svg
@@ -0,0 +1,5 @@
+
+
+desktop_mac
+
+
diff --git a/packages/uikit-workshop/src/icons/disco-ball.svg b/packages/uikit-workshop/src/icons/disco-ball.svg
new file mode 100644
index 000000000..6ec7b3bfb
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/disco-ball.svg
@@ -0,0 +1,15 @@
+
+
+
+ Artboard
+ Created with Sketch.
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/uikit-workshop/src/icons/hay.svg b/packages/uikit-workshop/src/icons/hay.svg
new file mode 100644
index 000000000..466695e0d
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/hay.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/uikit-workshop/src/icons/help.svg b/packages/uikit-workshop/src/icons/help.svg
new file mode 100644
index 000000000..016e9271a
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/help.svg
@@ -0,0 +1,5 @@
+
+
+help_outline
+
+
diff --git a/packages/uikit-workshop/src/icons/hide.svg b/packages/uikit-workshop/src/icons/hide.svg
new file mode 100644
index 000000000..f9513c403
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/hide.svg
@@ -0,0 +1,5 @@
+
+
+view-hide
+
+
diff --git a/packages/uikit-workshop/src/icons/laptop.svg b/packages/uikit-workshop/src/icons/laptop.svg
new file mode 100644
index 000000000..23da41cca
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/laptop.svg
@@ -0,0 +1,5 @@
+
+
+laptop_mac
+
+
diff --git a/packages/uikit-workshop/src/icons/layout-h.svg b/packages/uikit-workshop/src/icons/layout-h.svg
new file mode 100644
index 000000000..4878499d2
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/layout-h.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/uikit-workshop/src/icons/layout-v.svg b/packages/uikit-workshop/src/icons/layout-v.svg
new file mode 100644
index 000000000..9110dfa84
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/layout-v.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/uikit-workshop/src/icons/menu.svg b/packages/uikit-workshop/src/icons/menu.svg
new file mode 100644
index 000000000..98be1018e
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/menu.svg
@@ -0,0 +1,5 @@
+
+
+menu
+
+
diff --git a/packages/uikit-workshop/src/icons/new-tab.svg b/packages/uikit-workshop/src/icons/new-tab.svg
new file mode 100644
index 000000000..9c0db76d1
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/new-tab.svg
@@ -0,0 +1,5 @@
+
+
+open_in_new
+
+
diff --git a/packages/uikit-workshop/src/icons/phone.svg b/packages/uikit-workshop/src/icons/phone.svg
new file mode 100644
index 000000000..82b40fe84
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/phone.svg
@@ -0,0 +1,5 @@
+
+
+phone_iphone
+
+
diff --git a/packages/uikit-workshop/src/icons/random.svg b/packages/uikit-workshop/src/icons/random.svg
new file mode 100644
index 000000000..c42db187a
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/random.svg
@@ -0,0 +1,11 @@
+
+
+
+ casino
+ Created with Sketch.
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/icons/settings.svg b/packages/uikit-workshop/src/icons/settings.svg
new file mode 100644
index 000000000..49197cb34
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/settings.svg
@@ -0,0 +1,5 @@
+
+
+settings
+
+
diff --git a/packages/uikit-workshop/src/icons/show.svg b/packages/uikit-workshop/src/icons/show.svg
new file mode 100644
index 000000000..3377c33bf
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/show.svg
@@ -0,0 +1,5 @@
+
+
+view-show
+
+
diff --git a/packages/uikit-workshop/src/icons/tablet.svg b/packages/uikit-workshop/src/icons/tablet.svg
new file mode 100644
index 000000000..d85d35301
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/tablet.svg
@@ -0,0 +1,5 @@
+
+
+tablet_mac
+
+
diff --git a/packages/uikit-workshop/src/icons/theme-dark.svg b/packages/uikit-workshop/src/icons/theme-dark.svg
new file mode 100644
index 000000000..9589bfd5d
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/theme-dark.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/uikit-workshop/src/icons/theme-light.svg b/packages/uikit-workshop/src/icons/theme-light.svg
new file mode 100644
index 000000000..e8f54f0a9
--- /dev/null
+++ b/packages/uikit-workshop/src/icons/theme-light.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/packages/uikit-workshop/src/images/pattern-lab-logo--on-dark.svg b/packages/uikit-workshop/src/images/pattern-lab-logo--on-dark.svg
new file mode 100644
index 000000000..59cc46b0a
--- /dev/null
+++ b/packages/uikit-workshop/src/images/pattern-lab-logo--on-dark.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/images/pattern-lab-logo--on-light.svg b/packages/uikit-workshop/src/images/pattern-lab-logo--on-light.svg
new file mode 100644
index 000000000..549f60c02
--- /dev/null
+++ b/packages/uikit-workshop/src/images/pattern-lab-logo--on-light.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/sass/pattern-lab--iframe-loader.scss b/packages/uikit-workshop/src/sass/pattern-lab--iframe-loader.scss
index b23c481bc..7f72c956b 100644
--- a/packages/uikit-workshop/src/sass/pattern-lab--iframe-loader.scss
+++ b/packages/uikit-workshop/src/sass/pattern-lab--iframe-loader.scss
@@ -1,17 +1,6 @@
@import 'scss/01-abstracts/variables';
@import 'scss/01-abstracts/mixins';
-@keyframes animateIn {
- from {
- transform: translate3d(-50%, -100%, 0px);
- opacity: 0;
- }
- to {
- opacity: 1;
- transform: translate3d(-50%, calc(3rem - 50%), 0px);
- }
-}
-
@keyframes rotate {
0% {
transform: rotate(0deg);
@@ -21,21 +10,34 @@
}
}
+.pl-c-loader-wrapper {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+
+.pl-c-loader-wrapper:not(:last-child) {
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.2s ease, transform 0.2s ease;
+}
+
.pl-c-loader {
z-index: 1000;
position: absolute;
- top: 0;
+ top: 50%;
left: 50%;
margin: auto;
max-width: $pl-space * 25;
width: calc(90vw - #{$pl-doublespace});
border-radius: $pl-border-radius;
background: rgba($pl-color-black, 0.9);
- transform: translate3d(-50%, -100%, 0px);
+ transform: translate3d(-50%, -50%, 0px);
transition: opacity 0.3s ease, transform 0.3s ease;
pointer-events: none;
- opacity: 0;
- animation: animateIn ease 0.3s forwards;
+ opacity: 1;
}
.pl-c-loader__content {
diff --git a/packages/uikit-workshop/src/sass/pattern-lab.scss b/packages/uikit-workshop/src/sass/pattern-lab.scss
index d38ba1515..ebd3d02a3 100755
--- a/packages/uikit-workshop/src/sass/pattern-lab.scss
+++ b/packages/uikit-workshop/src/sass/pattern-lab.scss
@@ -43,39 +43,84 @@
/*------------------------------------*\
#COMPONENTS
\*------------------------------------*/
-
-/**
- * Pattern Lab Header
- */
+@import '../scripts/components/pl-nav/index.scss';
@import '../scripts/components/pl-search/pl-search.scss';
-@import '../scripts/components/pl-layout/pl-layout.scss';
-@import 'scss/04-components/header';
-@import 'scss/04-components/logo';
-@import 'scss/04-components/navigation';
-@import 'scss/04-components/ish-sizing';
-@import 'scss/04-components/controls';
-@import 'scss/04-components/tools';
-
-/**
- * Viewport
- */
-@import 'scss/04-components/viewport';
-
-/**
- * Pattern Styles
- */
-@import 'scss/04-components/pattern';
+@import 'scss/04-components/annotations';
+@import 'scss/04-components/annotations-inside-modal';
+@import 'scss/04-components/breadcrumbs';
@import 'scss/04-components/pattern-category';
@import 'scss/04-components/pattern-info';
-@import 'scss/04-components/pattern-states';
@import 'scss/04-components/pattern-lineage';
-@import 'scss/04-components/breadcrumbs';
+@import 'scss/04-components/pattern-states';
+@import 'scss/04-components/pattern';
@import 'scss/04-components/tabs';
-@import 'scss/04-components/tools';
-@import 'scss/04-components/annotations';
-@import 'scss/04-components/modal';
@import 'scss/04-components/text-passage';
+.pl-c-code-copy-btn {
+ display: inline-block;
+ position: absolute;
+ top: 0.4rem;
+ right: 0.5rem;
+ padding: 0.2rem 0.4rem;
+ background-color: $pl-color-gray-07;
+ color: $pl-color-gray-87;
+ border: 1px solid $pl-color-gray-13;
+ border-radius: $pl-border-radius-med;
+ font-family: $pl-font;
+ font-size: $pl-font-size-norm;
+ text-transform: lowercase;
+ line-height: 1;
+ cursor: pointer;
+ z-index: 2;
+ transition: background-color $pl-animate-quick ease-out;
+
+ &:hover,
+ &:focus {
+ background-color: $pl-color-gray-20;
+ }
+}
+
+.pl-c-code-copy-btn__icon {
+ height: 1em;
+ width: 1em;
+}
+
+.pl-c-code-copy-btn__icon--paste {
+ display: none;
+
+ .is-copied & {
+ display: inline-block;
+ }
+}
+
+.pl-c-code-copy-btn__icon--copy {
+ display: inline-block;
+
+ .is-copied & {
+ display: none;
+ }
+}
+
+.pl-c-body {
+ overflow: hidden;
+}
+
+.pl-c-main {
+ // Preventing cropping pattern parts #1174 - absolutely positioned pattern parts at the vertical end of the "page" would get cropped elsewhere
+ min-height: 100vh;
+
+ max-width: 100vw;
+ padding-left: 0.5rem;
+ padding-right: 0.5rem;
+
+ // Clearing all remaining floats
+ &::after {
+ clear: both;
+ content: '';
+ display: table;
+ }
+}
+
/*------------------------------------*\
#THEMES
\*------------------------------------*/
diff --git a/packages/uikit-workshop/src/sass/scss/01-abstracts/_mixins.scss b/packages/uikit-workshop/src/sass/scss/01-abstracts/_mixins.scss
index c06101c06..14dfc5a6d 100644
--- a/packages/uikit-workshop/src/sass/scss/01-abstracts/_mixins.scss
+++ b/packages/uikit-workshop/src/sass/scss/01-abstracts/_mixins.scss
@@ -27,8 +27,8 @@
* Header Link Style
*/
@mixin linkStyle() {
- background-color: $pl-color-black;
- color: $pl-color-gray-50;
+ @include noSelect;
+ color: inherit;
text-decoration: none;
line-height: 1;
padding: 0.7rem 0.5rem;
@@ -37,38 +37,15 @@
transition: background-color $pl-animate-quick ease-out,
color $pl-animate-quick ease-out;
cursor: pointer;
- outline-offset: -3px;
- outline-width: 2px;
- &:hover {
- color: $pl-color-white;
- background-color: $pl-color-gray-87;
- }
-
- &.pl-is-active,
- &:active {
- color: $pl-color-white;
- background-color: $pl-color-gray-87;
- outline: 1px dotted $pl-color-gray-50;
- outline-offset: -1px;
+ &:hover,
+ &.pl-is-active:hover {
+ background-color: rgba(0, 0, 0, 0.1);
}
/**
* Header link styles inside light theme
*/
- .pl-c-body--theme-light & {
- background-color: $pl-color-white;
- color: $pl-color-gray-70;
-
- &:hover {
- background-color: $pl-color-gray-07;
- }
-
- &:active,
- &:focus {
- background-color: $pl-color-gray-13;
- }
- }
/**
* Header link styles inside cozy theme
@@ -93,16 +70,16 @@
@mixin accordionPanel() {
overflow: hidden;
max-height: 0;
- transition: max-height $pl-animate-quick ease-out;
+ transition: all $pl-animate-quick ease-out;
/**
* Active styles for when the accordion panel is open
* 1. WIP -- part of broader UI refactor
*/
&.pl-is-active {
- max-height: calc(100vh - #{$offset-top} - 1rem);
+ max-height: calc(95vh - #{$offset-top} - 1rem);
max-height: calc(
- var(--pl-viewport-height, calc(100vh - #{$offset-top})) - 1rem
+ var(--pl-viewport-height, calc(95vh - #{$offset-top})) - 1rem
); /* [1] */
overflow: auto;
-webkit-overflow-scrolling: touch;
@@ -115,3 +92,56 @@
-ms-user-select: none; /* IE 10+ */
user-select: none; /* Likely future */
}
+
+@mixin buttonStyles() {
+ color: inherit;
+ text-decoration: none;
+ background: transparent;
+ border: 0;
+ appearance: none;
+ display: flex;
+ align-items: center;
+ width: 100%;
+ margin: 0;
+ flex-direction: row-reverse;
+ justify-content: flex-end;
+ cursor: pointer;
+ position: relative;
+ min-width: 30px;
+
+ &::after {
+ content: '';
+ display: block;
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+ pointer-events: none;
+ opacity: 0;
+ transition: opacity 0.1s ease;
+ background-color: currentColor;
+ }
+
+ // &:focus,
+ &:hover {
+ &::after {
+ opacity: 0.1;
+ }
+ }
+
+ &:active:hover {
+ &::after {
+ opacity: 0.2;
+ }
+ }
+
+ &:focus {
+ outline: 1px dotted;
+ outline-offset: -1px;
+
+ &::after {
+ opacity: 0.1;
+ }
+ }
+}
diff --git a/packages/uikit-workshop/src/sass/scss/01-abstracts/_variables.scss b/packages/uikit-workshop/src/sass/scss/01-abstracts/_variables.scss
index 364b3aab4..726c96110 100644
--- a/packages/uikit-workshop/src/sass/scss/01-abstracts/_variables.scss
+++ b/packages/uikit-workshop/src/sass/scss/01-abstracts/_variables.scss
@@ -14,6 +14,7 @@ $pl-color-gray-07: #eee;
$pl-color-gray-13: #ddd;
$pl-color-gray-20: #ccc;
$pl-color-gray-50: #808080;
+$pl-color-gray-55: #737373;
$pl-color-gray-70: #4d4c4c;
$pl-color-gray-87: #222;
$pl-color-black: #000;
@@ -23,13 +24,14 @@ $pl-color-trans-white-25: rgba(255, 255, 255, 0.25);
$pl-color-state-info: #02a4d5;
$pl-color-state-complete: #03790f;
$pl-color-state-inreview: #c7a118;
+$pl-color-state-inprogress: #b00b02;
$pl-color-state-deprecated: #b00b02;
// Font Family
-$pl-font: 'HelveticaNeue', 'Helvetica', 'Arial', sans-serif;
+$pl-font: 'Open Sans', 'HelveticaNeue', 'Helvetica', 'Arial', sans-serif !default;
// Font sizes
-$pl-font-size-sm: 0.7rem;
+$pl-font-size-sm: 0.9rem;
$pl-font-size-sm-2: 0.85rem;
$pl-font-size-norm: 1rem;
$pl-font-size-large: 1.2rem;
@@ -38,7 +40,7 @@ $pl-font-size-large: 1.2rem;
$pl-space: 1rem;
$pl-doublespace: $pl-space * 2;
$pl-pad: 1rem;
-$pl-pad-half: $pl-pad/2;
+$pl-pad-half: $pl-pad * 0.5;
$offset-top: 2rem;
// Breakpoints
@@ -54,5 +56,4 @@ $pl-animate-normal: 0.3s;
$pl-border-radius: 3px;
$pl-border-radius-med: 6px;
-
-$pl-sidebar-width: 14rem; //Define sidebar width for calculating dimensions
\ No newline at end of file
+$pl-sidebar-width: 16rem; //Define sidebar width for calculating dimensions
diff --git a/packages/uikit-workshop/src/sass/scss/02-base/_body.scss b/packages/uikit-workshop/src/sass/scss/02-base/_body.scss
index 90bc557f0..c39879cd6 100644
--- a/packages/uikit-workshop/src/sass/scss/02-base/_body.scss
+++ b/packages/uikit-workshop/src/sass/scss/02-base/_body.scss
@@ -9,11 +9,33 @@
*/
.pl-c-html {
min-height: 100%;
+ display: flex;
+ height: 100%; // fix for IE 11
}
.pl-c-body {
margin: 0;
padding: 0;
+ width: 100%;
-webkit-text-size-adjust: 100%;
display: flex; // Required for IE 11 to display overall PL layout correctly
}
+
+.pl-c-body--theme-dark,
+:root {
+ --theme-bg: #161b3c;
+ --theme-primary: #464a6d;
+ --theme-secondary: #161f50;
+ --theme-text: white;
+ --theme-text-rgb: 255, 255, 255;
+ --theme-border: rgba(255, 255, 255, 0.2);
+}
+
+.pl-c-body--theme-light {
+ --theme-bg: white;
+ --theme-secondary: white;
+ --theme-text: #262829;
+ --theme-text-rgb: 38, 40, 41;
+ --theme-primary: white;
+ --theme-border: #ddd;
+}
diff --git a/packages/uikit-workshop/src/sass/scss/02-base/_reset.scss b/packages/uikit-workshop/src/sass/scss/02-base/_reset.scss
index 735a18995..3c9ffa270 100644
--- a/packages/uikit-workshop/src/sass/scss/02-base/_reset.scss
+++ b/packages/uikit-workshop/src/sass/scss/02-base/_reset.scss
@@ -16,7 +16,7 @@
box-sizing: border-box;
}
-button {
+button[class|='pl-c'] {
font-size: inherit;
background-color: transparent;
}
diff --git a/packages/uikit-workshop/src/sass/scss/03-vendor/_prism.scss b/packages/uikit-workshop/src/sass/scss/03-vendor/_prism.scss
index 6ab0ba455..ea440b16b 100644
--- a/packages/uikit-workshop/src/sass/scss/03-vendor/_prism.scss
+++ b/packages/uikit-workshop/src/sass/scss/03-vendor/_prism.scss
@@ -1,184 +1,211 @@
-/* http://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+handlebars+php+php-extras+twig&plugins=line-numbers+autolinker */
+/* https://prismjs.com/download.html?themes=prism&languages=markup+css+clike+javascript+handlebars+php+php-extras+twig&plugins=line-numbers+autolinker */
/**
* prism.js default theme for JavaScript, CSS and HTML
- * Based on dabblet (http://dabblet.com)
+ * Based on dabblet (https://dabblet.com)
* @author Lea Verou
*/
+.pl-c-tabs__panel {
+ pre[class*='language-'] {
+ background-image: linear-gradient(
+ to right,
+ $pl-color-white,
+ rgba($pl-color-white, 0)
+ ),
+ linear-gradient(to left, $pl-color-white, rgba($pl-color-white, 0)),
+ linear-gradient(to right, #eaf0f6, rgba($pl-color-gray-07, 0)),
+ linear-gradient(to left, #eaf0f6, rgba($pl-color-gray-07, 0)),
+ linear-gradient(to bottom, $pl-color-white, rgba($pl-color-white, 0)),
+ linear-gradient(to top, $pl-color-white, rgba($pl-color-white, 0)),
+ linear-gradient(to bottom, #eaf0f6, rgba($pl-color-gray-07, 0)),
+ linear-gradient(to top, #eaf0f6, rgba($pl-color-gray-07, 0));
+ background-color: $pl-color-white;
+ background-attachment: local, local, scroll, scroll, local, local, scroll,
+ scroll;
+ background-position: 0 0, 100% 0, 0 0, 100% 0, 0 0, 0 100%, 0 0, 0 100%;
+ background-size: 4em 100%, 4em 100%, 1em 100%, 1em 100%, 100% 4em, 100% 4em,
+ 100% 1em, 100% 1em;
+ background-repeat: no-repeat;
+ -ms-overflow-style: -ms-autohiding-scrollbar;
+ -webkit-overflow-scrolling: touch;
+ overflow: auto;
+ max-height: 100%;
+ }
-code[class*='language-'],
-pre[class*='language-'] {
- color: black;
- text-shadow: 0 1px white;
- font-family: Consolas, Monaco, 'Andale Mono', monospace;
- direction: ltr;
- text-align: left;
- white-space: pre;
- word-spacing: normal;
- word-break: normal;
- line-height: 1.5;
- word-wrap: normal; // fixes issue in Safari where code blocks can't scroll due to the code breaking into multiple lines unexpectedly
-
- -moz-tab-size: 4;
- -o-tab-size: 4;
- tab-size: 4;
-
- -webkit-hyphens: none;
- -moz-hyphens: none;
- -ms-hyphens: none;
- hyphens: none;
-}
-
-pre[class*='language-']::-moz-selection,
-pre[class*='language-'] ::-moz-selection,
-code[class*='language-']::-moz-selection,
-code[class*='language-'] ::-moz-selection {
- text-shadow: none;
- background-color: #b3d4fc;
-}
-
-pre[class*='language-']::selection,
-pre[class*='language-'] ::selection,
-code[class*='language-']::selection,
-code[class*='language-'] ::selection {
- text-shadow: none;
- background-color: #b3d4fc;
-}
-
-@media print {
code[class*='language-'],
pre[class*='language-'] {
+ color: black;
+ text-shadow: 0 1px white;
+ font-family: Consolas, Monaco, 'Andale Mono', monospace;
+ direction: ltr;
+ text-align: left;
+ white-space: pre;
+ word-spacing: normal;
+ word-break: normal;
+ line-height: 1.5;
+ word-wrap: normal; // fixes issue in Safari where code blocks can't scroll due to the code breaking into multiple lines unexpectedly
+
+ -moz-tab-size: 4;
+ -o-tab-size: 4;
+ tab-size: 4;
+
+ -webkit-hyphens: none;
+ -moz-hyphens: none;
+ -ms-hyphens: none;
+ hyphens: none;
+ }
+
+ pre[class*='language-']::-moz-selection,
+ pre[class*='language-'] ::-moz-selection,
+ code[class*='language-']::-moz-selection,
+ code[class*='language-'] ::-moz-selection {
text-shadow: none;
+ background-color: #b3d4fc;
}
-}
-/* Code blocks */
-pre[class*='language-'] {
- padding: 1em;
- margin: 0.5em 0;
- overflow: auto;
-}
+ pre[class*='language-']::selection,
+ pre[class*='language-'] ::selection,
+ code[class*='language-']::selection,
+ code[class*='language-'] ::selection {
+ text-shadow: none;
+ background-color: #b3d4fc;
+ }
-:not(pre) > code[class*='language-'],
-pre[class*='language-'] {
- background-color: #f5f2f0;
-}
+ @media print {
+ code[class*='language-'],
+ pre[class*='language-'] {
+ text-shadow: none;
+ }
+ }
-/* Inline code */
-:not(pre) > code[class*='language-'] {
- padding: 0.1em;
- border-radius: 0.3em;
-}
+ /* Code blocks */
+ pre[class*='language-'] {
+ padding: 1em;
+ margin: 0.5em 0;
+ overflow: scroll;
+ }
-.token.comment,
-.token.prolog,
-.token.doctype,
-.token.cdata {
- color: slategray;
-}
+ :not(pre) > code[class*='language-'],
+ pre[class*='language-'] {
+ background-color: #f5f2f0;
+ }
-.token.punctuation {
- color: #999;
-}
+ /* Inline code */
+ :not(pre) > code[class*='language-'] {
+ padding: 0.1em;
+ border-radius: 0.3em;
+ }
-.namespace {
- opacity: 0.7;
-}
+ .token.comment,
+ .token.prolog,
+ .token.doctype,
+ .token.cdata {
+ color: slategray;
+ }
-.token.property,
-.token.tag,
-.token.boolean,
-.token.number,
-.token.constant,
-.token.symbol,
-.token.deleted {
- color: #905;
-}
+ .token.punctuation {
+ color: #999;
+ }
-.token.selector,
-.token.attr-name,
-.token.string,
-.token.char,
-.token.builtin,
-.token.inserted {
- color: #690;
-}
+ .namespace {
+ opacity: 0.7;
+ }
-.token.operator,
-.token.entity,
-.token.url,
-.language-css .token.string,
-.style .token.string {
- color: #a67f59;
- background-color: hsla(0, 0%, 100%, 0.5);
-}
+ .token.property,
+ .token.tag,
+ .token.boolean,
+ .token.number,
+ .token.constant,
+ .token.symbol,
+ .token.deleted {
+ color: #905;
+ }
-.token.atrule,
-.token.attr-value,
-.token.keyword {
- color: #07a;
-}
+ .token.selector,
+ .token.attr-name,
+ .token.string,
+ .token.char,
+ .token.builtin,
+ .token.inserted {
+ color: #690;
+ }
-.token.function {
- color: #dd4a68;
-}
+ .token.operator,
+ .token.entity,
+ .token.url,
+ .language-css .token.string,
+ .style .token.string {
+ color: #a67f59;
+ background-color: hsla(0, 0%, 100%, 0.5);
+ }
-.token.regex,
-.token.important,
-.token.variable {
- color: #e90;
-}
+ .token.atrule,
+ .token.attr-value,
+ .token.keyword {
+ color: #07a;
+ }
-.token.important,
-.token.bold {
- font-weight: bold;
-}
-.token.italic {
- font-style: italic;
-}
+ .token.function {
+ color: #dd4a68;
+ }
-.token.entity {
- cursor: help;
-}
+ .token.regex,
+ .token.important,
+ .token.variable {
+ color: #e90;
+ }
-pre.line-numbers {
- position: relative;
- padding-left: 3.8em;
- counter-reset: linenumber;
-}
+ .token.important,
+ .token.bold {
+ font-weight: bold;
+ }
+ .token.italic {
+ font-style: italic;
+ }
-pre.line-numbers > code {
- position: relative;
-}
+ .token.entity {
+ cursor: help;
+ }
-.line-numbers .line-numbers-rows {
- position: absolute;
- pointer-events: none;
- top: 0;
- font-size: 100%;
- left: -3.8em;
- width: 3em; /* works for line-numbers below 1000 lines */
- letter-spacing: -1px;
- border-right: 1px solid #999;
-
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
+ pre.line-numbers {
+ position: relative;
+ padding-left: 3.8em;
+ counter-reset: linenumber;
+ }
-.line-numbers-rows > span {
- pointer-events: none;
- display: block;
- counter-increment: linenumber;
-}
+ pre.line-numbers > code {
+ position: relative;
+ }
-.line-numbers-rows > span:before {
- content: counter(linenumber);
- color: #999;
- display: block;
- padding-right: 0.8em;
- text-align: right;
-}
-.token a {
- color: inherit;
+ .line-numbers .line-numbers-rows {
+ position: absolute;
+ pointer-events: none;
+ top: 0;
+ font-size: 100%;
+ left: -3.8em;
+ width: 3em; /* works for line-numbers below 1000 lines */
+ letter-spacing: -1px;
+ border-right: 1px solid #999;
+
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ }
+
+ .line-numbers-rows > span {
+ pointer-events: none;
+ display: block;
+ counter-increment: linenumber;
+ }
+
+ .line-numbers-rows > span::before {
+ content: counter(linenumber);
+ color: #999;
+ display: block;
+ padding-right: 0.8em;
+ text-align: right;
+ }
+ .token a {
+ color: inherit;
+ }
}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_annotations-inside-modal.scss b/packages/uikit-workshop/src/sass/scss/04-components/_annotations-inside-modal.scss
new file mode 100644
index 000000000..f5f319c28
--- /dev/null
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_annotations-inside-modal.scss
@@ -0,0 +1,75 @@
+@charset "UTF-8";
+
+/*------------------------------------*\
+ #ANNOTATIONS INSIDE MODAL
+\*------------------------------------*/
+
+/**
+ * Annotations area
+ * 1) Appears inside of modal
+ */
+.pl-c-annotations {
+ margin: 1rem 0;
+}
+
+/**
+ * Annotations Title
+ * Says the word "Annotations"
+ */
+.pl-c-annotations__title {
+ font-size: 1.2rem !important;
+ margin: 0 0 0.5rem;
+}
+
+/**
+ * Annotations list
+ * 1) Ordered list of annotations
+ * 2) Presented with parent selector to force styles
+ * over pl-c-text-passage
+ */
+.pl-c-annotations .pl-c-annotations__list {
+ counter-reset: the-count;
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+/**
+ * Annotations list item
+ * 1) Displays each item as a number
+ */
+.pl-c-annotations__item {
+ position: relative;
+ padding-left: 1.5rem;
+ margin-bottom: 1rem;
+ border-radius: $pl-border-radius-med;
+ transition: background-color $pl-animate-quick ease;
+
+ &::before {
+ content: counter(the-count);
+ counter-increment: the-count;
+ font-size: 85%;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 14px;
+ height: 14px;
+ border-radius: 50%;
+ padding: 2px;
+ text-align: center;
+ background-color: $pl-color-gray-50;
+ color: $pl-color-white;
+ position: absolute;
+ top: 4px;
+ left: 0;
+ }
+
+ &.pl-is-active {
+ outline: 1px dotted $pl-color-gray-50;
+ outline-offset: -1px;
+ }
+}
+
+.pl-c-annotations .pl-c-annotations__item-title {
+ margin-bottom: 0;
+}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_annotations.scss b/packages/uikit-workshop/src/sass/scss/04-components/_annotations.scss
index 57c32f781..0939ab8d4 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_annotations.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_annotations.scss
@@ -36,12 +36,12 @@
/**
* Annotation tooltip
* 1) Appears inside the iframe over any element that has an
- * anootation attached to it.
- * 2) Annotation tip gets dynamically set to `display: none` via
- * JavaScript
+ * annotation attached to it.
*/
.pl-c-annotation-tip {
- display: flex; /* 2 */
+ &:not([hidden]) {
+ display: flex;
+ }
align-items: center;
justify-content: center;
width: 24px !important;
@@ -55,77 +55,3 @@
position: absolute;
z-index: 100;
}
-
-/*------------------------------------*\
- #ANNOTATIONS INSIDE MODAL
-\*------------------------------------*/
-
-/**
- * Annotations area
- * 1) Appears inside of modal
- */
-.pl-c-annotations {
- margin: 1rem 0;
-}
-
-/**
- * Annotations Title
- * Says the word "Annotations"
- */
-.pl-c-annotations__title {
- font-size: 1.2rem !important;
- margin: 0 0 0.5rem;
-}
-
-/**
- * Annotations list
- * 1) Ordered list of annotations
- * 2) Presented with parent selector to force styles
- * over pl-c-text-passage
- */
-.pl-c-annotations .pl-c-annotations__list {
- counter-reset: the-count;
- padding: 0;
- margin: 0;
- list-style: none;
-}
-
-/**
- * Annotations list item
- * 1) Displays each item as a number
- */
-.pl-c-annotations__item {
- position: relative;
- padding-left: 1.5rem;
- margin-bottom: 1rem;
- border-radius: $pl-border-radius-med;
- transition: background-color $pl-animate-quick ease;
-
- &:before {
- content: counter(the-count);
- counter-increment: the-count;
- font-size: 85%;
- display: flex;
- align-items: center;
- justify-content: center;
- width: 14px;
- height: 14px;
- border-radius: 50%;
- padding: 2px;
- text-align: center;
- background-color: $pl-color-gray-50;
- color: $pl-color-white;
- position: absolute;
- top: 4px;
- left: 0;
- }
-
- &.pl-is-active {
- outline: 1px dotted $pl-color-gray-50;
- outline-offset: -1px;
- }
-}
-
-.pl-c-annotations .pl-c-annotations__item-title {
- margin-bottom: 0;
-}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_breadcrumbs.scss b/packages/uikit-workshop/src/sass/scss/04-components/_breadcrumbs.scss
index ae1cb8f19..bf5cf134a 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_breadcrumbs.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_breadcrumbs.scss
@@ -12,7 +12,7 @@
margin-bottom: 0.5rem;
display: flex;
font-size: $pl-font-size-sm;
- color: $pl-color-gray-50;
+ color: inherit;
text-transform: capitalize;
}
@@ -20,7 +20,8 @@
* Breadcrumb Item
*/
.pl-c-breadcrumb__item {
- &:after {
+ color: inherit;
+ &::after {
content: '\25b6';
opacity: 0.4;
font-size: 6px;
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_controls.scss b/packages/uikit-workshop/src/sass/scss/04-components/_controls.scss
deleted file mode 100644
index 6a6a9e479..000000000
--- a/packages/uikit-workshop/src/sass/scss/04-components/_controls.scss
+++ /dev/null
@@ -1,29 +0,0 @@
-/*------------------------------------*\
- #CONTROLS
-\*------------------------------------*/
-
-/**
- * 1) Controls contains viewport resizer and tools dropdown
- * 2) Right-align inside of header
- */
-.pl-c-controls {
- margin-left: auto; /* 2 */
- display: flex;
- flex-wrap: nowrap;
-
- // IE 11 layout bug
- @media all and (min-width: $pl-bp-med) {
- .pl-c-body--theme-sidebar & {
- display: block;
- }
- }
-}
-
-/**
-* Control list
-*/
-.pl-c-controls__list {
- @include listReset();
- display: flex;
- flex-wrap: nowrap;
-}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_header.scss b/packages/uikit-workshop/src/sass/scss/04-components/_header.scss
deleted file mode 100644
index 2616b678f..000000000
--- a/packages/uikit-workshop/src/sass/scss/04-components/_header.scss
+++ /dev/null
@@ -1,43 +0,0 @@
-/*------------------------------------*\
- #HEADER
-\*------------------------------------*/
-
-/**
-* 1) Pattern Lab's header is fixed across the top of the viewport and
-* contains the primary pattern navigation, viewport resizing items,
-* and tools.
-* 2) Display nav and controls horizontally
-*/
-.pl-c-header {
- position: fixed;
- position: sticky;
- top: 0;
- left: 0;
- z-index: 4;
- display: flex; /* 2 */
- width: 100%;
- background-color: $pl-color-black;
- color: $pl-color-gray-50;
- font-family: $pl-font;
- font-size: $pl-font-size-sm;
- min-height: 30px; // magic number -- needed for initial skeleton screen styles used in the critical CSS
-
- @supports(padding: max(0px)) {
- padding-left: env(safe-area-inset-left);
- padding-right: env(safe-area-inset-right);
- }
-}
-
-/**
- * Nav toggle button
- * 1) Styles for the general nav toggle button, which
- * only appears on small screens
- */
-.pl-c-header__nav-toggle {
- @include linkStyle();
- border: 0;
-
- @media all and (min-width: $pl-bp-med) {
- display: none;
- }
-}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_navigation.scss b/packages/uikit-workshop/src/sass/scss/04-components/_navigation.scss
deleted file mode 100644
index ee71746b4..000000000
--- a/packages/uikit-workshop/src/sass/scss/04-components/_navigation.scss
+++ /dev/null
@@ -1,254 +0,0 @@
-/*------------------------------------*\
- #NAVIGATION
-\*------------------------------------*/
-
-/**
- * Navigation container
- * 1) Collapse height on small screens. Menu trigger button
- * activates nav
- */
-.pl-c-nav {
- @include accordionPanel;
- background-color: inherit; // allows the nav's children inherit from the parent header
- position: absolute;
- left: 0; // IE 11 layout broken
- top: 100%;
- width: 100%;
- display: flex;
- flex-direction: column;
- transition: max-height $pl-animate-quick ease-out;
-
- // if nav was opened on smaller screen and screen is resized, it'll be cut off otherwise
- @media all and (min-width: $pl-bp-med) {
- overflow: visible;
- max-height: none;
- }
-
- /**
- * Active navigaiton
- * 1) Slide
- * 2) Set the height to the vierport height minus the height
- * of the header
- */
- &.pl-is-active {
- box-shadow: 0 1px 1px $pl-color-black;
-
- .pl-c-body--theme-light & {
- box-shadow: 0 1px 1px darken($pl-color-gray-20, 15%);
- }
-
- .pl-c-body--theme-sidebar & {
- @media all and (min-width: $pl-bp-med) {
- box-shadow: none;
- }
- }
-
- // if nav was opened on smaller screen and screen is resized, it'll be cut off otherwise
- @media all and (min-width: $pl-bp-med) {
- overflow: visible;
- max-height: none;
- }
- }
-
- @media all and (min-width: $pl-bp-med) {
- flex-direction: row;
- position: relative;
- top: auto;
- width: auto;
- box-shadow: none;
- }
-}
-
-/**
- * Nav list
- * 1) appears as an
- * 2) display as a horizontal list on larger screens
- * 3) On small screens, move the nav list after the typeahead form field
- */
-.pl-c-nav__list {
- z-index: 1;
- margin: 0;
- padding: 0;
- list-style: none;
- flex-shrink: 0; // helps prevent top-level nav items from occasionally wrapping to multiple lines
- order: 2;
- background-color: inherit; // allows the nav's children inherit from the parent header
-
- @media all and (min-width: $pl-bp-med) {
- display: flex; /* 2 */
- order: 1;
-
- // workaround to Firefox-specific flexbox quirk
- .pl-c-body--theme-sidebar & {
- display: block;
- }
- }
-}
-
-/**
- * Nav list item
- */
-.pl-c-nav__item {
- background-color: inherit; // allows the nav's children inherit from the parent header
- transform: translateZ(0); // helps with more consistent rendering in Safari
- cursor: pointer;
- position: relative;
- display: flex;
- flex-direction: column;
- justify-content: center; // vertically align nav items
-
- .pl-c-body--theme-sidebar & {
- display: block;
- }
-}
-
-/**
- * Last sublist item
- */
-.pl-c-nav__sublist > .pl-c-nav__item:last-child {
- @media all and (min-width: $pl-bp-med) {
- overflow: hidden;
- border-bottom-left-radius: $pl-border-radius-med;
- border-bottom-right-radius: $pl-border-radius-med;
- }
-}
-
-/**
- * Nav link
- */
-.pl-c-nav__link {
- @include linkStyle;
- display: flex;
- align-items: center;
- margin: 0; // remove default button margin in Safari
-
- // makes link layout / size more consistent in the sidebar layout, especially when display: flex styles are removed for more consistent IE 11 rendering
- .pl-c-body--theme-sidebar & {
- width: 100%;
- }
-}
-
-/**
- * Nav sublink
- * 1) Visually differentiate sub-item links from
- * the other links. Creates better hierarchy.
- */
-.pl-c-nav__link--sublink {
- text-transform: none;
- padding-left: $pl-space / 2;
-}
-
-/**
- * Nav link
- */
-.pl-c-nav__link--dropdown {
- -webkit-appearance: none; // remove default button styling
- flex-grow: 1; // fill up extra space in parent nav item, if available
- /**
- * Dropdown caret after accordion handle
- */
- &:after {
- content: '\25bc';
- color: $pl-color-trans-white-25;
- display: inline-block;
- font-size: 7px;
- position: relative;
- top: 1px;
- right: -2px;
- transition: all $pl-animate-quick ease-out;
- }
-
- &:hover,
- &:focus {
- &:after {
- color: $pl-color-gray-50;
- }
- }
-
- /**
- * Active dropdown
- */
- &.pl-is-active {
- color: $pl-color-white;
- background-color: $pl-color-gray-87;
-
- /**
- * Caret rotation and positioning in active dropdown
- */
- &:after {
- color: $pl-color-gray-50;
- transform: rotate(180deg);
- }
- }
-}
-
-/**
- * Nav sublist
- * 1) On larger screens, display as dropdowns that
- * hang over the header
- */
-.pl-c-nav__sublist {
- background-color: inherit; // allows the nav's children inherit from the parent header
- @include listReset();
-
- @media all and (min-width: $pl-bp-med) {
- position: absolute;
- top: 100%; /* 1 */
- left: 0;
- min-width: 10rem;
- border-bottom-left-radius: $pl-border-radius-med;
- border-bottom-right-radius: $pl-border-radius-med;
- }
-}
-
-/**
- * Dropdown sublist
- */
-.pl-c-nav__sublist--dropdown,
-.pl-c-nav__subsublist--dropdown {
- @include listReset();
- @include accordionPanel();
- visibility: hidden;
-}
-
-/**
- * Dropdown sublist
- * 1) Set the height to the viewport height minus the height of the header
- */
-.pl-c-nav__sublist--dropdown.pl-is-active,
-.pl-c-nav__subsublist--dropdown.pl-is-active {
- margin-left: $pl-space / 2;
- visibility: visible;
- max-height: none;
-
- @media all and (min-width: $pl-bp-med) {
- height: auto;
- max-height: calc(100vh - #{$offset-top} - 1rem); /* 1 */
- }
-
- .pl-c-body--theme-sidebar & {
- max-height: none;
- }
-}
-
-.pl-c-nav__sublist--dropdown.pl-is-active {
- @media all and (min-width: $pl-bp-med) {
- margin-left: 0;
- border-width: 1px;
- border-style: solid;
- border-color: $pl-color-black;
-
- .pl-c-body--theme-light & {
- border-color: $pl-color-gray-20;
- }
- }
-}
-
-/**
- * Sub-navigation
- * 1) Third-level links are stylistically different
- * than first and second nav links.
- */
-.pl-c-nav__subsublist {
- @include listReset();
-}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss
index abe9d6142..fbca575bb 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-category.scss
@@ -10,11 +10,15 @@
*/
.pl-c-category {
margin-top: 6rem;
- font: $pl-font !important;
+ font-family: $pl-font !important;
&:first-of-type {
margin-top: 2rem;
}
+
+ & + & {
+ margin-top: 2rem;
+ }
}
/**
@@ -25,6 +29,10 @@
color: $pl-color-gray-87 !important;
margin: 0 0 0.2rem;
text-transform: capitalize;
+
+ &:hover {
+ color: $pl-color-gray-70 !important;
+ }
}
/**
@@ -32,6 +40,7 @@
*/
.pl-c-category__title-link {
transition: color $pl-animate-quick ease-out;
+ color: inherit;
}
/**
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-info.scss b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-info.scss
index 606ad8055..e0ca2aa26 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-info.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-info.scss
@@ -10,29 +10,39 @@
.pl-c-pattern-info {
flex-grow: 1; // fills space available when placed in the parent flex container
display: flex;
- flex-direction: row;
- flex-flow: row wrap;
- width: 100%;
- overflow: auto;
- -webkit-overflow-scrolling: touch;
+ flex-direction: column;
/**
* Pattern info inside the "view all" template
*/
.pl-c-pattern & {
- max-height: 20rem;
- min-height: 18rem;
+ max-height: 30rem;
overflow: scroll;
- @include hideScrollBar();
- display: flex;
+ display: block;
-webkit-overflow-scrolling: touch;
@media all and (min-width: $pl-bp-large) {
max-height: none;
height: 18rem;
+ display: flex;
+ flex-direction: row;
overflow: visible;
}
}
+
+ /**
+ * Pattern info inside modal
+ */
+ .pl-c-drawer & {
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+ flex-grow: 1;
+
+ @media all and (min-width: $pl-bp-large) {
+ position: static;
+ flex-direction: row;
+ }
+ }
}
/**
@@ -41,19 +51,56 @@
* Right side contains pattern code
*/
.pl-c-pattern-info__panel {
- flex-basis: 40%; // fills up 100% if only one panel exists. using 40% vs 50% due to quirky behavior in IE 11
- padding-top: 1rem;
- padding-right: 1rem;
- padding-bottom: 0;
- padding-left: 1rem;
- margin-bottom: 1rem;
- flex-grow: 1;
- max-width: 100%;
- min-width: 300px; // so panels stack automatically
- display: inline-flex;
+ padding: 0.5rem;
+ flex-shrink: 0; // prevent panel from collapsing in height (especially on smaller screens like iPhone)
+ display: flex;
flex-direction: column;
- overflow: auto;
- -webkit-overflow-scrolling: touch;
+
+ pl-drawer & {
+ padding: 1rem;
+ }
+
+ @media all and (min-width: $pl-bp-large) {
+ flex-basis: 50%;
+ flex-grow: 1;
+ padding: 1.5rem;
+ }
+}
+
+/**
+ * Pattern Info Panel
+ * 1) Left panel that contains pattern title, lineage, description, annotations
+ */
+.pl-c-pattern-info__panel--info {
+ @media all and (min-width: $pl-bp-large) {
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+ }
+
+ @media all and (min-width: $pl-bp-xl) {
+ min-width: 50%;
+ }
+}
+
+/**
+ * Pattern Code Panel
+ * 1) Right panel that displays the pattern's code (found in _tabs.scss)
+ * 2) Using a sibling selector because the pattern info isn't always present.
+ * The sibling selector allows the code panel to occupy the full width of
+ * the modal
+ * 1) Cap the height of the code panel in the modal
+ */
+.pl-c-pattern-info__panel--info + .pl-c-pattern-info__panel--code,
+.pl-c-pattern-info__panel--code:first-child {
+ flex-grow: 1;
+ flex-shrink: 0; // so the code panel doesn't get chopped off accidently
+ min-width: 50%;
+}
+
+.pl-c-pattern-info__panel--info + .pl-c-pattern-info__panel--code {
+ @media all and (max-width: $pl-bp-large) {
+ padding-top: 0;
+ }
}
/**
@@ -68,7 +115,7 @@
*/
.pl-c-pattern-info__title {
font-size: 1.4rem !important;
- font-weight: normal;
+ font-weight: bold;
margin-top: 0;
margin-bottom: 0;
color: inherit;
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-lineage.scss b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-lineage.scss
index a3e12f881..4587bc090 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-lineage.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-lineage.scss
@@ -6,19 +6,19 @@
* Pattern Lineage info
*/
.pl-c-lineage {
- font-size: $pl-font-size-sm-2;
+ font-size: $pl-font-size-norm;
line-height: 1.7;
margin-top: 0;
}
/**
- * Lineage link
+ * Lineage link
*/
.pl-c-lineage__link {
font-style: italic;
- color: $pl-color-gray-50;
+ color: inherit; // light vs dark text
text-decoration: underline;
- display: inline-flex;
+ display: inline;
align-items: center;
transition: opacity $pl-animate-quick ease;
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-states.scss b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-states.scss
index 42dcacb9e..d4b1f5f79 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_pattern-states.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_pattern-states.scss
@@ -7,17 +7,12 @@
* in the dropdown navigation.
*/
.pl-c-pattern-state {
- display: inline-block;
- width: 5px;
- height: 5px;
- margin-left: 10px;
- position: relative;
- top: 5px;
- left: 0;
+ width: 0.5em;
+ height: 0.5em;
+ margin-left: 0.5em;
border-radius: 50%;
+ display: inline-block;
background-color: $pl-color-state-info;
- line-height: 4px;
- text-indent: 10px;
&--complete {
background-color: $pl-color-state-complete;
@@ -27,6 +22,10 @@
background-color: $pl-color-state-inreview;
}
+ &--inprogress {
+ background-color: $pl-color-state-inprogress;
+ }
+
&--deprecated {
background-color: $pl-color-state-deprecated;
}
@@ -35,6 +34,6 @@
/**
* Complete state
*/
-.complete:before {
+.complete::before {
color: #03790f !important;
}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_pattern.scss b/packages/uikit-workshop/src/sass/scss/04-components/_pattern.scss
index 2fb724e2f..e478185f9 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_pattern.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_pattern.scss
@@ -24,7 +24,11 @@
padding: 0.5rem 0 0;
line-height: 1.3;
font-size: 90%;
- color: $pl-color-gray-50;
+ color: $pl-color-gray-55;
+
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
&:empty {
padding: 0;
@@ -50,9 +54,9 @@
*/
.pl-c-pattern__title-link {
display: inline-flex; /* 1 */
- align-items: flex-start; /* 1 */
+ align-items: center; /* 1 */
padding: $pl-pad 0 0.3rem;
- color: $pl-color-gray-50 !important;
+ color: $pl-color-gray-55 !important;
text-decoration: none;
cursor: pointer;
@@ -67,24 +71,21 @@
* 1) This is the button that twirls down extra pattern info
*/
.pl-c-pattern__extra-toggle {
- font-size: 9px;
- position: absolute;
- bottom: -1px;
- right: 0;
- z-index: 1;
- padding: 0.65em 0.65em 0.5em;
- line-height: 1;
- color: $pl-color-gray-50;
+ font-size: 0.8rem;
+ margin-bottom: -1px;
+ padding: 0.4rem 0.5rem;
+ padding-right: 1.75rem;
+ color: $pl-color-gray-55;
background-color: transparent;
+ cursor: pointer;
font-weight: normal;
- border: 1px solid $pl-color-gray-13;
- border-top-left-radius: $pl-border-radius-med;
- border-top-right-radius: $pl-border-radius-med;
- transition: background-color $pl-animate-quick ease-out;
-
- .pl-c-pattern__toggle-icon {
- display: inline-block;
- }
+ transition: all $pl-animate-quick ease-out;
+ font-family: $pl-font;
+ border-color: #ddd;
+ border-width: 1px; // fix for different browser defaults
+ border-style: solid; // fix for different browser defaults (ex. Safari)
+ display: flex;
+ align-items: center;
&:hover,
&:focus,
@@ -95,16 +96,60 @@
&:focus {
outline: 1px dotted $pl-color-gray-70;
+ outline-offset: -1px;
}
&.pl-is-active {
border-bottom-color: $pl-color-gray-02;
+ }
+}
+
+.pl-c-pattern__toggle-icon {
+ height: 0.9rem;
+ width: 0.9rem;
+ display: inline-block;
+ vertical-align: middle;
+ position: absolute;
+ right: 0.625rem;
+ transition: opacity 0.1s linear;
+}
+
+.pl-c-pattern__toggle-icon--expand {
+ z-index: 1;
+
+ .pl-is-active & {
+ opacity: 0;
+ }
+}
+
+.pl-c-pattern__toggle-icon--collapse {
+ opacity: 0;
+ z-index: 2;
+ height: 1rem;
+ width: 1rem;
+
+ .pl-is-active & {
+ opacity: 1;
+ }
+}
+
+.pl-c-pattern__extra-toggle-text ~ svg {
+ margin-left: 0.25rem;
+}
+
+.pl-c-pattern__extra-toggle-text--collapse {
+ display: none;
+
+ .pl-is-active & {
+ display: inline-block;
+ }
+}
+
+.pl-c-pattern__extra-toggle-text--expand {
+ display: inline-block;
- .pl-c-pattern__toggle-icon {
- -webkit-transform: rotate(180deg);
- -ms-transform: rotate(180deg);
- transform: rotate(180deg);
- }
+ .pl-is-active & {
+ display: none;
}
}
@@ -126,6 +171,6 @@
border: 1px solid $pl-color-gray-13;
border-radius: $pl-border-radius-med;
border-top-right-radius: 0;
- max-height: 150rem;
+ max-height: 9999px;
}
}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_tabs.scss b/packages/uikit-workshop/src/sass/scss/04-components/_tabs.scss
index d1458283f..c1f7ee4e7 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_tabs.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_tabs.scss
@@ -16,7 +16,7 @@
position: relative;
display: flex;
flex-direction: column;
- overflow: hidden;
+ max-height: 100%;
flex-grow: 1;
}
@@ -42,7 +42,7 @@
padding: 0.2rem 0.4rem;
border: 1px solid transparent;
border-radius: $pl-border-radius-med;
- color: $pl-color-gray-50;
+ color: $pl-color-gray-55;
background-color: $pl-color-white;
cursor: pointer;
text-decoration: none;
@@ -65,14 +65,41 @@
}
}
+.pl-c-tabs__header {
+ position: sticky;
+ z-index: 1; // fix for Safari for iOS sticky header appearing to be below the scrollable content
+ top: 0px;
+ border-top: 1px solid #ddd;
+ margin-left: calc(-0.5rem - 1px);
+ margin-right: calc(-0.5rem - 1px);
+ padding-left: 0.5rem;
+ padding-right: 0.5rem;
+ border: 1px solid #ddd;
+ margin-bottom: 0.5rem;
+ margin-top: -1px;
+ background-color: inherit;
+ border-top-left-radius: 5px;
+ border-top-right-radius: 5px;
+}
+
/**
* Tab Content
* 1) Tab content contains the tab panels
*/
.pl-c-tabs__content {
- overflow: auto;
+ flex-grow: 1;
+ flex-shrink: 1;
+ display: flex;
+ flex-basis: auto;
-webkit-overflow-scrolling: touch;
- padding-top: 0.5rem;
+ overflow-y: auto; // workaround to firefox background gradient overflow bug
+
+ /**
+ * Tab content inside modal
+ */
+ .pl-c-drawer & {
+ border: 0;
+ }
}
/**
@@ -82,7 +109,8 @@
*/
.pl-c-tabs__panel {
display: none;
- // min-height: 12rem;
+ width: 100%;
+ max-height: 100%;
&.pl-is-active-tab {
display: block;
@@ -100,6 +128,8 @@
padding: 0;
border: 0;
display: block;
+ width: 100%;
+ min-height: 100%;
}
code[class*='language-'] {
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_text-passage.scss b/packages/uikit-workshop/src/sass/scss/04-components/_text-passage.scss
index 208332563..0fa03d73d 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_text-passage.scss
+++ b/packages/uikit-workshop/src/sass/scss/04-components/_text-passage.scss
@@ -13,13 +13,17 @@
p {
margin-top: 0;
margin-bottom: 1rem;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
}
/**
* Link within the text passage
*/
a {
- color: $pl-color-gray-50;
+ color: $pl-color-gray-55;
text-decoration: underline;
transition: opacity $pl-animate-quick ease;
@@ -132,4 +136,29 @@
li {
margin-bottom: 0.5rem;
}
+
+ table {
+ width: 100%;
+ max-width: 100%;
+ border-collapse: collapse;
+ overflow-x: auto;
+ margin: 0.75rem auto;
+ }
+
+ tr:nth-of-type(odd) {
+ background: $pl-color-gray-07;
+ }
+
+ th {
+ background: $pl-color-gray-13;
+ color: black;
+ font-weight: bold;
+ }
+
+ td,
+ th {
+ padding: 10px;
+ border: 1px solid $pl-color-gray-20;
+ text-align: left;
+ }
}
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_tools.scss b/packages/uikit-workshop/src/sass/scss/04-components/_tools.scss
deleted file mode 100644
index cc9d9b657..000000000
--- a/packages/uikit-workshop/src/sass/scss/04-components/_tools.scss
+++ /dev/null
@@ -1,71 +0,0 @@
-/*------------------------------------*\
- #TOOLS
-\*------------------------------------*/
-
-/**
- * The tools dropdown contains more utilities such as show/hide
- * pattern info and pattern search, and also links to open in a
- * new window and view the documentation
- */
-.pl-c-tools {
- position: relative;
- display: flex;
-}
-
-/**
- * Tools menu button
- * 1) This is the button that contains the toggle and
- * triggers the tools dropdown list
- */
-.pl-c-tools__toggle {
- @include linkStyle();
- margin: 0;
- padding-top: 0.6rem;
- padding-bottom: 0.5rem;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- position: relative;
- min-width: 30px;
-}
-
-/**
- * Tools Toggle SVG icon
- * 1) Cog icon
- * 2) Set the width and height of the icon to be the same height of font
- */
-.pl-c-tools__toggle-icon {
- transition: inherit; // inherit transition styles from parent toggle
-}
-
-/**
- * Tools dropdown list
- */
-.pl-c-tools__list {
- @include listReset();
- @include accordionPanel();
- position: absolute;
- top: 100%;
- right: 0;
- z-index: 10; // make sure context dropdown z-index is higher than nav dropdown z-index
- width: 10rem;
- border-bottom-left-radius: $pl-border-radius-med;
- border-bottom-right-radius: $pl-border-radius-med;
-}
-
-/**
- * Tools dropdown actions
- * 1) Links and buttons inside of the tools dropdown
- */
-.pl-c-tools__action {
- @include linkStyle();
- display: flex;
- align-items: center;
- width: 100%;
- margin: 0;
-}
-
-// Make sure the text and icon align to the opposite ends
-.pl-c-tools__action-icon {
- margin-left: auto;
-}
diff --git a/packages/uikit-workshop/src/sass/scss/05-themes/_light-theme.scss b/packages/uikit-workshop/src/sass/scss/05-themes/_light-theme.scss
index 038ae4390..541f67a9a 100644
--- a/packages/uikit-workshop/src/sass/scss/05-themes/_light-theme.scss
+++ b/packages/uikit-workshop/src/sass/scss/05-themes/_light-theme.scss
@@ -38,25 +38,10 @@
* Nav link dropdown
*/
.pl-c-nav__link--dropdown {
- color: $pl-color-gray-70;
- background-color: $pl-color-white;
+ color: inherit;
- &:after {
- color: $pl-color-gray-20;
- }
- }
-
- /**
- * All Nav links inside of subnav dropdown
- */
-
- /**
- * Last sublist item
- */
- .pl-c-nav__sublist > .pl-c-nav__item:last-child .pl-c-nav__link {
- @media all and (min-width: $pl-bp-med) {
- border-bottom-left-radius: $pl-border-radius-med;
- border-bottom-right-radius: $pl-border-radius-med;
+ &::after {
+ color: inherit;
}
}
@@ -79,7 +64,6 @@
background-color: $pl-color-gray-13 !important;
}
-
/**
* Typeahead input
*/
@@ -101,20 +85,11 @@
}
}
- /**
- * Modal inside a light theme
- */
- .pl-c-modal {
- background-color: $pl-color-white;
- color: $pl-color-gray-70;
- border-top: 1px solid $pl-color-gray-20;
- }
-
/**
* Modal close button
* 1) Closes the modal popup
*/
- .pl-c-modal__close-btn,
+ .pl-c-drawer__close-btn,
.pl-c-tools__action {
background-color: $pl-color-white;
diff --git a/packages/uikit-workshop/src/sass/scss/05-themes/_sidebar-theme.scss b/packages/uikit-workshop/src/sass/scss/05-themes/_sidebar-theme.scss
index c271ad06a..1a4c129c7 100644
--- a/packages/uikit-workshop/src/sass/scss/05-themes/_sidebar-theme.scss
+++ b/packages/uikit-workshop/src/sass/scss/05-themes/_sidebar-theme.scss
@@ -8,106 +8,53 @@
*/
.pl-c-body--theme-sidebar {
/**
- * Header
- * 1) Set width to sidebar width defined above
- * 2) Make header 100% of the viewport height
- * 3) Stack header items on top of each other
- * 4) void bottom border for light theme
- */
+ * Header
+ * 1) Set width to sidebar width defined above
+ * 2) Make header 100% of the viewport height
+ * 3) Stack header items on top of each other
+ * 4) void bottom border for light theme
+ */
.pl-c-header {
width: $pl-sidebar-width; /* 1 */
height: 100vh; /* 2 */
+ padding-top: 0.5rem;
+ padding-bottom: 0.5rem;
flex-direction: column; /* 3 */
border-bottom: 0; /* 4 */
- padding: 1rem;
- overflow: auto;
- -webkit-overflow-scrolling: touch;
justify-content: space-between;
+ --nav-item-height: 2.5rem;
}
/**
- * Header within light theme
- */
- &.pl-c-body--theme-light {
- .pl-c-header {
- border-right: 1px solid $pl-color-gray-20;
- }
- }
-
- /**
- * Logo
- */
- .pl-c-logo {
- max-width: 7rem;
- margin: 0 auto 1rem;
- }
-
- /**
- * Nav sub sub list
- */
+ * Nav sub sub list
+ */
.pl-c-nav {
- display: block;
+ flex-grow: 1;
flex-direction: column;
+ flex-flow: column-reverse;
}
/**
- * Nav list
- * 1) Stack main categories on top of each other
- * 2) Put typeahead search above nav list
- */
+ * Nav list
+ * 1) Stack main categories on top of each other
+ * 2) Put typeahead search above nav list
+ */
.pl-c-nav__list {
flex-direction: column; /* 1 */
order: 2; /* 2 */
}
/**
- * Nav sublist
- */
+ * Nav sublist
+ */
.pl-c-nav__sublist {
position: relative;
border-radius: 0;
}
/**
- * Nav sublist
- */
- .pl-c-nav__sublist .pl-c-nav__link {
- padding-left: 1rem;
- }
-
- /**
- * Nav sublist
- */
- .pl-c-nav__sublist--dropdown.pl-is-active {
- border: 0;
- border-left: 1px solid $pl-color-gray-70;
- }
-
- /**
- * Nav sublist inside the light theme
- */
- &.pl-c-body--theme-light {
- .pl-c-nav__sublist--dropdown.pl-is-active {
- border-left-color: $pl-color-gray-07;
- }
- }
-
- /**
- * Dropdown sublist
- * 1) Undo fixed height
- */
-
- /**
- * Nav sub sub list
- */
- .pl-c-nav__subsublist {
- border-left: 1px solid $pl-color-gray-70;
- margin-left: 1rem;
- }
-
- /**
- * Nav sublist inside the light theme
- */
+ * Nav sublist inside the light theme
+ */
&.pl-c-body--theme-light {
.pl-c-nav__subsublist {
border-left-color: $pl-color-gray-07;
@@ -115,17 +62,17 @@
}
/**
- * All Nav links inside of subnav dropdown
- */
+ * All Nav links inside of subnav dropdown
+ */
.pl-c-nav__sublist .pl-c-nav__link {
border-left: 0;
border-right: 0;
}
/**
- * Last sublist item
- * 1) Undo bottom border radius when in sidebar
- */
+ * Last sublist item
+ * 1) Undo bottom border radius when in sidebar
+ */
.pl-c-nav__sublist > .pl-c-nav__item:last-child .pl-c-nav__link {
@media all and (min-width: $pl-bp-med) {
border-bottom-left-radius: 0; /* 1 */
@@ -135,30 +82,26 @@
}
/**
- * Nav controls
- * 1) Push off of navigation in flex container so
- * they appear at the bottom
- */
+ * Nav controls
+ * 1) Push off of navigation in flex container so
+ * they appear at the bottom
+ */
.pl-c-controls {
display: block; // Display flex + flex direction column gives a similar result, but this fixes a bunch of rendering quirks in IE 11
justify-self: flex-end;
margin-left: 0;
}
- .pl-c-viewport-size {
- display: none;
- }
-
/**
- * Tools toggle button
- */
+ * Tools toggle button
+ */
.pl-c-tools__toggle {
display: none;
}
/**
- * Tools list
- */
+ * Tools list
+ */
.pl-c-tools__list {
max-height: none;
overflow: visible;
@@ -175,9 +118,14 @@
* so it fits in remaining available space
* TODO: revisit to find ways to resize
*/
- .pl-c-modal {
+ .pl-c-drawer {
right: 0; /* 1 */
width: auto;
}
+
+ .pl-is-active + .pl-c-nav__subsublist,
+ .pl-is-active + .pl-js-acc-panel {
+ max-height: none;
+ }
}
}
diff --git a/packages/uikit-workshop/src/sass/scss/core.scss b/packages/uikit-workshop/src/sass/scss/core.scss
index 50ce042c1..edf3c3fbc 100644
--- a/packages/uikit-workshop/src/sass/scss/core.scss
+++ b/packages/uikit-workshop/src/sass/scss/core.scss
@@ -1,2 +1,2 @@
@import './01-abstracts/variables';
-@import './01-abstracts/mixins';
\ No newline at end of file
+@import './01-abstracts/mixins';
diff --git a/packages/uikit-workshop/src/scripts/actions/app.js b/packages/uikit-workshop/src/scripts/actions/app.js
index fa453303a..c3e335a22 100644
--- a/packages/uikit-workshop/src/scripts/actions/app.js
+++ b/packages/uikit-workshop/src/scripts/actions/app.js
@@ -1,7 +1,34 @@
export const UPDATE_THEME_MODE = 'UPDATE_THEME_MODE';
export const UPDATE_LAYOUT_MODE = 'UPDATE_LAYOUT_MODE';
+export const UPDATE_DRAWER_ANIMATION_STATE = 'UPDATE_DRAWER_ANIMATION_STATE';
+export const UPDATE_DRAWER_STATE = 'UPDATE_DRAWER_STATE';
+export const UPDATE_VIEWPORT_PX = 'UPDATE_VIEWPORT_PX';
+export const UPDATE_VIEWPORT_EM = 'UPDATE_VIEWPORT_EM';
+export const UPDATE_DRAWER_HEIGHT = 'UPDATE_DRAWER_HEIGHT';
+export const UPDATE_CURRENT_URL = 'UPDATE_CURRENT_URL';
+export const UPDATE_CURRENT_PATTERN = 'UPDATE_CURRENT_PATTERN';
+export const IS_VIEWALL_PAGE = 'IS_VIEWALL_PAGE';
-export const updateLayoutMode = layoutMode => (dispatch, getState) => {
+export const updateCurrentPattern =
+ (currentPattern) => (dispatch, getState) => {
+ if (getState().app.currentPattern !== currentPattern) {
+ dispatch({
+ type: UPDATE_CURRENT_PATTERN,
+ currentPattern,
+ });
+ }
+ };
+
+export const updateCurrentUrl = (currentUrl) => (dispatch, getState) => {
+ if (getState().app.currentUrl !== currentUrl) {
+ dispatch({
+ type: UPDATE_CURRENT_URL,
+ currentUrl,
+ });
+ }
+};
+
+export const updateLayoutMode = (layoutMode) => (dispatch, getState) => {
if (getState().app.layoutMode !== layoutMode) {
dispatch({
type: UPDATE_LAYOUT_MODE,
@@ -10,7 +37,25 @@ export const updateLayoutMode = layoutMode => (dispatch, getState) => {
}
};
-export const updateThemeMode = themeMode => (dispatch, getState) => {
+export const updateViewportPx = (viewportPx) => (dispatch, getState) => {
+ if (getState().app.viewportPx !== viewportPx) {
+ dispatch({
+ type: UPDATE_VIEWPORT_PX,
+ viewportPx,
+ });
+ }
+};
+
+export const updateViewportEm = (viewportEm) => (dispatch, getState) => {
+ if (getState().app.viewportEm !== viewportEm) {
+ dispatch({
+ type: UPDATE_VIEWPORT_EM,
+ viewportEm,
+ });
+ }
+};
+
+export const updateThemeMode = (themeMode) => (dispatch, getState) => {
if (getState().app.themeMode !== themeMode) {
dispatch({
type: UPDATE_THEME_MODE,
@@ -18,3 +63,40 @@ export const updateThemeMode = themeMode => (dispatch, getState) => {
});
}
};
+
+export const updateDrawerState = (opened) => (dispatch, getState) => {
+ if (getState().app.drawerOpened !== opened) {
+ dispatch({
+ type: UPDATE_DRAWER_STATE,
+ opened,
+ });
+ }
+};
+
+export const updateDrawerAnimationState =
+ (drawerIsAnimating) => (dispatch, getState) => {
+ if (getState().app.drawerIsAnimating !== drawerIsAnimating) {
+ dispatch({
+ type: UPDATE_DRAWER_ANIMATION_STATE,
+ drawerIsAnimating,
+ });
+ }
+ };
+
+export const updateDrawerHeight = (height) => (dispatch, getState) => {
+ if (getState().app.drawerHeight !== height) {
+ dispatch({
+ type: UPDATE_DRAWER_HEIGHT,
+ height,
+ });
+ }
+};
+
+export const isViewallPage = (isViewall) => (dispatch, getState) => {
+ if (getState().app.isViewallPage !== isViewall) {
+ dispatch({
+ type: IS_VIEWALL_PAGE,
+ isViewall,
+ });
+ }
+};
diff --git a/packages/uikit-workshop/src/scripts/components/base-component.js b/packages/uikit-workshop/src/scripts/components/base-component.js
index 1e1594993..bce76c746 100644
--- a/packages/uikit-workshop/src/scripts/components/base-component.js
+++ b/packages/uikit-workshop/src/scripts/components/base-component.js
@@ -1,24 +1,23 @@
-import { withComponent, shadow } from 'skatejs';
-import withPreact from '@skatejs/renderer-preact';
+/* eslint-disable no-unused-vars */
+import { withComponent, shadow, name } from 'skatejs';
import { store } from '../store.js';
-import { extend, supportsShadowDom } from '../utils/index.js';
-import { h } from 'preact';
+import withLitHtml from './with-lit-html';
+import { LitElement } from 'lit-element';
+import { SkatePreactElement } from './base-skate-preact-element';
-export class BaseComponent extends withComponent(withPreact()) {
- get renderRoot() {
- if (this.useShadow === true && supportsShadowDom) {
- return super.renderRoot || shadow(this);
- } else {
- return this;
- }
+export class BaseComponent extends SkatePreactElement {
+ constructor() {
+ super();
}
- disconnectedCallback() {
- this.__storeUnsubscribe();
-
- if (super.disconnectedCallback) {
- super.disconnectedCallback();
- }
+ get renderRoot() {
+ return this;
+ // @todo: re-enable Shadow DOM conditionally after further testing + making sure PL components have inline styles needed
+ // if (this.useShadow === true && supportsShadowDom) {
+ // return super.renderRoot || shadow(this);
+ // } else {
+ // return this;
+ // }
}
connectedCallback() {
@@ -31,8 +30,18 @@ export class BaseComponent extends withComponent(withPreact()) {
}
}
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ this.__storeUnsubscribe && this.__storeUnsubscribe();
+
+ if (super.disconnectedCallback) {
+ super.disconnectedCallback();
+ }
+ }
+
_stateChanged(state) {
- throw new Error('_stateChanged() not implemented', this);
+ // throw new Error('_stateChanged() not implemented', this);
+ this.triggerUpdate();
}
/**
@@ -44,20 +53,7 @@ export class BaseComponent extends withComponent(withPreact()) {
* updated
*/
setState(state, callback) {
- if (!this._prevState) {
- this._prevState = this.state;
- }
-
- this.state = extend(
- extend({}, this.state),
- typeof state === 'function' ? state(this.state, this.props) : state
- );
-
- if (callback) {
- this._renderCallbacks.push(callback);
- }
-
- this.triggerUpdate();
+ this.state = Object.assign({}, this.state, state);
}
_renderStyles(stylesheets) {
@@ -71,3 +67,47 @@ export class BaseComponent extends withComponent(withPreact()) {
}
}
}
+
+export class BaseLitComponent extends LitElement {
+ createRenderRoot() {
+ return this;
+ }
+
+ constructor() {
+ super();
+ }
+
+ disconnectedCallback() {
+ this.__storeUnsubscribe();
+
+ if (super.disconnectedCallback) {
+ super.disconnectedCallback();
+ }
+ }
+
+ connectedCallback() {
+ this.__storeUnsubscribe = store.subscribe(() =>
+ this._stateChanged(store.getState())
+ );
+ this._stateChanged(store.getState());
+ if (super.connectedCallback) {
+ super.connectedCallback();
+ }
+ }
+
+ _stateChanged(state) {
+ this.requestUpdate();
+ }
+
+ /**
+ * Update component state and schedule a re-render.
+ * @param {object} state A dict of state properties to be shallowly merged
+ * into the current state, or a function that will produce such a dict. The
+ * function is called with the current state and props.
+ * @param {() => void} callback A function to be called once component state is
+ * updated
+ */
+ setState(state, callback) {
+ this.state = Object.assign({}, this.state, state);
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/components/base-skate-element.js b/packages/uikit-workshop/src/scripts/components/base-skate-element.js
new file mode 100644
index 000000000..47bca23b8
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/base-skate-element.js
@@ -0,0 +1,315 @@
+import { dashCase, empty, keys } from 'skatejs/dist/esnext/util';
+
+const _extends =
+ Object.assign ||
+ function (target) {
+ for (let i = 1; i < arguments.length; i++) {
+ const source = arguments[i];
+ for (const key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+ }
+ return target;
+ };
+
+export function normalizeAttributeDefinition(name, prop) {
+ const { attribute } = prop;
+ const obj =
+ typeof attribute === 'object'
+ ? _extends({}, attribute)
+ : {
+ source: attribute,
+ target: attribute,
+ };
+ if (obj.source === true) {
+ obj.source = dashCase(name);
+ }
+ if (obj.target === true) {
+ obj.target = dashCase(name);
+ }
+ return obj;
+}
+
+function identity(v) {
+ return v;
+}
+
+export function normalizePropertyDefinition(name, prop) {
+ const { coerce, default: def, deserialize, serialize } = prop;
+ return {
+ attribute: normalizeAttributeDefinition(name, prop),
+ coerce: coerce || identity,
+ default: def,
+ deserialize: deserialize || identity,
+ serialize: serialize || identity,
+ };
+}
+
+const defaultTypesMap = new Map();
+
+function defineProps(constructor) {
+ if (constructor.hasOwnProperty('_propsNormalized')) {
+ return;
+ }
+ const { props } = constructor;
+ keys(props).forEach((name) => {
+ let func = props[name] || props.any;
+ if (defaultTypesMap.has(func)) {
+ func = defaultTypesMap.get(func);
+ }
+ if (typeof func !== 'function') {
+ func = prop(func);
+ }
+ func({ constructor }, name);
+ });
+}
+
+function delay(fn) {
+ if (window.Promise) {
+ Promise.resolve().then(fn);
+ } else {
+ setTimeout(fn);
+ }
+}
+
+export function prop(definition) {
+ const propertyDefinition = definition || {};
+
+ // Allows decorators, or imperative definitions.
+ const func = function ({ constructor }, name) {
+ const normalized = normalizePropertyDefinition(name, propertyDefinition);
+
+ // Ensure that we can cache properties. We have to do this so the _props object literal doesn't modify parent
+ // classes or share the instance anywhere where it's not intended to be shared explicitly in userland code.
+ if (!constructor.hasOwnProperty('_propsNormalized')) {
+ constructor._propsNormalized = {};
+ }
+
+ // Cache the value so we can reference when syncing the attribute to the property.
+ constructor._propsNormalized[name] = normalized;
+ const {
+ attribute: { source, target },
+ } = normalized;
+
+ if (source) {
+ constructor._observedAttributes.push(source);
+ constructor._attributeToPropertyMap[source] = name;
+ if (source !== target) {
+ constructor._attributeToAttributeMap[source] = target;
+ }
+ }
+
+ Object.defineProperty(constructor.prototype, name, {
+ configurable: true,
+ get() {
+ const val = this._props[name];
+ return val == null ? normalized.default : val;
+ },
+ set(val) {
+ const {
+ attribute: { target },
+ serialize,
+ } = normalized;
+ if (target) {
+ const serializedVal = serialize ? serialize(val) : val;
+ if (serializedVal == null) {
+ this.removeAttribute(target);
+ } else {
+ this.setAttribute(target, serializedVal);
+ }
+ }
+ this._props[name] = normalized.coerce(val);
+ this.triggerUpdate();
+ },
+ });
+ };
+
+ // Allows easy extension of pre-defined props { ...prop(), ...{} }.
+ Object.keys(propertyDefinition).forEach(
+ (key) => (func[key] = propertyDefinition[key])
+ );
+
+ return func;
+}
+
+export class SkateElement extends HTMLElement {
+ constructor(...args) {
+ let _temp;
+ return (
+ (_temp = super(...args)),
+ (this._prevProps = {}),
+ (this._prevState = {}),
+ (this._props = {}),
+ (this._state = {}),
+ _temp
+ );
+ }
+
+ static get observedAttributes() {
+ // We have to define props here because observedAttributes are retrieved
+ // only once when the custom element is defined. If we did this only in
+ // the constructor, then props would not link to attributes.
+ defineProps(this);
+ return this._observedAttributes.concat(super.observedAttributes || []);
+ }
+
+ static get props() {
+ return this._props;
+ }
+
+ static set props(props) {
+ this._props = props;
+ }
+
+ get props() {
+ return keys(this.constructor.props).reduce((prev, curr) => {
+ prev[curr] = this[curr];
+ return prev;
+ }, {});
+ }
+
+ set props(props) {
+ const ctorProps = this.constructor.props;
+ keys(props).forEach((k) => k in ctorProps && (this[k] = props[k]));
+ }
+
+ get state() {
+ return this._state;
+ }
+
+ set state(state) {
+ this._state = state;
+ this.triggerUpdate();
+ }
+
+ attributeChangedCallback(name, oldValue, newValue) {
+ const {
+ _attributeToAttributeMap,
+ _attributeToPropertyMap,
+ _propsNormalized,
+ } = this.constructor;
+
+ if (super.attributeChangedCallback) {
+ super.attributeChangedCallback(name, oldValue, newValue);
+ }
+
+ const propertyName = _attributeToPropertyMap[name];
+ if (propertyName) {
+ const propertyDefinition = _propsNormalized[propertyName];
+ if (propertyDefinition) {
+ const { default: defaultValue, deserialize } = propertyDefinition;
+ const propertyValue = deserialize ? deserialize(newValue) : newValue;
+ this._props[propertyName] =
+ propertyValue == null ? defaultValue : propertyValue;
+ this.triggerUpdate();
+ }
+ }
+
+ const targetAttributeName = _attributeToAttributeMap[name];
+ if (targetAttributeName) {
+ if (newValue == null) {
+ this.removeAttribute(targetAttributeName);
+ } else {
+ this.setAttribute(targetAttributeName, newValue);
+ }
+ }
+ }
+
+ connectedCallback() {
+ if (super.connectedCallback) {
+ super.connectedCallback();
+ }
+ this.triggerUpdate();
+ }
+
+ shouldUpdate() {
+ return true;
+ }
+
+ triggerUpdate() {
+ if (this._updating) {
+ return;
+ }
+ this._updating = true;
+ delay(() => {
+ const { _prevProps, _prevState } = this;
+ if (this.updating) {
+ this.updating(_prevProps, _prevState);
+ }
+ if (this.updated && this.shouldUpdate(_prevProps, _prevState)) {
+ this.updated(_prevProps, _prevState);
+ }
+ this._prevProps = this.props;
+ this._prevState = this.state;
+ this._updating = false;
+ });
+ }
+}
+
+SkateElement._attributeToAttributeMap = {};
+SkateElement._attributeToPropertyMap = {};
+SkateElement._observedAttributes = [];
+SkateElement._props = {};
+
+const { parse, stringify } = JSON;
+const attribute = Object.freeze({ source: true });
+const zeroOrNumber = (val) => (empty(val) ? 0 : Number(val));
+
+const any = prop({
+ attribute,
+});
+
+const array = prop({
+ attribute,
+ coerce: (val) => (Array.isArray(val) ? val : empty(val) ? null : [val]),
+ default: Object.freeze([]),
+ deserialize: parse,
+ serialize: stringify,
+});
+
+const boolean = prop({
+ attribute,
+ coerce: Boolean,
+ default: false,
+ deserialize: (val) => !empty(val),
+ serialize: (val) => (val ? '' : null),
+});
+
+const number = prop({
+ attribute,
+ default: 0,
+ coerce: zeroOrNumber,
+ deserialize: zeroOrNumber,
+ serialize: (val) => (empty(val) ? null : String(Number(val))),
+});
+
+const object = prop({
+ attribute,
+ default: Object.freeze({}),
+ deserialize: parse,
+ serialize: stringify,
+});
+
+const string = prop({
+ attribute,
+ default: '',
+ coerce: String,
+ serialize: (val) => (empty(val) ? null : String(val)),
+});
+
+defaultTypesMap.set(Array, array);
+defaultTypesMap.set(Boolean, boolean);
+defaultTypesMap.set(Number, number);
+defaultTypesMap.set(Object, object);
+defaultTypesMap.set(String, string);
+
+export const props = {
+ any,
+ array,
+ boolean,
+ number,
+ object,
+ string,
+};
diff --git a/packages/uikit-workshop/src/scripts/components/base-skate-preact-element.js b/packages/uikit-workshop/src/scripts/components/base-skate-preact-element.js
new file mode 100644
index 000000000..e92dfa06a
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/base-skate-preact-element.js
@@ -0,0 +1,63 @@
+const _extends =
+ Object.assign ||
+ function (target) {
+ for (let i = 1; i < arguments.length; i++) {
+ const source = arguments[i];
+ for (const key in source) {
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
+ target[key] = source[key];
+ }
+ }
+ }
+ return target;
+ };
+
+import { SkateElement } from './base-skate-element';
+
+/** @jsx h */
+
+import { h, render } from 'preact';
+
+export class SkatePreactElement extends SkateElement {
+ get props() {
+ // We override props so that we can satisfy most use
+ // cases for children by using a slot.
+ return _extends({}, super.props, { children: h('slot', null) });
+ }
+
+ renderer(root, call) {
+ this._renderRoot = root;
+ render(call(), root);
+ }
+
+ disconnectedCallback() {
+ this.disconnecting && this.disconnecting();
+ super.disconnectedCallback && super.disconnectedCallback();
+ this.disconnected && this.disconnected();
+ // Render null to unmount. See https://github.com/skatejs/skatejs/pull/1432#discussion_r183381359
+ render(null, this._renderRoot);
+
+ this.__storeUnsubscribe && this.__storeUnsubscribe();
+
+ if (super.disconnectedCallback) {
+ super.disconnectedCallback();
+ }
+ }
+
+ connectedCallback() {
+ this.connecting && this.connecting();
+ super.connectedCallback && super.connectedCallback();
+ this.connected && this.connected();
+ }
+
+ get renderRoot() {
+ return super.renderRoot || shadow(this);
+ }
+
+ updated(prevProps, prevState) {
+ super.updated && super.updated(prevProps, prevState);
+ this.rendering && this.rendering();
+ this.renderer(this.renderRoot, () => this.render && this.render(this));
+ this.rendered && this.rendered();
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/components/copy-to-clipboard.js b/packages/uikit-workshop/src/scripts/components/copy-to-clipboard.js
index 3cc09ed68..60cb46a8b 100644
--- a/packages/uikit-workshop/src/scripts/components/copy-to-clipboard.js
+++ b/packages/uikit-workshop/src/scripts/components/copy-to-clipboard.js
@@ -5,10 +5,21 @@
import Clipboard from 'clipboard';
const clipboard = new Clipboard('.pl-js-code-copy-btn');
-clipboard.on('success', function(e) {
+clipboard.on('success', function (e) {
const copyButton = document.querySelectorAll('.pl-js-code-copy-btn');
for (let i = 0; i < copyButton.length; i++) {
- copyButton[i].innerText = 'Copy';
+ copyButton[i].querySelector('.pl-c-code-copy-btn__icon-text').innerText =
+ 'Copy';
}
- e.trigger.textContent = 'Copied';
+ e.trigger.classList.add('is-copied');
+ e.trigger.querySelector('.pl-c-code-copy-btn__icon-text').textContent =
+ 'Copied';
+
+ setTimeout(() => {
+ e.trigger.classList.remove('is-copied');
+ e.trigger.querySelector('.pl-c-code-copy-btn__icon-text').textContent =
+ 'Copy';
+ e.clearSelection();
+ e.trigger.blur();
+ }, 2000);
});
diff --git a/packages/uikit-workshop/src/scripts/components/modal-styleguide.js b/packages/uikit-workshop/src/scripts/components/modal-styleguide.js
index a7a8e8254..665628c5f 100644
--- a/packages/uikit-workshop/src/scripts/components/modal-styleguide.js
+++ b/packages/uikit-workshop/src/scripts/components/modal-styleguide.js
@@ -1,9 +1,11 @@
+/* eslint-disable no-param-reassign, no-unused-vars */
/**
* "Modal" (aka Panel UI) for the Styleguide Layer - for both annotations and code/info
*/
import { panelsUtil } from './panels-util';
-import './copy-to-clipboard';
+import './pl-copy-to-clipboard/pl-copy-to-clipboard';
+import { iframeMsgDataExtraction } from '../utils';
export const modalStyleguide = {
// set up some defaults
@@ -18,12 +20,13 @@ export const modalStyleguide = {
*/
onReady() {
// go through the panel toggles and add click event to the pattern extra toggle button
- const els = document.querySelectorAll('.pl-js-pattern-extra-toggle');
- for (let i = 0; i < els.length; ++i) {
- els[i].onclick = function(e) {
- const patternPartial = this.getAttribute('data-patternpartial');
+ const toggles = document.querySelectorAll('.pl-js-pattern-extra-toggle');
+
+ for (let i = 0; i < toggles.length; i++) {
+ toggles[i].addEventListener('click', (e) => {
+ const patternPartial = toggles[i].getAttribute('data-patternpartial');
modalStyleguide.toggle(patternPartial);
- };
+ });
}
},
@@ -62,15 +65,17 @@ export const modalStyleguide = {
content = panelsUtil.addClickEvents(content, patternPartial);
// make sure the modal viewer and other options are off just in case
- modalStyleguide.close(patternPartial);
+ // modalStyleguide.close(patternPartial);
// note it's turned on in the viewer
modalStyleguide.active[patternPartial] = true;
// make sure there's no content
div = document.getElementById('pl-pattern-extra-' + patternPartial);
- if (div.childNodes.length > 0) {
- div.removeChild(div.childNodes[0]);
+ if (div && div.childNodes) {
+ if (div.childNodes.length > 0) {
+ div.removeChild(div.childNodes[0]);
+ }
}
// add the content
@@ -79,9 +84,13 @@ export const modalStyleguide = {
.appendChild(content);
// show the modal
- document
- .getElementById('pl-pattern-extra-toggle-' + patternPartial)
- .classList.add('pl-is-active');
+ const toggle = document.getElementById(
+ 'pl-pattern-extra-toggle-' + patternPartial
+ );
+ if (toggle) {
+ toggle.classList.add('pl-is-active');
+ }
+
document
.getElementById('pl-pattern-extra-' + patternPartial)
.classList.add('pl-is-active');
@@ -96,12 +105,18 @@ export const modalStyleguide = {
modalStyleguide.active[patternPartial] = false;
// hide the modal, look at info-panel.js
- document
- .getElementById('pl-pattern-extra-toggle-' + patternPartial)
- .classList.remove('pl-is-active');
- document
- .getElementById('pl-pattern-extra-' + patternPartial)
- .classList.remove('pl-is-active');
+ const toggle = document.getElementById(
+ 'pl-pattern-extra-toggle-' + patternPartial
+ );
+ if (toggle) {
+ toggle.classList.remove('pl-is-active');
+ }
+
+ if (document.getElementById('pl-pattern-extra-' + patternPartial)) {
+ document
+ .getElementById('pl-pattern-extra-' + patternPartial)
+ .classList.remove('pl-is-active');
+ }
},
/**
@@ -153,7 +168,7 @@ export const modalStyleguide = {
patternPartialSelector + '.pl-c-annotation-tip'
);
for (let i = 0; i < elsToHide.length; i++) {
- elsToHide[i].style.display = 'none';
+ elsToHide[i].hidden = true;
}
},
@@ -181,24 +196,11 @@ export const modalStyleguide = {
/**
* toggle the comment pop-up based on a user clicking on the pattern
* based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
- * @param {Object} event info
+ *
+ * @param {MessageEvent} e A message received by a target object.
*/
- receiveIframeMessage(event) {
- // does the origin sending the message match the current host? if not dev/null the request
- if (
- window.location.protocol !== 'file:' &&
- event.origin !== window.location.protocol + '//' + window.location.host
- ) {
- return;
- }
-
- let data = {};
- try {
- data =
- typeof event.data !== 'string' ? event.data : JSON.parse(event.data);
- } catch (e) {
- // @todo: how do we want to handle exceptions here?
- }
+ receiveIframeMessage(e) {
+ const data = iframeMsgDataExtraction(e);
// see if it got a path to replace
if (data.event !== undefined && data.event === 'patternLab.patternQuery') {
@@ -240,7 +242,7 @@ export const modalStyleguide = {
.getComputedStyle(elsToHighlight[j], null)
.getPropertyValue('max-height') === '0px'
) {
- span.style.display = 'none';
+ span.hidden = true;
}
const annotationTip = document.querySelector(
@@ -252,13 +254,13 @@ export const modalStyleguide = {
elsToHighlight[j].firstChild
);
} else {
- annotationTip.style.display = 'inline-flex';
+ annotationTip.hidden = false;
}
- elsToHighlight[j].onclick = (function(el) {
- return function(e) {
- e.preventDefault();
- e.stopPropagation();
+ elsToHighlight[j].onclick = (function (el) {
+ return function (event) {
+ event.preventDefault();
+ event.stopPropagation();
const obj = JSON.stringify({
event: 'patternLab.annotationNumberClicked',
displayNumber: el.displayNumber,
diff --git a/packages/uikit-workshop/src/scripts/components/modal-viewer.js b/packages/uikit-workshop/src/scripts/components/modal-viewer.js
index c099711c8..ca919894b 100644
--- a/packages/uikit-workshop/src/scripts/components/modal-viewer.js
+++ b/packages/uikit-workshop/src/scripts/components/modal-viewer.js
@@ -1,13 +1,20 @@
+/* eslint-disable no-unused-vars */
/**
* "Modal" (aka Panel UI) for the Viewer Layer - for both annotations and code/info
*/
-import $ from 'jquery';
-import { urlHandler, DataSaver, Dispatcher } from '../utils';
+import { scrollTo } from 'scroll-js';
+import { urlHandler, Dispatcher, iframeMsgDataExtraction } from '../utils';
import { panelsViewer } from './panels-viewer';
+import { store } from '../store.js';
+// These are the actions needed by this element.
+import { updateDrawerState, isViewallPage } from '../actions/app.js';
export const modalViewer = {
// set up some defaults
+ delayCheckingModalViewer: false,
+ iframeElement: document.querySelector('.pl-js-iframe'),
+ iframeCustomElement: document.querySelector('pl-iframe'),
active: false,
switchText: true,
template: 'info',
@@ -21,54 +28,27 @@ export const modalViewer = {
* initialize the modal window
*/
onReady() {
+ window.addEventListener('message', modalViewer.receiveIframeMessage, false);
// make sure the listener for checkpanels is set-up
Dispatcher.addListener('insertPanels', modalViewer.insert);
- // add the info/code panel onclick handler
- $('.pl-js-pattern-info-toggle').click(function(e) {
- modalViewer.toggle();
- });
-
- // make sure the close button handles the click
- $('.pl-js-modal-close-btn').on('click', function(e) {
- // hide any open annotations
- const obj = JSON.stringify({
- event: 'patternLab.annotationsHighlightHide',
- });
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, modalViewer.targetOrigin);
-
- // hide the viewer
- modalViewer.close();
- });
+ modalViewer.__storeUnsubscribe = store.subscribe(() =>
+ modalViewer._stateChanged(store.getState())
+ );
+ modalViewer._stateChanged(store.getState());
- // see if the modal is already active, if so update attributes as appropriate
- if (DataSaver.findValue('modalActive') === 'true') {
- modalViewer.active = true;
- $('.pl-js-pattern-info-toggle').html('Hide Pattern Info');
- }
-
- // make sure the modal viewer is not viewable, it's always hidden by default. the pageLoad event determines when it actually opens
- modalViewer.hide();
-
- // review the query strings in case there is something the modal viewer is supposed to handle by default
+ // check query strings to handle auto-opening behavior
const queryStringVars = urlHandler.getRequestVars();
// show the modal if code view is called via query string
if (
queryStringVars.view !== undefined &&
- (queryStringVars.view === 'code' || queryStringVars.view === 'c')
- ) {
- modalViewer.queryPattern();
- }
-
- // show the modal if the old annotations view is called via query string
- if (
- queryStringVars.view !== undefined &&
- (queryStringVars.view === 'annotations' || queryStringVars.view === 'a')
+ (queryStringVars.view === 'code' ||
+ queryStringVars.view === 'c' ||
+ queryStringVars.view === 'annotations' ||
+ queryStringVars.view === 'a')
) {
- modalViewer.queryPattern();
+ store.dispatch(updateDrawerState(true));
}
},
@@ -76,16 +56,10 @@ export const modalViewer = {
* toggle the modal window open and closed
*/
toggle() {
- if (modalViewer.active === false) {
- modalViewer.queryPattern();
+ if (modalViewer.active) {
+ store.dispatch(updateDrawerState(false));
} else {
- const obj = JSON.stringify({
- event: 'patternLab.annotationsHighlightHide',
- });
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, modalViewer.targetOrigin);
- modalViewer.close();
+ store.dispatch(updateDrawerState(true));
}
},
@@ -93,50 +67,70 @@ export const modalViewer = {
* open the modal window
*/
open() {
- // make sure the modal viewer and other options are off just in case
- modalViewer.close();
-
- // note it's turned on in the viewer
- DataSaver.updateValue('modalActive', 'true');
- modalViewer.active = true;
+ modalViewer.queryPattern();
- // show the modal
- modalViewer.show();
+ // Show annotations if data is available and modal is open
+ if (modalViewer.patternData) {
+ if (
+ modalViewer.patternData.annotations &&
+ modalViewer.patternData.annotations.length > 0
+ ) {
+ const obj = JSON.stringify({
+ event: 'patternLab.annotationsHighlightShow',
+ annotations: modalViewer.patternData.annotations,
+ });
+
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.iframeElement.contentWindow.postMessage(
+ obj,
+ modalViewer.targetOrigin
+ );
+ } else {
+ modalViewer.iframeElement = document.querySelector('.pl-js-iframe');
+
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.open();
+ } else {
+ console.log('modelViewer open cannot find the iframeElement...');
+ }
+ }
+ }
+ }
},
/**
* close the modal window
*/
close() {
- // note that the modal viewer is no longer active
- DataSaver.updateValue('modalActive', 'false');
- modalViewer.active = false;
-
- //Remove active class to modal
- $('.pl-js-modal').removeClass('pl-is-active');
- $('.pl-js-modal').removeAttr('style'); // remove inline height CSS
-
- // WIP: refactoring viewport panel to use CSS vars to resize
- // $('html').css('--pl-viewport-height', window.innerHeight - 32 + 'px');
-
- // update the wording
- $('.pl-js-pattern-info-toggle').html('Show Pattern Info');
-
// tell the styleguide to close
const obj = JSON.stringify({
event: 'patternLab.patternModalClose',
});
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, modalViewer.targetOrigin);
- },
- /**
- * hide the modal window
- */
- hide() {
- $('.pl-js-modal').removeClass('pl-is-active');
- $('.pl-js-modal').removeAttr('style'); // remove inline height CSS
+ if (modalViewer.iframeElement) {
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.iframeElement.contentWindow.postMessage(
+ obj,
+ modalViewer.targetOrigin
+ );
+
+ const obj2 = JSON.stringify({
+ event: 'patternLab.annotationsHighlightHide',
+ });
+ modalViewer.iframeElement.contentWindow.postMessage(
+ obj2,
+ modalViewer.targetOrigin
+ );
+ } else {
+ modalViewer.iframeElement = document.querySelector('.pl-js-iframe');
+
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.close();
+ } else {
+ console.log('modelViewer close cannot find the iframeElement...');
+ }
+ }
+ }
},
/**
@@ -154,21 +148,48 @@ export const modalViewer = {
patternPartial,
modalContent: templateRendered.outerHTML,
});
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, modalViewer.targetOrigin);
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.iframeElement.contentWindow.postMessage(
+ obj,
+ modalViewer.targetOrigin
+ );
+ } else {
+ modalViewer.iframeElement = document.querySelector('.pl-js-iframe');
+
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.insert(templateRendered, patternPartial, iframePassback);
+ } else {
+ console.log('modelViewer insert cannot find the iframeElement...');
+ }
+ }
} else {
- // insert the panels and open the viewer
- $('.pl-js-modal-content').html(templateRendered);
- modalViewer.open();
- }
+ const contentContainer = document.querySelector('.pl-js-drawer-content');
- // update the wording unless this is a default viewall opening
- if (switchText === true) {
- $('.pl-js-pattern-info-toggle').html('Hide Pattern Info');
+ // Clear out any existing children before appending the new panel content
+ if (contentContainer.firstChild !== null) {
+ while (contentContainer.firstChild !== null) {
+ contentContainer.removeChild(contentContainer.firstChild);
+ }
+ }
+
+ contentContainer.appendChild(templateRendered);
+ modalViewer.addClickEvents(contentContainer);
}
},
+ addClickEvents(contentContainer = document) {
+ contentContainer.querySelectorAll('.pl-js-lineage-link').forEach((link) => {
+ link.addEventListener('click', (e) => {
+ const patternPartial = e.target.getAttribute('data-patternpartial');
+
+ if (patternPartial && modalViewer.iframeCustomElement) {
+ e.preventDefault();
+ modalViewer.iframeCustomElement.navigateTo(patternPartial);
+ }
+ });
+ });
+ },
+
/**
* refresh the modal if a new pattern is loaded and the modal is active
* @param {Object} the patternData sent back from the query
@@ -176,10 +197,7 @@ export const modalViewer = {
* @param {Boolean} if the text in the dropdown should be switched
*/
refresh(patternData, iframePassback, switchText) {
- // if this is a styleguide view close the modal
- if (iframePassback) {
- modalViewer.hide();
- }
+ modalViewer.patternData = patternData;
// gather the data that will fill the modal window
panelsViewer.gatherPanels(patternData, iframePassback, switchText);
@@ -190,7 +208,7 @@ export const modalViewer = {
* @param {Integer} where the modal window should be slide to
*/
slide(pos) {
- $('.pl-js-modal').toggleClass('pl-is-active');
+ modalViewer.toggle();
},
/**
@@ -204,73 +222,89 @@ export const modalViewer = {
els[i].classList.remove('pl-is-active');
}
+ const patternInfoElem = document.querySelector('.pl-js-pattern-info');
+ // const scroll = new Scroll(patternInfoElem);
+
// add active class to called element and scroll to it
for (let i = 0; i < els.length; ++i) {
if (i + 1 === pos) {
els[i].classList.add('pl-is-active');
- $('.pl-js-pattern-info').animate(
- {
- scrollTop: els[i].offsetTop - 10,
- },
- 600
- );
+
+ scrollTo(patternInfoElem, {
+ top: els[i].offsetTop - 14,
+ behavior: 'smooth',
+ }).then(function () {
+ // console.log('finished scrolling');
+ });
}
}
},
- /**
- * Show modal
- */
- show() {
- $('.pl-js-modal').addClass('pl-is-active');
- },
-
/**
* ask the pattern for info so we can open the modal window and populate it
* @param {Boolean} if the dropdown text should be changed
*/
queryPattern(switchText) {
- // note that the modal is active and set switchText
- if (switchText === undefined || switchText) {
- switchText = true;
- DataSaver.updateValue('modalActive', 'true');
- modalViewer.active = true;
- }
-
// send a message to the pattern
const obj = JSON.stringify({
event: 'patternLab.patternQuery',
switchText,
});
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, modalViewer.targetOrigin);
+
+ // only emit this when the iframe element exists.
+ // @todo: refactor to better handle async UI rendering
+ if (modalViewer.iframeElement) {
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.iframeElement.contentWindow.postMessage(
+ obj,
+ modalViewer.targetOrigin
+ );
+ } else {
+ modalViewer.iframeElement = document.querySelector('.pl-js-iframe');
+
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.queryPattern(switchText);
+ } else {
+ console.log('queryPattern cannot find the iframeElement...');
+ }
+ }
+ } else {
+ modalViewer.iframeElement = document.querySelector('.pl-js-iframe');
+
+ if (modalViewer.iframeElement.contentWindow) {
+ modalViewer.iframeElement.contentWindow.postMessage(
+ obj,
+ modalViewer.targetOrigin
+ );
+ }
+ }
},
/**
* toggle the comment pop-up based on a user clicking on the pattern
* based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
- * @param {Object} event info
+ *
+ * @param {MessageEvent} e A message received by a target object.
*/
- receiveIframeMessage(event) {
- // does the origin sending the message match the current host? if not dev/null the request
- if (
- window.location.protocol !== 'file:' &&
- event.origin !== window.location.protocol + '//' + window.location.host
- ) {
- return;
- }
+ receiveIframeMessage(e) {
+ const data = iframeMsgDataExtraction(e);
- let data = {};
+ if (data.event !== undefined && data.event === 'patternLab.pageLoad') {
+ // @todo: refactor to better handle async iframe loading
+ // extra check to make sure the PL drawer will always render even if the iframe gets async loaded / rendered.
+ if (modalViewer.delayCheckingModalViewer) {
+ modalViewer._handleInitialModalViewerState();
+ }
- try {
- data =
- typeof event.data !== 'string' ? event.data : JSON.parse(event.data);
- } catch (e) {
- // @todo: how do we want to handle exceptions here?
- }
+ if (
+ data.patternpartial.indexOf('viewall-') === 0 ||
+ data.patternpartial.indexOf('all') === 0
+ ) {
+ store.dispatch(isViewallPage(true));
+ } else {
+ store.dispatch(isViewallPage(false));
+ }
- if (data.event !== undefined && data.event === 'patternLab.pageLoad') {
if (
modalViewer.active === false &&
data.patternpartial !== undefined &&
@@ -286,12 +320,18 @@ export const modalViewer = {
data.event !== undefined &&
data.event === 'patternLab.patternQueryInfo'
) {
- // refresh the modal if a new pattern is loaded and the modal is active
- modalViewer.refresh(
- data.patternData,
- data.iframePassback,
- data.switchText
- );
+ if (
+ !modalViewer.panelRendered ||
+ modalViewer.previouslyRenderedPattern !==
+ data.patternData.patternPartial
+ ) {
+ // refresh the modal contents, but only when necessary (ex. when the page changes) -- prevents extra, unnecessary re-renders of content.
+ modalViewer.refresh(
+ data.patternData,
+ data.iframePassback,
+ data.switchText
+ );
+ }
} else if (
data.event !== undefined &&
data.event === 'patternLab.annotationNumberClicked'
@@ -300,11 +340,35 @@ export const modalViewer = {
modalViewer.slideToAnnotation(data.displayNumber);
}
},
-};
-// when the document is ready make sure the modal is ready
-$(document).ready(function() {
- modalViewer.onReady();
-});
+ _handleInitialModalViewerState() {
+ // try to re-locate the iframe element if this UI logic ran too early and the iframe component wasn't yet rendered
+ if (!modalViewer.iframeElement) {
+ modalViewer.iframeElement = document.querySelector('.pl-js-iframe');
+ }
+
+ // only try to auto-open / auto-close the drawer UI if the iframe element exists
+ // @todo: refactor to better handle async UI rendering
+ if (modalViewer.iframeElement) {
+ modalViewer.delayCheckingModalViewer = false;
+ if (modalViewer.active) {
+ modalViewer.open();
+ } else {
+ modalViewer.close();
+ }
+ } else {
+ modalViewer.delayCheckingModalViewer = true;
+ }
+ },
+
+ _stateChanged(state) {
+ if (modalViewer.active !== state.app.drawerOpened) {
+ modalViewer.active = state.app.drawerOpened;
+ if (modalViewer.iframeElement) {
+ modalViewer._handleInitialModalViewerState();
+ }
+ }
+ },
+};
-window.addEventListener('message', modalViewer.receiveIframeMessage, false);
+modalViewer.onReady();
diff --git a/packages/uikit-workshop/src/scripts/components/panels-util.js b/packages/uikit-workshop/src/scripts/components/panels-util.js
index 8a9c6d0ac..a485e3c97 100644
--- a/packages/uikit-workshop/src/scripts/components/panels-util.js
+++ b/packages/uikit-workshop/src/scripts/components/panels-util.js
@@ -1,3 +1,4 @@
+/* eslint-disable no-unused-vars */
/**
* Panels Util - for both styleguide and viewer
*/
@@ -11,7 +12,7 @@ export const panelsUtil = {
addClickEvents(templateRendered, patternPartial) {
const els = templateRendered.querySelectorAll('.pl-js-tab-link');
for (let i = 0; i < els.length; ++i) {
- els[i].onclick = function(e) {
+ els[i].onclick = function (e) {
e.preventDefault();
const partial = this.getAttribute('data-patternpartial');
@@ -31,22 +32,24 @@ export const panelsUtil = {
show(patternPartial, panelID) {
const activeTabClass = 'pl-is-active-tab';
+ // tabPanelabout to become active
+ const activeTabPanel = document.querySelector(
+ `#pl-${patternPartial}-${panelID}-panel`
+ );
+
+ const parentTabs = activeTabPanel.closest('.pl-js-tabs');
+
// turn off all of the active tabs
- const allTabLinks = document.querySelectorAll(`.pl-js-tab-link`);
+ const allTabLinks = parentTabs.querySelectorAll(`.pl-js-tab-link`);
// hide all of the panels
- const allTabPanels = document.querySelectorAll(`.pl-js-tab-panel`);
+ const allTabPanels = parentTabs.querySelectorAll(`.pl-js-tab-panel`);
// tabLink about to become active
- const activeTabLink = document.querySelector(
+ const activeTabLink = parentTabs.querySelector(
`#pl-${patternPartial}-${panelID}-tab`
);
- // tabPanelabout to become active
- const activeTabPanel = document.querySelector(
- `#pl-${patternPartial}-${panelID}-panel`
- );
-
for (let i = 0; i < allTabLinks.length; ++i) {
allTabLinks[i].classList.remove(activeTabClass);
}
diff --git a/packages/uikit-workshop/src/scripts/components/panels-viewer.js b/packages/uikit-workshop/src/scripts/components/panels-viewer.js
index 273d17a5c..f97cb4a79 100644
--- a/packages/uikit-workshop/src/scripts/components/panels-viewer.js
+++ b/packages/uikit-workshop/src/scripts/components/panels-viewer.js
@@ -1,14 +1,30 @@
/**
* Panel Builder - supports building the panels to be included in the modal or styleguide
*/
+/* eslint-disable no-param-reassign, no-unused-vars */
-import $ from 'jquery';
-import Hogan from 'hogan.js';
-import Prism from 'prismjs';
+import Handlebars from 'handlebars/dist/handlebars';
+import pretty from 'pretty';
+import { html, render } from 'lit-html';
+import { unsafeHTML } from 'lit-html/directives/unsafe-html.js';
import { Panels } from './panels';
import { panelsUtil } from './panels-util';
import { urlHandler, Dispatcher } from '../utils';
-import './copy-to-clipboard';
+import './pl-copy-to-clipboard/pl-copy-to-clipboard';
+import { PrismLanguages as Prism } from './prism-languages';
+import Normalizer from 'prismjs/plugins/normalize-whitespace/prism-normalize-whitespace.js';
+
+const normalizeWhitespace = new Normalizer({
+ 'remove-trailing': true,
+ 'remove-indent': true,
+ 'left-trim': true,
+ 'right-trim': true,
+ 'break-lines': 100,
+ indent: 2,
+ 'remove-initial-line-feed': true,
+ 'tabs-to-spaces': 2,
+ 'spaces-to-tabs': 2,
+});
export const panelsViewer = {
// set up some defaults
@@ -54,7 +70,7 @@ export const panelsViewer = {
Dispatcher.addListener('checkPanels', panelsViewer.checkPanels);
// set-up defaults
- let template, templateCompiled, templateRendered;
+ let template, templateCompiled, templateRendered, templateFormatted;
// get the base panels
const panels = Panels.get();
@@ -71,6 +87,10 @@ export const panelsViewer = {
}
// if httpRequestReplace has not been set, use the extension. this is likely for the raw template
+ if (panel.httpRequestReplace === undefined) {
+ panel.httpRequestReplace = '';
+ }
+
if (panel.httpRequestReplace === '') {
panel.httpRequestReplace =
panel.httpRequestReplace + '.' + patternData.patternExtension;
@@ -86,19 +106,57 @@ export const panelsViewer = {
const e = new XMLHttpRequest();
// @todo: look deeper into how we can refactor this particular code block
/* eslint-disable */
- e.onload = (function(i, panels, patternData, iframeRequest) {
- return function() {
- const prismedContent = Prism.highlight(
- this.responseText,
- Prism.languages.html
+ e.onload = (function (i, panels, patternData, iframeRequest) {
+ return function () {
+ // since non-existant files (such as .scss from plugin-tab) still return a 200, we need to instead inspect the contents
+ // we look for responseText that starts with the doctype
+ let rText = this.responseText;
+ if (rText.startsWith('')) {
+ rText = '';
+ }
+
+ // use pretty to format HTML
+ if (panels[i].name === 'HTML') {
+ templateFormatted = pretty(rText, { ocd: true });
+ } else {
+ templateFormatted = rText;
+ }
+
+ const templateHighlighted = Prism.highlight(
+ templateFormatted,
+ Prism.languages[panels[i].name.toLowerCase()] ||
+ Prism.languages['markup']
+ // Prism.languages[panels[i].name.toLowerCase()],
);
- template = document.getElementById(panels[i].templateID);
- templateCompiled = Hogan.compile(template.innerHTML);
- templateRendered = templateCompiled.render({
- language: 'html',
- code: prismedContent,
- });
- panels[i].content = templateRendered;
+
+ const codeTemplate = (code, language) =>
+ html`
+ ${unsafeHTML(
+ code
+ )}
+ `;
+
+ const result = document.createDocumentFragment();
+ const fallBackResult = document.createDocumentFragment();
+
+ render(codeTemplate(templateHighlighted, 'html'), result);
+ render(codeTemplate(templateFormatted, 'html'), fallBackResult);
+
+ if (result.children) {
+ panels[i].content = result.children[0].outerHTML;
+ } else if (fallBackResult.children) {
+ panels[i].content = fallBackResult.children[0].outerHTML;
+ } else {
+ panels[i].content =
+ '' +
+ templateFormatted
+ .replace(//g, '>') +
+ ' ';
+ }
+
Dispatcher.trigger('checkPanels', [
panels,
patternData,
@@ -117,9 +175,16 @@ export const panelsViewer = {
} else {
// vanilla render of pattern data
template = document.getElementById(panel.templateID);
- templateCompiled = Hogan.compile(template.innerHTML);
- templateRendered = templateCompiled.render(patternData);
- panels[i].content = templateRendered;
+ templateCompiled = Handlebars.compile(template.innerHTML);
+ templateRendered = templateCompiled(patternData);
+ const normalizedCode =
+ normalizeWhitespace.normalize(templateRendered);
+ normalizedCode.replace(/[\r\n]+/g, '\n\n');
+ const highlightedCode = Prism.highlight(
+ normalizedCode,
+ Prism.languages.html
+ );
+ panels[i].content = highlightedCode;
Dispatcher.trigger('checkPanels', [
panels,
patternData,
@@ -207,7 +272,7 @@ export const panelsViewer = {
}
}
- // add *Exists attributes for Hogan templates
+ // add *Exists attributes for Handlebars templates
// figure out if the description exists
patternData.patternDescExists =
patternData.patternDesc.length > 0 ||
@@ -239,8 +304,8 @@ export const panelsViewer = {
// render all of the panels in the base panel template
const template = document.querySelector('.pl-js-panel-template-base');
- const templateCompiled = Hogan.compile(template.innerHTML);
- templateRendered = templateCompiled.render(patternData);
+ const templateCompiled = Handlebars.compile(template.innerHTML);
+ templateRendered = templateCompiled(patternData);
// make sure templateRendered is modified to be an HTML element
const div = document.createElement('div');
@@ -273,18 +338,6 @@ export const panelsViewer = {
}
}
- // find lineage links in the rendered content and add postmessage handlers in case it's in the modal
- $('.pl-js-lineage-link', templateRendered).on('click', function(e) {
- e.preventDefault();
- const obj = JSON.stringify({
- event: 'patternLab.updatePath',
- path: urlHandler.getFileName($(this).attr('data-patternpartial')),
- });
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, panelsViewer.targetOrigin);
- });
-
// gather panels from plugins
Dispatcher.trigger('insertPanels', [
templateRendered,
@@ -307,19 +360,3 @@ export const panelsViewer = {
* 5) Add mouseup event to the body so that when drag is released, the modal
* stops resizing and modal cover doesn't display anymore.
*/
-$('.pl-js-modal-resizer').mousedown(function(event) {
- /* 1 */
-
- $('.pl-js-modal-cover').css('display', 'block'); /* 2 */
-
- $('.pl-js-modal-cover').mousemove(function(e) {
- /* 3 */
- const panelHeight = window.innerHeight - e.clientY + 32; /* 4 */
- $('.pl-js-modal').css('height', panelHeight + 'px'); /* 4 */
- });
-});
-
-$('body').mouseup(function() {
- $('.pl-js-modal').unbind('mousemove'); /* 5 */
- $('.pl-js-modal-cover').css('display', 'none'); /* 5 */
-});
diff --git a/packages/uikit-workshop/src/scripts/components/panels.js b/packages/uikit-workshop/src/scripts/components/panels.js
index 1b37959aa..52666e571 100644
--- a/packages/uikit-workshop/src/scripts/components/panels.js
+++ b/packages/uikit-workshop/src/scripts/components/panels.js
@@ -4,7 +4,7 @@
* note: config is coming from the default viewer and is passed through from PL's config
*/
-import { PrismLanguages } from './prism-languages';
+import { PrismLanguages as Prism } from './prism-languages';
import { Dispatcher } from '../utils';
export const Panels = {
@@ -15,7 +15,7 @@ export const Panels = {
},
get() {
- return JSON.parse(JSON.stringify(this.panels));
+ return JSON.parse(JSON.stringify(Panels.panels));
},
add(panel) {
@@ -46,45 +46,63 @@ export const Panels = {
},
};
-const fileSuffixPattern =
- window.config.outputFileSuffixes !== undefined &&
- window.config.outputFileSuffixes.rawTemplate !== undefined
- ? window.config.outputFileSuffixes.rawTemplate
- : '';
-const fileSuffixMarkup =
- window.config.outputFileSuffixes !== undefined &&
- window.config.outputFileSuffixes.markupOnly !== undefined
- ? window.config.outputFileSuffixes.markupOnly
- : '.markup-only';
+function init() {
+ // does the origin sending the message match the current host? if not dev/null the request
-// add the default panels
-// Panels.add({ 'id': 'pl-panel-info', 'name': 'info', 'default': true, 'templateID': 'pl-panel-template-info', 'httpRequest': false, 'prismHighlight': false, 'keyCombo': '' });
-// TODO: sort out pl-panel-html
-Panels.add({
- id: 'pl-panel-pattern',
- name: window.config.patternExtension.toUpperCase(),
- default: true,
- templateID: 'pl-panel-template-code',
- httpRequest: true,
- httpRequestReplace: fileSuffixPattern,
- httpRequestCompleted: false,
- prismHighlight: true,
- language: PrismLanguages.get(window.config.patternExtension),
- keyCombo: 'ctrl+shift+u',
-});
+ const fileSuffixPattern =
+ window.config.outputFileSuffixes !== undefined &&
+ window.config.outputFileSuffixes.rawTemplate !== undefined
+ ? window.config.outputFileSuffixes.rawTemplate
+ : '';
-Panels.add({
- id: 'pl-panel-html',
- name: 'HTML',
- default: false,
- templateID: 'pl-panel-template-code',
- httpRequest: true,
- httpRequestReplace: fileSuffixMarkup + '.html',
- httpRequestCompleted: false,
- prismHighlight: true,
- language: 'markup',
- keyCombo: 'ctrl+shift+y',
-});
+ const fileSuffixMarkup =
+ window.config.outputFileSuffixes !== undefined &&
+ window.config.outputFileSuffixes.markupOnly !== undefined
+ ? window.config.outputFileSuffixes.markupOnly
+ : '.markup-only';
+
+ // add the default panels
+ // Panels.add({ 'id': 'pl-panel-info', 'name': 'info', 'default': true, 'templateID': 'pl-panel-template-info', 'httpRequest': false, 'prismHighlight': false, 'keyCombo': '' });
+ const languages = Object.keys(Prism.languages);
+ // TODO: sort out pl-panel-html
+ Panels.add({
+ id: 'pl-panel-pattern',
+ name: window.config.patternExtension.toUpperCase(),
+ default:
+ !window.config.defaultPatternInfoPanelCode ||
+ window.config.defaultPatternInfoPanelCode ===
+ window.config.patternExtension,
+ templateID: 'pl-panel-template-code',
+ httpRequest: true,
+ httpRequestReplace: fileSuffixPattern,
+ httpRequestCompleted: false,
+ prismHighlight: true,
+ language: languages[window.config.patternExtension],
+ keyCombo: 'ctrl+shift+u',
+ });
+
+ Panels.add({
+ id: 'pl-panel-html',
+ name: 'HTML',
+ default:
+ window.config.defaultPatternInfoPanelCode &&
+ window.config.defaultPatternInfoPanelCode === 'html',
+ templateID: 'pl-panel-template-code',
+ httpRequest: true,
+ httpRequestReplace: fileSuffixMarkup + '.html',
+ httpRequestCompleted: false,
+ prismHighlight: true,
+ language: 'markup',
+ keyCombo: 'ctrl+shift+y',
+ });
+
+ if (!window.patternlab) {
+ window.patternlab = {};
+ }
+ window.patternlab.panels = Panels;
+}
// gather panels from plugins
Dispatcher.trigger('setupPanels');
+
+init();
diff --git a/packages/uikit-workshop/src/scripts/components/pl-copy-to-clipboard/pl-copy-to-clipboard.js b/packages/uikit-workshop/src/scripts/components/pl-copy-to-clipboard/pl-copy-to-clipboard.js
new file mode 100755
index 000000000..60cb46a8b
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-copy-to-clipboard/pl-copy-to-clipboard.js
@@ -0,0 +1,25 @@
+/**
+ * Copy to clipboard functionality for code snippet examples
+ */
+
+import Clipboard from 'clipboard';
+
+const clipboard = new Clipboard('.pl-js-code-copy-btn');
+clipboard.on('success', function (e) {
+ const copyButton = document.querySelectorAll('.pl-js-code-copy-btn');
+ for (let i = 0; i < copyButton.length; i++) {
+ copyButton[i].querySelector('.pl-c-code-copy-btn__icon-text').innerText =
+ 'Copy';
+ }
+ e.trigger.classList.add('is-copied');
+ e.trigger.querySelector('.pl-c-code-copy-btn__icon-text').textContent =
+ 'Copied';
+
+ setTimeout(() => {
+ e.trigger.classList.remove('is-copied');
+ e.trigger.querySelector('.pl-c-code-copy-btn__icon-text').textContent =
+ 'Copy';
+ e.clearSelection();
+ e.trigger.blur();
+ }, 2000);
+});
diff --git a/packages/uikit-workshop/src/scripts/components/pl-layout/pl-layout.js b/packages/uikit-workshop/src/scripts/components/pl-layout/pl-layout.js
deleted file mode 100644
index 7fa8b8e91..000000000
--- a/packages/uikit-workshop/src/scripts/components/pl-layout/pl-layout.js
+++ /dev/null
@@ -1,88 +0,0 @@
-import { define, props } from 'skatejs';
-import { h } from 'preact';
-import Hogan from 'hogan.js';
-const classNames = require('classnames');
-
-import { store } from '../../store.js'; // connect to redux
-import { BaseComponent } from '../base-component.js';
-
-import iFrameResize from 'iframe-resizer/js/iframeResizer.js';
-iFrameResize({
- checkOrigin: false,
- scrolling: false,
- heightCalculationMethod: 'documentElementOffset', // most accurate calculation in testing available options
- initCallback() {
- document.querySelector('.pl-js-iframe').classList.add('is-ready'); // toggles class that removes initial min-height styling
- },
-});
-
-@define
-class Layout extends BaseComponent {
- static is = 'pl-layout';
-
- constructor(self) {
- self = super(self);
- try {
- /* load pattern nav */
- const template = document.querySelector('.pl-js-pattern-nav-template');
- const templateCompiled = Hogan.compile(template.innerHTML);
- const templateRendered = templateCompiled.render(window.navItems);
- this.renderRoot.querySelector(
- '.pl-js-pattern-nav-target'
- ).innerHTML = templateRendered;
-
- /* load ish controls */
- const controlsTemplate = document.querySelector(
- '.pl-js-ish-controls-template'
- );
- const controlsTemplateCompiled = Hogan.compile(
- controlsTemplate.innerHTML
- );
- const controlsTemplateRendered = controlsTemplateCompiled.render(
- window.ishControls
- );
- this.renderRoot.querySelector(
- '.pl-js-controls'
- ).innerHTML = controlsTemplateRendered;
- } catch (e) {
- const message =
- 'Please generate your site before trying to view it.
';
- this.renderRoot.querySelector(
- '.pl-js-pattern-nav-target'
- ).innerHTML = message;
- }
- return self;
- }
-
- static props = {
- layoutMode: props.string,
- themeMode: props.string,
- };
-
- connected() {
- const state = store.getState();
- this.layoutMode = state.app.layoutMode;
- this.themeMode = state.app.themeMode;
- }
-
- get renderRoot() {
- return this;
- }
-
- _stateChanged(state) {
- this.layoutMode = state.app.layoutMode;
- this.themeMode = state.app.themeMode;
-
- const classes = classNames({
- [`pl-c-body--theme-${this.themeMode}`]: this.themeMode !== undefined,
- [`pl-c-body--theme-${
- this.layoutMode === 'vertical' ? 'sidebar' : 'horizontal'
- }`]:
- this.layoutMode !== undefined,
- });
-
- this.className = classes;
- }
-}
-
-export { Layout };
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/get-parents.js b/packages/uikit-workshop/src/scripts/components/pl-nav/get-parents.js
new file mode 100644
index 000000000..8b9ac4b61
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/get-parents.js
@@ -0,0 +1,18 @@
+export const getParents = (elem, selector) => {
+ // Set up a parent array
+ const parents = [];
+
+ // Push each parent element to the array
+ for (; elem && elem !== document; elem = elem.parentNode) {
+ if (selector) {
+ if (elem.matches(selector)) {
+ parents.push(elem);
+ }
+ continue;
+ }
+ parents.push(elem);
+ }
+
+ // Return our parent array
+ return parents;
+};
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/index.scss b/packages/uikit-workshop/src/scripts/components/pl-nav/index.scss
new file mode 100644
index 000000000..ef1048381
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/index.scss
@@ -0,0 +1,9 @@
+/*------------------------------------*\
+ #NAVIGATION
+\*------------------------------------*/
+
+@import './nav.scss';
+@import './nav-link.scss';
+@import './nav-list.scss';
+@import './nav-dropdown.scss';
+@import './nav-accordion.scss';
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav-accordion.scss b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-accordion.scss
new file mode 100644
index 000000000..e70a4d989
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-accordion.scss
@@ -0,0 +1,26 @@
+@import '../../../sass/scss/core.scss';
+
+.pl-c-nav__accordion {
+ background-color: inherit; // allows the nav's children inherit from the parent header
+ @include listReset();
+ @include accordionPanel();
+ display: flex;
+ flex-flow: row wrap;
+ opacity: 0;
+ visibility: hidden;
+}
+
+.is-open ~ .pl-c-nav__accordion {
+ visibility: visible;
+ max-height: none;
+ transform: translateY(0);
+ opacity: 1;
+
+ .pl-c-body--theme-horizontal & {
+ overflow: auto;
+
+ @media all and (min-width: $pl-bp-med) {
+ max-height: calc(100vh - #{$offset-top} - 2rem); /* 1 */
+ }
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav-dropdown.scss b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-dropdown.scss
new file mode 100644
index 000000000..0c461649b
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-dropdown.scss
@@ -0,0 +1,42 @@
+@import '../../../sass/scss/core.scss';
+
+/**
+ * Nav Dropdown
+ * 1) On larger screens, display as dropdowns that
+ * hangs over the header
+ */
+.pl-c-nav__dropdown {
+ @media all and (min-width: $pl-bp-med) {
+ position: absolute;
+ top: 100%; /* 1 */
+ left: 0;
+ min-width: 14rem;
+ border-radius: $pl-border-radius-med;
+ border-style: solid;
+ border-width: 1px;
+ box-shadow: 0 2px 5px rgba($pl-color-black, 0.1);
+ transition: all 0.2s ease;
+ transform: translateY(-12px);
+ z-index: 1;
+ transition: all $pl-animate-quick ease-out;
+
+ .pl-c-body--theme-sidebar & {
+ position: relative;
+ }
+ }
+
+ .pl-c-body--theme-light & {
+ border-color: rgba($pl-color-black, 0.2);
+ }
+
+ .pl-c-body--theme-dark & {
+ border-color: rgba($pl-color-white, 0.2);
+ }
+
+ .pl-c-body--theme-sidebar & {
+ border-width: 0;
+ transform: none;
+ box-shadow: none;
+ border-radius: 0;
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav-link.js b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-link.js
new file mode 100644
index 000000000..27d4b22cc
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-link.js
@@ -0,0 +1,47 @@
+// this line is required for rendering even if it is note used in the code
+import { h, Fragment } from 'preact';
+const classNames = require('classnames');
+
+export const NavLink = (props) => {
+ const classes = classNames('pl-c-nav__link', {
+ [`pl-c-nav__link--level-${props.level}`]: props.level !== undefined,
+ 'pl-c-nav__link--icon-only': props.iconOnly,
+ 'pl-c-nav__link--title': props.isTitle,
+ });
+
+ const Tag = props.href ? 'a' : 'button';
+
+ return (
+
+ {props.iconPos === 'before' && props.iconName && (
+ `,
+ }}
+ />
+ )}
+
+ {props.children}
+ {props.status && (
+
+ )}
+
+ {props.iconPos !== 'before' && props.iconName && (
+ `,
+ }}
+ />
+ )}
+
+ );
+};
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav-link.scss b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-link.scss
new file mode 100644
index 000000000..4950b1b8d
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-link.scss
@@ -0,0 +1,194 @@
+@import '../../../sass/scss/core.scss';
+
+/**
+ * Nav link
+ */
+.pl-c-nav__link {
+ @include linkStyle;
+ border: 0;
+ text-align: left;
+ text-decoration: none;
+ cursor: pointer;
+ outline: 0;
+ color: inherit;
+ display: flex;
+ align-items: center;
+ margin: 0; // remove default button margin in Safari
+ color: inherit;
+ flex-grow: 1;
+ flex-shrink: 1;
+ padding: 0.6rem 0.6rem;
+ flex-basis: calc(100% - 2.5rem);
+ position: relative;
+ height: var(--nav-item-height, auto);
+
+ &::after {
+ content: '';
+ pointer-events: none;
+ opacity: 0;
+ background-color: currentColor;
+ transition: opacity $pl-animate-quick ease-out;
+ position: absolute;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ display: block;
+ }
+
+ &:hover::after {
+ opacity: 0.1;
+ }
+
+ &:focus::after {
+ opacity: 0.1;
+ }
+
+ &:focus {
+ outline-offset: -1px;
+ outline: 1px dotted;
+ }
+
+ &--level-0 {
+ .pl-c-body--theme-sidebar & {
+ padding-left: 1.45rem;
+ }
+
+ @media all and (max-width: $pl-bp-med) {
+ padding-left: 1.45rem;
+ }
+ }
+
+ &--level-1 {
+ padding-left: $pl-space + ($pl-space * 0.5);
+ font-size: 0.85rem;
+ }
+
+ &--level-2 {
+ font-size: 0.825rem;
+ padding-left: $pl-space * 2 + ($pl-space * 0.25);
+ }
+
+ // top level nav links (categories)
+ &--title {
+ font-size: 0.8rem;
+ color: $pl-color-gray-20;
+ color: var(--theme-text, $pl-color-gray-20);
+
+ > .pl-c-nav__link-icon {
+ font-size: inherit;
+ }
+
+ .pl-c-body--theme-light & {
+ color: $pl-color-black;
+ color: var(--theme-text);
+ }
+ }
+
+ &.is-active:not(.pl-c-nav__link--title) {
+ box-shadow: inset 4px 0 0 #6c79d9;
+
+ // move the "active" border style to the bottom on ONLY the top level links (ex. "All")
+ @media all and (min-width: $pl-bp-med) {
+ &.pl-c-nav__link--level-0 {
+ .pl-c-body--theme-horizontal & {
+ box-shadow: inset 0 -4px 0 #6c79d9;
+ }
+ }
+ }
+ }
+}
+
+.pl-c-nav__link-text {
+ flex-grow: 1;
+ pointer-events: none;
+ display: flex;
+ align-items: center;
+}
+
+.pl-c-nav__link-icon {
+ margin-top: -0.5rem;
+ margin-bottom: -0.5rem;
+ pointer-events: none;
+ color: currentColor;
+ display: inline;
+ transition: all $pl-animate-quick ease-out;
+ transform: rotate(-90deg);
+ flex-grow: 0;
+ line-height: 0;
+ font-size: 1.3rem; // temp solution till new pl-button used in Navigation
+}
+
+.pl-c-nav__link.is-open > .pl-c-nav__link-icon,
+.pl-c-nav__link.is-open ~ .pl-c-nav__link > .pl-c-nav__link-icon {
+ transform: rotate(0);
+}
+
+// workaround to disable focus on links inside open panels within a closed dropdown
+.pl-c-nav__link:first-child:not(.is-open) ~ .pl-c-nav__list--panel {
+ .pl-c-nav__link {
+ visibility: hidden;
+ }
+}
+
+// workaround to disable focus on links inside open panels within a closed dropdown
+.is-open ~ .pl-c-nav__list--panel {
+ .pl-c-nav__link {
+ visibility: visible;
+ }
+}
+
+.pl-c-nav__link--icon-only {
+ position: relative;
+ width: 2.5rem !important;
+ height: 2.5rem !important;
+ padding: 0 !important;
+ display: inline-flex;
+ justify-content: center;
+ font-size: 0;
+ flex-basis: 2.5rem;
+ right: 0;
+ border: 2px solid transparent !important;
+ justify-content: center;
+ align-items: center;
+ color: currentColor;
+
+ // border to indicate which nav links have two specific actions
+ &::before {
+ opacity: 0.1;
+ right: 2.4rem;
+ width: 1px;
+ left: auto;
+ transform: translateY(-50%);
+ }
+
+ &::after {
+ opacity: 0;
+ width: 2.5rem;
+ left: 50%;
+ transform: translateY(-50%) translateX(-50%);
+ }
+
+ &::before,
+ &::after {
+ height: 2.5rem;
+ transition: opacity $pl-animate-quick ease-out;
+ content: '';
+ display: block;
+ position: absolute;
+ top: 50%;
+ background-color: currentColor;
+ }
+
+ &:hover {
+ &::after,
+ &:focus::after {
+ opacity: 0.1;
+ }
+ }
+
+ &:focus {
+ outline-offset: -1px;
+ outline: 1px dotted;
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav-list.js b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-list.js
new file mode 100644
index 000000000..b8538fa54
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-list.js
@@ -0,0 +1,89 @@
+/* eslint-disable no-unused-vars, no-shadow */
+// this line is required for rendering even if it is note used in the code
+import { h, Fragment } from 'preact';
+import { NavLink } from './nav-link';
+
+export const NavList = (props) => {
+ const { children, category, elem } = props;
+
+ const nonViewAllItems = elem.noViewAll
+ ? children.filter((item) => item.patternName !== 'View All')
+ : children.filter(
+ (item) =>
+ item.patternName !== 'View All' && !item.patternName.includes(' Docs')
+ );
+ const viewAllItems = elem.noViewAll
+ ? []
+ : children.filter((item) => item.patternName === 'View All');
+
+ return (
+
+ {viewAllItems.length > 0 ? (
+ viewAllItems.map((patternSubtypeItem) => (
+ <>
+
+ elem.handleClick(e, patternSubtypeItem.patternPartial)
+ }
+ state={patternSubtypeItem.patternState}
+ data-patternpartial={patternSubtypeItem.patternPartial}
+ >
+ {patternSubtypeItem.patternName === 'View All'
+ ? `${category}`
+ : patternSubtypeItem.patternName}
+
+
+ {nonViewAllItems.length >= 1 && (
+ elem.iconOnlyPanelToggle(e.target)}
+ >
+ {category}
+
+ )}
+ >
+ ))
+ ) : (
+ elem.panelToggle(e.target)}
+ >
+ {category}
+
+ )}
+
+ {((viewAllItems.length && nonViewAllItems.length) ||
+ viewAllItems.length === 0) && (
+
+ {nonViewAllItems.map((patternSubtypeItem) => (
+
+
+ elem.handleClick(e, patternSubtypeItem.patternPartial)
+ }
+ data-patternpartial={patternSubtypeItem.patternPartial}
+ status={patternSubtypeItem.patternState}
+ >
+ {patternSubtypeItem.patternName === 'View All'
+ ? `${category} Overview`
+ : patternSubtypeItem.patternName}
+
+
+ ))}
+
+ )}
+
+ );
+};
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav-list.scss b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-list.scss
new file mode 100644
index 000000000..0e01cf1c5
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav-list.scss
@@ -0,0 +1,37 @@
+@import '../../../sass/scss/core.scss';
+
+/**
+ * Nav list
+ * 1) appears as an
+ * 2) display as a horizontal list on larger screens
+ * 3) On small screens, move the nav list after the typeahead form field
+ */
+.pl-c-nav__list {
+ z-index: 1;
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ flex-shrink: 0; // helps prevent top-level nav items from occasionally wrapping to multiple lines
+ flex-grow: 1; // auto-fill extra space available
+ width: 100%;
+ max-width: 100%; // so content doesn't won't spill out horizontally
+ order: 2;
+ background-color: inherit; // allows the nav's children inherit from the parent header
+
+ @media all and (min-width: $pl-bp-med) {
+ display: flex; /* 2 */
+ order: 1;
+ }
+}
+
+/**
+ * Nav list item
+ */
+.pl-c-nav__list-item {
+ background-color: inherit; // allows the nav's children inherit from the parent header
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ flex-flow: row wrap;
+ width: 100%;
+}
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/nav.js
new file mode 100644
index 000000000..a38cf006c
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav.js
@@ -0,0 +1,308 @@
+/* eslint-disable no-unused-vars, no-shadow */
+import { define, props } from 'skatejs';
+// this line is required for rendering even if it is note used in the code
+import { h, Fragment } from 'preact';
+
+const classNames = require('classnames');
+
+import { getParents } from './get-parents';
+import { store } from '../../store.js'; // redux store
+import { BaseComponent } from '../base-component.js';
+import Mousetrap from 'mousetrap';
+
+import { NavLink } from './nav-link';
+import { NavList } from './nav-list';
+import { iframeMsgDataExtraction } from '../../utils';
+
+@define
+class Nav extends BaseComponent {
+ static is = 'pl-nav';
+
+ static props = {
+ autoClose: {
+ ...props.boolean,
+ ...{ default: true },
+ },
+ currentPattern: props.string,
+ layoutMode: props.string,
+ collapsedByDefault: {
+ ...props.boolean,
+ ...{ default: true },
+ },
+ noViewAll: {
+ ...props.boolean,
+ ...{ default: window.config?.theme?.noViewAll || false },
+ },
+ };
+
+ constructor(self) {
+ self = super(self);
+ self.panelToggle = self.panelToggle.bind(self);
+ self.iconOnlyPanelToggle = self.iconOnlyPanelToggle.bind(self);
+ self.handleClick = self.handleClick.bind(self);
+ self.handleTopLevelNavClick = self.handleTopLevelNavClick.bind(self);
+ self.handleURLChange = self.handleURLChange.bind(self);
+ self.handlePageClick = self.handlePageClick.bind(self);
+ self._hasInitiallyRendered = false;
+ self.receiveIframeMessage = self.receiveIframeMessage.bind(self);
+ self.useShadow = false;
+ return self;
+ }
+
+ handlePageClick(e) {
+ if (
+ e.target.closest &&
+ e.target.closest('.pl-c-nav') === null &&
+ e.target.closest('.pl-js-nav-trigger') === null &&
+ e.target.closest('svg') === null &&
+ e.target.closest('pl-toggle-layout') === null
+ ) {
+ if (this.layoutMode !== 'vertical' && window.innerWidth > 670) {
+ this.cleanupActiveNav(true);
+ }
+ }
+ }
+
+ connected() {
+ this.isOpenClass = 'is-open';
+ const state = store.getState();
+ this.layoutMode = state.app.layoutMode || '';
+ this.currentPattern = state.app.currentPattern || '';
+ this.elem = this;
+ this.previouslyActiveLinks = [];
+ this.iframeElem = document.querySelector('pl-iframe');
+
+ window.addEventListener('message', this.receiveIframeMessage, false);
+ document.body.addEventListener('click', this.handlePageClick);
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+
+ Mousetrap.bind('esc', () => {
+ if (this.layoutMode !== 'vertical' && window.innerWidth > 670) {
+ this.cleanupActiveNav(true);
+ }
+ });
+ }
+
+ disconnected() {
+ super.disconnected && super.disconnected();
+ document.body.removeEventListener('click', this.handlePageClick);
+ window.removeEventListener('message', this.receiveIframeMessage);
+ }
+
+ _stateChanged(state) {
+ if (this.layoutMode !== state.app.layoutMode) {
+ this.layoutMode = state.app.layoutMode || '';
+ }
+
+ if (
+ state.app.currentPattern &&
+ this.currentPattern !== state.app.currentPattern
+ ) {
+ this.currentPattern = state.app.currentPattern;
+ this.handleURLChange(); // so the nav logic is always correct (ex. layout changes)
+ }
+ }
+
+ receiveIframeMessage(event) {
+ const self = this;
+ const data = iframeMsgDataExtraction(event);
+
+ if (data.event !== undefined && data.event === 'patternLab.pageClick') {
+ try {
+ if (self.layoutMode !== 'vertical') {
+ self.cleanupActiveNav(true);
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ }
+
+ /**
+ * Helper method that partially cleans up the active nav links
+ * @param {boolean} topLevelOnly - only clean up the top most level nav links
+ * @param {Node} exceptFor - optionally specify an element to skip cleaning up
+ */
+ cleanupActiveNav(topLevelOnly, exceptFor) {
+ this.navContainer = document.querySelector('.pl-js-nav-container');
+ this.topLevelTriggers = document.querySelectorAll(
+ '.pl-c-nav__link--title.is-open'
+ );
+
+ if (topLevelOnly === true && window.innerWidth > 670) {
+ this.navContainer.classList.remove('is-open');
+ this.topLevelTriggers.forEach((trigger) => {
+ if (trigger !== exceptFor || exceptFor === undefined) {
+ trigger.classList.remove('is-open');
+ }
+ });
+ } else {
+ this.navContainer.classList.remove('is-open');
+ }
+ }
+
+ handleClick(event, pattern) {
+ event.preventDefault();
+ this.iframeElem.navigateTo(pattern);
+ this.cleanupActiveNav();
+ }
+
+ // auto-close other top level nav dropdowns on larger screens
+ handleTopLevelNavClick(e) {
+ if (this.layoutMode !== 'vertical' && window.innerWidth > 670) {
+ this.cleanupActiveNav(true, e.target);
+ }
+ this.panelToggle(e.target);
+ }
+
+ handleURLChange() {
+ const currentPattern = this.currentPattern;
+ this.activeLink = document.querySelector(
+ `[data-patternpartial="${currentPattern}"]`
+ );
+
+ if (this.previouslyActiveLinks) {
+ this.previouslyActiveLinks.forEach((link, index) => {
+ this.previouslyActiveLinks[index].classList.remove('is-open');
+ this.previouslyActiveLinks[index].classList.remove('is-active');
+ });
+ }
+ this.previouslyActiveLinks = [];
+
+ if (this.activeLink) {
+ this.activeLink.classList.add('is-active');
+
+ const triggers = [this.activeLink];
+ const panels = Array.from(
+ getParents(this.activeLink, '.pl-js-nav-accordion')
+ );
+
+ panels.forEach((panel) => {
+ const panelTrigger = panel.previousSibling;
+ if (panelTrigger) {
+ if (panelTrigger.previousSibling) {
+ triggers.push(panelTrigger.previousSibling);
+ } else {
+ triggers.push(panelTrigger);
+ }
+ }
+ });
+
+ triggers.forEach((trigger) => {
+ trigger.classList.add('is-open');
+ this.previouslyActiveLinks.push(trigger);
+ });
+ }
+ }
+
+ iconOnlyPanelToggle(target) {
+ target.previousSibling.classList.toggle('is-open');
+ }
+
+ panelToggle(target) {
+ target.classList.toggle('is-open');
+ }
+
+ rendered() {
+ if (this._hasInitiallyRendered === false) {
+ this._hasInitiallyRendered = true;
+ }
+
+ if (!this.activeLink) {
+ this.handleURLChange();
+ }
+
+ if (this.layoutMode !== 'vertical' && window.innerWidth > 670) {
+ this.cleanupActiveNav(true);
+ }
+ }
+
+ render({ layoutMode }) {
+ const patternGroups = window.navItems.patternGroups;
+
+ return (
+
+ {patternGroups.map((item, i) => {
+ const classes = classNames('pl-c-nav__list-item');
+ const patternItems = item.patternItems;
+
+ return (
+
+
+ {item.patternGroupLC}
+
+
+ {item.patternGroupItems.map((patternSubgroup, i) => {
+ return (
+
+ {patternSubgroup.patternSubgroupItems}
+
+ );
+ })}
+
+ {patternItems &&
+ patternItems.map((patternItem, i) => {
+ return this.noViewAll &&
+ patternItem.patternPartial.includes('viewall') ? (
+ ''
+ ) : (
+
+
+ this.handleClick(e, patternItem.patternPartial)
+ }
+ data-patternpartial={patternItem.patternPartial}
+ state={patternItem.patternState}
+ >
+ {patternItem.patternName === 'View All'
+ ? patternItem.patternName + ' ' + item.patternTypeUC
+ : patternItem.patternName}
+
+
+ );
+ })}
+
+
+ );
+ })}
+
+ {/* display the All link if window.ishControlsHide is undefined (for some reason) OR window.ishControls.ishControlsHide doesn't have `views-all` and/or `all` set to true */}
+ {(window.ishControls === undefined ||
+ window.ishControls.ishControlsHide === undefined ||
+ (window.ishControls.ishControlsHide['views-all'] !== true &&
+ window.ishControls.ishControlsHide.all !== true)) &&
+ !this.noViewAll && (
+
+ this.handleClick(e, 'all')}
+ href="styleguide/html/styleguide.html"
+ level={0}
+ data-patternpartial="all"
+ >
+ All
+
+
+ )}
+
+ );
+ }
+}
+
+export { Nav };
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/nav.scss b/packages/uikit-workshop/src/scripts/components/pl-nav/nav.scss
new file mode 100644
index 000000000..9a2c1e682
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/nav.scss
@@ -0,0 +1,137 @@
+/*------------------------------------*\
+ #NAVIGATION
+\*------------------------------------*/
+
+pl-nav {
+ background-color: inherit; // so the inside of dropdowns inherits the correct color
+ display: block; // vertically align children
+ flex-grow: 1;
+ align-items: center;
+
+ @media all and (min-width: $pl-bp-med) {
+ padding: 0;
+ display: flex; // vertically align children
+ }
+
+ .pl-c-body--theme-sidebar & {
+ display: block;
+ max-height: 100%;
+ overflow-y: scroll;
+ }
+}
+
+/**
+ * Navigation container
+ * 1) Collapse height on small screens. Menu trigger button
+ * activates nav
+ */
+.pl-c-nav {
+ @include accordionPanel;
+ background-color: inherit; // allows the nav's children inherit from the parent header
+ position: absolute;
+ left: 0; // IE 11 layout broken
+ top: 100%;
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ transition: max-height $pl-animate-quick ease-out;
+ flex-shrink: 1;
+ visibility: hidden;
+ transition: transform 0.2s ease-out, opacity 0 0.2s ease-out;
+
+ @media all and (max-width: $pl-bp-med) {
+ position: fixed;
+ top: 44px;
+ bottom: 0;
+ height: auto;
+ z-index: -1;
+ }
+
+ &.pl-is-active {
+ visibility: visible;
+ opacity: 1;
+ }
+
+ .pl-c-body--theme-sidebar & {
+ display: block;
+ display: flex;
+ overflow: hidden;
+ visibility: visible;
+ flex-shrink: 0;
+
+ @media all and (min-height: 500px) {
+ flex-shrink: 1;
+ }
+
+ @media all and (max-width: $pl-bp-med) {
+ max-width: 240px;
+
+ position: fixed;
+ top: 44px;
+ bottom: 0;
+ height: auto;
+ max-height: calc(100% - 2rem);
+ overflow: auto;
+ -webkit-overflow-scrolling: touch;
+ transform: translateX(-100%);
+ transition: all 0.3s ease;
+ opacity: 0;
+ box-shadow: 0 3px 6px rgba(21, 22, 25, 0.16),
+ 0 3px 6px rgba(21, 22, 25, 0.23);
+ visibility: visible;
+
+ &.pl-is-active {
+ transform: translateX(0);
+ opacity: 1;
+ transition: transform 0.2s ease-out;
+ }
+ }
+ }
+
+ @media all and (max-width: $pl-bp-med) {
+ &.is-open {
+ padding-top: 1rem;
+ padding-bottom: 1rem;
+ }
+ }
+
+ // if nav was opened on smaller screen and screen is resized, it'll be cut off otherwise
+ @media all and (min-width: $pl-bp-med) {
+ overflow: visible;
+ max-height: none;
+ visibility: visible;
+
+ &.is-open {
+ overflow: visible;
+ }
+ }
+
+ /**
+ * Active navigaiton
+ * 1) Slide
+ * 2) Set the height to the vierport height minus the height
+ * of the header
+ */
+ &.is-open {
+ @media all and (max-width: $pl-bp-med - 1) {
+ box-shadow: 0 2px 4px $pl-color-black;
+
+ .pl-c-body--theme-light & {
+ box-shadow: 0 2px 4px darken($pl-color-gray-20, 15%);
+ }
+ }
+
+ // if nav was opened on smaller screen and screen is resized, it'll be cut off otherwise
+ @media all and (min-width: $pl-bp-med) {
+ max-height: none;
+ }
+ }
+
+ @media all and (min-width: $pl-bp-med) {
+ flex-direction: row;
+ position: relative;
+ top: auto;
+ width: auto;
+ box-shadow: none;
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.iframe-helper.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.iframe-helper.js
new file mode 100644
index 000000000..5b2a0fd13
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.iframe-helper.js
@@ -0,0 +1,32 @@
+// Tiny helper script to listen for keyboard combos and to communicate back to the main Search component (via the Pattern Lab iframe)
+import Mousetrap from 'mousetrap';
+import { targetOrigin } from '../../utils';
+
+document.addEventListener('click', function () {
+ try {
+ const obj = JSON.stringify({
+ event: 'patternLab.pageClick',
+ });
+ window.parent.postMessage(obj, targetOrigin);
+ } catch (error) {
+ // @todo: how do we want to handle exceptions here?
+ }
+});
+
+Mousetrap.bind('esc', function (e) {
+ try {
+ const obj = JSON.stringify({
+ event: 'patternLab.keyPress',
+ key: e.key,
+ altKey: e.altKey,
+ ctrlKey: e.ctrlKey,
+ metaKey: e.metaKey,
+ shiftKey: e.shiftKey,
+ });
+ window.parent.postMessage(obj, targetOrigin);
+ } catch (error) {
+ // @todo: how do we want to handle exceptions here?
+ }
+
+ return false;
+});
diff --git a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.iframe-helper.js b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.iframe-helper.js
index f330c8cd7..b62896af0 100644
--- a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.iframe-helper.js
+++ b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.iframe-helper.js
@@ -2,7 +2,7 @@
import Mousetrap from 'mousetrap';
import { targetOrigin } from '../../utils';
-Mousetrap.bind('command+shift+f', function(e) {
+Mousetrap.bind('command+shift+f', function (e) {
e.preventDefault();
try {
diff --git a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js
index c27480a44..8aa566a73 100644
--- a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js
+++ b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.js
@@ -1,22 +1,23 @@
+/* eslint-disable no-unused-vars, no-param-reassign */
import { define, props } from 'skatejs';
import { h } from 'preact';
+import { store } from '../../store.js'; // connect to redux
+
import Fuse from 'fuse.js';
import ReactHtmlParser from 'react-html-parser';
import classNames from 'classnames';
import Mousetrap from 'mousetrap';
-
-import VisuallyHidden from '@reach/visually-hidden';
import Autosuggest from 'react-autosuggest';
-import { urlHandler } from '../../utils';
+import { urlHandler, iframeMsgDataExtraction } from '../../utils';
import { BaseComponent } from '../base-component';
@define
class Search extends BaseComponent {
static is = 'pl-search';
- constructor(self) {
- self = super(self);
+ constructor() {
+ super();
this.useShadow = false;
this.defaultMaxResults = 10;
@@ -28,42 +29,48 @@ class Search extends BaseComponent {
this.state = {
value: '',
suggestions: [],
+ isFocused: false,
};
this.receiveIframeMessage = this.receiveIframeMessage.bind(this);
this.onChange = this.onChange.bind(this);
this.toggleSearch = this.toggleSearch.bind(this);
- // this.clearSearch = this.clearSearch.bind(this);
this.closeSearch = this.closeSearch.bind(this);
this.renderInputComponent = this.renderInputComponent.bind(this);
this.openSearch = this.openSearch.bind(this);
+ }
+
+ connecting() {
+ super.connecting && super.connecting();
this.items = [];
- for (const patternType in window.patternPaths) {
- if (window.patternPaths.hasOwnProperty(patternType)) {
- for (const pattern in window.patternPaths[patternType]) {
- if (window.patternPaths[patternType].hasOwnProperty(pattern)) {
+ for (const patternGroup in window.patternPaths) {
+ if (window.patternPaths.hasOwnProperty(patternGroup)) {
+ for (const pattern in window.patternPaths[patternGroup]) {
+ if (window.patternPaths[patternGroup].hasOwnProperty(pattern)) {
const obj = {};
- obj.label = patternType + '-' + pattern;
- obj.id = window.patternPaths[patternType][pattern];
+ obj.label = patternGroup + '-' + pattern;
+ obj.id = window.patternPaths[patternGroup][pattern];
this.items.push(obj);
}
}
}
}
-
- return self;
}
connected() {
- const self = this;
- Mousetrap.bind('command+shift+f', function(e) {
+ Mousetrap.bind('command+shift+f', function (e) {
e.preventDefault();
- self.toggleSearch();
+ this.toggleSearch();
});
window.addEventListener('message', this.receiveIframeMessage, false);
}
+ _stateChanged(state) {
+ // throw new Error('_stateChanged() not implemented', this);
+ this.triggerUpdate();
+ }
+
rendered() {
this.inputElement = this.querySelector('.js-c-typeahead__input');
}
@@ -75,8 +82,8 @@ class Search extends BaseComponent {
clearButtonText: props.string,
};
- onInput = e => {
- let value = e.target.value;
+ onInput = (e) => {
+ const value = e.target.value;
this.setState({
value: value,
@@ -85,9 +92,6 @@ class Search extends BaseComponent {
this.onSuggestionsFetchRequested({ value }); // re-render search results immediately based on latest input value
};
- // External Redux store not yet in use
- _stateChanged(state) {}
-
toggleSearch() {
if (!this.state.isOpen) {
this.openSearch();
@@ -111,22 +115,12 @@ class Search extends BaseComponent {
document.activeElement.blur();
}
- receiveIframeMessage(event) {
- // does the origin sending the message match the current host? if not dev/null the request
- if (
- window.location.protocol !== 'file:' &&
- event.origin !== window.location.protocol + '//' + window.location.host
- ) {
- return;
- }
-
- let data = {};
- try {
- data =
- typeof event.data !== 'string' ? event.data : JSON.parse(event.data);
- } catch (e) {
- // @todo: how do we want to handle exceptions here?
- }
+ /**
+ *
+ * @param {MessageEvent} e A message received by a target object.
+ */
+ receiveIframeMessage(e) {
+ const data = iframeMsgDataExtraction(e);
if (data.event !== undefined && data.event === 'patternLab.keyPress') {
if (data.key === 'f' && data.metaKey === true) {
@@ -135,7 +129,7 @@ class Search extends BaseComponent {
}
}
- getSuggestionValue = suggestion => suggestion.label;
+ getSuggestionValue = (suggestion) => suggestion.label;
renderSuggestion(item, { query, isHighlighted }) {
return {item.highlightedLabel} ;
@@ -150,20 +144,18 @@ class Search extends BaseComponent {
const fuseOptions = {
shouldSort: true,
threshold: 0.3,
- tokenize: true,
includeMatches: true,
location: 0,
distance: 100,
- maxPatternLength: 32,
minMatchCharLength: 1,
keys: ['label'],
};
const fuse = new Fuse(this.items, fuseOptions);
const results = fuse.search(value);
- const highlighter = function(item) {
+ const highlighter = function (item) {
const resultItem = item;
- resultItem.matches.forEach(matchItem => {
+ resultItem.matches.forEach((matchItem) => {
const text = resultItem.item[matchItem.key];
const result = [];
const matches = [].concat(matchItem.indices);
@@ -187,14 +179,14 @@ class Search extends BaseComponent {
);
if (resultItem.children && resultItem.children.length > 0) {
- resultItem.children.forEach(child => {
+ resultItem.children.forEach((child) => {
highlighter(child);
});
}
});
};
- results.forEach(resultItem => {
+ results.forEach((resultItem) => {
highlighter(resultItem);
});
@@ -215,14 +207,7 @@ class Search extends BaseComponent {
const patternName = urlHandler.getFileName(newValue);
if (patternName) {
- const obj = JSON.stringify({
- event: 'patternLab.updatePath',
- path: patternName,
- });
-
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, urlHandler.targetOrigin);
+ document.querySelector('pl-iframe').navigateTo(newValue);
}
this.setState({
@@ -254,7 +239,8 @@ class Search extends BaseComponent {
return (
@@ -266,8 +252,9 @@ class Search extends BaseComponent {
onClick={() => {
this.clearSearch();
}}
+ type="button"
>
-
{clearButtonText}
+
{clearButtonText}
+
);
}
}
diff --git a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.scss b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.scss
index 94e6d3a4e..7daf4614e 100644
--- a/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.scss
+++ b/packages/uikit-workshop/src/scripts/components/pl-search/pl-search.scss
@@ -13,24 +13,29 @@ $pl-clear-button-size-at-med: 1.4rem;
pl-search {
background-color: inherit;
- order: 2; // Display after nav list items
top: 0;
- z-index: 10;
flex-shrink: 0;
- padding: 0.3rem 0.5rem;
+ padding: 0.4rem 0.5rem;
display: inline-block;
+ align-self: stretch;
+ transition: all 0.2s ease;
@media screen and (min-width: $pl-bp-med) {
- margin-left: 1rem;
flex-direction: row;
flex-shrink: 1;
+ order: 2; // Display after nav list items on wider screens
+ align-self: center;
+
+ // grow in size when focusing on inner input
+ &:focus-within {
+ flex-shrink: 0.5;
+ }
.pl-c-body--theme-sidebar & {
flex-direction: column;
margin-left: 0;
- padding-left: 0;
- padding-right: 0;
width: 100%;
+ margin-bottom: 0.5rem;
}
}
}
@@ -75,23 +80,27 @@ pl-search {
text-transform: capitalize;
background-color: $pl-color-gray-87;
color: $pl-color-white;
- border-color: darken($pl-color-gray-87, 10%);
+ background-color: rgba(var(--theme-text-rgb), 0.05);
+ color: rgba(var(--theme-text-rgb), 0.67);
+ border-color: rgba(0, 0, 0, 0.1);
+ border-color: rgba(var(--theme-text-rgb), 0.17);
text-overflow: ellipsis;
border-width: 1px;
border-style: solid;
transition: all 0.1s ease;
max-width: 100%;
- padding: 0.31rem 0.5rem;
+ padding: 0.4rem 0.5rem;
font-size: 16px; // prevent zooming in on mobile
width: 100%;
outline-offset: -3px;
outline-width: 2px;
+ border-radius: 3px;
-webkit-appearance: none; // removes default styling (ex. heavy box shadow) in Safari
@media all and (min-width: 900px) {
font-size: inherit;
}
-
+
// Remove the native
clear button in IE 11 in lieu of JS-controlled clear button
&::-ms-clear {
display: none;
@@ -111,7 +120,6 @@ pl-search {
}
@media all and (min-width: $pl-bp-med) {
-
.pl-c-body--theme-sidebar & {
max-width: none;
}
@@ -119,11 +127,26 @@ pl-search {
.pl-c-body--theme-light & {
background-color: $pl-color-gray-07;
- color: $pl-color-gray-70 !important;
- border-color: $pl-color-gray-13 !important;
+ background-color: rgba(var(--theme-text-rgb), 0.05);
+ color: $pl-color-gray-70;
+ color: rgba(var(--theme-text-rgb), 0.67);
+
+ &::-webkit-input-placeholder {
+ color: black !important;
+ transition: all 0.1s ease;
+ }
+
+ &::-moz-input-placeholder {
+ color: black !important;
+ transition: all 0.1s ease;
+ }
+ }
+
+ &::-webkit-input-placeholder {
+ color: $pl-color-white !important;
+ transition: all 0.1s ease;
}
- &::-webkit-input-placeholder,
&::-moz-input-placeholder {
color: $pl-color-white !important;
transition: all 0.1s ease;
@@ -132,12 +155,9 @@ pl-search {
&:hover,
&:focus {
color: $pl-color-white;
- background-color: darken($pl-color-gray-87, 2%) !important;
.pl-c-body--theme-light & {
color: $pl-color-gray-87 !important;
- background-color: $pl-color-gray-13 !important;
- border-color: $pl-color-gray-20 !important;
}
&::-moz-input-placeholder,
@@ -154,6 +174,8 @@ pl-search {
.pl-c-typeahead__menu {
@include accordionPanel;
background-color: $pl-color-gray-87;
+ background-color: var(--theme-primary);
+ color: var(--theme-text);
text-transform: capitalize;
position: absolute;
min-width: 100%;
@@ -176,8 +198,8 @@ pl-search {
}
&.pl-is-open {
- max-height: 120rem;
- max-height: calc(var(--viewport-height) - 4rem);
+ max-height: 90vh;
+ overflow: auto;
opacity: 1;
}
@@ -229,14 +251,20 @@ pl-search {
.pl-c-typeahead__result {
transition: all 0.3s ease;
background-color: inherit;
- padding: 0.8em;
+ padding: 0.5rem 0.75rem;
cursor: pointer;
overflow: hidden;
+ font-size: 0.8rem;
+ color: inherit;
&:last-child {
border-bottom-right-radius: $pl-border-radius-med;
border-bottom-left-radius: $pl-border-radius-med;
+ @media all and (max-width: $pl-bp-med - 1) {
+ border-radius: 0;
+ }
+
.pl-c-body--theme-sidebar & {
border-radius: 0;
}
@@ -272,6 +300,7 @@ pl-search {
.pl-c-typeahead__input-wrapper {
position: relative; // used for positioning search clear button in relation to the
+ flex-shrink: 1;
}
.pl-c-typeahead__clear-button {
diff --git a/packages/uikit-workshop/src/scripts/components/pl-toggle-layout/pl-toggle-layout.js b/packages/uikit-workshop/src/scripts/components/pl-toggle-layout/pl-toggle-layout.js
deleted file mode 100644
index 5c32b282b..000000000
--- a/packages/uikit-workshop/src/scripts/components/pl-toggle-layout/pl-toggle-layout.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import { define, props } from 'skatejs';
-import { h } from 'preact';
-
-import { store } from '../../store.js'; // connect to the Redux store.
-import { updateLayoutMode } from '../../actions/app.js'; // redux actions
-import { BaseComponent } from '../base-component.js';
-
-import './pl-toggle-layout.scss?external';
-import styles from './pl-toggle-layout.scss';
-
-@define
-class LayoutToggle extends BaseComponent {
- static is = 'pl-toggle-layout';
-
- constructor(self) {
- self = super(self);
- this.useShadow = false;
- return self;
- }
-
- connected() {
- const state = store.getState();
- this.layoutMode = state.app.layoutMode || 'vertical';
- store.dispatch(updateLayoutMode(this.layoutMode));
- }
-
- static props = {
- layoutMode: props.string,
- text: props.string,
- };
-
- _stateChanged(state) {
- if (this.layoutMode !== state.app.layoutMode) {
- this.layoutMode = state.app.layoutMode;
- }
- }
-
- render({ layoutMode, text }) {
- const toggleLayoutMode =
- layoutMode !== 'vertical' ? 'vertical' : 'horizontal';
- return (
-
- {this._renderStyles([styles])}
-
store.dispatch(updateLayoutMode(toggleLayoutMode))}
- >
- {text && {text} }
-
-
- {layoutMode === 'horizontal' ? (
-
-
-
- ) : (
-
-
-
- )}
-
-
-
- );
- }
-}
-
-export { LayoutToggle };
diff --git a/packages/uikit-workshop/src/scripts/components/pl-toggle-theme/pl-toggle-theme.js b/packages/uikit-workshop/src/scripts/components/pl-toggle-theme/pl-toggle-theme.js
deleted file mode 100644
index 776a429ea..000000000
--- a/packages/uikit-workshop/src/scripts/components/pl-toggle-theme/pl-toggle-theme.js
+++ /dev/null
@@ -1,92 +0,0 @@
-import { define, props } from 'skatejs';
-import { h } from 'preact';
-
-import { store } from '../../store.js'; // connect to the Redux store.
-import { updateThemeMode } from '../../actions/app.js'; // redux actions needed
-import { BaseComponent } from '../base-component.js';
-
-import './pl-toggle-theme.scss?external';
-import styles from './pl-toggle-theme.scss';
-
-@define
-class ThemeToggle extends BaseComponent {
- static is = 'pl-toggle-theme';
-
- constructor(self) {
- self = super(self);
- this.useShadow = false;
- return self;
- }
-
- connected() {
- const state = store.getState();
- this.themeMode = state.app.themeMode || 'dark';
- store.dispatch(updateThemeMode(this.themeMode));
- }
-
- static props = {
- themeMode: props.string,
- };
-
- _stateChanged(state) {
- this.themeMode = state.app.themeMode;
- }
-
- render({ themeMode }) {
- const toggleThemeMode = this.themeMode !== 'dark' ? 'dark' : 'light';
- return (
-
- {this._renderStyles([styles])}
-
store.dispatch(updateThemeMode(toggleThemeMode))}
- >
- Switch Theme
-
-
- {themeMode === 'dark' ? (
-
-
-
-
-
-
-
-
-
-
-
- ) : (
-
-
-
- )}
-
-
-
- );
- }
-}
-
-export { ThemeToggle };
diff --git a/packages/uikit-workshop/src/scripts/components/plugin-loader.js b/packages/uikit-workshop/src/scripts/components/plugin-loader.js
index 239e1b992..7a7cc5c64 100644
--- a/packages/uikit-workshop/src/scripts/components/plugin-loader.js
+++ b/packages/uikit-workshop/src/scripts/components/plugin-loader.js
@@ -10,7 +10,7 @@ const scriptjs = require('scriptjs');
export const pluginLoader = {
init() {
for (let i = 0; i < window.plugins.length; ++i) {
- const plugin = window.lugins[i];
+ const plugin = window.plugins[i];
// load the templates
for (const key in plugin.templates) {
diff --git a/packages/uikit-workshop/src/scripts/components/prism-languages.js b/packages/uikit-workshop/src/scripts/components/prism-languages.js
index 11a807c46..c418f9194 100644
--- a/packages/uikit-workshop/src/scripts/components/prism-languages.js
+++ b/packages/uikit-workshop/src/scripts/components/prism-languages.js
@@ -1,45 +1,17 @@
-/**
- * Default languages for Prism to match rendering capability
- */
-
-export const PrismLanguages = {
- languages: [],
-
- get(key) {
- let language;
-
- for (let i = 0; i < this.languages.length; ++i) {
- language = this.languages[i];
- if (language[key] !== undefined) {
- return language[key];
- }
- }
-
- return 'markup';
- },
-
- add(language) {
- // see if the language already exists, overwrite if it does
- for (const key in language) {
- if (language.hasOwnProperty(key)) {
- for (let i = 0; i < this.languages.length; ++i) {
- if (this.languages[i][key] !== undefined) {
- this.languages[i][key] = language[key];
- return;
- }
- }
- }
- }
-
- this.languages.push(language);
- },
-};
-
-// this shouldn't get hardcoded, also need to think about including Prism's real lang libraries (e.g. handlebars & twig)
-PrismLanguages.add({
- twig: 'markup',
-});
-
-PrismLanguages.add({
- mustache: 'markup',
-});
+import Prism from 'prismjs/components/prism-core';
+import 'prismjs/components/prism-markup-templating';
+import 'prismjs/components/prism-markup';
+import 'prismjs/components/prism-twig';
+import 'prismjs/components/prism-clike';
+import 'prismjs/components/prism-javascript';
+import 'prismjs/components/prism-typescript';
+import 'prismjs/components/prism-json';
+import 'prismjs/components/prism-css';
+import 'prismjs/components/prism-css-extras';
+import 'prismjs/components/prism-scss';
+import 'prismjs/components/prism-bash';
+import 'prismjs/components/prism-markdown';
+import 'prismjs/components/prism-yaml';
+import 'prismjs/components/prism-handlebars';
+
+export const PrismLanguages = Prism;
diff --git a/packages/uikit-workshop/src/scripts/components/styleguide.js b/packages/uikit-workshop/src/scripts/components/styleguide.js
index 1e996eec9..86dcc7a7e 100644
--- a/packages/uikit-workshop/src/scripts/components/styleguide.js
+++ b/packages/uikit-workshop/src/scripts/components/styleguide.js
@@ -2,688 +2,528 @@
* Styleguide.js - misc UI logic for Pattern Lab that needs refactoring
*/
-import $ from 'jquery';
-import Mousetrap from 'mousetrap';
-import { urlHandler, DataSaver } from '../utils';
-
-(function(w) {
- let sw = document.body.clientWidth; //Viewport Width
-
- let minViewportWidth = 240;
- let maxViewportWidth = 2600;
-
- //set minimum and maximum viewport based on confg
- if (window.config.ishMinimum !== undefined) {
- minViewportWidth = parseInt(window.config.ishMinimum, 10); //Minimum Size for Viewport
- }
- if (window.config.ishMaximum !== undefined) {
- maxViewportWidth = parseInt(window.config.ishMaximum, 10); //Maxiumum Size for Viewport
- }
-
- //alternatively, use the ishViewportRange object
- if (window.config.ishViewportRange !== undefined) {
- minViewportWidth = window.config.ishViewportRange.s[0];
- maxViewportWidth = window.config.ishViewportRange.l[1];
- }
-
- //if both are set, then let's use the larger one.
- if (window.config.ishViewportRange && window.config.ishMaximum) {
- const largeRange = parseInt(window.config.ishViewportRange.l[1], 10);
- const ishMaximum = parseInt(window.config.ishMaximum, 10);
- maxViewportWidth = largeRange > ishMaximum ? largeRange : ishMaximum;
- }
-
- const viewportResizeHandleWidth = 14; //Width of the viewport drag-to-resize handle
- const $sgIframe = $('.pl-js-iframe'); //Viewport element
- const $sizePx = $('#pl-size-px'); //Px size input element in toolbar
- const $sizeEms = $('#pl-size-em'); //Em size input element in toolbar
- const $bodySize =
- window.config.ishFontSize !== undefined
- ? parseInt(window.config.ishFontSize, 10)
- : parseInt($('body').css('font-size'), 10); //Body size of the document
- let discoID = false;
- let discoMode = false;
- let fullMode = true;
- let hayMode = false;
-
- //Update dimensions on resize
- $(w).resize(function() {
- sw = document.body.clientWidth;
-
- if (fullMode === true) {
- sizeiframe(sw, false);
- }
- });
-
- // Nav menu button on small screens
- $('.pl-js-nav-trigger').on('click', function(e) {
- e.preventDefault();
- $('.pl-js-nav-target').toggleClass('pl-is-active');
- });
-
- // Accordion dropdown
- $('.pl-js-acc-handle').on('click', function(e) {
- const $this = $(this);
- const $panel = $this.next('.pl-js-acc-panel');
- const subnav = $this
- .parent()
- .parent()
- .hasClass('pl-js-acc-panel');
-
- //Close other panels if link isn't a subnavigation item
- if (!subnav) {
- $('.pl-js-acc-handle')
- .not($this)
- .removeClass('pl-is-active');
- $('.pl-js-acc-panel')
- .not($panel)
- .removeClass('pl-is-active');
- }
-
- //Activate selected panel
- $this.toggleClass('pl-is-active');
- $panel.toggleClass('pl-is-active');
- });
-
- //Size View Events
-
- // handle small button
- function goSmall() {
+// import $ from 'jquery';
+// import Mousetrap from 'mousetrap';
+// import { urlHandler, DataSaver, patternName } from '../utils';
+
+// import { store } from '../store.js'; // connect to the Redux store.
+// import { updateViewportPx, updateViewportEm } from '../actions/app.js'; // redux actions needed
+
+// import { minViewportWidth, maxViewportWidth } from '../utils';
+
+// (function(w) {
+// let sw = document.body.clientWidth; //Viewport Width
+
+// const viewportResizeHandleWidth = 14; //Width of the viewport drag-to-resize handle
+// const $sgIframe = $('.pl-js-iframe'); //Viewport element
+// const $sizePx = $('#pl-size-px'); //Px size input element in toolbar
+// const $sizeEms = $('#pl-size-em'); //Em size input element in toolbar
+// let discoID = false;
+// let discoMode = false;
+// let fullMode = true;
+// let hayMode = false;
+
+//Update dimensions on resize
+// $(w).resize(function() {
+// sw = document.body.clientWidth;
+
+// if (fullMode === true) {
+// sizeiframe(sw, false);
+// }
+// });
+
+//Size View Events
+
+// handle small button
+// function goSmall() {
+// killDisco();
+// killHay();
+// fullMode = false;
+// sizeiframe(
+// getRandom(
+// minViewportWidth,
+// window.config.ishViewportRange !== undefined
+// ? parseInt(window.config.ishViewportRange.s[1], 10)
+// : 500
+// )
+// );
+// }
+
+// $('#pl-size-s').on('click', function(e) {
+// e.preventDefault();
+// goSmall();
+// });
+
+Mousetrap.bind('ctrl+shift+s', function (e) {
+ goSmall();
+ return false;
+});
+
+// // handle medium button
+// function goMedium() {
+// killDisco();
+// killHay();
+// fullMode = false;
+// sizeiframe(
+// getRandom(
+// window.config.ishViewportRange !== undefined
+// ? parseInt(window.config.ishViewportRange.m[0], 10)
+// : 500,
+// window.config.ishViewportRange !== undefined
+// ? parseInt(window.config.ishViewportRange.m[1], 10)
+// : 800
+// )
+// );
+// }
+
+// $('#pl-size-m').on('click', function(e) {
+// e.preventDefault();
+// goMedium();
+// });
+
+Mousetrap.bind('ctrl+shift+m', function (e) {
+ goMedium();
+ return false;
+});
+
+// // handle large button
+// function goLarge() {
+// killDisco();
+// killHay();
+// fullMode = false;
+// sizeiframe(
+// getRandom(
+// window.config.ishViewportRange !== undefined
+// ? parseInt(window.config.ishViewportRange.l[0], 10)
+// : 800,
+// maxViewportWidth
+// )
+// );
+// }
+
+// $('#pl-size-l').on('click', function(e) {
+// e.preventDefault();
+// goLarge();
+// });
+
+Mousetrap.bind('ctrl+shift+l', function (e) {
+ goLarge();
+ return false;
+});
+
+// //Click Full Width Button
+// $('#pl-size-full').on('click', function(e) {
+// //Resets
+// e.preventDefault();
+// killDisco();
+// killHay();
+// fullMode = true;
+// sizeiframe(sw);
+// });
+
+//Click Random Size Button
+$('#pl-size-random').on('click', function (e) {
+ e.preventDefault();
+ killDisco();
+ killHay();
+ fullMode = false;
+ sizeiframe(getRandom(minViewportWidth, sw));
+});
+
+//Click for Disco Mode, which resizes the viewport randomly
+$('#pl-size-disco').on('click', function (e) {
+ e.preventDefault();
+ killHay();
+ fullMode = false;
+
+ if (discoMode) {
killDisco();
- killHay();
- fullMode = false;
- sizeiframe(
- getRandom(
- minViewportWidth,
- window.config.ishViewportRange !== undefined
- ? parseInt(window.config.ishViewportRange.s[1], 10)
- : 500
- )
- );
+ } else {
+ startDisco();
}
-
- $('#pl-size-s').on('click', function(e) {
- e.preventDefault();
- goSmall();
- });
-
- Mousetrap.bind('ctrl+shift+s', function(e) {
- goSmall();
- return false;
- });
-
- // handle medium button
- function goMedium() {
+});
+
+// Disco Mode
+function disco() {
+ sizeiframe(getRandom(minViewportWidth, sw));
+}
+
+function killDisco() {
+ discoMode = false;
+ clearInterval(discoID);
+ discoID = false;
+}
+
+function startDisco() {
+ discoMode = true;
+ discoID = setInterval(disco, 800);
+}
+
+Mousetrap.bind('ctrl+shift+d', function (e) {
+ if (!discoMode) {
+ startDisco();
+ } else {
killDisco();
- killHay();
- fullMode = false;
- sizeiframe(
- getRandom(
- window.config.ishViewportRange !== undefined
- ? parseInt(window.config.ishViewportRange.m[0], 10)
- : 500,
- window.config.ishViewportRange !== undefined
- ? parseInt(window.config.ishViewportRange.m[1], 10)
- : 800
- )
- );
}
-
- $('#pl-size-m').on('click', function(e) {
- e.preventDefault();
- goMedium();
- });
-
- Mousetrap.bind('ctrl+shift+m', function(e) {
- goMedium();
- return false;
- });
-
- // handle large button
- function goLarge() {
- killDisco();
+ return false;
+});
+
+//Stephen Hay Mode - "Start with the small screen first, then expand until it looks like shit. Time for a breakpoint!"
+$('#pl-size-hay').on('click', function (e) {
+ e.preventDefault();
+ killDisco();
+ if (hayMode) {
killHay();
- fullMode = false;
- sizeiframe(
- getRandom(
- window.config.ishViewportRange !== undefined
- ? parseInt(window.config.ishViewportRange.l[0], 10)
- : 800,
- maxViewportWidth
- )
- );
- }
-
- $('#pl-size-l').on('click', function(e) {
- e.preventDefault();
- goLarge();
- });
-
- Mousetrap.bind('ctrl+shift+l', function(e) {
- goLarge();
- return false;
- });
-
- //Click Full Width Button
- $('#pl-size-full').on('click', function(e) {
- //Resets
- e.preventDefault();
- killDisco();
- killHay();
- fullMode = true;
- sizeiframe(sw);
- });
-
- //Click Random Size Button
- $('#pl-size-random').on('click', function(e) {
- e.preventDefault();
- killDisco();
- killHay();
- fullMode = false;
- sizeiframe(getRandom(minViewportWidth, sw));
- });
-
- //Click for Disco Mode, which resizes the viewport randomly
- $('#pl-size-disco').on('click', function(e) {
- e.preventDefault();
- killHay();
- fullMode = false;
-
- if (discoMode) {
- killDisco();
- } else {
- startDisco();
- }
- });
-
- // Disco Mode
- function disco() {
- sizeiframe(getRandom(minViewportWidth, sw));
- }
-
- function killDisco() {
- discoMode = false;
- clearInterval(discoID);
- discoID = false;
- }
-
- function startDisco() {
- discoMode = true;
- discoID = setInterval(disco, 800);
+ } else {
+ startHay();
}
-
- Mousetrap.bind('ctrl+shift+d', function(e) {
- if (!discoMode) {
- startDisco();
- } else {
- killDisco();
- }
- return false;
- });
-
- //Stephen Hay Mode - "Start with the small screen first, then expand until it looks like shit. Time for a breakpoint!"
- $('#pl-size-hay').on('click', function(e) {
+});
+
+//Stop Hay! Mode
+function killHay() {
+ const currentWidth = $sgIframe.width();
+ hayMode = false;
+ $sgIframe.removeClass('hay-mode');
+ $('.pl-js-vp-iframe-container').removeClass('hay-mode');
+ sizeiframe(Math.floor(currentWidth));
+}
+
+// start Hay! mode
+// function startHay() {
+// hayMode = true;
+// $('.pl-js-vp-iframe-container')
+// .removeClass('vp-animate')
+// .width(minViewportWidth + viewportResizeHandleWidth);
+// $sgIframe.removeClass('vp-animate').width(minViewportWidth);
+
+// const timeoutID = window.setTimeout(function() {
+// $('.pl-js-vp-iframe-container')
+// .addClass('hay-mode')
+// .width(maxViewportWidth + viewportResizeHandleWidth);
+// $sgIframe.addClass('hay-mode').width(maxViewportWidth);
+
+// setInterval(function() {
+// const vpSize = $sgIframe.width();
+// updateSizeReading(vpSize);
+// }, 100);
+// }, 200);
+// }
+
+// start hay from a keyboard shortcut
+// Mousetrap.bind('ctrl+shift+h', function(e) {
+// if (!hayMode) {
+// startHay();
+// } else {
+// killHay();
+// }
+// });
+
+//Pixel input
+$sizePx.on('keydown', function (e) {
+ let val = Math.floor($(this).val());
+
+ if (e.keyCode === 38) {
+ //If the up arrow key is hit
+ val++;
+ sizeiframe(val, false);
+ } else if (e.keyCode === 40) {
+ //If the down arrow key is hit
+ val--;
+ sizeiframe(val, false);
+ } else if (e.keyCode === 13) {
+ //If the Enter key is hit
e.preventDefault();
- killDisco();
- if (hayMode) {
- killHay();
- } else {
- startHay();
- }
- });
-
- //Stop Hay! Mode
- function killHay() {
- const currentWidth = $sgIframe.width();
- hayMode = false;
- $sgIframe.removeClass('hay-mode');
- $('.pl-js-vp-iframe-container').removeClass('hay-mode');
- sizeiframe(Math.floor(currentWidth));
+ sizeiframe(val); //Size Iframe to value of text box
+ $(this).blur();
}
-
- // start Hay! mode
- function startHay() {
- hayMode = true;
- $('.pl-js-vp-iframe-container')
- .removeClass('vp-animate')
- .width(minViewportWidth + viewportResizeHandleWidth);
- $sgIframe.removeClass('vp-animate').width(minViewportWidth);
-
- const timeoutID = window.setTimeout(function() {
- $('.pl-js-vp-iframe-container')
- .addClass('hay-mode')
- .width(maxViewportWidth + viewportResizeHandleWidth);
- $sgIframe.addClass('hay-mode').width(maxViewportWidth);
-
- setInterval(function() {
- const vpSize = $sgIframe.width();
- updateSizeReading(vpSize);
- }, 100);
- }, 200);
- }
-
- // start hay from a keyboard shortcut
- Mousetrap.bind('ctrl+shift+h', function(e) {
- if (!hayMode) {
- startHay();
- } else {
- killHay();
- }
- });
-
- //Pixel input
- $sizePx.on('keydown', function(e) {
- let val = Math.floor($(this).val());
-
- if (e.keyCode === 38) {
- //If the up arrow key is hit
- val++;
- sizeiframe(val, false);
- } else if (e.keyCode === 40) {
- //If the down arrow key is hit
- val--;
- sizeiframe(val, false);
- } else if (e.keyCode === 13) {
- //If the Enter key is hit
- e.preventDefault();
- sizeiframe(val); //Size Iframe to value of text box
- $(this).blur();
- }
- });
-
- $sizePx.on('keyup', function() {
- const val = Math.floor($(this).val());
- updateSizeReading(val, 'px', 'updateEmInput');
- });
-
- //Em input
- $sizeEms.on('keydown', function(e) {
- let val = parseFloat($(this).val());
-
- if (e.keyCode === 38) {
- //If the up arrow key is hit
- val++;
- sizeiframe(Math.floor(val * $bodySize), false);
- } else if (e.keyCode === 40) {
- //If the down arrow key is hit
- val--;
- sizeiframe(Math.floor(val * $bodySize), false);
- } else if (e.keyCode === 13) {
- //If the Enter key is hit
- e.preventDefault();
- sizeiframe(Math.floor(val * $bodySize)); //Size Iframe to value of text box
- }
- });
-
- $sizeEms.on('keyup', function() {
- const val = parseFloat($(this).val());
- updateSizeReading(val, 'em', 'updatePxInput');
- });
-
- // set 0 to 320px as a default
- Mousetrap.bind('ctrl+shift+0', function(e) {
+});
+
+$sizePx.on('keyup', function () {
+ const val = Math.floor($(this).val());
+ updateSizeReading(val, 'px', 'updateEmInput');
+});
+
+//Em input
+$sizeEms.on('keydown', function (e) {
+ let val = parseFloat($(this).val());
+
+ if (e.keyCode === 38) {
+ //If the up arrow key is hit
+ val++;
+ sizeiframe(Math.floor(val * $bodySize), false);
+ } else if (e.keyCode === 40) {
+ //If the down arrow key is hit
+ val--;
+ sizeiframe(Math.floor(val * $bodySize), false);
+ } else if (e.keyCode === 13) {
+ //If the Enter key is hit
e.preventDefault();
- sizeiframe(320, true);
- return false;
- });
-
- //Resize the viewport
- //'size' is the target size of the viewport
- //'animate' is a boolean for switching the CSS animation on or off. 'animate' is true by default, but can be set to false for things like nudging and dragging
- function sizeiframe(size, animate) {
- let theSize;
-
- if (size > maxViewportWidth) {
- //If the entered size is larger than the max allowed viewport size, cap value at max vp size
- theSize = maxViewportWidth;
- } else if (size < minViewportWidth) {
- //If the entered size is less than the minimum allowed viewport size, cap value at min vp size
- theSize = minViewportWidth;
- } else {
- theSize = size;
- }
-
- //Conditionally remove CSS animation class from viewport
- if (animate === false) {
- $('.pl-js-vp-iframe-container, .pl-js-iframe').removeClass('vp-animate'); //If aninate is set to false, remove animate class from viewport
- } else {
- $('.pl-js-vp-iframe-container, .pl-js-iframe').addClass('vp-animate');
- }
-
- $('.pl-js-vp-iframe-container').width(theSize + viewportResizeHandleWidth); //Resize viewport wrapper to desired size + size of drag resize handler
- $sgIframe.width(theSize); //Resize viewport to desired size
-
- const targetOrigin =
- window.location.protocol === 'file:'
- ? '*'
- : window.location.protocol + '//' + window.location.host;
- const obj = JSON.stringify({
- event: 'patternLab.resize',
- resize: 'true',
- });
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, targetOrigin);
-
- updateSizeReading(theSize); //Update values in toolbar
- saveSize(theSize); //Save current viewport to cookie
- }
-
- $('.pl-js-vp-iframe-container').on(
- 'transitionend webkitTransitionEnd',
- function(e) {
- const targetOrigin =
- window.location.protocol === 'file:'
- ? '*'
- : window.location.protocol + '//' + window.location.host;
- const obj = JSON.stringify({
- event: 'patternLab.resize',
- resize: 'true',
- });
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, targetOrigin);
- }
- );
-
- function saveSize(size) {
- if (!DataSaver.findValue('vpWidth')) {
- DataSaver.addValue('vpWidth', size);
- } else {
- DataSaver.updateValue('vpWidth', size);
- }
- }
-
- //Update Pixel and Em inputs
- //'size' is the input number
- //'unit' is the type of unit: either px or em. Default is px. Accepted values are 'px' and 'em'
- //'target' is what inputs to update. Defaults to both
- function updateSizeReading(size, unit, target) {
- let emSize, pxSize;
-
- if (unit === 'em') {
- //If size value is in em units
- emSize = size;
- pxSize = Math.floor(size * $bodySize);
- } else {
- //If value is px or absent
- pxSize = size;
- emSize = size / $bodySize;
- }
-
- if (target === 'updatePxInput') {
- $sizePx.val(pxSize);
- } else if (target === 'updateEmInput') {
- $sizeEms.val(emSize.toFixed(2));
- } else {
- $sizeEms.val(emSize.toFixed(2));
- $sizePx.val(pxSize);
- }
- }
-
- /* Returns a random number between min and max */
- function getRandom(min, max) {
- return Math.floor(Math.random() * (max - min) + min);
- }
-
- //Update The viewport size
- function updateViewportWidth(size) {
- $('.pl-js-iframe').width(size);
- $('.pl-js-vp-iframe-container').width(size * 1 + 14);
-
- updateSizeReading(size);
- }
-
- $('.pl-js-vp-iframe-container').on('touchstart', function(event) {});
-
- // handles widening the "viewport"
- // 1. on "mousedown" store the click location
- // 2. make a hidden div visible so that it can track mouse movements and make sure the pointer doesn't get lost in the iframe
- // 3. on "mousemove" calculate the math, save the results to a cookie, and update the viewport
- $('.pl-js-resize-handle').mousedown(function(event) {
- // capture default data
- const origClientX = event.clientX;
- const origViewportWidth = $sgIframe.width();
-
- fullMode = false;
-
- // show the cover
- $('.pl-js-viewport-cover').css('display', 'block');
-
- // add the mouse move event and capture data. also update the viewport width
- $('.pl-js-viewport-cover').mousemove(function(e) {
- const viewportWidth = origViewportWidth + 2 * (e.clientX - origClientX);
-
- if (viewportWidth > minViewportWidth) {
- if (!DataSaver.findValue('vpWidth')) {
- DataSaver.addValue('vpWidth', viewportWidth);
- } else {
- DataSaver.updateValue('vpWidth', viewportWidth);
- }
-
- sizeiframe(viewportWidth, false);
- }
- });
-
- return false;
- });
-
- // on "mouseup" we unbind the "mousemove" event and hide the cover again
- $('body').mouseup(function() {
- $('.pl-js-viewport-cover').unbind('mousemove');
- $('.pl-js-viewport-cover').css('display', 'none');
- });
-
- // capture the viewport width that was loaded and modify it so it fits with the pull bar
- const origViewportWidth = $('.pl-js-iframe').width();
- $('.pl-js-vp-iframe-container').width(origViewportWidth);
-
- let testWidth = window.screen.width;
- if (window.orientation !== undefined) {
- testWidth =
- window.orientation === 0 ? window.screen.width : window.screen.height;
+ sizeiframe(Math.floor(val * $bodySize)); //Size Iframe to value of text box
}
+});
+
+$sizeEms.on('keyup', function () {
+ const val = parseFloat($(this).val());
+ updateSizeReading(val, 'em', 'updatePxInput');
+});
+
+// set 0 to 320px as a default
+Mousetrap.bind('ctrl+shift+0', function (e) {
+ e.preventDefault();
+ sizeiframe(320, true);
+ return false;
+});
+
+// //Resize the viewport
+// //'size' is the target size of the viewport
+// //'animate' is a boolean for switching the CSS animation on or off. 'animate' is true by default, but can be set to false for things like nudging and dragging
+// function sizeiframe(size, animate) {
+// let theSize;
+
+// console.log('sizeiframe');
+
+// // @todo: refactor to better handle the iframe async rendering
+// if (document.querySelector('.pl-js-iframe')){
+// if (size > maxViewportWidth) {
+// //If the entered size is larger than the max allowed viewport size, cap value at max vp size
+// theSize = maxViewportWidth;
+// } else if (size < minViewportWidth) {
+// //If the entered size is less than the minimum allowed viewport size, cap value at min vp size
+// theSize = minViewportWidth;
+// } else {
+// theSize = size;
+// }
+
+// //Conditionally remove CSS animation class from viewport
+// if (animate === false) {
+// $('.pl-js-vp-iframe-container, .pl-js-iframe').removeClass('vp-animate'); //If aninate is set to false, remove animate class from viewport
+// } else {
+// $('.pl-js-vp-iframe-container, .pl-js-iframe').addClass('vp-animate');
+// }
+
+// $('.pl-js-vp-iframe-container').width(theSize + viewportResizeHandleWidth); //Resize viewport wrapper to desired size + size of drag resize handler
+// $sgIframe.width(theSize); //Resize viewport to desired size
+// const state = store.getState();
+// const isViewallPage = state.app.isViewallPage;
+
+// const targetOrigin =
+// window.location.protocol === 'file:'
+// ? '*'
+// : window.location.protocol + '//' + window.location.host;
+// const obj = JSON.stringify({
+// event: 'patternLab.resize',
+// resize: 'true',
+// });
+// document
+// .querySelector('.pl-js-iframe')
+// .contentWindow.postMessage(obj, targetOrigin);
+
+// updateSizeReading(theSize); //Update values in toolbar
+// saveSize(theSize); //Save current viewport to cookie
+// }
+// }
+
+// $('.pl-js-vp-iframe-container').on(
+// 'transitionend webkitTransitionEnd',
+// function(e) {
+// const targetOrigin =
+// window.location.protocol === 'file:'
+// ? '*'
+// : window.location.protocol + '//' + window.location.host;
+// const obj = JSON.stringify({
+// event: 'patternLab.resize',
+// resize: 'true',
+// });
+// document
+// .querySelector('.pl-js-iframe')
+// .contentWindow.postMessage(obj, targetOrigin);
+// }
+// );
+
+// function saveSize(size) {
+// if (!DataSaver.findValue('vpWidth')) {
+// DataSaver.addValue('vpWidth', size);
+// } else {
+// DataSaver.updateValue('vpWidth', size);
+// }
+// }
+
+// /* Returns a random number between min and max */
+// function getRandom(min, max) {
+// return Math.floor(Math.random() * (max - min) + min);
+// }
+
+//Update The viewport size
+// function updateViewportWidth(size) {
+
+// // @todo: update to conditionally adjust behavior of viewall page width
+// const state = store.getState();
+// const isViewallPage = state.app.isViewallPage;
+
+// if(!isViewallPage){
+// $('.pl-js-iframe').width(size);
+// $('.pl-js-vp-iframe-container').width(size * 1 + 14);
+// }
+
+// updateSizeReading(size);
+// }
+
+// $('.pl-js-vp-iframe-container').on('touchstart', function(event) {});
+
+// handles widening the "viewport"
+// 1. on "mousedown" store the click location
+// 2. make a hidden div visible so that it can track mouse movements and make sure the pointer doesn't get lost in the iframe
+// 3. on "mousemove" calculate the math, save the results to a cookie, and update the viewport
+// $('.pl-js-resize-handle').mousedown(function(event) {
+// // capture default data
+// const origClientX = event.clientX;
+// const origViewportWidth = $sgIframe.width();
+
+// fullMode = false;
+
+// // show the cover
+// $('.pl-js-viewport-cover').css('display', 'block');
+
+// // add the mouse move event and capture data. also update the viewport width
+// $('.pl-js-viewport-cover').mousemove(function(e) {
+// const viewportWidth = origViewportWidth + 2 * (e.clientX - origClientX);
+
+// if (viewportWidth > minViewportWidth) {
+// if (!DataSaver.findValue('vpWidth')) {
+// DataSaver.addValue('vpWidth', viewportWidth);
+// } else {
+// DataSaver.updateValue('vpWidth', viewportWidth);
+// }
+
+// sizeiframe(viewportWidth, false);
+// }
+// });
+
+// return false;
+// });
+
+// on "mouseup" we unbind the "mousemove" event and hide the cover again
+// $('body').mouseup(function() {
+// $('.pl-js-viewport-cover').unbind('mousemove');
+// $('.pl-js-viewport-cover').css('display', 'none');
+// });
+
+// capture the viewport width that was loaded and modify it so it fits with the pull bar
+// const origViewportWidth = $('.pl-js-iframe').width();
+// $('.pl-js-vp-iframe-container').width(origViewportWidth);
+
+// let testWidth = window.screen.width;
+// if (window.orientation !== undefined) {
+// testWidth =
+// window.orientation === 0 ? window.screen.width : window.screen.height;
+// }
+// if (
+// $(window).width() === testWidth &&
+// 'ontouchstart' in document.documentElement &&
+// $(window).width() <= 1024
+// ) {
+// $('.pl-js-resize-container').width(0);
+// } else {
+// $('.pl-js-iframe').width(origViewportWidth - 14);
+// }
+// updateSizeReading($('.pl-js-iframe').width());
+
+// get the request vars
+const oGetVars = urlHandler.getRequestVars();
+
+// pre-load the viewport width
+let vpWidth = 0;
+const trackViewportWidth = true; // can toggle this feature on & off
+
+// if (oGetVars.h !== undefined || oGetVars.hay !== undefined) {
+// startHay();
+// } else if (oGetVars.d !== undefined || oGetVars.disco !== undefined) {
+// startDisco();
+// } else if (oGetVars.w !== undefined || oGetVars.width !== undefined) {
+// vpWidth = oGetVars.w !== undefined ? oGetVars.w : oGetVars.width;
+// vpWidth =
+// vpWidth.indexOf('em') !== -1
+// ? Math.floor(Math.floor(vpWidth.replace('em', '')) * $bodySize)
+// : Math.floor(vpWidth.replace('px', ''));
+// DataSaver.updateValue('vpWidth', vpWidth);
+// updateViewportWidth(vpWidth);
+// } else if (trackViewportWidth && (vpWidth = DataSaver.findValue('vpWidth'))) {
+// updateViewportWidth(vpWidth);
+// }
+
+// watch the iframe source so that it can be sent back to everyone else.
+// based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
+function receiveIframeMessage(event) {
+ // does the origin sending the message match the current host? if not dev/null the request
if (
- $(window).width() === testWidth &&
- 'ontouchstart' in document.documentElement &&
- $(window).width() <= 1024
+ (window.location.protocol !== 'file:' &&
+ event.origin !==
+ window.location.protocol + '//' + window.location.host) ||
+ event.data === '' // message received, but no data included; prevents JSON.parse error below
) {
- $('.pl-js-resize-container').width(0);
- } else {
- $('.pl-js-iframe').width(origViewportWidth - 14);
- }
- updateSizeReading($('.pl-js-iframe').width());
-
- // get the request vars
- const oGetVars = urlHandler.getRequestVars();
-
- // pre-load the viewport width
- let vpWidth = 0;
- const trackViewportWidth = true; // can toggle this feature on & off
-
- if (oGetVars.h !== undefined || oGetVars.hay !== undefined) {
- startHay();
- } else if (oGetVars.d !== undefined || oGetVars.disco !== undefined) {
- startDisco();
- } else if (oGetVars.w !== undefined || oGetVars.width !== undefined) {
- vpWidth = oGetVars.w !== undefined ? oGetVars.w : oGetVars.width;
- vpWidth =
- vpWidth.indexOf('em') !== -1
- ? Math.floor(Math.floor(vpWidth.replace('em', '')) * $bodySize)
- : Math.floor(vpWidth.replace('px', ''));
- DataSaver.updateValue('vpWidth', vpWidth);
- updateViewportWidth(vpWidth);
- } else if (trackViewportWidth && (vpWidth = DataSaver.findValue('vpWidth'))) {
- updateViewportWidth(vpWidth);
- }
-
- // set up the defaults for the
- const baseIframePath =
- window.location.protocol +
- '//' +
- window.location.host +
- window.location.pathname.replace('index.html', '');
- let patternName =
- window.config.defaultPattern !== undefined &&
- typeof window.config.defaultPattern === 'string' &&
- window.config.defaultPattern.trim().length > 0
- ? window.config.defaultPattern
- : 'all';
- let iFramePath =
- baseIframePath + 'styleguide/html/styleguide.html?' + Date.now();
- if (oGetVars.p !== undefined || oGetVars.pattern !== undefined) {
- patternName = oGetVars.p !== undefined ? oGetVars.p : oGetVars.pattern;
- }
-
- if (patternName !== 'all') {
- const patternPath = urlHandler.getFileName(patternName);
- iFramePath =
- patternPath !== ''
- ? baseIframePath + patternPath + '?' + Date.now()
- : iFramePath;
- document.getElementById('title').innerHTML = 'Pattern Lab - ' + patternName;
- window.history.replaceState(
- {
- pattern: patternName,
- },
- null,
- null
- );
+ return;
}
- // Open in new window link
- if (document.querySelector('.pl-js-open-new-window')) {
- // Set value of href to the path to the pattern
- document
- .querySelector('.pl-js-open-new-window')
- .setAttribute('href', urlHandler.getFileName(patternName));
+ let data = {};
+ try {
+ data = typeof event.data !== 'string' ? event.data : JSON.parse(event.data);
+ } catch (e) {
+ // @todo: how do we want to handle exceptions here?
}
- urlHandler.skipBack = true;
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.location.replace(iFramePath);
-
- // Close all dropdowns and navigation
- function closePanels() {
- $('.pl-js-nav-container, .pl-js-acc-handle, .pl-js-acc-panel').removeClass(
- 'pl-is-active'
- );
- }
-
- // update the iframe with the source from clicked element in pull down menu. also close the menu
- // having it outside fixes an auto-close bug i ran into
- $('a[data-patternpartial]').on('click', function(e) {
- e.preventDefault();
- // update the iframe via the history api handler
- const obj = JSON.stringify({
- event: 'patternLab.updatePath',
- path: urlHandler.getFileName($(this).attr('data-patternpartial')),
- });
- document
- .querySelector('.pl-js-iframe')
- .contentWindow.postMessage(obj, urlHandler.targetOrigin);
- closePanels();
- });
-
- // handle when someone clicks on the grey area of the viewport so it auto-closes the nav
- $('.pl-js-viewport').click(function() {
- closePanels();
- });
-
- // Listen for resize changes
- if (window.orientation !== undefined) {
- let origOrientation = window.orientation;
- window.addEventListener(
- 'orientationchange',
- function() {
- if (window.orientation !== origOrientation) {
- $('.pl-js-vp-iframe-container').width($(window).width());
- $('.pl-js-iframe').width($(window).width());
- updateSizeReading($(window).width());
- origOrientation = window.orientation;
- }
- },
- false
- );
- }
-
- // watch the iframe source so that it can be sent back to everyone else.
- // based on the great MDN docs at https://developer.mozilla.org/en-US/docs/Web/API/window.postMessage
- function receiveIframeMessage(event) {
- // does the origin sending the message match the current host? if not dev/null the request
- if (
- (window.location.protocol !== 'file:' &&
- event.origin !==
- window.location.protocol + '//' + window.location.host) ||
- event.data === '' // message received, but no data included; prevents JSON.parse error below
- ) {
- return;
- }
-
- let data = {};
- try {
- data =
- typeof event.data !== 'string' ? event.data : JSON.parse(event.data);
- } catch (e) {
- // @todo: how do we want to handle exceptions here?
- }
-
- if (data.event !== undefined) {
- if (data.event === 'patternLab.pageLoad') {
- if (!urlHandler.skipBack) {
- if (
- window.history.state === undefined ||
- window.history.state === null ||
- window.history.state.pattern !== data.patternpartial
- ) {
- urlHandler.pushPattern(data.patternpartial, data.path);
- }
-
- /*
- if (wsnConnected) {
- var iFramePath = urlHandler.getFileName(data.patternpartial);
- wsn.send( '{"url": "'+iFramePath+'", "patternpartial": "'+event.data.patternpartial+'" }' );
- }
- */
+ if (data.event !== undefined) {
+ if (data.event === 'patternLab.pageLoad') {
+ // if (!urlHandler.skipBack) {
+ // if (
+ // window.history.state === undefined ||
+ // window.history.state === null ||
+ // window.history.state.pattern !== data.patternpartial
+ // ) {
+ // urlHandler.pushPattern(data.patternpartial, data.path);
+ // }
+ // /*
+ // if (wsnConnected) {
+ // var iFramePath = urlHandler.getFileName(data.patternpartial);
+ // wsn.send( '{"url": "'+iFramePath+'", "patternpartial": "'+event.data.patternpartial+'" }' );
+ // }
+ // */
+ // }
+ // // reset the defaults
+ // urlHandler.skipBack = false;
+ } else if (data.event === 'patternLab.keyPress') {
+ if (data.keyPress === 'ctrl+shift+s') {
+ goSmall();
+ } else if (data.keyPress === 'ctrl+shift+m') {
+ goMedium();
+ } else if (data.keyPress === 'ctrl+shift+l') {
+ goLarge();
+ } else if (data.keyPress === 'ctrl+shift+d') {
+ if (!discoMode) {
+ startDisco();
+ } else {
+ killDisco();
}
-
- // reset the defaults
- urlHandler.skipBack = false;
- } else if (data.event === 'patternLab.keyPress') {
- if (data.keyPress === 'ctrl+shift+s') {
- goSmall();
- } else if (data.keyPress === 'ctrl+shift+m') {
- goMedium();
- } else if (data.keyPress === 'ctrl+shift+l') {
- goLarge();
- } else if (data.keyPress === 'ctrl+shift+d') {
- if (!discoMode) {
- startDisco();
- } else {
- killDisco();
- }
- } else if (data.keyPress === 'ctrl+shift+h') {
- if (!hayMode) {
- startHay();
- } else {
- killHay();
- }
- } else if (data.keyPress === 'ctrl+shift+0') {
- sizeiframe(320, true);
+ } else if (data.keyPress === 'ctrl+shift+h') {
+ if (!hayMode) {
+ startHay();
+ } else {
+ killHay();
}
-
- // @todo: chat with Brian on if this code is still used and necessary; both the `mqs` and `found` variables are both currently undefined.
- // else if (found === data.keyPress.match(/ctrl\+shift\+([1-9])/)) {
- // let val = mqs[found[1] - 1];
- // const type = val.indexOf('px') !== -1 ? 'px' : 'em';
- // val = val.replace(type, '');
- // const width = type === 'px' ? val * 1 : val * $bodySize;
- // sizeiframe(width, true);
- // }
- // return false;
+ } else if (data.keyPress === 'ctrl+shift+0') {
+ sizeiframe(320, true);
}
+
+ // @todo: chat with Brian on if this code is still used and necessary; both the `mqs` and `found` variables are both currently undefined.
+ // else if (found === data.keyPress.match(/ctrl\+shift\+([1-9])/)) {
+ // let val = mqs[found[1] - 1];
+ // const type = val.indexOf('px') !== -1 ? 'px' : 'em';
+ // val = val.replace(type, '');
+ // const width = type === 'px' ? val * 1 : val * $bodySize;
+ // sizeiframe(width, true);
+ // }
+ // return false;
}
}
- window.addEventListener('message', receiveIframeMessage, false);
-})(this);
+}
+window.addEventListener('message', receiveIframeMessage, false);
+// })(this);
diff --git a/packages/uikit-workshop/src/scripts/components/with-lit-html.js b/packages/uikit-workshop/src/scripts/components/with-lit-html.js
new file mode 100644
index 000000000..055f78960
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/components/with-lit-html.js
@@ -0,0 +1,8 @@
+import { render } from 'lit-html';
+
+export default (Base = HTMLElement) =>
+ class extends Base {
+ renderer(root, call) {
+ render(call(), root);
+ }
+ };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-button/pl-button.js b/packages/uikit-workshop/src/scripts/lit-components/pl-button/pl-button.js
new file mode 100644
index 000000000..80e539fe1
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-button/pl-button.js
@@ -0,0 +1,107 @@
+import { LitElement, html } from 'lit-element';
+import { Slotify } from '../slotify';
+import styles from './pl-button.scss?external';
+import { ifDefined } from 'lit-html/directives/if-defined';
+
+// This decorator defines the element.
+class Button extends Slotify(LitElement) {
+ static get properties() {
+ return {
+ href: {
+ attribute: true,
+ type: String,
+ },
+ target: {
+ attribute: true,
+ type: String,
+ },
+ size: {
+ attribute: true,
+ type: String,
+ },
+ iconOnly: {
+ attribute: 'icon-only',
+ type: Boolean,
+ reflect: true,
+ },
+ title: {
+ attribute: true,
+ type: String,
+ },
+ };
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ innerTemplate() {
+ return html`
+ ${this.slotify('before')
+ ? html`
+
${this.slotify('before')}
+ `
+ : ''}
+ ${this.slotify('default')
+ ? html`
+
${this.slotify('default')}
+ `
+ : ''}
+ ${this.slotify('after')
+ ? html`
+
${this.slotify('after')}
+ `
+ : ''}
+ `;
+ }
+
+ // Render element DOM by returning a `lit-html` template.
+ render() {
+ const size = this.size || 'medium';
+ // const iconOnly = this.iconOnly !== false|| false;
+
+ return html`
+ ${this.href
+ ? html`
+
+ ${this.innerTemplate()}
+
+ `
+ : html`
+
+ ${this.innerTemplate()}
+
+ `}
+ `;
+ }
+}
+
+customElements.define('pl-button', Button);
+
+export { Button };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-button/pl-button.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-button/pl-button.scss
new file mode 100644
index 000000000..bec09cc4d
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-button/pl-button.scss
@@ -0,0 +1,42 @@
+@import '../../../sass/scss/core.scss';
+
+:host {
+ width: 100%;
+}
+
+pl-button {
+ width: 100%;
+}
+
+.pl-c-button {
+ @include buttonStyles;
+}
+
+.pl-c-button__text {
+ text-align: left;
+}
+
+.pl-c-button--medium {
+ padding: 0.65rem 1rem;
+
+ &.pl-c-button--icon-only {
+ padding: 0.65rem;
+ }
+}
+
+.pl-c-button--small {
+ padding: 0.5rem 1rem;
+
+ &.pl-c-button--icon-only {
+ padding: 0.5rem;
+ }
+}
+
+// Make sure the text and icon align to the opposite ends
+* + .pl-c-button__icon {
+ margin-right: 0.5rem;
+}
+
+.pl-c-button__icon + * {
+ margin-right: 0.5rem;
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-controls/pl-controls.js b/packages/uikit-workshop/src/scripts/lit-components/pl-controls/pl-controls.js
new file mode 100644
index 000000000..d7b736330
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-controls/pl-controls.js
@@ -0,0 +1,28 @@
+import { BaseLitComponent } from '../../components/base-component';
+import { html, customElement } from 'lit-element';
+import styles from './pl-controls.scss?external';
+
+@customElement('pl-controls')
+class Controls extends BaseLitComponent {
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ render() {
+ return html`
+
+ `;
+ }
+}
+
+export { Controls };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-controls/pl-controls.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-controls/pl-controls.scss
new file mode 100644
index 000000000..2f648f880
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-controls/pl-controls.scss
@@ -0,0 +1,62 @@
+/*------------------------------------*\
+ #CONTROLS
+\*------------------------------------*/
+
+@import '../../../sass/scss/core.scss';
+
+pl-controls {
+ margin-left: auto; /* 2 */
+ display: flex;
+ flex-wrap: nowrap;
+ align-self: center;
+
+ .pl-c-body--theme-sidebar & {
+ display: block;
+
+ @media all and (min-width: $pl-bp-med) {
+ width: 100%;
+ position: relative;
+ padding-top: 0.5rem;
+ // box-shadow: 0 -2px 5px rgba($pl-color-black, 0.1);
+
+ &::before {
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ border-top: 1px solid;
+ border-top-color: $pl-color-gray-20;
+ border-top-color: var(--theme-border, $pl-color-gray-20);
+ height: 1px;
+ content: '';
+ width: auto;
+ }
+ }
+ }
+}
+
+/**
+ * 1) Controls contains viewport resizer and tools dropdown
+ * 2) Right-align inside of header
+ */
+.pl-c-controls {
+ margin-left: auto; /* 2 */
+ display: flex;
+ flex-wrap: nowrap;
+
+ // IE 11 layout bug
+ @media all and (min-width: $pl-bp-med) {
+ .pl-c-body--theme-sidebar & {
+ display: block;
+ }
+ }
+}
+
+/**
+* Control list
+*/
+.pl-c-controls__list {
+ @include listReset();
+ display: flex;
+ flex-wrap: nowrap;
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-drawer/pl-drawer.js b/packages/uikit-workshop/src/scripts/lit-components/pl-drawer/pl-drawer.js
new file mode 100644
index 000000000..6fa309662
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-drawer/pl-drawer.js
@@ -0,0 +1,210 @@
+import { styleMap } from 'lit-html/directives/style-map';
+import { classMap } from 'lit-html/directives/class-map';
+import { LitElement, html, customElement } from 'lit-element';
+import { store } from '../../store.js'; // redux store
+import {
+ updateDrawerState,
+ updateDrawerHeight,
+ updateDrawerAnimationState,
+} from '../../actions/app.js'; // redux actions needed by this element.
+import styles from './pl-drawer.scss?external';
+
+@customElement('pl-drawer')
+class Drawer extends LitElement {
+ constructor() {
+ super();
+ this.onMouseDown = this.onMouseDown.bind(this); // fix bindings so "this" works properly
+ this.onMouseUp = this.onMouseUp.bind(this); // fix bindings so "this" works properly
+ this.onMouseMove = this.onMouseMove.bind(this); // fix bindings so "this" works properly
+ }
+
+ connectedCallback() {
+ styles.use();
+ if (super.connectedCallback) {
+ super.connectedCallback();
+ }
+ this.__storeUnsubscribe = store.subscribe(() =>
+ this._stateChanged(store.getState())
+ );
+ this._stateChanged(store.getState());
+ }
+
+ disconnectedCallback() {
+ styles.unuse();
+ this.__storeUnsubscribe && this.__storeUnsubscribe();
+
+ if (super.disconnectedCallback) {
+ super.disconnectedCallback();
+ }
+ }
+
+ static get properties() {
+ return {
+ drawerOpened: {
+ attribute: true,
+ type: Boolean,
+ },
+ drawerHeight: {
+ attribute: true,
+ type: Number,
+ },
+ isViewallPage: {
+ attribute: true,
+ type: Boolean,
+ },
+ isMouseDown: {
+ attribute: true,
+ type: Boolean,
+ },
+ };
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ onMouseDown() {
+ this.isMouseDown = true;
+ store.dispatch(updateDrawerAnimationState(true));
+
+ document.addEventListener('mousemove', this.onMouseMove);
+ document.addEventListener('mouseup', this.onMouseUp);
+ }
+
+ onMouseMove(event) {
+ // 1/2 the height of the UI being dragged. @todo: make sure this 20px is calculated
+ const clientHeight = event.targetTouches
+ ? event.targetTouches[0].clientY
+ : event.clientY;
+ const panelHeight = window.innerHeight - clientHeight + 28;
+
+ this.drawerHeight = panelHeight;
+ }
+
+ onMouseUp() {
+ this.isMouseDown = false;
+ document.removeEventListener('mousemove', this.onMouseMove);
+ document.removeEventListener('mouseup', this.onMouseUp);
+
+ store.dispatch(updateDrawerHeight(this.drawerHeight));
+ store.dispatch(updateDrawerAnimationState(false));
+ }
+
+ render() {
+ const classes = {
+ 'pl-c-drawer': true,
+ 'pl-js-drawer': true,
+ 'pl-is-active': this.drawerOpened && !this.isViewallPage,
+ };
+
+ const renderedHeight =
+ this.drawerOpened && !this.isViewallPage
+ ? this.drawerHeight > 20
+ ? this.drawerHeight
+ : 300
+ : 0;
+
+ const drawerStyles = {
+ height: `${renderedHeight}px`,
+ transitionDuration: this.isMouseDown ? '0ms' : '300ms',
+ };
+
+ return html`
+
+
+
+
+
+ Drag to resize Pattern Lab Drawer
+
+
+
+
+
+
+ `;
+ }
+
+ _stateChanged(state) {
+ if (this.themeMode !== state.app.themeMode) {
+ this.themeMode = state.app.themeMode || 'dark';
+ }
+ if (this.drawerOpened !== state.app.drawerOpened) {
+ this.drawerOpened = state.app.drawerOpened;
+ }
+ if (this.drawerHeight !== state.app.drawerHeight) {
+ this.drawerHeight = state.app.drawerHeight;
+ }
+ if (this.isDragging !== state.app.isDragging) {
+ this.isDragging = state.app.isDragging;
+ }
+ if (this.isViewallPage !== state.app.isViewallPage) {
+ this.isViewallPage = state.app.isViewallPage;
+ }
+ }
+}
+
+export { Drawer };
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_modal.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-drawer/pl-drawer.scss
old mode 100644
new mode 100755
similarity index 51%
rename from packages/uikit-workshop/src/sass/scss/04-components/_modal.scss
rename to packages/uikit-workshop/src/scripts/lit-components/pl-drawer/pl-drawer.scss
index 384e44f86..7cc307b1f
--- a/packages/uikit-workshop/src/sass/scss/04-components/_modal.scss
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-drawer/pl-drawer.scss
@@ -1,46 +1,46 @@
/*------------------------------------*\
- #MODAL
+ #drawer
\*------------------------------------*/
-$pl-resizer-height: 14px;
+@import '../../../sass/scss/core.scss';
-pl-modal {
+$pl-drawer-resizer-height: 20px;
+
+pl-drawer {
display: flex;
flex-direction: column;
position: relative;
position: sticky;
+ top: auto;
+ bottom: 0;
+ left: 0;
+ right: 0;
z-index: 20;
- max-height: 100vh;
- box-shadow: 0 0 2px 0 $pl-color-gray-70;
overflow: visible;
}
-
/**
- * 1) The modal slides up from the bottom of the viewport when
+ * 1) The drawer slides up from the bottom of the viewport when
* "show pattern info" is selected on the pattern detail screen.
*/
-.pl-c-modal {
+.pl-c-drawer {
display: flex;
flex-direction: column;
font-family: $pl-font;
background-color: $pl-color-gray-87;
+ background-color: var(--theme-secondary, $pl-color-gray-87);
color: $pl-color-gray-20;
- position: sticky;
- top: auto;
- bottom: 0;
- left: 0;
- right: 0;
- z-index: 5;
width: 100%;
- height: 0;
- transition: transform 0.3s ease, height 0.3s ease;
- transform: translate3d(0, 100%, 0);
+ height: 100%;
+ transform: translate3d(0, 0, 0);
pointer-events: none;
- will-change: height, transform;
overflow: hidden;
max-width: 100vw;
- box-shadow: 0 -1px 2px rgba($pl-color-gray-70, 0.1);
+
+ @supports (padding: max(0px)) {
+ padding-left: calc(env(safe-area-inset-left) / 2);
+ padding-right: calc(env(safe-area-inset-right) / 2);
+ }
.pl-c-body--theme-sidebar & {
@media all and (min-width: $pl-bp-med) {
@@ -48,64 +48,77 @@ pl-modal {
}
}
+ .pl-c-body--theme-light & {
+ // Modal / Drawer inside a light theme
+ background-color: $pl-color-white;
+ color: $pl-color-gray-70;
+ }
+
/**
- * Active modal
+ * Active drawer
*/
&.pl-is-active {
- transform: translate3d(0, 0, 0);
- height: 40vh; // default height unless manually resized
- transition: transform 0.3s ease;
pointer-events: auto;
}
}
-.pl-c-modal__wrapper {
+.pl-c-drawer__wrapper {
transform: translate3d(0, 0, 0);
+ will-change: height;
+ overflow: hidden;
}
-.pl-c-modal__wrapper > * {
+.pl-c-drawer__wrapper > * {
height: 100%;
}
-.pl-c-modal__content {
+.pl-c-drawer__content {
flex-grow: 1;
display: flex;
width: 100%;
overflow: hidden; // needed for IE 11 so scrollbars show up
+ max-height: calc(
+ 100% - 32px - 1.5rem
+ ); // workaround to fix drawer content collapsing. @todo: remove once larger tabs refactor PR'd
}
-.pl-c-modal__toolbar {
+.pl-c-drawer__toolbar {
display: flex;
flex-direction: column;
flex-shrink: 0; // so that the resizer height doesn't change unexpectedly
}
-.pl-c-modal__content-wrapper {
+.pl-c-drawer__content-wrapper {
display: flex;
flex-direction: column;
flex-grow: 1;
overflow: hidden; // needed for IE 11 so scrollbars show up
+
+ @supports (padding: env(safe-area-inset-top)) {
+ padding-right: calc(env(safe-area-inset-right) - 0.9rem);
+ }
}
-.pl-c-modal__toolbar-controls {
+.pl-c-drawer__toolbar-controls {
display: flex;
flex-direction: row;
align-self: flex-end;
position: relative;
z-index: 10;
- flex-shrink: 0;
+ flex-shrink: 0; // fix for IE 11 squishing UI controls
}
/**
- * Modal close button
- * 1) Closes the modal popup
+ * drawer close button
+ * 1) Closes the drawer popup
*/
-.pl-c-modal__close-btn {
+.pl-c-drawer__close-btn {
@include linkStyle;
margin: 0;
+ padding: 0.2rem;
-webkit-appearance: none;
flex-shrink: 0; // needed for IE 11
-
+
@media all and (max-width: $pl-bp-med - 1) {
border-radius: 20rem;
padding-top: 0.5rem;
@@ -128,88 +141,77 @@ pl-modal {
}
}
-
-.pl-c-modal__cover {
+.pl-c-drawer__cover {
width: 100%;
height: 100%;
- display: none;
- position: absolute;
+ top: 0;
+ left: 0;
+ position: fixed;
z-index: 20;
cursor: move;
}
-.pl-c-modal__resizer {
+.pl-c-drawer__resizer {
display: flex;
- position: absolute;
+ position: relative;
top: 0;
left: 0;
right: 0;
align-items: center;
justify-content: center;
- left: 0;
- height: $pl-resizer-height;
+ height: $pl-drawer-resizer-height;
width: 100%;
background-color: inherit;
z-index: 2;
cursor: ns-resize;
+ border-bottom: 1.1px solid $pl-color-gray-20; // sub-pixel bug in Chrome. border disappears sometimes when set to 1px
+ border-bottom-color: $pl-color-gray-20;
+ border-bottom-color: var(--theme-border, $pl-color-gray-20);
+ padding-top: 5px;
+ padding-bottom: 5px;
- &:after {
+ &::after {
content: '';
- height: 3px;
- width: 50px;
- border-top: 1px solid currentColor;
- border-bottom: 1px solid currentColor;
- transition: opacity $pl-animate-normal ease-out;
- opacity: 0.5;
- background-color: currentColor;
- border-radius: 3px;
+ height: 100%;
+ width: 100%;
+ left: 0;
+ opacity: 0;
+ top: 0;
+ position: absolute;
+ pointer-events: none;
display: block;
+ background-color: currentColor;
+ transition: 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
- &:hover:after {
- opacity: 0.8;
+ &:hover::after {
+ opacity: 0.1;
}
- &:focus:after,
- &:active:after {
- opacity: 0.95;
+ &:focus::after,
+ &:active::after {
+ opacity: 0.2;
}
}
+.pl-c-drawer__resizer-icon {
+ width: 10px;
+ height: 100%;
+ fill: currentColor;
+ z-index: 100;
+ transform: scale(3, 1) rotate(90deg);
+}
+
/**
* Close button icon
* 1) Displayed as an e
*/
-.pl-c-modal__close-btn-icon {
- width: 12px;
- height: 12px;
+.pl-c-drawer__close-btn-icon {
+ width: 20px;
+ height: 20px;
color: currentColor;
fill: currentColor;
transition: fill $pl-animate-quick ease-out;
flex-shrink: 0; // needed for IE 11
align-self: center; // valign in IE 11
}
-
-.pl-c-code-copy-btn {
- display: inline-block;
- position: absolute;
- top: 0.5rem;
- right: 0.5rem;
- padding: 0.2rem 0.4rem;
- background-color: $pl-color-gray-07;
- color: $pl-color-gray-87;
- border: 1px solid $pl-color-gray-13;
- border-radius: $pl-border-radius-med;
- font-family: $pl-font;
- font-size: $pl-font-size-norm;
- text-transform: lowercase;
- line-height: 1;
- cursor: pointer;
- z-index: 2;
- transition: background-color $pl-animate-quick ease-out;
-
- &:hover,
- &:focus {
- background-color: $pl-color-gray-20;
- }
-}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.js b/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.js
new file mode 100644
index 000000000..91dc15a64
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.js
@@ -0,0 +1,172 @@
+/* eslint-disable no-unused-vars, no-param-reassign */
+import { store } from '../../store.js'; // connect to redux
+import { ifDefined } from 'lit-html/directives/if-defined';
+import { html } from 'lit-html';
+import { BaseLitComponent } from '../../components/base-component';
+import { iframeMsgDataExtraction } from '../../utils';
+import { customElement } from 'lit-element';
+import Mousetrap from 'mousetrap';
+import styles from './pl-header.scss?external';
+
+@customElement('pl-header')
+class Header extends BaseLitComponent {
+ constructor() {
+ super();
+ this._wasInitiallyRendered = false;
+ this.receiveIframeMessage = this.receiveIframeMessage.bind(this);
+ this.handleExternalClicks = this.handleExternalClicks.bind(this);
+ this.toggleNav = this.toggleNav.bind(this);
+ }
+
+ static get properties() {
+ return {
+ themeMode: String,
+ isActive: Boolean,
+ currentPattern: String,
+ };
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ const state = store.getState();
+ this.currentPattern = state.app.currentPattern || '';
+ this.themeMode = state.app.themeMode || 'dark';
+
+ window.addEventListener('message', this.receiveIframeMessage, false);
+ document.addEventListener('click', this.handleExternalClicks);
+
+ Mousetrap(this).bind('esc', () => {
+ if (window.innerWidth <= 670) {
+ this.isActive = false;
+ }
+ });
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ window.removeEventListener('message', this.receiveIframeMessage);
+ document.removeEventListener('click', this.handleExternalClicks);
+ }
+
+ _stateChanged(state) {
+ if (this.themeMode !== state.app.themeMode) {
+ this.themeMode = state.app.themeMode || 'dark';
+ }
+
+ if (this.currentPattern !== state.app.currentPattern) {
+ if (this.isActive === true) {
+ this.isActive = false;
+ }
+ this.currentPattern = state.app.currentPattern;
+ }
+ }
+
+ handleExternalClicks(e) {
+ if (window.innerWidth <= 670) {
+ if (
+ e.target !== this.navToggle &&
+ !e.target.closest('.pl-js-nav-container') &&
+ !e.target.closest('pl-toggle-layout') &&
+ this.isActive === true
+ ) {
+ this.isActive = false;
+ }
+ }
+ }
+
+ firstUpdated() {
+ this.navToggle = this.renderRoot.querySelector('.pl-js-nav-trigger');
+ this.navTarget = this.querySelector('.pl-js-nav-target');
+
+ if (!window.__PRERENDER_INJECTED) {
+ this._wasInitiallyRendered = true;
+ }
+ }
+
+ toggleNav() {
+ this.isActive = !this.isActive;
+ }
+
+ render() {
+ return html`
+
+ `;
+ }
+
+ /**
+ *
+ * @param {MessageEvent} e A message received by a target object.
+ */
+ receiveIframeMessage(event) {
+ const self = this;
+
+ const data = iframeMsgDataExtraction(event);
+
+ if (data.event !== undefined && data.event === 'patternLab.pageClick') {
+ try {
+ if (
+ window.innerWidth <= 670 ||
+ (window.innerWidth >= 670 && self.layoutMode !== 'vertical')
+ ) {
+ this.isActive = false;
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ }
+}
+
+export { Header };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.scss
new file mode 100644
index 000000000..9732e0c23
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-header/pl-header.scss
@@ -0,0 +1,95 @@
+/*------------------------------------*\
+ #HEADER
+\*------------------------------------*/
+
+@import '../../../sass/scss/core.scss';
+
+pl-header {
+ position: relative;
+ position: sticky;
+ top: 0;
+ left: 0;
+ z-index: 100;
+ display: flex; /* 2 */
+ width: 100%;
+ background-color: $pl-color-black;
+ background-color: var(--theme-secondary, $pl-color-black);
+ max-height: 100vh;
+
+ color: $pl-color-gray-20;
+ color: var(--theme-text, $pl-color-gray-20);
+ border-right: 1px solid;
+ border-right-color: $pl-color-gray-20;
+ border-right-color: var(--theme-border, $pl-color-gray-20);
+ padding-left: calc(env(safe-area-inset-left) / 2);
+ padding-right: calc(env(safe-area-inset-right) / 2);
+
+ .pl-c-body--theme-light & {
+ color: $pl-color-black;
+ background-color: $pl-color-white;
+ }
+
+ .pl-c-body--theme-sidebar & {
+ padding-right: 0;
+ }
+
+ @media all and (min-width: $pl-bp-med) {
+ .pl-c-body--theme-sidebar & {
+ position: fixed;
+ position: sticky;
+ overflow: auto;
+ /**
+ * Header
+ * 1) Set width to sidebar width defined above
+ * 2) Make header 100% of the viewport height
+ * 3) Stack header content stack on top of each other
+ * 4) void bottom border for light theme
+ */
+ width: $pl-sidebar-width; /* 1 */
+ border-bottom: 0; /* 4 */
+ }
+ }
+}
+
+/**
+* 1) Pattern Lab's header is fixed across the top of the viewport and
+* contains the primary pattern navigation, viewport resizing items,
+* and tools.
+* 2) Display nav and controls horizontally
+*/
+.pl-c-header {
+ display: flex; /* 2 */
+ flex-direction: row;
+ width: 100%;
+ font-family: $pl-font;
+ font-size: $pl-font-size-sm;
+ min-height: 30px; // magic number -- needed for initial skeleton screen styles used in the critical CSS
+ background-color: inherit;
+
+ @media all and (min-width: $pl-bp-med) {
+ .pl-c-body--theme-sidebar & {
+ flex-direction: column; /* 3 */
+ justify-content: space-between;
+ }
+ }
+}
+
+/**
+ * Nav toggle button
+ * 1) Styles for the general nav toggle button, which
+ * only appears on small screens
+ */
+.pl-c-header__nav-toggle {
+ @include linkStyle();
+ padding: 11px 12px;
+ border: 0;
+
+ @media all and (min-width: $pl-bp-med) {
+ display: none;
+ }
+
+ &:focus {
+ outline: 1px dotted;
+ outline-offset: -1px;
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-icon/pl-icon.js b/packages/uikit-workshop/src/scripts/lit-components/pl-icon/pl-icon.js
new file mode 100644
index 000000000..0d8a2d8d2
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-icon/pl-icon.js
@@ -0,0 +1,65 @@
+import { html, LitElement, customElement } from 'lit-element';
+import styles from './pl-icon.scss?external';
+import { unsafeHTML } from 'lit-html/directives/unsafe-html';
+const icons = {};
+
+// automatically pull in every SVG icon file in from the icons folder
+const svgIcons = require.context('../../../icons', true, /\.svg$/);
+svgIcons.keys().forEach((iconName) => {
+ const name = iconName.replace('./', '');
+ const icon = import(`../../../icons/${name}`);
+
+ icon.then((Icon) => {
+ icons[Icon.default.id] = Icon.default;
+ });
+});
+
+// This decorator defines the element.
+@customElement('pl-icon')
+class Icon extends LitElement {
+ static get properties() {
+ return {
+ name: String,
+ size: String,
+ };
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ // Render element DOM by returning a `lit-html` template.
+ render() {
+ const svgMarkup = `
+
+
+
+
+ `;
+
+ return html` ${unsafeHTML(svgMarkup)} `;
+ }
+}
+
+export { Icon };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-icon/pl-icon.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-icon/pl-icon.scss
new file mode 100644
index 000000000..392a1ba29
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-icon/pl-icon.scss
@@ -0,0 +1,15 @@
+@import '../../../sass/scss/core.scss';
+
+pl-icon {
+ display: block;
+ width: 1.2em;
+ height: 1.2em;
+ pointer-events: none; // so click events aren't disrupted when clicking into an SVG;
+}
+
+// @todo: build out additional icon sizes
+.c-icon {
+ display: block;
+ width: 1.2em;
+ height: 1.2em;
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-icon/unsafe-svg.js b/packages/uikit-workshop/src/scripts/lit-components/pl-icon/unsafe-svg.js
new file mode 100644
index 000000000..f6d374dae
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-icon/unsafe-svg.js
@@ -0,0 +1,64 @@
+/**
+ * @license
+ * Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
+ * This code may only be used under the BSD style license found at
+ * https://polymer.github.io/LICENSE.txt
+ * The complete set of authors may be found at
+ * https://polymer.github.io/AUTHORS.txt
+ * The complete set of contributors may be found at
+ * https://polymer.github.io/CONTRIBUTORS.txt
+ * Code distributed by Google as part of the polymer project is also
+ * subject to an additional IP rights grant found at
+ * https://polymer.github.io/PATENTS.txt
+ */
+
+import { reparentNodes } from 'lit-html/lib/dom.js';
+// import { isPrimitive } from 'lit-html/lib/parts.js';
+import { directive } from 'lit-html/lit-html.js';
+import importNode from '@ungap/import-node';
+// document.importNode = importNode;
+
+// interface PreviousValue {
+// readonly value: unknown;
+// readonly fragment: DocumentFragment;
+// }
+
+// For each part, remember the value that was last rendered to the part by the
+// unsafeSVG directive, and the DocumentFragment that was last set as a value.
+// The DocumentFragment is used as a unique key to check if the last value
+// rendered to the part was with unsafeSVG. If not, we'll always re-render the
+// value passed to unsafeSVG.
+
+/**
+ * Renders the result as SVG, rather than text.
+ *
+ * Note, this is unsafe to use with any user-provided input that hasn't been
+ * sanitized or escaped, as it may lead to cross-site-scripting
+ * vulnerabilities.
+ */
+export const unsafeSVG = directive((value) => (part) => {
+ // if (!(part instanceof NodePart)) {
+ // throw new Error('unsafeSVG can only be used in text bindings');
+ // }
+
+ // const previousValue = previousValues.get(part);
+
+ // if (
+ // previousValue !== undefined &&
+ // isPrimitive(value) &&
+ // value === previousValue.value &&
+ // part.value === previousValue.fragment
+ // ) {
+ // return;
+ // }
+
+ const template = document.createElement('template');
+ template.innerHTML = `
${value} `;
+ const content = template.content;
+ const svgElement = content.firstElementChild;
+ content.removeChild(svgElement);
+ reparentNodes(content, svgElement.firstChild);
+ const fragment = importNode(content, true);
+ part.setValue(fragment);
+ // previousValues.set(part, { value, fragment });
+});
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-layout/pl-layout.js b/packages/uikit-workshop/src/scripts/lit-components/pl-layout/pl-layout.js
new file mode 100644
index 000000000..1f6a7f73d
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-layout/pl-layout.js
@@ -0,0 +1,84 @@
+/* eslint-disable no-unused-vars, no-param-reassign */
+import { define, props } from 'skatejs';
+const classNames = require('classnames');
+import { html } from 'lit-html';
+
+import { store } from '../../store.js'; // connect to redux
+import { BaseLitComponent } from '../../components/base-component.js';
+import styles from './pl-layout.scss?external';
+
+class Layout extends BaseLitComponent {
+ constructor() {
+ super();
+ this.targetOrigin =
+ window.location.protocol === 'file:'
+ ? '*'
+ : window.location.protocol + '//' + window.location.host;
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ const state = store.getState();
+ this.layoutMode = state.app.layoutMode;
+ this.themeMode = state.app.themeMode;
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ firstUpdated() {
+ this.iframeElement = this.renderRoot.querySelector('.pl-js-iframe');
+ }
+
+ _stateChanged(state) {
+ let hasChanged = false;
+ if (this.layoutMode !== state.app.layoutMode) {
+ hasChanged = true;
+ this.layoutMode = state.app.layoutMode || 'vertical';
+ }
+
+ if (this.themeMode !== state.app.themeMode) {
+ hasChanged = true;
+ this.themeMode = state.app.themeMode;
+ }
+
+ if (hasChanged === true) {
+ hasChanged = false;
+ const layoutModeClass =
+ this.layoutMode === 'vertical' ? 'sidebar' : 'horizontal';
+
+ const classes = classNames(`pl-c-body--theme-${layoutModeClass}`, {
+ [`pl-c-body--theme-${this.themeMode}`]: this.themeMode !== undefined,
+ });
+
+ this.className = classes;
+ }
+
+ this.iframeElement = document.querySelector('.pl-js-iframe');
+
+ if (this.iframeElement) {
+ const obj = JSON.stringify({
+ event: 'patternLab.stateChange',
+ state,
+ });
+ this.iframeElement.contentWindow.postMessage(obj, this.targetOrigin);
+ }
+ }
+
+ render() {
+ return html`
+
+
+ `;
+ }
+}
+
+customElements.define('pl-layout', Layout);
+
+export { Layout };
diff --git a/packages/uikit-workshop/src/scripts/components/pl-layout/pl-layout.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-layout/pl-layout.scss
similarity index 79%
rename from packages/uikit-workshop/src/scripts/components/pl-layout/pl-layout.scss
rename to packages/uikit-workshop/src/scripts/lit-components/pl-layout/pl-layout.scss
index 00dde1208..1d4cf9253 100644
--- a/packages/uikit-workshop/src/scripts/components/pl-layout/pl-layout.scss
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-layout/pl-layout.scss
@@ -4,15 +4,20 @@ pl-layout {
display: flex;
flex-direction: column;
width: 100%;
- min-height: 100vh;
+ min-height: 100%;
max-width: 100vw;
- background-color: $pl-color-gray-13;
-
+ background-color: $pl-color-white;
+ overflow: initial;
+
// Prevent extra scrollbars in just IE 11
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
overflow: hidden;
}
+ .pl-c-layout {
+ flex-grow: 1;
+ }
+
&.pl-c-body--theme-sidebar {
@media all and (min-width: $pl-bp-med) {
flex-direction: row;
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-logo/pl-logo.js b/packages/uikit-workshop/src/scripts/lit-components/pl-logo/pl-logo.js
new file mode 100644
index 000000000..75eba1f21
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-logo/pl-logo.js
@@ -0,0 +1,64 @@
+import { store } from '../../store.js'; // connect to redux
+import { ifDefined } from 'lit-html/directives/if-defined';
+import { html } from 'lit-html';
+import { customElement } from 'lit-element';
+import { BaseLitComponent } from '../../components/base-component';
+import styles from './pl-logo.scss?external';
+
+@customElement('pl-logo')
+class Logo extends BaseLitComponent {
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ const state = store.getState();
+ this.theme = this.theme || state.app.themeMode || 'dark';
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ static get properties() {
+ return {
+ width: String,
+ height: String,
+ theme: String,
+ url: String,
+ text: String,
+ altText: {
+ type: String,
+ attribute: 'alt-text',
+ },
+ srcLight: {
+ type: String,
+ attribute: 'src-light',
+ },
+ srcDark: {
+ type: String,
+ attribute: 'src-dark',
+ },
+ };
+ }
+
+ render() {
+ const imageSrc = this.theme === 'dark' ? this.srcDark : this.srcLight;
+
+ return html`
+
+
+ ${this.text && this.text !== ''
+ ? html` ${this.text} `
+ : ''}
+
+ `;
+ }
+}
+
+export { Logo };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-logo/pl-logo.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-logo/pl-logo.scss
new file mode 100644
index 000000000..0156a983c
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-logo/pl-logo.scss
@@ -0,0 +1,63 @@
+/*------------------------------------*\
+ #LOGO
+\*------------------------------------*/
+
+@import '../../../sass/scss/core.scss';
+
+pl-logo {
+ align-self: center;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ position: relative;
+ z-index: 100;
+ padding: 0;
+ min-height: 44px;
+ min-width: 44px;
+}
+
+.pl-c-logo {
+ width: auto;
+ flex-grow: 1;
+ padding: 0.5rem 0.25rem;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: inherit;
+ text-decoration: none;
+
+ @media screen and (min-width: 400px) {
+ padding: 0.5rem 12px;
+ }
+
+ outline: 0;
+ text-transform: lowercase;
+ font-size: 1.2rem;
+ font-weight: bold;
+ line-height: 1;
+ margin: 0;
+ transition: color 0.2s ease;
+
+ &:focus {
+ outline: 1px dotted;
+ outline-offset: -1px;
+ }
+}
+
+.pl-c-logo__img {
+ display: block;
+ height: 100%; // fix to address scaling issue in ie 11 on windows 7
+ max-width: 100%;
+ max-height: 23px;
+
+ &:not(:last-child) {
+ margin-right: 0.25rem;
+ }
+}
+
+.pl-c-logo__text {
+ display: flex;
+ white-space: nowrap;
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-info/pl-toggle-info.js b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-info/pl-toggle-info.js
new file mode 100644
index 000000000..1264e8919
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-info/pl-toggle-info.js
@@ -0,0 +1,82 @@
+import { LitElement, html, customElement } from 'lit-element';
+import { store } from '../../store.js'; // connect to the Redux store.
+import { updateDrawerState } from '../../actions/app.js'; // redux actions
+import styles from './pl-toggle-info.scss?external';
+
+@customElement('pl-toggle-info')
+class InfoToggle extends LitElement {
+ constructor() {
+ super();
+ this.handleClick = this.handleClick.bind(this);
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ static get properties() {
+ return {
+ isDrawerOpen: {
+ attribute: 'is-drawer-open',
+ type: Boolean,
+ },
+ isViewallPage: {
+ attribute: 'is-viewall-page',
+ type: Boolean,
+ },
+ };
+ }
+
+ connectedCallback() {
+ if (super.connectedCallback) {
+ super.connectedCallback();
+ }
+ styles.use();
+
+ const state = store.getState();
+ this.isDrawerOpen = state.app.drawerOpened;
+ this.isViewallPage = state.app.isViewallPage;
+
+ this.__storeUnsubscribe = store.subscribe(() =>
+ this._stateChanged(store.getState())
+ );
+ this._stateChanged(store.getState());
+ }
+
+ disconnectedCallback() {
+ this.__storeUnsubscribe && this.__storeUnsubscribe();
+ styles.unuse();
+
+ if (super.disconnectedCallback) {
+ super.disconnectedCallback();
+ }
+ }
+
+ _stateChanged(state) {
+ this.isDrawerOpen = state.app.drawerOpened;
+ this.isViewallPage = state.app.isViewallPage;
+ }
+
+ handleClick() {
+ this.isDrawerOpen = !this.isDrawerOpen;
+ store.dispatch(updateDrawerState(this.isDrawerOpen));
+ }
+
+ render() {
+ return html`
+
+ ${this.isDrawerOpen ? 'Collapse' : 'Expand'}
+ ${this.isViewallPage ? 'All Panels' : 'Panel'}
+
+
+ `;
+ }
+}
+
+export { InfoToggle };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-info/pl-toggle-info.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-info/pl-toggle-info.scss
new file mode 100644
index 000000000..8896eb2aa
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-info/pl-toggle-info.scss
@@ -0,0 +1,16 @@
+@import '../../../sass/scss/core.scss';
+
+pl-toggle-info {
+ display: flex;
+ align-self: center;
+ justify-content: center;
+ align-items: center;
+ z-index: 10;
+ width: 100%;
+ cursor: pointer;
+}
+
+.pl-c-toggle-info,
+.pl-c-toggle-info__action {
+ width: 100%;
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-layout/pl-toggle-layout.js b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-layout/pl-toggle-layout.js
new file mode 100644
index 000000000..ff6b00cfc
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-layout/pl-toggle-layout.js
@@ -0,0 +1,98 @@
+import { LitElement, html, customElement } from 'lit-element';
+import { store } from '../../store.js'; // connect to the Redux store.
+import { updateLayoutMode } from '../../actions/app.js'; // redux actions
+import styles from './pl-toggle-layout.scss?external';
+
+@customElement('pl-toggle-layout')
+class LayoutToggle extends LitElement {
+ constructor() {
+ super();
+ this.handleClick = this.handleClick.bind(this);
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ connectedCallback() {
+ if (super.connectedCallback) {
+ super.connectedCallback();
+ }
+ styles.use();
+
+ const state = store.getState();
+ this.layoutMode = state.app.layoutMode || 'vertical';
+
+ this.__storeUnsubscribe = store.subscribe(() =>
+ this._stateChanged(store.getState())
+ );
+ this._stateChanged(store.getState());
+
+ this.size = this.size || 'medium';
+ }
+
+ disconnectedCallback() {
+ this.__storeUnsubscribe && this.__storeUnsubscribe();
+ styles.unuse();
+
+ if (super.disconnectedCallback) {
+ super.disconnectedCallback();
+ }
+ }
+
+ static get properties() {
+ return {
+ layoutMode: {
+ attribute: true,
+ type: String,
+ },
+ text: {
+ attribute: true,
+ type: String,
+ },
+ size: {
+ attribute: true,
+ type: String,
+ },
+ iconOnly: {
+ attribute: 'icon-only',
+ type: Boolean,
+ reflect: true,
+ },
+ };
+ }
+
+ _stateChanged(state) {
+ if (this.layoutMode !== state.app.layoutMode) {
+ this.layoutMode = state.app.layoutMode;
+ }
+ }
+
+ handleClick() {
+ const getLayoutMode =
+ this.layoutMode !== 'vertical' ? 'vertical' : 'horizontal';
+
+ this.layoutMode = getLayoutMode;
+ store.dispatch(updateLayoutMode(this.layoutMode));
+ }
+
+ render() {
+ return html`
+
+ ${this.text}
+
+
+ `;
+ }
+}
+
+export { LayoutToggle };
diff --git a/packages/uikit-workshop/src/scripts/components/pl-toggle-layout/pl-toggle-layout.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-layout/pl-toggle-layout.scss
similarity index 74%
rename from packages/uikit-workshop/src/scripts/components/pl-toggle-layout/pl-toggle-layout.scss
rename to packages/uikit-workshop/src/scripts/lit-components/pl-toggle-layout/pl-toggle-layout.scss
index f9c6a9cab..4412646f8 100644
--- a/packages/uikit-workshop/src/scripts/components/pl-toggle-layout/pl-toggle-layout.scss
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-layout/pl-toggle-layout.scss
@@ -1,20 +1,16 @@
@import '../../../sass/scss/core.scss';
pl-toggle-layout {
- display: none;
+ display: flex;
align-self: center;
justify-content: center;
align-items: center;
z-index: 10;
width: 100%;
cursor: pointer;
-
- @media all and (min-width: $pl-bp-med) {
- display: flex;
- }
}
.pl-c-toggle-layout,
.pl-c-toggle-layout__action {
width: 100%;
-}
\ No newline at end of file
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-theme/pl-toggle-theme.js b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-theme/pl-toggle-theme.js
new file mode 100644
index 000000000..d98c8f654
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-theme/pl-toggle-theme.js
@@ -0,0 +1,89 @@
+/* eslint-disable no-unused-vars, no-param-reassign */
+import { LitElement, html, customElement } from 'lit-element';
+import { store } from '../../store.js'; // connect to the Redux store.
+import { updateThemeMode } from '../../actions/app.js'; // redux actions needed
+import styles from './pl-toggle-theme.scss?external';
+
+@customElement('pl-toggle-theme')
+class ThemeToggle extends LitElement {
+ constructor() {
+ super();
+ this.targetOrigin =
+ window.location.protocol === 'file:'
+ ? '*'
+ : window.location.protocol + '//' + window.location.host;
+ }
+
+ static get properties() {
+ return {
+ themeMode: {
+ attribute: true,
+ type: String,
+ },
+ };
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ connectedCallback() {
+ if (super.connectedCallback) {
+ super.connectedCallback();
+ }
+ styles.use();
+
+ const state = store.getState();
+ this.themeMode = state.app.themeMode || 'dark';
+
+ this.__storeUnsubscribe = store.subscribe(() =>
+ this._stateChanged(store.getState())
+ );
+ this._stateChanged(store.getState());
+
+ store.dispatch(updateThemeMode(this.themeMode));
+ }
+
+ disconnectedCallback() {
+ this.__storeUnsubscribe && this.__storeUnsubscribe();
+ styles.unuse();
+
+ if (super.disconnectedCallback) {
+ super.disconnectedCallback();
+ }
+ }
+
+ _stateChanged(state) {
+ this.themeMode = state.app.themeMode;
+ this.iframeElement = document.querySelector('.pl-js-iframe');
+
+ if (this.iframeElement) {
+ const obj = JSON.stringify({
+ event: 'patternLab.stateChange',
+ state,
+ });
+ this.iframeElement.contentWindow.postMessage(obj, this.targetOrigin);
+ }
+ }
+
+ render() {
+ const toggleThemeMode = this.themeMode !== 'dark' ? 'dark' : 'light';
+ return html`
+
store.dispatch(updateThemeMode(toggleThemeMode))}"
+ >
+ Switch Theme
+
+
+
+ `;
+ }
+}
+
+export { ThemeToggle };
diff --git a/packages/uikit-workshop/src/scripts/components/pl-toggle-theme/pl-toggle-theme.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-theme/pl-toggle-theme.scss
similarity index 66%
rename from packages/uikit-workshop/src/scripts/components/pl-toggle-theme/pl-toggle-theme.scss
rename to packages/uikit-workshop/src/scripts/lit-components/pl-toggle-theme/pl-toggle-theme.scss
index 26aa1ba53..074dbaac8 100644
--- a/packages/uikit-workshop/src/scripts/components/pl-toggle-theme/pl-toggle-theme.scss
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-toggle-theme/pl-toggle-theme.scss
@@ -1,5 +1,4 @@
@import '../../../sass/scss/core.scss';
-@import '{ .pl-c-tools__action, .pl-c-tools__action-text, .pl-c-tools__action-icon } from ../../../sass/scss/04-components/_tools.scss';
pl-toggle-theme {
display: flex;
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.js b/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.js
new file mode 100644
index 000000000..fed628846
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.js
@@ -0,0 +1,187 @@
+/* eslint-disable no-unused-vars */
+import { define, props } from 'skatejs';
+import Mousetrap from 'mousetrap';
+import { h } from 'preact';
+import { urlHandler, patternName, iframeMsgDataExtraction } from '../../utils';
+import { store } from '../../store'; // redux store
+import styles from './pl-tools-menu.scss?external';
+
+const listeningForBodyClicks = false;
+
+import { html } from 'lit-html';
+import { BaseLitComponent } from '../../components/base-component';
+import { customElement } from 'lit-element';
+
+@customElement('pl-tools-menu')
+class ToolsMenu extends BaseLitComponent {
+ static get properties() {
+ return {
+ isOpen: Boolean,
+ layoutMode: String,
+ currentUrl: String,
+ };
+ }
+
+ _stateChanged(state) {
+ if (this.currentUrl !== state.app.currentUrl) {
+ this.currentUrl = state.app.currentUrl;
+ }
+
+ if (this.layoutMode !== state.app.layoutMode) {
+ this.layoutMode = state.app.layoutMode || 'vertical';
+ }
+ }
+
+ constructor() {
+ super();
+ this.handleClick = this.handleClick.bind(this);
+ this.receiveIframeMessage = this.receiveIframeMessage.bind(this);
+ this.handleExternalClicks = this.handleExternalClicks.bind(this);
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ const state = store.getState();
+ const { ishControlsHide } = window.ishControls;
+ this.currentUrl = state.app.currentUrl || '';
+ this.ishControlsHide = ishControlsHide;
+
+ window.addEventListener('message', this.receiveIframeMessage, false);
+ document.addEventListener('click', this.handleExternalClicks);
+
+ Mousetrap(this).bind('esc', () => {
+ this.close();
+ });
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ document.removeEventListener('click', this.handleExternalClicks);
+ window.removeEventListener('message', this.receiveIframeMessage);
+ }
+
+ handleExternalClicks(e) {
+ if (window.innerWidth >= 670 && this.layoutMode === 'vertical') {
+ return;
+ }
+
+ if (!this.contains(e.target) && this.isOpen === true) {
+ this.isOpen = false;
+ }
+ }
+
+ close() {
+ this.isOpen = false;
+ }
+
+ toggle() {
+ if (this.isOpen) {
+ this.close();
+ } else {
+ this.open();
+ }
+ }
+
+ open() {
+ this.isOpen = true;
+ }
+
+ handleClick(e) {
+ if (window.innerWidth >= 670 && this.layoutMode === 'vertical') {
+ return;
+ }
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ this.toggle();
+ }
+
+ /**
+ *
+ * @param {MessageEvent} e A message received by a target object.
+ */
+ receiveIframeMessage(event) {
+ const self = this;
+
+ const data = iframeMsgDataExtraction(event);
+
+ if (data.event !== undefined && data.event === 'patternLab.pageClick') {
+ try {
+ self.isOpen = false;
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ }
+
+ render() {
+ if (window.innerWidth >= 670 && this.layoutMode === 'vertical') {
+ this.isOpen = true;
+ }
+
+ return html`
+
+ `;
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.scss
new file mode 100644
index 000000000..00a453234
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-tools-menu/pl-tools-menu.scss
@@ -0,0 +1,129 @@
+/*------------------------------------*\
+ #TOOLS
+\*------------------------------------*/
+
+@import '../../../sass/scss/core.scss';
+
+// vertical align in
container
+pl-tools-menu {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+}
+
+/**
+ * The tools dropdown contains more utilities such as show/hide
+ * pattern info and pattern search, and also links to open in a
+ * new window and view the documentation
+ */
+.pl-c-tools {
+ position: relative;
+ display: flex;
+}
+
+/**
+ * Tools dropdown list
+ */
+.pl-c-tools__list {
+ @include listReset();
+ transform: translateY(-10px);
+ position: absolute;
+ right: 5px;
+ z-index: 10; // make sure context dropdown z-index is higher than nav dropdown z-index
+ width: 12rem;
+ border-radius: 6px;
+ top: calc(100% - 2px);
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.2);
+ background-color: $pl-color-gray-87;
+ background-color: var(--theme-primary, $pl-color-gray-87);
+ transform: translateY(-4rem);
+ opacity: 0;
+ max-height: 0;
+ visibility: hidden;
+ pointer-events: none;
+
+ &.is-open {
+ opacity: 1;
+ max-height: 9999px;
+ visibility: visible;
+ pointer-events: auto;
+ transform: translateY(0);
+ }
+
+ .pl-c-body--theme-light & {
+ background-color: $pl-color-white;
+ background-color: var(--theme-primary, $pl-color-white);
+ }
+
+ .pl-c-body--theme-sidebar & {
+ @media all and (min-width: $pl-bp-med) {
+ box-shadow: none;
+ top: 0;
+ transform: none;
+ border-radius: 0;
+ background-color: transparent;
+ right: 0;
+ opacity: 1;
+ visibility: visible;
+ pointer-events: auto;
+ }
+ }
+
+ &.is-active {
+ overflow: visible;
+ }
+
+ &::before {
+ content: '';
+ height: 14px;
+ width: 14px;
+ background-color: $pl-color-gray-87;
+ background-color: var(--theme-primary, $pl-color-gray-87);
+ position: absolute;
+ right: 0px;
+ top: -10px;
+ transform: translateY(50%) translateX(-50%) rotate(45deg);
+ transition: opacity 0.1s ease-out;
+ box-shadow: 0 0 5px rgba(0, 0, 0, 0.1);
+
+ .pl-c-body--theme-sidebar & {
+ @media all and (min-width: $pl-bp-med) {
+ display: none;
+ }
+ }
+ }
+
+ &.is-active::before {
+ opacity: 1;
+ visibility: visible;
+ }
+}
+
+.pl-c-tools__item {
+ position: relative;
+ overflow: hidden;
+ background-color: inherit;
+
+ // crop list item when hover
+ &:first-child {
+ border-top-left-radius: 6px;
+ border-top-right-radius: 6px;
+
+ .pl-c-body--theme-sidebar & {
+ @media all and (min-width: $pl-bp-med) {
+ border-radius: 0;
+ }
+ }
+ }
+
+ &:last-child {
+ border-bottom-left-radius: 6px;
+ border-bottom-right-radius: 6px;
+
+ .pl-c-body--theme-sidebar & {
+ @media all and (min-width: $pl-bp-med) {
+ border-radius: 0;
+ }
+ }
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-tooltip/pl-tooltip.js b/packages/uikit-workshop/src/scripts/lit-components/pl-tooltip/pl-tooltip.js
new file mode 100644
index 000000000..f24f73043
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-tooltip/pl-tooltip.js
@@ -0,0 +1,59 @@
+import { LitElement, html } from 'lit-element';
+import styles from './pl-tooltip.scss?external';
+import { Slotify } from '../slotify';
+
+class Tooltip extends Slotify(LitElement) {
+ static get properties() {
+ return {
+ message: { type: String },
+ position: { type: String },
+ child: {},
+ };
+ }
+
+ constructor() {
+ super();
+
+ // property defaults
+ this.position = 'top';
+ }
+
+ createRenderRoot() {
+ return this;
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ render() {
+ return html`
+
+ ${this.slotify('default') ? this.slotify('default') : ''}
+ ${this.message}
+
+ `;
+ }
+
+ hideTooltip() {
+ this.opened = false;
+ }
+
+ showTooltip() {
+ this.opened = true;
+ }
+
+ toggleTooltip() {
+ this.opened = !this.opened;
+ }
+}
+
+customElements.define('pl-tooltip', Tooltip);
+
+export { Tooltip };
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-tooltip/pl-tooltip.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-tooltip/pl-tooltip.scss
new file mode 100644
index 000000000..f54842395
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-tooltip/pl-tooltip.scss
@@ -0,0 +1,62 @@
+@import '../../../sass/scss/core.scss';
+
+.tooltip-container {
+ color: $pl-color-gray-87;
+}
+
+pl-tooltip {
+ > *:not(.pl-tooltip) {
+ display: none;
+ }
+}
+
+.pl-tooltip {
+ position: relative;
+ display: inline-block;
+
+ &__text {
+ visibility: hidden;
+ width: 120px;
+ max-width: 200px;
+ background-color: black;
+ color: #fff;
+ text-align: center;
+ padding: 5px 0;
+ border-radius: 6px;
+
+ position: absolute;
+ z-index: 50;
+ }
+
+ &--right &__text,
+ &--left &__text {
+ top: 50%;
+ transform: translateY(-50%);
+ }
+
+ &--right &__text {
+ left: 115%;
+ }
+
+ &--left &__text {
+ right: 115%;
+ }
+
+ &--top &__text,
+ &--bottom &__text {
+ left: 50%;
+ transform: translateX(-50%);
+ }
+
+ &--top &__text {
+ bottom: 115%;
+ }
+
+ &--bottom &__text {
+ top: 115%;
+ }
+
+ &:hover &__text {
+ visibility: visible;
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper.js
new file mode 100644
index 000000000..c1fe8b7a0
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.iframe-helper.js
@@ -0,0 +1,24 @@
+import { targetOrigin } from '../../utils';
+
+function sendPatternLabKeyEvent(e, name) {
+ try {
+ window.parent.postMessage(
+ JSON.stringify({
+ event: `patternLab.${name}`,
+ key: e.key,
+ code: e.code,
+ }),
+ targetOrigin
+ );
+ } catch (error) {
+ // @todo: how do we want to handle exceptions here?
+ }
+}
+
+document.addEventListener('keydown', (e) => {
+ sendPatternLabKeyEvent(e, 'iframeKeyDownEvent');
+});
+
+document.addEventListener('keyup', (e) => {
+ sendPatternLabKeyEvent(e, 'iframeKeyUpEvent');
+});
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js
new file mode 100644
index 000000000..b7ec9f3e3
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.js
@@ -0,0 +1,436 @@
+/* eslint-disable no-unused-vars */
+import { h } from 'preact';
+import { define, props } from 'skatejs';
+import { BaseComponent } from '../../components/base-component.js';
+import { store } from '../../store.js'; // connect to redux
+
+import {
+ minViewportWidth,
+ maxViewportWidth,
+ getRandom,
+ iframeMsgDataExtraction,
+} from '../../utils';
+
+import styles from './pl-viewport-size-list.scss?external';
+
+@define
+class ViewportSizes extends BaseComponent {
+ static is = 'pl-viewport-sizes';
+
+ sizes = Object.freeze({
+ ZERO: 'zero',
+ SMALL: 'small',
+ MEDIUM: 'medium',
+ LARGE: 'large',
+ FULL: 'full',
+ RANDOM: 'random',
+ DISCO: 'disco',
+ HAY: 'hay',
+ });
+
+ discomode = false;
+ doscoId = null;
+ hayMode = false;
+ hayId = null;
+ layoutMode = null;
+ tooltipPos = null;
+
+ controlIsPressed = false;
+ altIsPressed = false;
+
+ _stateChanged(state) {
+ this.triggerUpdate();
+
+ if (this.layoutMode !== state.app.layoutMode) {
+ this.layoutMode = state.app.layoutMode || 'vertical';
+ this.tooltipPos = this.layoutMode === 'horizontal' ? 'bottom' : 'top';
+ }
+ }
+
+ constructor() {
+ super();
+ this.resizeViewport = this.resizeViewport.bind(this);
+ this.useShadow = false;
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ const state = store.getState();
+ const { ishControlsHide } = window?.ishControls;
+ this.ishControlsHide = ishControlsHide;
+
+ // Remove EventListener or they will be added multiple times when reloading in serve mode
+ document.removeEventListener('keydown', this.handleKeyDownEvent);
+ document.removeEventListener('keyup', this.handleKeyCombination);
+ document.addEventListener('keydown', this.handleKeyDownEvent.bind(this));
+ document.addEventListener('keyup', this.handleKeyCombination.bind(this));
+ this.receiveIframeMessage = this.receiveIframeMessage.bind(this);
+
+ window.removeEventListener('message', this.receiveIframeMessage);
+ window.addEventListener('message', this.receiveIframeMessage, false);
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ shouldUpdate(prevProps, prevState) {
+ return true;
+ }
+
+ resizeViewport(size) {
+ if (this.iframe) {
+ this.killDisco();
+ this.killHay();
+
+ switch (size) {
+ case this.sizes.ZERO:
+ this.iframe.fullMode = false;
+ this.iframe.sizeiframe(0, true);
+ case this.sizes.SMALL:
+ this.iframe.fullMode = false;
+ this.iframe.sizeiframe(
+ getRandom(
+ minViewportWidth,
+ window.config.ishViewportRange !== undefined
+ ? parseInt(window.config.ishViewportRange.s[1], 10)
+ : 500
+ ),
+ true
+ );
+ break;
+ case this.sizes.MEDIUM:
+ this.iframe.fullMode = false;
+ this.iframe.sizeiframe(
+ getRandom(
+ window.config.ishViewportRange !== undefined
+ ? parseInt(window.config.ishViewportRange.m[0], 10)
+ : 500,
+ window.config.ishViewportRange !== undefined
+ ? parseInt(window.config.ishViewportRange.m[1], 10)
+ : 800
+ ),
+ true
+ );
+ break;
+ case this.sizes.LARGE:
+ this.iframe.fullMode = false;
+ this.iframe.sizeiframe(
+ getRandom(
+ window.config.ishViewportRange !== undefined
+ ? parseInt(window.config.ishViewportRange.l[0], 10)
+ : 800,
+ window.config.ishViewportRange !== undefined
+ ? parseInt(window.config.ishViewportRange.l[1], 10)
+ : 1000
+ ),
+ true
+ );
+ break;
+ case this.sizes.FULL:
+ this.iframe.fullMode = true;
+ this.iframe.sizeiframe(maxViewportWidth, true);
+ break;
+ case this.sizes.RANDOM:
+ this.fullMode = false;
+ this.iframe.sizeiframe(this.getRangeRandomNumber(), true);
+ break;
+ case this.sizes.DISCO:
+ this.fullMode = false;
+ this.startDisco();
+ break;
+ case this.sizes.HAY:
+ this.fullMode = false;
+ this.iframe.sizeiframe(minViewportWidth, true);
+ this.startHay();
+ break;
+ }
+ }
+ }
+
+ /**
+ * Get a random number between minViewportWidth and maxViewportWidth
+ */
+ getRangeRandomNumber() {
+ return getRandom(
+ minViewportWidth,
+ // Do not evaluate a number higher than the clientWidth of the Iframe
+ // to prevent having max size multiple times
+ maxViewportWidth > this.iframe.clientWidth
+ ? this.iframe.clientWidth
+ : maxViewportWidth
+ );
+ }
+
+ /**
+ * Start the disco mode, which means in a specific interval resize
+ * the iframe random between minViewportWidth and maxViewportWidth
+ */
+ startDisco() {
+ this.discoMode = true;
+ this.discoId = setInterval(this.disco.bind(this), 1000);
+ }
+
+ /**
+ * Stop the disco mode
+ */
+ killDisco() {
+ this.discoMode = false;
+ clearInterval(this.discoId);
+ this.discoID = null;
+ }
+
+ /**
+ * Action to resize the Iframe in disco mode
+ */
+ disco() {
+ this.iframe.sizeiframe(this.getRangeRandomNumber(), true);
+ }
+
+ /**
+ * Start the Hay! mode, which means the iframe is growing slowly
+ * from minViewportWidth to maxViewportWidth
+ */
+ startHay() {
+ this.hayMode = true;
+ this.hayId = setInterval(this.hay.bind(this), 100);
+ }
+
+ /**
+ * Stop the Hay! Mode
+ */
+ killHay() {
+ this.hayMode = false;
+ clearInterval(this.hayId);
+ this.hayId = null;
+ }
+
+ /**
+ * Action to resize the Iframe in Hay! mode
+ */
+ hay() {
+ this.iframe.sizeiframe(store.getState().app.viewportPx + 1, true);
+ }
+
+ /**
+ * Litte workaround for Firefox Bug.
+ *
+ * On QWERTZ keyboards the e.altKey and e.ctrlKey will
+ * not be set if you click on a key that has a specific
+ * secondary or third char at ALT + ...
+ *
+ * @param {KeyboardEvent} e the keyevent
+ */
+ handleKeyDownEvent(e) {
+ if (e.key === 'Control') {
+ this.controlIsPressed = true;
+ }
+ if (e.key === 'Alt') {
+ this.altIsPressed = true;
+ }
+ }
+
+ /**
+ * https://patternlab.io/docs/advanced-keyboard-shortcuts.html
+ *
+ * Why use these specific key combinations?
+ * Works on QUERTZ, QUERTY and AZERTY keyboard and they are no
+ * reserved browser functionality key combinations.
+ *
+ * QUERTY https://en.wikipedia.org/wiki/QWERTY
+ * QUERTZ https://en.wikipedia.org/wiki/QWERTZ
+ * AZERTY https://en.wikipedia.org/wiki/AZERTY
+ *
+ * Chromium
+ * https://support.google.com/chrome/answer/157179?hl=en
+ *
+ * Firefox
+ * https://support.mozilla.org/en-US/kb/keyboard-shortcuts-perform-firefox-tasks-quickly
+ *
+ * @param {KeyboardEvent} e the keyevent
+ */
+ handleKeyCombination(e) {
+ const ctrlKey = this.controlIsPressed;
+ const altKey = this.altIsPressed;
+
+ if (ctrlKey && altKey && (e.code === 'Digit0' || e.code === 'Numpad0')) {
+ this.resizeViewport(this.sizes.ZERO);
+ } else if (ctrlKey && altKey && e.code === 'KeyS') {
+ this.resizeViewport(this.sizes.SMALL);
+ } else if (ctrlKey && altKey && e.code === 'KeyM') {
+ this.resizeViewport(this.sizes.MEDIUM);
+ } else if (ctrlKey && altKey && e.code === 'KeyL') {
+ this.resizeViewport(this.sizes.LARGE);
+ } else if (ctrlKey && altKey && e.code === 'KeyF') {
+ this.resizeViewport(this.sizes.FULL);
+ } else if (ctrlKey && altKey && e.code === 'KeyR') {
+ this.resizeViewport(this.sizes.RANDOM);
+ } else if (ctrlKey && altKey && e.code === 'KeyD') {
+ this.resizeViewport(this.sizes.DISCO);
+ } else if (ctrlKey && altKey && e.code === 'KeyH') {
+ this.resizeViewport(this.sizes.HAY);
+ }
+
+ if (e.key === 'Control') {
+ this.controlIsPressed = false;
+ }
+ if (e.key === 'Alt') {
+ this.altIsPressed = false;
+ }
+ }
+
+ /**
+ * Interpret and handle the received message input
+ *
+ * @param {MessageEvent} e A message received by a target object.
+ */
+ receiveIframeMessage(e) {
+ const data = iframeMsgDataExtraction(e);
+
+ if (data.event && data.event === 'patternLab.iframeKeyDownEvent') {
+ this.handleKeyDownEvent(data);
+ } else if (data.event && data.event === 'patternLab.iframeKeyUpEvent') {
+ this.handleKeyCombination(data);
+ }
+ }
+
+ rendered() {
+ this.iframe = document.querySelector('pl-iframe');
+ this.iframeElem = document.querySelector('pl-iframe iframe');
+ }
+
+ render() {
+ return (
+
+ {!this.ishControlsHide?.s && (
+
+
+ this.resizeViewport(this.sizes.SMALL)}
+ dangerouslySetInnerHTML={{
+ __html: `
+ Resize viewport to small
+
+ `,
+ }}
+ type="button"
+ />
+
+
+ )}
+ {!this.ishControlsHide?.m && (
+
+
+ this.resizeViewport(this.sizes.MEDIUM)}
+ dangerouslySetInnerHTML={{
+ __html: `
+ Resize viewport to medium
+
+ `,
+ }}
+ type="button"
+ />
+
+
+ )}
+ {!this.ishControlsHide?.l && (
+
+
+ this.resizeViewport(this.sizes.LARGE)}
+ dangerouslySetInnerHTML={{
+ __html: `
+ Resize viewport to large
+
+ `,
+ }}
+ type="button"
+ />
+
+
+ )}
+ {!this.ishControlsHide?.full && (
+
+
+ this.resizeViewport(this.sizes.FULL)}
+ dangerouslySetInnerHTML={{
+ __html: `
+ Resize viewport to full
+
+ `,
+ }}
+ type="button"
+ />
+
+
+ )}
+ {!this.ishControlsHide?.random && (
+
+
+ this.resizeViewport(this.sizes.RANDOM)}
+ dangerouslySetInnerHTML={{
+ __html: `
+ Resize viewport to random
+
+ `,
+ }}
+ type="button"
+ />
+
+
+ )}
+ {!this.ishControlsHide?.disco && (
+
+
+ this.resizeViewport(this.sizes.DISCO)}
+ dangerouslySetInnerHTML={{
+ __html: `
+ Resize viewport using disco mode!
+
+ `,
+ }}
+ type="button"
+ />
+
+
+ )}
+ {!this.ishControlsHide?.hay && (
+
+
+ this.resizeViewport(this.sizes.HAY)}
+ dangerouslySetInnerHTML={{
+ __html: `
+ Resize viewport using hay mode!
+
+ `,
+ }}
+ type="button"
+ />
+
+
+ )}
+
+ );
+ }
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.scss
new file mode 100644
index 000000000..3048f46ed
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size-list/pl-viewport-size-list.scss
@@ -0,0 +1,56 @@
+@import '../../../sass/scss/core.scss';
+
+pl-viewport-sizes {
+ display: flex;
+ justify-content: center;
+}
+
+/**
+ * Size options
+ * 1) This holds the S, M, L, Rand, Disco links
+ * 2) Depending on the config, these number of options may be
+ * larger or smaller.
+ */
+.pl-c-size-list {
+ display: none;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ padding: 0 0.25rem;
+
+ @media all and (min-width: $pl-bp-med) {
+ align-items: center;
+ -webkit-overflow-scrolling: touch;
+ }
+
+ @media all and (min-width: $pl-bp-med) {
+ display: block;
+ display: flex;
+ }
+}
+
+/**
+ * Size actions
+ * 1) These are the buttons that control the viewport resizing
+ */
+.pl-c-size-list__action {
+ @include buttonStyles;
+ display: inline-block; // workaround to fix valign issues in IE 11
+ min-height: 35px;
+ min-width: 0;
+ padding-left: 0.35rem;
+ padding-right: 0.35rem;
+
+ pl-icon {
+ pointer-events: none;
+ }
+}
+
+// Force list items to center align if not overflow scrolling
+.pl-c-size-list__item:first-child {
+ margin-left: auto;
+}
+
+.pl-c-size-list__item:last-child {
+ margin-right: auto;
+}
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.js
new file mode 100644
index 000000000..96e189bee
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.js
@@ -0,0 +1,204 @@
+/* eslint-disable no-unused-vars */
+import { h } from 'preact';
+
+import { BaseLitComponent } from '../../components/base-component';
+import { html, customElement } from 'lit-element';
+import styles from './pl-viewport-size.scss?external';
+import { store } from '../../store.js'; // connect to redux
+
+const nRegex = /\D+/g;
+const fpRegex = /[^0-9\.]+/g;
+
+function round(value, decimals) {
+ return Number(Math.round(value + 'e' + decimals) + 'e-' + decimals);
+}
+
+@customElement('pl-viewport-size')
+class ViewportSize extends BaseLitComponent {
+ static get properties() {
+ return {
+ px: String,
+ em: String,
+ };
+ }
+
+ constructor() {
+ super();
+ this.state = { inputPixelValue: 0, inputEmValue: 0 };
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ styles.use();
+ const state = store.getState();
+ this.setPxEm(state);
+ this.iframe = document.querySelector('pl-iframe');
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ styles.unuse();
+ }
+
+ _stateChanged(state) {
+ this.setPxEm(state);
+ }
+
+ setPxEm(state) {
+ if (state.app.viewportPx !== this.px) {
+ this.px = round(state.app.viewportPx, 0);
+ this.setState({ inputPixelValue: this.px }, () => {});
+ }
+
+ if (round(state.app.viewportEm, 1) !== this.em) {
+ this.em = round(state.app.viewportEm, 1);
+ this.setState({ inputEmValue: this.em }, () => {});
+ }
+ }
+
+ firstUpdated() {
+ this.viewport = document.querySelector('pl-viewport');
+ }
+
+ updated() {
+ if (this.viewport && this.viewport.bodySize) {
+ this.em = Math.floor(this.px * this.bodySize);
+ }
+ }
+
+ handlePixelUpdateUp(e) {
+ this.setState(
+ { inputPixelValue: e.target.value.replace(nRegex, '') },
+ () => {}
+ );
+ }
+
+ handlePixelUpdatePress(e) {
+ if (e.key.match(nRegex)) {
+ // Prevent inserting letters or symbols
+ e.preventDefault();
+ }
+ }
+
+ handlePixelUpdateDown(e) {
+ if (e.key === 'Enter') {
+ event.preventDefault();
+ this.iframe.sizeiframe(this.state.inputPixelValue, true);
+ } else if (e.key === 'ArrowUp') {
+ this.setState(
+ {
+ inputPixelValue:
+ Number(e.target.value.replace(nRegex, '')) + (e.shiftKey ? 10 : 1),
+ },
+ () => {}
+ );
+ this.iframe.sizeiframe(this.state.inputPixelValue, true);
+ } else if (e.key === 'ArrowDown') {
+ this.setState(
+ {
+ inputPixelValue:
+ Number(e.target.value.replace(nRegex, '')) - (e.shiftKey ? 10 : 1),
+ },
+ () => {}
+ );
+ this.iframe.sizeiframe(this.state.inputPixelValue, true);
+ }
+ }
+
+ handlePixelBlur(e) {
+ this.setState({ inputPixelValue: this.px }, () => {});
+ e.target.value = this.state.inputPixelValue;
+ }
+
+ handleEmUpdateUp(e) {
+ this.setState(
+ { inputEmValue: e.target.value.replace(fpRegex, '') },
+ () => {}
+ );
+ }
+
+ handleEmUpdatePress(e) {
+ if (e.key.match(fpRegex)) {
+ // Prevent inserting letters or symbols
+ e.preventDefault();
+ }
+ }
+
+ handleEmUpdateDown(e) {
+ if (e.key === 'Enter') {
+ event.preventDefault();
+ this.iframe.sizeiframe(this.toPixelValue(), true);
+ } else if (e.key === 'ArrowUp') {
+ this.setState(
+ {
+ inputEmValue: round(
+ Number(e.target.value.replace(fpRegex, '')) +
+ (e.shiftKey ? 0.5 : 0.1),
+ 1
+ ),
+ },
+ () => {}
+ );
+ this.iframe.sizeiframe(this.toPixelValue(), true);
+ } else if (e.key === 'ArrowDown') {
+ this.setState(
+ {
+ inputEmValue: round(
+ Number(e.target.value.replace(fpRegex, '')) -
+ (e.shiftKey ? 0.5 : 0.1),
+ 1
+ ),
+ },
+ () => {}
+ );
+ this.iframe.sizeiframe(this.toPixelValue(), true);
+ }
+ }
+
+ handleEmBlur(e) {
+ this.setState({ inputEmValue: this.em }, () => {});
+ e.target.value = this.state.inputEmValue;
+ }
+
+ toPixelValue() {
+ return Math.floor(this.state.inputEmValue * this.iframe.bodySize);
+ }
+
+ render() {
+ if (!window.__PRERENDER_INJECTED) {
+ return html`
+
+ `;
+ }
+ }
+}
+
+export { ViewportSize };
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_ish-sizing.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.scss
similarity index 53%
rename from packages/uikit-workshop/src/sass/scss/04-components/_ish-sizing.scss
rename to packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.scss
index 5435c4537..a811d6ced 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_ish-sizing.scss
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport-size/pl-viewport-size.scss
@@ -2,18 +2,34 @@
#ISH SIZING
\*------------------------------------*/
+@import '../../../sass/scss/core.scss';
+
/**
* Viewport size form
* 1) This is the form for the form that houses the current
* viewport size in px and em
*/
+pl-viewport-size {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
.pl-c-viewport-size {
margin: 0;
border: 0;
- padding: 0.3rem 0.5rem 0.4rem;
+
+ // Prevent zooming on phone browser when the font size is smaller than 16px
+ // As it would break the visualization the field itself will be scaled to 85%
+ font-size: 1rem;
+ transform: scale(0.85);
+
+ padding: 0.3rem 0.25rem;
line-height: 1;
display: flex;
align-items: center;
+ flex-shrink: 0;
+ justify-content: center;
}
/**
@@ -25,11 +41,18 @@
border: 0;
border-radius: $pl-border-radius;
background-color: transparent;
- font-size: inherit;
- color: $pl-color-gray-50;
- width: 35px;
+ color: inherit;
+ width: auto;
text-align: right;
transition: all $pl-animate-quick ease-out;
+ pointer-events: none;
+ text-overflow: ellipsis;
+}
+
+.pl-c-viewport-size__input-action {
+ max-width: 47px;
+ font-size: inherit;
+ pointer-events: auto;
&::-moz-focus-inner {
padding: 0;
@@ -49,7 +72,6 @@
outline-offset: -1px;
}
}
-
/**
* Size input labels
*/
@@ -57,47 +79,5 @@
display: block;
margin: 0;
padding: 0;
+ cursor: pointer;
}
-
-/**
- * Size options
- * 1) This holds the S, M, L, Rand, Disco links
- * 2) Depending on the config, these number of options may be
- * larger or smaller.
- */
-.pl-c-size-list {
- display: none;
- list-style: none;
- margin: 0;
- padding: 0;
- overflow-x: auto;
- padding: 0 0.25rem;
-
- @media all and (min-width: $pl-bp-med) {
- align-items: center;
- -webkit-overflow-scrolling: touch;
-
- }
-
- @media all and (min-width: $pl-bp-large) {
- display: block;
- display: flex;
- }
-}
-
-/**
- * Size actions
- * 1) These are the buttons that control the viewport resizing
- */
-.pl-c-size-list__action {
- @include linkStyle();
-}
-
-// Force list items to center align if not overflow scrolling
-.pl-c-size-list__item:first-child {
- margin-left: auto;
-}
-
-.pl-c-size-list__item:last-child {
- margin-right: auto;
-}
\ No newline at end of file
diff --git a/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js
new file mode 100644
index 000000000..ffbef44d7
--- /dev/null
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.js
@@ -0,0 +1,543 @@
+/* eslint-disable no-unused-vars, no-param-reassign */
+import { ifDefined } from 'lit-html/directives/if-defined';
+import { store } from '../../store.js'; // connect to redux
+import { updateCurrentPattern, updateCurrentUrl } from '../../actions/app.js'; // redux actions
+import { updateViewportPx, updateViewportEm } from '../../actions/app.js'; // redux actions needed
+import {
+ minViewportWidth,
+ maxViewportWidth,
+ urlHandler,
+ patternName,
+ iframeMsgDataExtraction,
+} from '../../utils';
+
+import { html } from 'lit-html';
+import { BaseLitComponent } from '../../components/base-component.js';
+
+import iframeLoaderStyles from '../../../sass/pattern-lab--iframe-loader.scss?external';
+import styles from './pl-viewport.scss?external';
+import { customElement } from 'lit-element';
+
+let trackingPageChange = false;
+
+@customElement('pl-iframe')
+class IFrame extends BaseLitComponent {
+ constructor() {
+ super();
+ this.handlePageChange = this.handlePageChange.bind(this);
+ this.handlePageLoad = this.handlePageLoad.bind(this);
+ this.receiveIframeMessage = this.receiveIframeMessage.bind(this);
+ this.handleResize = this.handleResize.bind(this);
+ this.handleMouseDown = this.handleMouseDown.bind(this);
+ this.handleIframe404 = this.handleIframe404.bind(this);
+ }
+
+ connectedCallback() {
+ super.connectedCallback && super.connectedCallback();
+ iframeLoaderStyles.use();
+ styles.use();
+
+ this.defaultPattern =
+ window.config && window.config.defaultPattern
+ ? window.config.defaultPattern
+ : 'all';
+
+ this.defaultIframeUrl = urlHandler.getFileName(this.defaultPattern);
+
+ if (trackingPageChange === false) {
+ trackingPageChange = true;
+ document.addEventListener('patternPartial', this.handlePageLoad);
+ window.addEventListener('popstate', this.handlePageChange);
+ }
+
+ const state = store.getState();
+ this.themeMode = state.app.themeMode || 'dark';
+ this.isViewallPage = state.app.isViewallPage || false;
+ this.currentPattern = state.app.currentPattern || '';
+ this.layoutMode = state.app.layoutMode;
+
+ if (state.app.viewportPx) {
+ this.sizeiframe(state.app.viewportPx, false);
+ }
+
+ window.addEventListener('message', this.receiveIframeMessage, false);
+ window.addEventListener('resize', this.handleResize);
+ this.handleOrientationChange();
+
+ // the simple HTML to render in the iFrame when encountering broken links
+ this.iframe404Fallback = `
+
+
+
+
+
Oh snap, a 404!
+
You might want to double-check to see if the page you're looking for has moved or if your URL is correct.
+
Alternatively, click here to head back to the default Pattern Lab page!
+
+
+
+
+ `;
+
+ this._hasInitiallyRendered = false;
+ this.fullMode = true;
+ this.viewportResizeHandleWidth = 22; //Width of the viewport drag-to-resize handle
+ this.bodySize =
+ window.config.ishFontSize !== undefined
+ ? parseInt(window.config.ishFontSize, 10)
+ : parseInt(
+ window
+ .getComputedStyle(document.body, null)
+ .getPropertyValue('font-size'),
+ 10
+ ); //Body size of the document
+
+ //set up the default for the
+ this.baseIframePath =
+ window.location.protocol +
+ '//' +
+ window.location.host +
+ window.location.pathname.replace('index.html', '');
+ this.defaultIframePath = this.baseIframePath + '?p=components-overview';
+ }
+
+ disconnectedCallback() {
+ super.disconnectedCallback && super.disconnectedCallback();
+ iframeLoaderStyles.unuse();
+ styles.unuse();
+ }
+
+ /**
+ * returns the current patternName after removing any numbers / dashes
+ * Workaround to PL Node not always having clean viewall / pattern links
+ */
+ sanitizePatternName(plName) {
+ if (urlHandler.getFileName(plName)) {
+ return plName;
+ } else if (
+ !document.querySelector(`[data-patternpartial="${plName}"]`) &&
+ plName
+ ) {
+ return plName.replace(/[-][0-9][0-9]/g, '');
+ } else {
+ return plName;
+ }
+ }
+
+ // returns the current patternName based on the `p=` query string OR the default pattern that's set globall (as a fallback)
+ getPatternParam() {
+ const queryString = window.location.search;
+ const urlParams = new URLSearchParams(queryString);
+ const patternParam = urlParams.get('p');
+
+ if (patternParam === null) {
+ return this.defaultPattern;
+ } else {
+ return this.sanitizePatternName(patternParam);
+ }
+ }
+
+ // adds / updates the page's query string
+ handlePageLoad(e) {
+ const currentPattern = this.getPatternParam();
+
+ if (currentPattern) {
+ document.title = 'Pattern Lab - ' + currentPattern;
+
+ const addressReplacement =
+ window.location.protocol === 'file:'
+ ? null
+ : window.location.protocol +
+ '//' +
+ window.location.host +
+ (window.config.noIndexHtmlremoval
+ ? window.location.pathname
+ : window.location.pathname.replace('index.html', '')) +
+ '?p=' +
+ currentPattern;
+
+ if (this.dontWipeBrowserHistory === true) {
+ window.history.replaceState(
+ {
+ currentPattern: currentPattern,
+ },
+ null,
+ addressReplacement
+ );
+ this.dontWipeBrowserHistory = false;
+ } else {
+ window.history.pushState(
+ {
+ currentPattern: currentPattern,
+ },
+ null,
+ addressReplacement
+ );
+ }
+ }
+ }
+
+ // navigate to the new PL page (based on the query string) when the page's pop state changes
+ handlePageChange(e) {
+ if (e?.state?.currentPattern) {
+ this.navigateTo(e.state.currentPattern);
+ } else {
+ this.navigateTo(this.getPatternParam());
+ }
+ }
+
+ //Resize the viewport
+ //'size' is the target size of the viewport
+ //'animate' is a boolean for switching the CSS animation on or off. 'animate' is true by default, but can be set to false for things like nudging and dragging
+ sizeiframe(size, animate) {
+ let theSize;
+ const self = this;
+
+ // @todo: refactor to better handle the iframe async rendering
+ if (this.iframe) {
+ if (animate === true) {
+ this.iframeContainer.classList.add('is-animating');
+ this.iframe.classList.add('is-animating');
+ }
+
+ if (size < maxViewportWidth) {
+ theSize = size;
+ } else {
+ //If the entered size is larger than the max allowed viewport size, cap value at max vp size
+ theSize = maxViewportWidth;
+ }
+
+ if (size < minViewportWidth) {
+ //If the entered size is less than the minimum allowed viewport size, cap value at min vp size
+ theSize = minViewportWidth;
+ }
+
+ if (theSize > this.clientWidth) {
+ theSize = this.clientWidth;
+ }
+
+ // resize viewport wrapper to desired size + size of drag resize handler
+ // this.iframeContainer.style.width = theSize + this.viewportResizeHandleWidth + 'px';
+ this.iframeContainer.style.width = theSize + 'px';
+ // this.iframe.style.width = theSize + 'px'; // resize viewport to desired size
+
+ // auto-remove transition classes if not the animate param isn't set to true
+ setTimeout(function () {
+ if (animate === true) {
+ self.iframeContainer.classList.remove('is-animating');
+ self.iframe.classList.remove('is-animating');
+ }
+ }, 800);
+
+ const targetOrigin =
+ window.location.protocol === 'file:'
+ ? '*'
+ : window.location.protocol + '//' + window.location.host;
+
+ const obj = JSON.stringify({
+ event: 'patternLab.resize',
+ resize: 'true',
+ });
+
+ // only tell the iframe to resize when it's ready
+ if (this._hasInitiallyRendered) {
+ this.iframe.contentWindow.postMessage(obj, targetOrigin);
+ }
+
+ this.updateSizeReading(theSize); // update the displayed values in the toolbar
+ }
+ }
+
+ handleOrientationChange() {
+ // Listen for resize changes
+ const self = this;
+ if (window.orientation !== undefined) {
+ this.origOrientation = window.orientation;
+ window.addEventListener(
+ 'orientationchange',
+ function () {
+ if (window.orientation !== this.origOrientation) {
+ const newWidth = window.innerWidth;
+ self.iframeContainer.style.width = newWidth;
+ self.iframe.style.width = newWidth;
+ self.updateSizeReading(newWidth);
+ this.origOrientation = window.orientation;
+ }
+ },
+ false
+ );
+ }
+ }
+
+ handleResize() {
+ this.updateSizeReading(this.iframeContainer.clientWidth);
+ }
+
+ // Update Pixel and Em inputs
+ // 'size' is the input number
+ // 'unit' is the type of unit: either px or em. Default is px.
+ // Accepted values are 'px' and 'em'
+ // 'target' is what inputs to update. Defaults to both
+ updateSizeReading(size, unit, target) {
+ if (size === 0) {
+ return;
+ }
+ let emSize, pxSize;
+
+ if (unit === 'em') {
+ // if size value is in em units
+ emSize = size;
+ pxSize = Math.floor(size * this.bodySize);
+ } else {
+ // if value is px or absent
+ pxSize = size;
+ emSize = size / this.bodySize;
+ }
+
+ if (target === 'updatePxInput') {
+ store.dispatch(updateViewportPx(pxSize));
+ } else if (target === 'updateEmInput') {
+ store.dispatch(updateViewportEm(emSize.toFixed(2)));
+ } else {
+ store.dispatch(updateViewportPx(pxSize));
+ store.dispatch(updateViewportEm(emSize.toFixed(2)));
+ }
+ }
+
+ _stateChanged(state) {
+ if (this._hasInitiallyRendered) {
+ if (state.app.viewportPx) {
+ this.sizeiframe(state.app.viewportPx, false);
+ } else {
+ this.sizeiframe(this.iframe.clientWidth, false);
+ }
+ }
+
+ // Update size when layout is changed
+ if (this.layoutMode !== state.app.layoutMode) {
+ this.layoutMode = state.app.layoutMode;
+ if (this.iframeContainer) {
+ this.updateSizeReading(this.iframeContainer.clientWidth);
+ }
+ }
+ }
+
+ navigateTo(pattern = patternName) {
+ const plName = this.sanitizePatternName(pattern);
+ const plPath = urlHandler.getFileName(plName);
+
+ if (plPath) {
+ this.iFramePath =
+ plPath !== ''
+ ? this.baseIframePath + plPath + '?' + Date.now()
+ : this.defaultIframePath;
+ this.dontWipeBrowserHistory = true;
+
+ document
+ .querySelector('.pl-js-iframe')
+ .contentWindow.location.replace(this.iFramePath);
+ }
+ }
+
+ firstUpdated() {
+ this.iframe = this.querySelector('.pl-js-iframe');
+ this.iframeContainer = this.querySelector('.pl-js-vp-iframe-container');
+ this.iframeCover = this.querySelector('.pl-js-viewport-cover');
+ this.updateSizeReading(this.iframeContainer.clientWidth);
+
+ // watch for URL changes to try and catch any 404s within PL's iFrame
+ //
+ // technique loosely based off of https://stackoverflow.com/a/47675884
+ const unloadIframeHandler = () => {
+ // Timeout needed since the URL changes immediately after the `unload` event is dispatched.
+ setTimeout(() => {
+ this.handleIframe404();
+ }, 0);
+ };
+
+ const attachIframeUnload = () => {
+ // Remove the unloadIframeHandler in case it was already attached to avoid firing twice
+ if (this.iframe.contentWindow) {
+ this.iframe.contentWindow.removeEventListener(
+ 'unload',
+ unloadIframeHandler
+ );
+ this.iframe.contentWindow.addEventListener(
+ 'unload',
+ unloadIframeHandler
+ );
+ }
+ };
+
+ this.iframe.addEventListener('load', attachIframeUnload);
+ attachIframeUnload();
+ }
+
+ // logic that trying to handle 404s in the PL iframe
+ handleIframe404() {
+ setTimeout(() => {
+ if (
+ this.iframe?.contentWindow?.document?.body?.textContent.includes(
+ 'Cannot GET'
+ ) ||
+ this.iframe?.contentWindow?.document?.title.includes('Error')
+ ) {
+ /**
+ * Replace the iFrame's inner contents vs literally use a srcdoc.
+ * Workaround to avoiding an infinite loop (if using srcdoc) which breaks the ability to
+ * hit the back button if you hit a 404
+ */
+ this.iframe.contentWindow.document.body.innerHTML =
+ this.iframe404Fallback;
+ }
+ }, 100);
+ }
+
+ render() {
+ const url = urlHandler.getFileName(this.getPatternParam());
+
+ const initialWidth =
+ !window.config.defaultInitialViewportWidth &&
+ store.getState().app.viewportPx &&
+ store.getState().app.viewportPx <= this.clientWidth
+ ? store.getState().app.viewportPx + 'px;'
+ : '100%';
+
+ return html`
+
+
+
+
+
+
+
+
+ Drag to resize Pattern Lab
+
+
+
+
+
+
+ `;
+ }
+
+ handleMouseDown(event) {
+ // capture default data
+ const self = this;
+ self.querySelector('.pl-js-resize-handle').classList.add('is-resizing');
+ const origClientX = event.clientX;
+ const origViewportWidth = this.iframeContainer.clientWidth;
+
+ this.fullMode = false;
+
+ // show the cover
+ this.iframeCover.hidden = false;
+
+ function handleIframeCoverResize(e) {
+ const viewportWidth = origViewportWidth + 2 * (e.clientX - origClientX);
+ if (
+ viewportWidth > minViewportWidth &&
+ viewportWidth < maxViewportWidth
+ ) {
+ self.sizeiframe(viewportWidth, false);
+ } else if (viewportWidth > maxViewportWidth) {
+ self.sizeiframe(maxViewportWidth, false);
+ } else {
+ self.sizeiframe(minViewportWidth, false);
+ }
+ }
+
+ // add the mouse move event and capture data. also update the viewport width
+ this.iframeCover.addEventListener('mousemove', handleIframeCoverResize);
+
+ document.body.addEventListener(
+ 'mouseup',
+ function () {
+ self.iframeCover.removeEventListener(
+ 'mousemove',
+ handleIframeCoverResize
+ );
+ self.iframeCover.hidden = true;
+ self
+ .querySelector('.pl-js-resize-handle')
+ .classList.remove('is-resizing');
+ },
+ {
+ once: true,
+ }
+ );
+
+ return false;
+ }
+
+ /**
+ * updates the nav after the iframed page tells the iframe it's done loading
+ *
+ * @param {MessageEvent} e A message received by a target object.
+ */
+ receiveIframeMessage(e) {
+ const data = iframeMsgDataExtraction(e);
+
+ // try to auto-correct for currentPattern data that doesn't always match with url
+ // workaround for certain pages (especially view all pages) not always matching up internally with the expected current pattern key
+ if (data.event !== undefined && data.event === 'patternLab.pageLoad') {
+ try {
+ const currentPattern =
+ this.sanitizePatternName(data.patternpartial) ||
+ this.getPatternParam();
+
+ document.title = 'Pattern Lab - ' + currentPattern;
+
+ const addressReplacement =
+ window.location.protocol === 'file:'
+ ? null
+ : window.location.protocol +
+ '//' +
+ window.location.host +
+ (window.config.noIndexHtmlremoval
+ ? window.location.pathname
+ : window.location.pathname.replace('index.html', '')) +
+ '?p=' +
+ currentPattern;
+
+ window.history.replaceState(
+ {
+ currentPattern: currentPattern,
+ },
+ null,
+ addressReplacement
+ );
+
+ const currentUrl = urlHandler.getFileName(currentPattern);
+ if (currentUrl) {
+ store.dispatch(updateCurrentUrl(currentUrl));
+ }
+ store.dispatch(updateCurrentPattern(currentPattern));
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ }
+}
+
+export { IFrame };
diff --git a/packages/uikit-workshop/src/sass/scss/04-components/_viewport.scss b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.scss
similarity index 61%
rename from packages/uikit-workshop/src/sass/scss/04-components/_viewport.scss
rename to packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.scss
index a2dcdd6a7..d5e3211f0 100644
--- a/packages/uikit-workshop/src/sass/scss/04-components/_viewport.scss
+++ b/packages/uikit-workshop/src/scripts/lit-components/pl-viewport/pl-viewport.scss
@@ -2,12 +2,27 @@
#VIEWPORT
\*------------------------------------*/
+@import '../../../sass/scss/core.scss';
+
/**
* To keep user code and PL code separate, and to make
* resizing the viewport possible, PL contains an iframe
* that houses all user code.
*/
+$pl-resizer-width: 20px;
+$pl-viewport-bg: #f4f4f4;
+
+.pl-c-viewport-modal-wrapper {
+ background-color: $pl-viewport-bg;
+}
+
+pl-iframe {
+ display: flex;
+ flex-grow: 1;
+ background-color: $pl-viewport-bg;
+}
+
/**
* Viewport
* 1) This wrapper div occupies all remaining viewport space after PL's header
@@ -17,7 +32,7 @@
flex-direction: column;
width: 100%;
position: relative;
- top: $offset-top;
+ top: 0;
bottom: 0;
left: 0;
right: 0;
@@ -25,13 +40,13 @@
flex-grow: 1;
transition: height 0.3s ease;
- @supports (position: sticky) {
- top: 0;
- }
+ // @supports (position: sticky) {
+ // top: 0;
+ // }
- .pl-c-body--theme-sidebar & {
- top: 0;
- }
+ // .pl-c-body--theme-sidebar & {
+ // top: 0;
+ // }
}
/**
@@ -42,7 +57,6 @@
.pl-c-viewport__cover {
width: 100%;
height: 100%;
- display: none;
position: fixed;
top: 0;
left: 0;
@@ -59,31 +73,40 @@
.pl-c-viewport__iframe-wrapper {
display: flex;
flex-direction: column;
+ width: 100vw;
max-width: 100vw;
- width: 100%; // bug fix for Safari and Firefox getting stuck calculating a width of 0px when the JS first kicks in
position: relative;
margin: 0 auto;
- flex: 1;
+ flex-grow: 1;
-webkit-overflow-scrolling: touch;
+ min-width: 240px;
+ max-width: 100vw;
+ background: $pl-viewport-bg;
+ padding-right: 0;
+ padding-left: 0;
+ // box-shadow: 0 3px 6px rgba(21,22,25,.16), 0 3px 6px rgba(21,22,25,.23);
&.hay-mode {
transition: all 40s linear;
}
- width: 100%; // bug fix for Safari and Firefox getting stuck calculating a width of 0px when the JS first kicks in
.pl-c-body--theme-sidebar & {
@media all and (min-width: $pl-bp-med) {
max-width: calc(100vw - #{$pl-sidebar-width});
+ width: calc(100vw - #{$pl-sidebar-width});
}
}
}
+.is-animating {
+ transition: all 0.2s linear;
+}
+
/**
* Viewport iframe
* 1) this is the actual
+
+
\ No newline at end of file
diff --git a/packages/uikit-workshop/webpack.config.js b/packages/uikit-workshop/webpack.config.js
index 7ea85e70d..b8b2b1c97 100644
--- a/packages/uikit-workshop/webpack.config.js
+++ b/packages/uikit-workshop/webpack.config.js
@@ -1,30 +1,58 @@
// webpack.config.js
-const CleanWebpackPlugin = require('clean-webpack-plugin');
-const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
-const NoEmitPlugin = require('no-emit-webpack-plugin');
-const autoprefixer = require('autoprefixer');
-const CriticalCssPlugin = require('critical-css-webpack-plugin');
+const { CleanWebpackPlugin } = require('clean-webpack-plugin');
+const TerserPlugin = require('terser-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
-const selectorImporter = require('node-sass-selector-importer');
+const CopyPlugin = require('copy-webpack-plugin');
const path = require('path');
+const argv = require('yargs').argv;
+const { merge } = require('webpack-merge');
+const WebpackBar = require('webpackbar');
+const fs = require('node:fs');
-const cosmiconfig = require('cosmiconfig');
-const explorer = cosmiconfig('patternlab');
+const cosmiconfigSync = require('cosmiconfig').cosmiconfigSync;
+const explorerSync = cosmiconfigSync('patternlab');
// @todo: wire these two ocnfigs up to use cosmicconfig!
const defaultConfig = {
+ rootDir: process.cwd(),
buildDir: './dist',
- prod: false, // or false for local dev
+ prod: argv.watch ? false : true, // or false for local dev
sourceMaps: true,
+ watch: argv.watch ? true : false,
publicPath: './styleguide/',
+ copy: {
+ patterns: [
+ { from: '../uikit-workshop/src/images/**', to: 'images/[name][ext]' },
+ ],
+ },
+ noViewAll: false,
};
-module.exports = async function() {
- return new Promise(async (resolve, reject) => {
+// Requiring partials
+// adapted from https://github.com/webpack-contrib/html-loader/issues/291#issuecomment-721909576
+const INCLUDE_PATTERN = /\(?:\<\/include\>)?/gi;
+const processNestedHtml = (content, loaderContext) =>
+ !INCLUDE_PATTERN.test(content)
+ ? content
+ : content.replace(INCLUDE_PATTERN, (m, src) =>
+ processNestedHtml(
+ fs.readFileSync(path.resolve(loaderContext.context, src), 'utf8'),
+ loaderContext
+ )
+ );
+
+module.exports = function (apiConfig) {
+ return new Promise(async (resolve) => {
let customConfig = defaultConfig;
+ let configToSearchFor;
+
+ if (argv.patternlabrc) {
+ configToSearchFor = await explorerSync.load(argv.patternlabrc);
+ } else {
+ configToSearchFor = await explorerSync.search();
+ }
- const configToSearchFor = await explorer.searchSync();
if (configToSearchFor) {
if (configToSearchFor.config) {
customConfig = configToSearchFor.config;
@@ -32,7 +60,57 @@ module.exports = async function() {
}
// Allow external flags for modifying PL's prod mode, on top of the .patternlabrc config file
- const config = Object.assign({}, defaultConfig, customConfig);
+ const config = Object.assign({}, defaultConfig, customConfig, apiConfig);
+
+ function getBabelConfig(isModern = false) {
+ return {
+ presets: [
+ [
+ '@babel/preset-env',
+ {
+ targets: {
+ browsers: isModern
+ ? [
+ // NOTE: I'm not using the `esmodules` target due to this issue:
+ // https://github.com/babel/babel/issues/8809
+ 'last 2 Chrome versions',
+ 'last 2 Safari versions',
+ 'last 2 iOS versions',
+ 'last 2 Edge versions',
+ 'Firefox ESR',
+ ]
+ : ['ie 11'],
+ },
+ useBuiltIns: 'entry',
+ corejs: 3,
+ modules: false,
+ debug: false,
+ },
+ ],
+ ],
+ plugins: [
+ '@babel/plugin-proposal-optional-chaining',
+ ['@babel/plugin-proposal-decorators', { legacy: true }],
+ ['@babel/plugin-proposal-class-properties', { loose: true }],
+ ['@babel/plugin-proposal-private-methods', { loose: true }],
+ [
+ '@babel/plugin-proposal-private-property-in-object',
+ { loose: true },
+ ],
+ '@babel/plugin-syntax-dynamic-import',
+ '@babel/plugin-syntax-jsx' /* [1] */,
+ [
+ '@babel/plugin-transform-react-jsx' /* [1] */,
+ {
+ pragma: 'h',
+ pragmaFrag: 'Fragment',
+ throwIfNamespace: false,
+ useBuiltIns: false,
+ },
+ ],
+ ],
+ };
+ }
// organize the series of plugins to run our Sass through as an external array -- this is necessary since we need to add additional loaders when compiling Sass to standalone CSS files vs compiling Sass and returning an inline-able