Skip to content

Commit

Permalink
Merge pull request #877 from OfficeDev/jahnp/scoped-versioning
Browse files Browse the repository at this point in the history
Add support for scoped versioning
  • Loading branch information
Mike Wheaton committed Jan 4, 2017
2 parents b34f471 + fc043ac commit f17c069
Show file tree
Hide file tree
Showing 17 changed files with 385 additions and 168 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -11,6 +11,7 @@ npm-debug.log
*.sublime-workspace
docs.css
dist
temp

# Docs files
docs/app
Expand Down
43 changes: 43 additions & 0 deletions ghdocs/SCOPING.md
@@ -0,0 +1,43 @@
# Version scoping
"Version-scoping" is a variation of Fabric Core which provides a wrapped or "scoped" version of every Fabric class under a modifier of the `.ms-Fabric` base class, which is tied to the current version. If the version is `5.1.0`, this "scope class" would take the form `.ms-Fabric--v5-1-0`.

## Why is this useful?
Version scoping is targeted at the scenario where multiple versions of Fabric Core may live on a single web page, whose differences between major versions could potentially introduce regressions or conflicts.

A practical example of this is the SharePoint Web Parts used for publishing articles. Web Parts are effectively miniature applications, each of which can depend on their own version of Fabric. To ensure that they can continue to exist on the same publishing page without:
1. Risking regressions from other web parts that might be using an older version of Fabric, and
2. Forcing them to consume the latest (which would likely require work to update),

the Web Part developer can scope the Fabric styles for their entire Web Part to the particular version that was used during development.

## Usage
Usage of version scoping is straightforward. Simply append the "versioned class" to the container element you wish to scope, then use Fabric Core classes as you normally would.

Here's a minimal HTML page demonstrating this:

```html
<html>
<head>
<!-- Link to the scoped styles for the current version of Fabric Core -->
<link rel="stylesheet" href="/fabric-5.1.0.scoped.css">
</head>
<body>
<!-- Add the scoping class -->
<div class="ms-Fabric--v5-1-0">
<!--
Use Fabric as usual. These styles will be unaffected
by other versions of Fabric. They also cannot be used
outside of a scoped class.
-->
<h1 class="ms-font-su">Some scoped title <i class="ms-Icon ms-Icon--Info"></i></h1>
</div>
</body>
</html>
```

## Notes on fonts
Icon `@font-face` definitions (including the `font-family` name) and their font files are only scoped to **major versions** of Fabric. What this means is that all of the normal, additive changes to icon font files that occur within a major version's lifetime will be applied to a single font file, rather than maintaining separate font files for each minor or patch release. What this means is that there will not be `fabricmdl2icons-5.1.0.ttf`, `fabricmdl2icons-5.2.0.ttf`, etc. There will simply be `fabricmdl2icons-5.ttf`.

This is because generally icon font changes are purely additive, and rarely change significantly even between minor versions. However, the CSS classes for those icons (e.g. `ms-Icon--X`) *are* version scoped like normal classes. Also, note that the "unscoped" version of the icon font file as used today will still be available.

Finally, the standard, "unscoped" `@font-face` definitions to the Segoe UI webfonts are included in scoped Fabric unchanged. These fonts almost never change appreciably and are not considered risky to depend on between major releases.
47 changes: 41 additions & 6 deletions gulp/FabricBuild.js
Expand Up @@ -7,14 +7,25 @@ var BuildConfig = require('./modules/BuildConfig');
var ConsoleHelper = require('./modules/ConsoleHelper');
var ErrorHandling = require('./modules/ErrorHandling');
var Plugins = require('./modules/Plugins');
var pkg = require('../package.json');

var versionParts = pkg.version.split('.');

var version = {
major: versionParts[0],
minor: versionParts[1],
patch: versionParts[2]
}

var versionCommaDelim = pkg.version.split('.').join(',');

//
// Clean/Delete Tasks
// ----------------------------------------------------------------------------

// Clean out the distribution folder.
gulp.task('Fabric-nuke', function () {
return Plugins.del.sync([Config.paths.distCSS, Config.paths.distSass]);
return Plugins.del.sync([Config.paths.distCSS, Config.paths.distSass, Config.paths.temp]);
});


Expand All @@ -24,9 +35,10 @@ gulp.task('Fabric-nuke', function () {

// Copy all Sass files to distribution folder.
gulp.task('Fabric-copyAssets', function () {
var moveSass = gulp.src([Config.paths.srcSass + '/**/*'])
var moveSass = gulp.src([Config.paths.srcSass + '/**/*', !Config.paths.srcSass + '/Fabric.Scoped.scss'])
.pipe(Plugins.plumber(ErrorHandling.onErrorInPipe))
.pipe(Plugins.changed(Config.paths.distSass))
.pipe(Plugins.replace('<%= fabricVersion %>', versionCommaDelim))
.pipe(Plugins.gulpif(Config.debugMode, Plugins.debug({
title: "Moving Sass files over to Dist"
})))
Expand All @@ -38,8 +50,6 @@ gulp.task('Fabric-copyAssets', function () {
// Sass tasks
// ----------------------------------------------------------------------------

// Build Sass files for core Fabric into LTR and RTL CSS files.

gulp.task('Fabric-buildStyles', function () {
var fabric = gulp.src(BuildConfig.srcPath + '/' + 'Fabric.' + BuildConfig.fileExtension)
.pipe(Plugins.plumber(ErrorHandling.onErrorInPipe))
Expand All @@ -64,8 +74,32 @@ gulp.task('Fabric-buildStyles', function () {
}))
.pipe(Plugins.header(Banners.getBannerTemplate(), Banners.getBannerData()))
.pipe(Plugins.header(Banners.getCSSCopyRight(), Banners.getBannerData()))
.pipe(gulp.dest(Config.paths.distCSS));

var fabricScoped = gulp.src(BuildConfig.srcPath + '/' + 'Fabric.Scoped.' + BuildConfig.fileExtension)
.pipe(Plugins.gulpif(Config.debugMode, Plugins.debug({
title: "Building Core Fabric Scoped " + BuildConfig.fileExtension + " File"
})))
.pipe(Plugins.header(Banners.getBannerTemplate(), Banners.getBannerData()))
.pipe(Plugins.header(Banners.getCSSCopyRight(), Banners.getBannerData()))
.pipe(Plugins.replace('<%= fabricVersion %>', versionCommaDelim))
.pipe(BuildConfig.processorPlugin().on('error', BuildConfig.compileErrorHandler))
.pipe(Plugins.rename('fabric-' + version.major + '.' + version.minor + '.' + version.patch + '.scoped.css'))
.pipe(Plugins.autoprefixer({
browsers: ['last 2 versions', 'ie >= 9'],
cascade: false
}))
.pipe(Plugins.cssbeautify())
.pipe(Plugins.csscomb())
.pipe(gulp.dest(Config.paths.distCSS))
.pipe(Plugins.rename('fabric-' + version.major + '.' + version.minor + '.' + version.patch + '.scoped.min.css'))
.pipe(Plugins.cssMinify({
safe: true
}))
.pipe(Plugins.header(Banners.getBannerTemplate(), Banners.getBannerData()))
.pipe(Plugins.header(Banners.getCSSCopyRight(), Banners.getBannerData()))
.pipe(gulp.dest(Config.paths.distCSS));

// Build full and minified Fabric RTL CSS.
var fabricRtl = gulp.src(BuildConfig.srcPath + '/' + 'Fabric.Rtl.' + BuildConfig.fileExtension)
.pipe(Plugins.plumber(ErrorHandling.onErrorInPipe))
Expand All @@ -92,8 +126,9 @@ gulp.task('Fabric-buildStyles', function () {
.pipe(Plugins.header(Banners.getBannerTemplate(), Banners.getBannerData()))
.pipe(Plugins.header(Banners.getCSSCopyRight(), Banners.getBannerData()))
.pipe(gulp.dest(Config.paths.distCSS));

// Merge all current streams into one.
return Plugins.mergeStream(fabric, fabricRtl);
return Plugins.mergeStream(fabric, fabricScoped, fabricRtl);
});

//
Expand Down
1 change: 1 addition & 0 deletions gulp/modules/Config.js
Expand Up @@ -17,6 +17,7 @@ var Config = function() {
src: 'src',
componentsPath : 'src/components',
srcLibPath: 'lib',
temp: 'temp'
};

this.paths.distComponents = this.paths.dist + '/components';
Expand Down
1 change: 1 addition & 0 deletions gulp/modules/Plugins.js
Expand Up @@ -35,6 +35,7 @@ var Plugins = function() {
this.path = require('path');
this.pkg = require('../../package.json');
this.fs = require('fs');
this.replace = require('gulp-replace');
};

module.exports = new Plugins();
4 changes: 2 additions & 2 deletions package.json
Expand Up @@ -35,6 +35,7 @@
"gulp-nuget-pack": "0.0.6",
"gulp-plumber": "^1.0.1",
"gulp-rename": "^1.2.2",
"gulp-replace": "^0.5.4",
"gulp-sass": "^3.0.0",
"gulp-size": "^1.0.0",
"gulp-template": "^3.0.0",
Expand All @@ -50,6 +51,5 @@
"typescript": "^2.0.3",
"walk-sync": "^0.3.0"
},
"dependencies": {
}
"dependencies": {}
}
36 changes: 36 additions & 0 deletions src/documentation/pages/Scoping/index.html
@@ -0,0 +1,36 @@
@@include('../../templates/modules/components/DocumentationPageHeader.html')
<style>
.ms-Fabric--v5-1-0 .ms-fontColor-themePrimary {
color: #ff0000;
}
</style>

<div class="docs-Styles-section" id="scoping">
<h2>Version Scoping Sample</h2>
<p>For scenarios where multiple major versions may live in the same DOM, Fabric provides a "scoped" version of all Core styles that will only apply those styles when used under a versioned wrapper class.</p>

<p>
To use scoped Fabric styles, simply add the versioned wrapper class to the parent DOM element you wish to scope, then use Fabric as usual.
</p>

<p>For example, take this following title, which uses unscoped Fabric:</p>

<pre><code>
&lt;div class="ms-font-xxl ms-fontColor-themePrimary">This title uses ms-fontColor-themePrimary from unscoped Fabric.&lt;/div&gt;
</code></pre>

<div class="ms-font-xxl ms-fontColor-themePrimary">This title uses ms-fontColor-themePrimary from unscoped Fabric.</div>

<p>To scope this title to v5.1.0, add an extra wrapper <code>div</code> around it and add both the <code>ms-Fabric</code> wrapper class and the scoping class for the current version of Fabric. Note that to illustrate this behavior for this demonstration, <code>.ms-fontColor-themePrimary</code> has been overridden with a different color when used under the <code>ms-Fabric--v5-1-0</code> version-scoping class.</p>

<pre><code>
&lt;div class="ms-Fabric ms-Fabric--v5-1-0">
&lt;div class="ms-font-xxl ms-fontColor-themePrimary">This title uses ms-fontColor-themePrimary from Fabric 5.1.0.&lt;/div&gt;
&lt;/div&gt;
</code></pre>

<div class="ms-Fabric ms-Fabric--v5-1-0">
<div class="ms-font-xxl ms-fontColor-themePrimary">This title uses ms-fontColor-themePrimary from Fabric 5.1.0.</div>
</div>
</div>
@@include('../../templates/modules/components/DocumentationPageFooter.html')
Expand Up @@ -18,5 +18,8 @@
<div class="LeftNav-item">
<a class="Localization LeftNav-link ms-border-color-themePrimary ms-font-l ms-font-color-neutralSecondary" href="/Localization">Localization</a>
</div>
<div class="LeftNav-item">
<a class="Scoping LeftNav-link ms-border-color-themePrimary ms-font-l ms-font-color-neutralSecondary" href="/Scoping">Scoping</a>
</div>
</div>
</div>
33 changes: 33 additions & 0 deletions src/sass/Fabric.Scoped.scss
@@ -0,0 +1,33 @@
// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE in the project root for license information.

//
// Office UI Fabric
// Core styles scoped to the current major version of Fabric

// Variable is set during gulp task as comma seperated list. i.e. 5,1,0
$ms-fabric-version: <%= fabricVersion %>;

@import './References';
@import './mixins/ScopedStyles.Mixins';

// Sets a global flag to enable scoped styles within certain files
$do-scope-styles: true;

// Scope all core styles under a helper class for the current major version.
// This produces styles of the form .ms-Fabric-{version #} .ms-font-m.

@include scope-fabric {
@import './Animation';
@import './BrandIcon';
@import './Color';
@import './Font';
@import './Grid';
@import './Icon';
@import './Responsive';
@import './Utility';
@import './Wrapper';
}

// @font-face definitions do not need to be scoped
@import './Font.Definitions';
@import './Icon.Definitions';
2 changes: 2 additions & 0 deletions src/sass/Fabric.scss
Expand Up @@ -12,8 +12,10 @@
@import './Animation';
@import './BrandIcon';
@import './Color';
@import './Font.Definitions';
@import './Font';
@import './Grid';
@import './Icon.Definitions';
@import './Icon';
@import './Responsive';
@import './Utility';
Expand Down
119 changes: 119 additions & 0 deletions src/sass/_Font.Definitions.scss
@@ -0,0 +1,119 @@
// Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE in the project root for license information.

//
// Office UI Fabric
// --------------------------------------------------
// @font-face rules for Segoe UI

// Additional @font-face rules for the Leelawadee font.
@font-face {
font-family: 'Leelawadee UI';
src: local('Leelawadee UI Bold'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-bold.woff2') format('woff2'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-bold.woff') format('woff'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-bold.ttf') format('truetype');
font-weight: 600;
font-style: normal;
}

@font-face {
font-family: 'Leelawadee UI';
src: local('Leelawadee UI Regular'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-regular.woff2') format('woff2'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-regular.woff') format('woff'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-regular.ttf') format('truetype');
font-weight: 400;
font-style: normal;
}

@font-face {
font-family: 'Leelawadee UI';
src: local('Leelawadee UI Semilight'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-semilight.woff2') format('woff2'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-semilight.woff') format('woff'),
url('#{$ms-font-directory}/leelawadeeui-thai/leelawadeeui-semilight.ttf') format('truetype');
font-weight: 300;
font-style: normal;
}

// Output the standard fonts
@include SegoeUIWestEuropeanLight;
@include SegoeUIWestEuropeanRegular;
@include SegoeUIWestEuropeanSemibold;
@include SegoeUIWestEuropeanSemilight;

// Mixins to generate language-specific font faces.
@include SegoeUIArabicLight;
@include SegoeUIArabicRegular;
@include SegoeUIArabicSemibold;
@include SegoeUIArabicSemilight;

@include SegoeUICyrillicLight;
@include SegoeUICyrillicRegular;
@include SegoeUICyrillicSemibold;
@include SegoeUICyrillicSemilight;

@include SegoeUIEastEuropeanLight;
@include SegoeUIEastEuropeanRegular;
@include SegoeUIEastEuropeanSemibold;
@include SegoeUIEastEuropeanSemilight;

@include SegoeUIGreekLight;
@include SegoeUIGreekRegular;
@include SegoeUIGreekSemibold;
@include SegoeUIGreekSemilight;

@include SegoeUIHebrewLight;
@include SegoeUIHebrewRegular;
@include SegoeUIHebrewSemibold;
@include SegoeUIHebrewSemilight;

@include SegoeUIVietnameseLight;
@include SegoeUIVietnameseRegular;
@include SegoeUIVietnameseSemibold;
@include SegoeUIVietnameseSemilight;

// Generate the override classes for non-distributed fonts.
@include language-override-system-fonts(jpn, $ms-font-stack-japanese);
@include language-override-system-fonts(kor, $ms-font-stack-korean);
@include language-override-system-fonts(cmn, $ms-font-stack-chinese-simplified);
@include language-override-system-fonts(yue, $ms-font-stack-chinese-traditional);
@include language-override-system-fonts(hin, $ms-font-stack-hindi);

// Generate the override classes for web fonts.
// Thai (Leelawadee)
// tha
@include language-override-system-fonts(tha, $ms-font-stack-leelawadee);

// Arabic
// ara
@include language-override-system-fonts(ara, $ms-font-stack-arabic);

// East European
// ces, et, hrv, hun, lit, pl, lat, tur, slk, kaz
@include language-override-system-fonts(ces, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(est, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(hrv, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(hun, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(kaz, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(lav, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(lit, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(pol, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(slk, $ms-font-stack-eastEuropean);
@include language-override-system-fonts(tur, $ms-font-stack-eastEuropean);

// Cyrillic
// rus
@include language-override-system-fonts(rus, $ms-font-stack-cyrillic);

// Greek
// ell
@include language-override-system-fonts(ell, $ms-font-stack-greek);

// Hebrew
// heb
@include language-override-system-fonts(heb, $ms-font-stack-hebrew);

// Vietnamese
// vie
@include language-override-system-fonts(vie, $ms-font-stack-vietnamese);

0 comments on commit f17c069

Please sign in to comment.