diff --git a/packages/development-edition-engine-handlebars/patternlab-config.json b/packages/development-edition-engine-handlebars/patternlab-config.json index d8fa3fb2b..5b9e9a0c2 100644 --- a/packages/development-edition-engine-handlebars/patternlab-config.json +++ b/packages/development-edition-engine-handlebars/patternlab-config.json @@ -78,7 +78,8 @@ "theme": { "color": "dark", "density": "compact", - "layout": "horizontal" + "layout": "horizontal", + "noViewAll": false }, "uikits": [ { diff --git a/packages/edition-twig/.patternlabrc.js b/packages/edition-twig/.patternlabrc.js index f7c2ff8fa..8c9ff01d0 100644 --- a/packages/edition-twig/.patternlabrc.js +++ b/packages/edition-twig/.patternlabrc.js @@ -1,5 +1,5 @@ module.exports = { - buildDir: __dirname + '/public', - wwwDir: __dirname + '/public/', - publicPath: '/public/styleguide/', + // target the UIKit installed / symlinked under node_modules + buildDir: __dirname + '/node_modules/@pattern-lab/uikit-workshop/dist', + // noViewAll: true, }; diff --git a/packages/edition-twig/package-lock.json b/packages/edition-twig/package-lock.json index cb30f303e..e68ff4f21 100644 --- a/packages/edition-twig/package-lock.json +++ b/packages/edition-twig/package-lock.json @@ -1,13 +1,59 @@ { "name": "@pattern-lab/edition-twig", - "version": "3.0.0-alpha.1", + "version": "3.1.5", "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==" + "cross-env": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-6.0.3.tgz", + "integrity": "sha512-+KqxF6LCvfhWvADcDPqo64yVIB31gv/jQulX2NGzKS/g3GEVz6/pt4wjHFtFWsHMddebWD/sDthJemzM4MaAag==", + "requires": { + "cross-spawn": "7.0.1" + }, + "dependencies": { + "cross-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.1.tgz", + "integrity": "sha512-u7v4o84SwFpD32Z8IIcPZ6z1/ie24O6RU3RbtL5Y316l3KuHVPx9ItBgWQ6VlfAFnRnTtMUrsQ9MUUTuEZjogg==", + "requires": { + "path-key": "3.1.0", + "shebang-command": "2.0.0", + "which": "2.0.1" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "path-key": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.0.tgz", + "integrity": "sha512-8cChqz0RP6SHJkMt48FW0A7+qUOn+OsnOsVtzI59tZ8m+5bCSk7hzwET0pulwOM2YMn9J1efb07KB9l9f30SGg==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "which": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.1.tgz", + "integrity": "sha512-N7GBZOTswtB9lkQBZA4+zAXrjEIWAUOB93AvzUiudRzRxhUdLURQ7D/gAIMY1gatT/LTbmbcv8SiYazy3eYB7w==", + "requires": { + "isexe": "2.0.0" + } + } + } } } } diff --git a/packages/edition-twig/package.json b/packages/edition-twig/package.json index efe3f57d5..5989483f9 100644 --- a/packages/edition-twig/package.json +++ b/packages/edition-twig/package.json @@ -13,7 +13,7 @@ ], "main": "patternlab-config.json", "scripts": { - "build:uikit": "npm run build --prefix node_modules/@pattern-lab/uikit-workshop -- --patternlabrc $INIT_CWD/.patternlabrc.js", + "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", diff --git a/packages/edition-twig/patternlab-config.json b/packages/edition-twig/patternlab-config.json index 20ab60345..e9652bde5 100644 --- a/packages/edition-twig/patternlab-config.json +++ b/packages/edition-twig/patternlab-config.json @@ -147,7 +147,8 @@ "theme": { "color": "light", "density": "compact", - "layout": "horizontal" + "layout": "horizontal", + "noViewAll": false }, "uikits": [ { diff --git a/packages/uikit-workshop/build-tools.js b/packages/uikit-workshop/build-tools.js index 5c6d7c3b3..2cf5d898a 100644 --- a/packages/uikit-workshop/build-tools.js +++ b/packages/uikit-workshop/build-tools.js @@ -12,5 +12,6 @@ patternlab.build({ webpackServer.serve( patternlab, + configFilePath, path.resolve(process.cwd(), config.paths.public.root) ); diff --git a/packages/uikit-workshop/build/webpack-server.js b/packages/uikit-workshop/build/webpack-server.js index 269d583ee..6021d1509 100644 --- a/packages/uikit-workshop/build/webpack-server.js +++ b/packages/uikit-workshop/build/webpack-server.js @@ -12,14 +12,14 @@ const portfinder = require('portfinder'); const fileHashes = {}; -async function serve(patternlab, buildDir = 'public') { +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: false, + watch: true, prod: false, buildDir: root, rootDir: process.cwd(), @@ -37,6 +37,24 @@ async function serve(patternlab, buildDir = 'public') { // customize bs reload behavior based on the type of asset that's changed const filesToWatch = [ + { + match: [`${process.cwd()}/patternlab-config.json`], + fn: async function(event, filePath) { + // 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`, { 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..7ee70c5bc --- /dev/null +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/get-parents.js @@ -0,0 +1,34 @@ +export const getParents = (elem, selector) => { + // Element.matches() polyfill + if (!Element.prototype.matches) { + Element.prototype.matches = + Element.prototype.matchesSelector || + Element.prototype.mozMatchesSelector || + Element.prototype.msMatchesSelector || + Element.prototype.oMatchesSelector || + Element.prototype.webkitMatchesSelector || + function(s) { + var matches = (this.document || this.ownerDocument).querySelectorAll(s), + i = matches.length; + while (--i >= 0 && matches.item(i) !== this) {} + return i > -1; + }; + } + + // Set up a parent array + var 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/pl-nav.js b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js index 17aeca296..af3d0bf26 100644 --- a/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js +++ b/packages/uikit-workshop/src/scripts/components/pl-nav/pl-nav.js @@ -4,6 +4,7 @@ import { h } 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'; @@ -13,12 +14,15 @@ const SubSubList = props => { const { children, category, elem } = props; const reorderedChildren = []; - const nonViewAllItems = children.filter( - item => - item.patternName !== 'View All' && !item.patternName.includes(' Docs') - ); - // const nonViewAllItems = children.filter((item => (item.patternName !== 'View All'))); - const viewAllItems = children.filter(item => item.patternName === 'View All'); + 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'); reorderedChildren.push(...viewAllItems, ...nonViewAllItems); @@ -227,16 +231,12 @@ class Nav extends BaseComponent { this.layoutMode = state.app.layoutMode || ''; } - if (this.currentPattern !== state.app.currentPattern) { - if ( - state.app.currentPattern !== '' && - this.currentPattern !== state.app.currentPattern && - this._hasInitiallyRendered === true - ) { - this.handleURLChange(); // so the nav logic is always correct (ex. layout changes) - } - + 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) } } @@ -314,70 +314,35 @@ class Nav extends BaseComponent { } handleURLChange() { - const shouldAutoOpenNav = true; - const currentPattern = this.currentPattern; - const activeLink = document.querySelector( + this.activeLink = document.querySelector( `[data-patternpartial="${currentPattern}"]` ); - const self = this; if (this.previousActiveLinks) { - this.previousActiveLinks.forEach(function(link, index) { - self.previousActiveLinks[index].classList.remove('pl-is-active'); + this.previousActiveLinks.forEach((link, index) => { + this.previousActiveLinks[index].classList.remove('pl-is-active'); }); } this.previousActiveLinks = []; - if (activeLink) { - activeLink.classList.add('pl-is-active'); - this.previousActiveLinks.push(activeLink); - - if ( - activeLink.parentNode.classList.contains( - 'pl-c-nav__link--overview-wrapper' - ) - ) { - activeLink.parentNode.classList.add('pl-is-active'); - this.previousActiveLinks.push(activeLink.parentNode); - } + if (this.activeLink) { + const triggers = [this.activeLink]; + const panels = Array.from( + getParents(this.activeLink, '.pl-js-acc-panel') + ); - const parentDropdown = activeLink.closest('.pl-js-acc-panel'); - let parentDropdownTrigger; - - if (parentDropdown) { - if (parentDropdown.previousSibling) { - parentDropdownTrigger = parentDropdown.previousSibling; - - if ( - parentDropdown.previousSibling.classList.contains( - 'pl-c-nav__link--overview-wrapper' - ) && - shouldAutoOpenNav - ) { - parentDropdown.previousSibling.classList.add('pl-is-active'); - this.previousActiveLinks.push(parentDropdown.previousSibling); - parentDropdownTrigger = parentDropdown.previousSibling.querySelector( - '.pl-js-acc-handle' - ); - } - - const grandparentDropdown = parentDropdown.closest( - '.pl-c-nav__sublist--dropdown' - ); - const grandparentDropdownTrigger = - grandparentDropdown.previousSibling; - - if (grandparentDropdownTrigger && shouldAutoOpenNav) { - if (shouldAutoOpenNav) { - grandparentDropdownTrigger.classList.add('pl-is-active'); - } - this.previousActiveLinks.push(grandparentDropdownTrigger); - } + panels.forEach(panel => { + const panelTrigger = panel.previousSibling; + if (panelTrigger) { + triggers.push(panelTrigger); } - } - } else { - this.cleanupActiveNav(); + }); + + triggers.forEach(trigger => { + trigger.classList.add('pl-is-active'); + this.previousActiveLinks.push(trigger); + }); } } @@ -392,6 +357,10 @@ class Nav extends BaseComponent { ...props.boolean, ...{ default: true }, }, + noViewAll: { + ...props.boolean, + ...{ default: window.config?.theme?.noViewAll || false }, + }, }; toggleSpecialNavPanel(e) { @@ -409,7 +378,9 @@ class Nav extends BaseComponent { this._hasInitiallyRendered = true; } - this.handleURLChange(); + if (!this.activeLink) { + this.handleURLChange(); + } if (this.layoutMode !== 'vertical' && window.innerWidth > 670) { this.cleanupActiveNav(true); @@ -436,7 +407,6 @@ class Nav extends BaseComponent { > {item.patternTypeUC} -
    { - return ( + return this.noViewAll && + patternItem.patternPartial.includes('viewall') ? ( + '' + ) : (