diff --git a/.gitignore b/.gitignore
index 3d341f5c10..1c23ecef2b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -15,6 +15,7 @@
.sass-cache/*
.yardoc
_build
+.customizer
bower_components
bundle
diff --git a/customizer/complete.json b/customizer/complete.json
new file mode 100644
index 0000000000..9244c56190
--- /dev/null
+++ b/customizer/complete.json
@@ -0,0 +1,46 @@
+{
+ "modules": [
+ "grid",
+ "typography",
+ "button",
+ "forms",
+ "abide",
+ "accordion",
+ "accordion_menu",
+ "badge",
+ "breadcrumbs",
+ "button_group",
+ "callout",
+ "close_button",
+ "menu",
+ "menu_icon",
+ "drilldown_menu",
+ "dropdown",
+ "dropdown_menu",
+ "equalizer",
+ "flex_video",
+ "interchange",
+ "label",
+ "magellan",
+ "media_object",
+ "off_canvas",
+ "orbit",
+ "pagination",
+ "progress_bar",
+ "responsive_menu",
+ "responsive_toggle",
+ "reveal",
+ "slider",
+ "sticky",
+ "switch",
+ "table",
+ "tabs",
+ "thumbnail",
+ "title_bar",
+ "toggler",
+ "tooltip",
+ "top_bar",
+ "visibility",
+ "float"
+ ]
+}
diff --git a/customizer/config.yml b/customizer/config.yml
new file mode 100644
index 0000000000..a315fc33cc
--- /dev/null
+++ b/customizer/config.yml
@@ -0,0 +1,204 @@
+# This is the customizer's master module list.
+# Each item in the list is a module with any of these keys:
+# - sass: Name of the CSS export. 'grid' becomes '@include foundation-grid;'
+# - js: Name of the JavaScript file. 'accordion' becomes 'foundation.accordion.js'
+# - js_utils: Names of plugin dependencies. 'box' becomes 'foundation.util.box.js'
+
+grid:
+ sass: grid
+
+typography:
+ sass: typography
+
+button:
+ sass: button
+
+forms:
+ sass: forms
+
+input_range:
+ sass: range-input
+
+abide:
+ js: abide
+
+accordion:
+ sass: accordion
+ js: accordion
+ js_utils:
+ - keyboard
+ - motion
+
+accordion_menu:
+ sass: accordion-menu
+ js: accordionMenu
+ js_utils:
+ - keyboard
+ - motion
+ - nest
+
+badge:
+ sass: badge
+
+breadcrumbs:
+ sass: breadcrumbs
+
+button_group:
+ sass: button-group
+
+callout:
+ sass: callout
+
+close_button:
+ sass: close-button
+
+drilldown_menu:
+ sass: drilldown-menu
+ js: drilldown
+ js_utils:
+ - keyboard
+ - motion
+ - nest
+
+dropdown:
+ sass: dropdown
+ js: dropdown
+ js_utils:
+ - keyboard
+ - box
+ - triggers
+
+dropdown_menu:
+ sass: dropdown-menu
+ js: dropdownMenu
+ js_utils:
+ - keyboard
+ - motion
+ - box
+ - nest
+
+equalizer:
+ js: equalizer
+
+flex_video:
+ sass: flex-video
+
+interchange:
+ js: interchange
+ js_utils:
+ - triggers
+ - timerAndImageLoader
+
+label:
+ sass: label
+
+magellan:
+ js: magellan
+ js_utils:
+ - motion
+
+media_object:
+ sass: media-object
+
+menu:
+ sass: menu
+
+off_canvas:
+ sass: off-canvas
+ js: offcanvas
+
+orbit:
+ sass: orbit
+ js: orbit
+ js_utils:
+ - motion
+ - timerAndImageLoader
+ - keyboard
+ - touch
+
+progress_bar:
+ sass: progress-bar
+
+progress_element:
+ sass: progress-element
+
+responsive_menu:
+ js: responsiveMenu
+ js_utils:
+ - triggers
+ - mediaQuery
+
+responsive_toggle:
+ js: responsiveToggle
+ js_utils:
+ - mediaQuery
+
+meter_element:
+ sass: meter-element
+
+slider:
+ sass: slider
+ js: slider
+ js_utils:
+ - box
+ - motion
+ - triggers
+ - mediaQuery
+
+sticky:
+ sass: sticky
+ js: sticky
+ js_utils:
+ - triggers
+ - mediaQuery
+
+reveal:
+ sass: reveal
+ js: reveal
+ js_utils:
+ - box
+ - motion
+ - triggers
+ - mediaQuery
+
+switch:
+ sass: switch
+
+table:
+ sass: table
+
+tabs:
+ sass: tabs
+ js: tabs
+ js_utils:
+ - keyboard
+ - timerAndImageLoader
+
+thumbnail:
+ sass: thumbnail
+
+title_bar:
+ sass: title-bar
+
+toggler:
+ js: toggler
+ js_utils:
+ - motion
+
+tooltip:
+ sass: tooltip
+ js: tooltip
+ js_utils:
+ - box
+ - triggers
+ - mediaQuery
+ - motion
+
+top_bar:
+ sass: top-bar
+
+visibility:
+ sass: visibility-classes
+
+float:
+ sass: float-classes
diff --git a/customizer/essential.json b/customizer/essential.json
new file mode 100644
index 0000000000..05ed36302d
--- /dev/null
+++ b/customizer/essential.json
@@ -0,0 +1,11 @@
+{
+ "modules": [
+ "typography",
+ "grid",
+ "forms",
+ "button",
+ "callout",
+ "reveal"
+ ],
+ "variables": {}
+}
diff --git a/customizer/index.html b/customizer/index.html
new file mode 100644
index 0000000000..486ac94ed9
--- /dev/null
+++ b/customizer/index.html
@@ -0,0 +1,169 @@
+
+
+
+
+
+
+ Foundation for Sites
+
+
+
+
+
+
+
Welcome to Foundation
+
+
+
+
+
+
+
We’re stoked you want to try Foundation!
+
To get going, this file (index.html) includes some basic styles you can modify, play around with, or totally destroy to get going.
+
Once you've exhausted the fun in this document, you should check out:
+
+
+
+
Foundation Code Skills These online courses offer you a chance to better understand how Foundation works and how you can master it to create awesome projects.
+
+
+
Foundation Forum Join the Foundation community to ask a question or show off your knowlege.
+
+
+
+
+
+
@zurbfoundation Ping us on Twitter if you have questions. When you build something with this we'd love to see it (and send you a totally boss sticker).
+
+
+
+
+
+
+
+
+
Here’s your basic grid:
+
+
+
+
+
+
This is a twelve column section in a row. Each of these includes a div.callout element so you can see where the columns are - it's not required at all for the grid.
+
+
+
+
+
+
+
+
+
We bet you’ll need a form somewhere:
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/customizer/lib/index.js b/customizer/lib/index.js
new file mode 100644
index 0000000000..ba43e9a8a1
--- /dev/null
+++ b/customizer/lib/index.js
@@ -0,0 +1,4 @@
+module.exports = {
+ sass: require('./sass'),
+ js: require('./js')
+}
diff --git a/customizer/lib/js.js b/customizer/lib/js.js
new file mode 100644
index 0000000000..e7763d1f88
--- /dev/null
+++ b/customizer/lib/js.js
@@ -0,0 +1,45 @@
+var empty = require('is-empty-object');
+var unique = require('array-uniq');
+
+/**
+ * Creates an array of file paths that can be passed to `gulp.src()`.
+ * @param {Object} config - Customizer configuration file.
+ * @param {String[]} modules - Modules to include in the file list.
+ * @returns {String[]} Array of file paths.
+ */
+module.exports = function(config, modules) {
+ var files = ['core'];
+ var utils = ['mediaQuery'];
+ var libraries = [];
+
+ if (empty(modules)) {
+ modules = Object.keys(config);
+ }
+
+ for (var i in modules) {
+ var name = modules[i];
+
+ // Check if the module has JS files
+ if (config[name] && config[name].js) {
+ libraries.push(config[name].js);
+
+ // Check if the module has dependencies
+ if (config[name].js_utils) {
+ utils = utils.concat(config[name].js_utils);
+ }
+ }
+ }
+
+ // Prune duplicate entries from the list of utility files
+ utils = unique(utils).map(function(name) {
+ return 'util.' + name;
+ });
+
+ // Combine foundation.core.js, utilities, and plugins into one array
+ files = files.concat(utils, libraries);
+
+ // Format the modules as paths
+ return files.map(function(file) {
+ return 'js/foundation.' + file + '.js';
+ });
+}
diff --git a/customizer/lib/sass.js b/customizer/lib/sass.js
new file mode 100644
index 0000000000..1df0a10712
--- /dev/null
+++ b/customizer/lib/sass.js
@@ -0,0 +1,76 @@
+var empty = require('is-empty-object');
+var format = require('util').format;
+var multiline = require('multiline').stripIndent;
+
+var SASS_TEMPLATE = multiline(function() {/*
+ @charset 'utf-8';
+
+ // Variables go here
+ %s
+
+ // Core imports go here
+ @import 'foundation';
+ @import 'motion-ui';
+
+ // Modules go here
+ %s
+
+ // Motion UI goes here
+ @include motion-ui-transitions;
+ @include motion-ui-animations;
+*/});
+
+/**
+ * Generates an entry point Sass file with a custom list of CSS exports and Sass variables.
+ * @param {Object} config - Customizer configuration object.
+ * @param {String[]} modules - Modules to include CSS for.
+ * @param {Object} variables - Sass variable overrides to include. The key is the name of the variable, and the value is the value.
+ * @returns {String} Formatted Sass file.
+ */
+module.exports = function(config, modules, variables) {
+ var variableList = [];
+ var colorList = {};
+ var exportList = ['@include foundation-global-styles;'];
+
+ if (empty(modules)) {
+ modules = Object.keys(config);
+ }
+
+ // Create variable overrides code
+ for (var i in variables) {
+ var name = i.replace('_', '-');
+ if (name.match(/-color$/)) {
+ var key = name.replace('-color', '');
+ colorList[key] = variables[i];
+ }
+ else {
+ variableList.push(format('$%s: %s;', name, variables[i]));
+ }
+ }
+
+ if (!empty(colorList)) {
+ variableList.push(createPaletteMap(colorList));
+ }
+
+ // Create module exports with @include
+ for (var i in modules) {
+ var name = modules[i];
+
+ if (config[name] && config[name].sass) {
+ exportList.push(format('@include foundation-%s;', config[name].sass));
+ }
+ }
+
+ return format(SASS_TEMPLATE, variableList.join('\n'), exportList.join('\n'))
+}
+
+function createPaletteMap(colors) {
+ var output = '$foundation-palette: (%s\n);';
+ var keys = '';
+
+ for (var i in colors) {
+ keys += format('\n %s: %s,', i, colors[i]);
+ }
+
+ return format(output, keys);
+}
diff --git a/gulp/customizer.js b/gulp/customizer.js
new file mode 100644
index 0000000000..e033244b58
--- /dev/null
+++ b/gulp/customizer.js
@@ -0,0 +1,115 @@
+var addSrc = require('gulp-add-src');
+var babel = require('gulp-babel');
+var concat = require('gulp-concat');
+var cssnano = require('gulp-cssnano');
+var customizer = require('../customizer/lib');
+var File = require('vinyl');
+var fs = require('fs');
+var gulp = require('gulp');
+var If = require('gulp-if');
+var path = require('path');
+var Readable = require('stream').Readable;
+var replace = require('gulp-replace');
+var rename = require('gulp-rename');
+var rimraf = require('rimraf');
+var sass = require('gulp-sass');
+var source = require('vinyl-source-stream');
+var touch = require('touch');
+var uglify = require('gulp-uglify');
+var yaml = require('js-yaml').safeLoad;
+var yargs = require('yargs');
+var zip = require('gulp-zip');
+
+var ARGS = require('yargs').argv;
+var FOUNDATION_VERSION = require('../package.json').version;
+var OUTPUT_DIR = ARGS.output || 'custom-build';
+var CUSTOMIZER_CONFIG;
+var MODULE_LIST;
+var VARIABLE_LIST;
+
+// Load the configuration file for the customizer. It's a list of modules to load and Sass variables to override
+gulp.task('customizer:loadConfig', function(done) {
+ fs.readFile('customizer/config.yml', function(err, data) {
+ var moduleListPath = ARGS.modules || '../customizer/complete';
+ var moduleList = require(moduleListPath);
+
+ CUSTOMIZER_CONFIG = yaml(data.toString());
+ MODULE_LIST = moduleList.modules;
+ VARIABLE_LIST = moduleList.variables || {};
+ done();
+ });
+});
+
+// Creates a Sass file from the module/variable list and creates foundation.css and foundation.min.css
+gulp.task('customizer:sass', ['customizer:loadConfig'], function() {
+ var sassFile = customizer.sass(CUSTOMIZER_CONFIG, MODULE_LIST, VARIABLE_LIST);
+
+ // Create a stream with our makeshift Sass file
+ var stream = new Readable({ objectMode: true });
+ stream._read = function() {};
+ stream.push(new File({
+ path: 'foundation.scss',
+ contents: new Buffer(sassFile)
+ }));
+ stream.push(null);
+
+ return stream
+ .pipe(sass({
+ includePaths: [
+ 'scss',
+ 'node_modules/motion-ui/src'
+ ]
+ }))
+ .pipe(gulp.dest(path.join(OUTPUT_DIR, 'css')))
+ .pipe(cssnano())
+ .pipe(rename('foundation.min.css'))
+ .pipe(gulp.dest(path.join(OUTPUT_DIR, 'css')));
+});
+
+// Creates a Foundation JavaScript file from the module list, and also copies dependencies (jQuery, what-input)
+gulp.task('customizer:javascript', ['customizer:loadConfig'], function() {
+ var jsPaths = customizer.js(CUSTOMIZER_CONFIG, MODULE_LIST);
+
+ return gulp.src(jsPaths)
+ .pipe(babel())
+ .pipe(concat('foundation.js'))
+ .pipe(gulp.dest(path.join(OUTPUT_DIR, 'js/vendor')))
+ .pipe(uglify())
+ .pipe(rename('foundation.min.js'))
+ .pipe(addSrc([
+ 'node_modules/jquery/dist/jquery.js',
+ 'node_modules/what-input/what-input.js'
+ ]))
+ .pipe(gulp.dest(path.join(OUTPUT_DIR, 'js/vendor')));
+});
+
+// Copies the boilerplate index.html to the custom download folder
+gulp.task('customizer:html', ['customizer:loadConfig'], function() {
+ var rtlEnabled = VARIABLE_LIST['global-text-direction'] && VARIABLE_LIST['global-text-direction'] === 'rtl';
+
+ return gulp.src('customizer/index.html')
+ .pipe(If(rtlEnabled, replace('ltr', 'rtl')))
+ .pipe(gulp.dest(OUTPUT_DIR));
+});
+
+// Creates a custom build by:
+// - Generating a CSS file
+// - Generating a JS file
+// - Copying the index.html file
+// - Creating a blank app.css file
+// - Creating an app.js file with Foundation initialization code
+gulp.task('customizer', ['customizer:sass', 'customizer:javascript', 'customizer:html'], function(done) {
+ var outputFolder = path.dirname(OUTPUT_DIR);
+ var outputFileName = path.basename(OUTPUT_DIR);
+
+ touch(path.join(OUTPUT_DIR, 'css/app.css'));
+ touch(path.join(OUTPUT_DIR, 'js/app.js'));
+ fs.writeFileSync(path.join(OUTPUT_DIR, 'js/app.js'), '$(document).foundation()\n');
+
+ gulp.src(path.join(OUTPUT_DIR, '/**/*'))
+ .pipe(zip(path.basename(outputFileName) + '.zip'))
+ .pipe(gulp.dest(outputFolder))
+ .on('finish', function() {
+ rimraf(OUTPUT_DIR, done);
+ });
+});
diff --git a/lib/util-map.json b/lib/util-map.json
deleted file mode 100644
index b181491432..0000000000
--- a/lib/util-map.json
+++ /dev/null
@@ -1,88 +0,0 @@
-{
- "accordion": [
- "foundation.util.keyboard.js",
- "foundation.util.motion.js"
- ],
- "accordionMenu": [
- "foundation.util.keyboard.js",
- "foundation.util.motion.js",
- "foundation.util.nest.js"
- ],
- "drilldown": [
- "foundation.util.keyboard.js",
- "foundation.util.motion.js",
- "foundation.util.nest.js"
- ],
- "dropdownMenu": [
- "foundation.util.keyboard.js",
- "foundation.util.motion.js",
- "foundation.util.box.js",
- "foundation.util.nest.js"
- ],
- "dropdown": [
- "foundation.util.keyboard.js",
- "foundation.util.box.js",
- "foundation.util.triggers.js"
- ],
- "interchange": [
- "foundation.util.triggers.js",
- "foundation.util.timerAndImageLoader.js"
- ],
- "magellan": [
- "foundation.util.motion.js"
- ],
- "offcanvas": [
- "foundation.util.mediaQuery.js",
- "foundation.util.motion.js",
- "foundation.util.triggers.js"
- ],
- "orbit": [
- "foundation.util.motion.js",
- "foundation.util.timerAndImageLoader.js",
- "foundation.util.keyboard.js",
- "foundation.util.touch.js"
- ],
- "responsiveMenu": [
- "foundation.util.triggers.js",
- "foundation.util.mediaQuery.js",
- "foundation.accordionMenu.js",
- "foundation.drilldown.js",
- "foundation.dropdownMenu.js",
- "foundation.util.nest.js"
- ],
- "responsiveToggle": [
- "foundation.util.mediaQuery.js"
- ],
- "reveal": [
- "foundation.util.box.js",
- "foundation.util.motion.js",
- "foundation.util.triggers.js",
- "foundation.util.mediaQuery.js"
- ],
- "slider": [
- "foundation.util.triggers.js",
- "foundation.util.motion.js",
- "foundation.util.keyboard.js",
- "foundation.util.touch.js"
- ],
- "sticky": [
- "foundation.util.triggers.js",
- "foundation.util.mediaQuery.js"
- ],
- "tabs": [
- "foundation.util.keyboard.js",
- "foundation.util.timerAndImageLoader.js"
- ],
- "toggler": [
- "foundation.util.motion.js"
- ],
- "tooltip": [
- "foundation.util.box.js",
- "foundation.util.triggers.js",
- "foundation.util.mediaQuery.js",
- "foundation.util.motion.js"
- ],
- "motion-ui": [
- "foundation.util.motion.js"
- ]
-}
diff --git a/package.json b/package.json
index 46a8a1750c..12e6256349 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,7 @@
},
"license": "MIT",
"devDependencies": {
+ "array-uniq": "^1.0.2",
"babel-core": "^6.3.26",
"babel-eslint": "^5.0.0",
"babel-plugin-transform-es2015-arrow-functions": "^6.3.13",
@@ -38,6 +39,7 @@
"corejs-typeahead": "corejavascript/typeahead.js",
"foundation-docs": "zurb/foundation-docs",
"gulp": "^3.8.10",
+ "gulp-add-src": "^0.2.0",
"gulp-autoprefixer": "^2.3.1",
"gulp-babel": "^6.1.1",
"gulp-cache-bust": "^1.0.2",
@@ -45,6 +47,7 @@
"gulp-cssnano": "^2.1.0",
"gulp-eslint": "^2.0.0",
"gulp-filter": "^3.0.1",
+ "gulp-if": "^2.0.0",
"gulp-load-plugins": "^1.2.0",
"gulp-mocha": "^2.2.0",
"gulp-newer": "^1.1.0",
@@ -58,10 +61,14 @@
"gulp-scss-lint": "^0.3.9",
"gulp-sourcemaps": "^1.6.0",
"gulp-uglify": "^1.1.0",
+ "gulp-zip": "^3.2.0",
"inquirer": "^0.11.4",
+ "is-empty-object": "^1.1.1",
+ "js-yaml": "^3.5.4",
"mocha": "^2.3.3",
"mocha-phantomjs": "^4.0.2",
"motion-ui": "^1.1.0",
+ "multiline": "^1.0.2",
"octophant": "^1.0.0",
"opener": "^1.4.1",
"panini": "^1.1.1",
@@ -72,7 +79,11 @@
"run-sequence": "^1.1.4",
"sass-true": "^2.0.3",
"sinon": "^1.17.3",
- "supercollider": "^1.4.0"
+ "supercollider": "^1.4.0",
+ "touch": "^1.0.0",
+ "vinyl": "^1.1.1",
+ "vinyl-source-stream": "^1.1.0",
+ "yargs": "^4.2.0"
},
"repository": {
"type": "git",