diff --git a/blue-shark/.editorconfig b/blue-shark/.editorconfig
new file mode 100644
index 0000000000..2536d66bf1
--- /dev/null
+++ b/blue-shark/.editorconfig
@@ -0,0 +1,12 @@
+# http://editorconfig.org
+root = true
+
+[*]
+indent_style = space
+indent_size = 4
+charset = utf-8
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.md]
+trim_trailing_whitespace = false
diff --git a/blue-shark/LICENSE.md b/blue-shark/LICENSE.md
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/README.md b/blue-shark/README.md
new file mode 100644
index 0000000000..d17acff66d
--- /dev/null
+++ b/blue-shark/README.md
@@ -0,0 +1,6 @@
+# blue-shark
+The Montage-based widget set created for FreeNAS
+
+`npm install` then `gulp` for editing css
+
+moretk
diff --git a/blue-shark/assets/fonts/icons/freenas.ttf b/blue-shark/assets/fonts/icons/freenas.ttf
new file mode 100755
index 0000000000..ca79ea2c24
Binary files /dev/null and b/blue-shark/assets/fonts/icons/freenas.ttf differ
diff --git a/blue-shark/assets/fonts/icons/freenas.woff b/blue-shark/assets/fonts/icons/freenas.woff
new file mode 100755
index 0000000000..16779af7c1
Binary files /dev/null and b/blue-shark/assets/fonts/icons/freenas.woff differ
diff --git a/blue-shark/assets/fonts/lato/Lato-Light-7244318390cc4d36aac4a613ff42d308.woff2 b/blue-shark/assets/fonts/lato/Lato-Light-7244318390cc4d36aac4a613ff42d308.woff2
new file mode 100644
index 0000000000..ce49f82217
Binary files /dev/null and b/blue-shark/assets/fonts/lato/Lato-Light-7244318390cc4d36aac4a613ff42d308.woff2 differ
diff --git a/blue-shark/assets/fonts/lato/Lato-Light-90301aa07d780a09812229d6375c3b28.woff b/blue-shark/assets/fonts/lato/Lato-Light-90301aa07d780a09812229d6375c3b28.woff
new file mode 100644
index 0000000000..77b4e148f7
Binary files /dev/null and b/blue-shark/assets/fonts/lato/Lato-Light-90301aa07d780a09812229d6375c3b28.woff differ
diff --git a/blue-shark/assets/fonts/lato/Lato-LightItalic-314210a4825a7cc8ca7db893dfd9d283.woff2 b/blue-shark/assets/fonts/lato/Lato-LightItalic-314210a4825a7cc8ca7db893dfd9d283.woff2
new file mode 100644
index 0000000000..0c897ce40c
Binary files /dev/null and b/blue-shark/assets/fonts/lato/Lato-LightItalic-314210a4825a7cc8ca7db893dfd9d283.woff2 differ
diff --git a/blue-shark/assets/fonts/lato/Lato-LightItalic-b55e385f24f0f9f724dac935fe292ecf.woff b/blue-shark/assets/fonts/lato/Lato-LightItalic-b55e385f24f0f9f724dac935fe292ecf.woff
new file mode 100644
index 0000000000..da3dfa30a4
Binary files /dev/null and b/blue-shark/assets/fonts/lato/Lato-LightItalic-b55e385f24f0f9f724dac935fe292ecf.woff differ
diff --git a/blue-shark/assets/fonts/lato/Lato-Regular-27bd77b9162d388cb8d4c4217c7c5e2a.woff b/blue-shark/assets/fonts/lato/Lato-Regular-27bd77b9162d388cb8d4c4217c7c5e2a.woff
new file mode 100644
index 0000000000..ae1307ff5f
Binary files /dev/null and b/blue-shark/assets/fonts/lato/Lato-Regular-27bd77b9162d388cb8d4c4217c7c5e2a.woff differ
diff --git a/blue-shark/assets/fonts/lato/Lato-Regular-bd03a2cc277bbbc338d464e679fe9942.woff2 b/blue-shark/assets/fonts/lato/Lato-Regular-bd03a2cc277bbbc338d464e679fe9942.woff2
new file mode 100644
index 0000000000..3bf9843328
Binary files /dev/null and b/blue-shark/assets/fonts/lato/Lato-Regular-bd03a2cc277bbbc338d464e679fe9942.woff2 differ
diff --git a/blue-shark/assets/icons/apple-touch-icon-120x120-precomposed.png b/blue-shark/assets/icons/apple-touch-icon-120x120-precomposed.png
new file mode 100644
index 0000000000..c9f6d3522a
Binary files /dev/null and b/blue-shark/assets/icons/apple-touch-icon-120x120-precomposed.png differ
diff --git a/blue-shark/assets/icons/apple-touch-icon-152x152-precomposed.png b/blue-shark/assets/icons/apple-touch-icon-152x152-precomposed.png
new file mode 100644
index 0000000000..9056f7bc95
Binary files /dev/null and b/blue-shark/assets/icons/apple-touch-icon-152x152-precomposed.png differ
diff --git a/blue-shark/assets/icons/apple-touch-icon-76x76-precomposed.png b/blue-shark/assets/icons/apple-touch-icon-76x76-precomposed.png
new file mode 100644
index 0000000000..8b58980240
Binary files /dev/null and b/blue-shark/assets/icons/apple-touch-icon-76x76-precomposed.png differ
diff --git a/blue-shark/assets/icons/apple-touch-icon-precomposed.png b/blue-shark/assets/icons/apple-touch-icon-precomposed.png
new file mode 100644
index 0000000000..78934b42b2
Binary files /dev/null and b/blue-shark/assets/icons/apple-touch-icon-precomposed.png differ
diff --git a/blue-shark/assets/icons/apple-touch-icon.png b/blue-shark/assets/icons/apple-touch-icon.png
new file mode 100644
index 0000000000..92b51bf9b6
Binary files /dev/null and b/blue-shark/assets/icons/apple-touch-icon.png differ
diff --git a/blue-shark/assets/style/style.css b/blue-shark/assets/style/style.css
new file mode 100644
index 0000000000..41b5c5bee0
--- /dev/null
+++ b/blue-shark/assets/style/style.css
@@ -0,0 +1,15 @@
+.container > h1 {
+ background-color: #000;
+ color: #fff;
+ margin: -1rem;
+ padding: 1rem;
+}
+
+.container > h2 {
+ color: #E0E5E5;
+ margin-top: 2rem;
+}
+
+.container {
+ margin: 1rem;
+}
diff --git a/blue-shark/core/.npmignore b/blue-shark/core/.npmignore
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/favicon.ico b/blue-shark/favicon.ico
new file mode 100644
index 0000000000..0319ac1903
Binary files /dev/null and b/blue-shark/favicon.ico differ
diff --git a/blue-shark/gulpfile.js b/blue-shark/gulpfile.js
new file mode 100644
index 0000000000..3834db28eb
--- /dev/null
+++ b/blue-shark/gulpfile.js
@@ -0,0 +1,85 @@
+var path = require('path');
+ gulp = require('gulp'),
+ postcss = require('gulp-postcss'),
+ header = require('gulp-header'),
+ rename = require('gulp-rename'),
+ newer = require('gulp-newer'),
+ cssnext = require('postcss-cssnext'),
+ postcssImport = require('postcss-import'),
+ styleLint = require('stylelint'),
+ postcssDiscardComments = require('postcss-discard-comments'),
+ browserSync = require('browser-sync').create(),
+ cssnano = require('cssnano');
+
+var processors = [
+ styleLint({
+ config: {
+ "extends": "stylelint-config-standard",
+ },
+ plugins: [
+ "stylelint-declaration-strict-value"
+ ],
+ rules: {
+ "number-leading-zero": null,
+ "custom-property-empty-line-before": null,
+ "declaration-colon-space-after": null,
+ "indentation": [4, {
+ ignore: ["value"]
+ }],
+ "value-no-vendor-prefix": true,
+ "property-no-vendor-prefix": true,
+ "scale-unlimited/declaration-strict-value": [
+ ["/color/", "box-shadow", "border", "background"],
+ {"ignoreKeywords": ["inherit", "currentColor", "transparent", "none"]}
+ ]
+ }
+ }),
+ postcssImport,
+ cssnext,
+ postcssDiscardComments,
+ cssnano({autoprefixer: false, safe: true})
+ ],
+ gulpDir = process.cwd(),
+ cssConfig = gulpDir + "/ui/_config.css";
+
+// Tasks
+
+gulp.task('serve', ['allCss'], function() {
+ browserSync.init({
+ server: "./",
+ port: 3002,
+ ui: { port: 3003 }
+ });
+
+ gulp.watch(blue-shark/ui/**/**/_*.css", ['css']);
+ gulp.watch([blue-shark/ui/_config.css", "ui/_theme.css"], ['allCss']);
+ gulp.watch(blue-shark/ui/**/**/*.html").on('change', browserSync.reload);
+});
+
+gulp.task('css', function() {
+
+ return gulp.src([blue-shark/ui/**/**/_*.css", "!ui/**/**/_config.css"])
+ .pipe(rename(function(path) {
+ path.basename = path.basename.substring(1);
+ }))
+ .pipe(newer({dest: './ui'}))
+ .pipe(header("@import '" + cssConfig + "';"))
+ .pipe(postcss(processors))
+ .pipe(gulp.dest('./ui'))
+ .pipe(browserSync.stream());
+});
+
+gulp.task('allCss', function() {
+
+ return gulp.src([blue-shark/ui/**/**/_*.css", "!ui/**/**/_config.css"])
+ .pipe(rename(function(path) {
+ path.basename = path.basename.substring(1);
+ }))
+ .pipe(header("@import '" + cssConfig + "';"))
+ .pipe(postcss(processors))
+ .pipe(gulp.dest('./ui'))
+ .pipe(browserSync.stream());
+});
+
+// Default task to be run with `gulp`
+gulp.task('default', ['serve']);
diff --git a/blue-shark/index.html b/blue-shark/index.html
new file mode 100644
index 0000000000..60b6defa05
--- /dev/null
+++ b/blue-shark/index.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/input-search.reel/input-search.js b/blue-shark/ui/input-search.reel/input-search.js
new file mode 100644
index 0000000000..b6f750d46e
--- /dev/null
+++ b/blue-shark/ui/input-search.reel/input-search.js
@@ -0,0 +1,20 @@
+/**
+ * @module ui/input-search.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class InputSearch
+ * @extends Component
+ */
+exports.InputSearch = Component.specialize(/** @lends InputSearch# */ {
+ enabled: {
+ value: true
+ },
+
+ handleClearButtonAction: {
+ value: function () {
+ this._searchField.value = null;
+ }
+ }
+});
diff --git a/blue-shark/ui/layouts/table-header-layout.reel/_table-header-layout.css b/blue-shark/ui/layouts/table-header-layout.reel/_table-header-layout.css
new file mode 100644
index 0000000000..a50f3fbd4e
--- /dev/null
+++ b/blue-shark/ui/layouts/table-header-layout.reel/_table-header-layout.css
@@ -0,0 +1,45 @@
+/* Header Group */
+
+.Table-header-group {
+ display: flex;
+ flex: 1;
+ align-items: center;
+}
+
+.TableHeaderLayout-row {
+ display: flex;
+ flex: 1;
+ align-items: center;
+}
+
+.TableHeaderLayout-cell {
+ position: relative;
+ font-weight: 400;
+ padding: .5rem;
+ min-height: 3rem;
+ display: flex;
+ align-items: center;
+ flex: 1;
+
+ &:before {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: -1px;;
+ border-right: 1px solid var(--table-border-color);
+ }
+
+ &:after {
+ display: inline-block;
+ display: none;
+ content: "";
+ vertical-align: top;
+ margin-left: .5em;
+ margin-top: .5em;
+ border-left: .4em solid transparent;
+ border-right: .4em solid transparent;
+ border-top: .4em solid var(--grey-1);
+ }
+}
+
diff --git a/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.css b/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.css
new file mode 100644
index 0000000000..bea0360b95
--- /dev/null
+++ b/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.css
@@ -0,0 +1 @@
+.Table-header-group,.TableHeaderLayout-cell,.TableHeaderLayout-row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.TableHeaderLayout-cell{position:relative;font-weight:400;padding:8px;padding:.5rem;min-height:48px;min-height:3rem}.TableHeaderLayout-cell:before{content:"";position:absolute;top:0;bottom:0;right:-1px;border-right:1px solid #181e25}.TableHeaderLayout-cell:after{display:inline-block;display:none;content:"";vertical-align:top;margin-left:.5em;margin-top:.5em;border-left:.4em solid transparent;border-right:.4em solid transparent;border-top:.4em solid #939e9f}
\ No newline at end of file
diff --git a/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.html b/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.html
new file mode 100644
index 0000000000..017c023170
--- /dev/null
+++ b/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.html
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.js b/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.js
new file mode 100644
index 0000000000..4b7d133ab7
--- /dev/null
+++ b/blue-shark/ui/layouts/table-header-layout.reel/table-header-layout.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/table-read-only-header.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class TableHeaderLayout
+ * @extends Component
+ */
+exports.TableHeaderLayout = Component.specialize();
diff --git a/blue-shark/ui/layouts/table-layout.reel/_table-layout.css b/blue-shark/ui/layouts/table-layout.reel/_table-layout.css
new file mode 100644
index 0000000000..7491f6291c
--- /dev/null
+++ b/blue-shark/ui/layouts/table-layout.reel/_table-layout.css
@@ -0,0 +1,115 @@
+.Table-label {
+ color: var(--grey-2);
+ font-weight: 400;
+}
+
+/* Table-header-columns */
+
+.Table-header-columns {
+ display: flex;
+ align-items: center;
+ background-color: var(--primary--8);
+}
+
+.Table.content-is-empty .Table-header-columns { display: none;}
+
+.Table-row-group { width: 100%; }
+
+.Table-row-group:empty { display: none; } /* removes table row group if empty */
+
+/* Content */
+
+.Table-content { position: relative; }
+
+/*
+
+Row
+
+*/
+
+.Table-row {
+ display: flex;
+ flex: 1;
+ align-items: stretch;
+ transition: background-color .15s ease-in-out;
+
+ & > div:not(:last-child):after {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: -1px;;
+ border-right: 1px solid var(--table-border-color);
+ }
+}
+
+.Table-row-fields {
+ outline: none;
+}
+
+.Table-row-fields:nth-child(odd) .Table-row:not(.Table-cells) { background-color: var(--primary); }
+.Table-row-fields:nth-child(even) .Table-row:not(.Table-cells) { background-color: color(var(--primary) shade(10%)); }
+.Table-row-group .Table-row:not(.Table-cells):hover { background-color: color(var(--primary) tint(5%)); }
+
+/*
+
+Rows - selection Enabled
+
+*/
+
+.Table.has-selection-enabled .Table-row { cursor: pointer; }
+
+.Table-row-group .Table-row.selected:not(.Table-cells) {
+ color: var(--white);
+ background-color: var(--color-selected);
+}
+
+.Table-row-group .Table-row.selected:hover { background-color: var(--color-selected); }
+
+/* Table Cell */
+
+.Table-cell {
+ flex: 1;
+ flex-shrink: 0;
+ padding: .5em;
+ word-break: break-all;
+}
+
+/* Caption */
+
+.Table-caption {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ padding-bottom: .5em;
+}
+
+/* isLoading */
+
+.Table-isLoading {
+ justify-content: center;
+ min-height: 4em;
+}
+
+/* Empty State */
+
+.Table-emptyState {
+ display: none;
+ font-weight: 300;
+ color: var(--grey-1);
+ margin-top: .5em;
+ font-style: italic;
+}
+
+.Table.content-is-empty .Table-emptyState { display: block;}
+
+/* Scrollview */
+
+.Table-scroller {
+ position: relative;
+ overflow: auto;
+
+ @nest .content-is-empty & {
+ display: none;
+ }
+}
diff --git a/blue-shark/ui/layouts/table-layout.reel/table-layout.css b/blue-shark/ui/layouts/table-layout.reel/table-layout.css
new file mode 100644
index 0000000000..b866cd6d21
--- /dev/null
+++ b/blue-shark/ui/layouts/table-layout.reel/table-layout.css
@@ -0,0 +1 @@
+.Table-label{color:#b1bcbe;font-weight:400}.Table-header-columns{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;background-color:#13181d}.Table.content-is-empty .Table-header-columns{display:none}.Table-row-group{width:100%}.Table-row-group:empty{display:none}.Table-content{position:relative}.Table-row{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-transition:background-color .15s ease-in-out;transition:background-color .15s ease-in-out}.Table-row>div:not(:last-child):after{content:"";position:absolute;top:0;bottom:0;right:-1px;border-right:1px solid #181e25}.Table-row-fields{outline:none}.Table-row-fields:nth-child(odd) .Table-row:not(.Table-cells){background-color:#222b35}.Table-row-fields:nth-child(2n) .Table-row:not(.Table-cells){background-color:#1f2730}.Table-row-group .Table-row:not(.Table-cells):hover{background-color:#2d363f}.Table.has-selection-enabled .Table-row{cursor:pointer}.Table-row-group .Table-row.selected:not(.Table-cells){color:#fff;background-color:#0c5688}.Table-row-group .Table-row.selected:hover{background-color:#0c5688}.Table-cell{-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-negative:0;flex-shrink:0;padding:.5em;word-break:break-all}.Table-caption{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding-bottom:.5em}.Table-isLoading{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;min-height:4em}.Table-emptyState{display:none;font-weight:300;color:#939e9f;margin-top:.5em;font-style:italic}.Table.content-is-empty .Table-emptyState{display:block}.Table-scroller{position:relative;overflow:auto}.content-is-empty .Table-scroller{display:none}
\ No newline at end of file
diff --git a/blue-shark/ui/layouts/table-layout.reel/table-layout.html b/blue-shark/ui/layouts/table-layout.reel/table-layout.html
new file mode 100644
index 0000000000..a8fc7cdef0
--- /dev/null
+++ b/blue-shark/ui/layouts/table-layout.reel/table-layout.html
@@ -0,0 +1,113 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/layouts/table-layout.reel/table-layout.js b/blue-shark/ui/layouts/table-layout.reel/table-layout.js
new file mode 100644
index 0000000000..1eb3875e79
--- /dev/null
+++ b/blue-shark/ui/layouts/table-layout.reel/table-layout.js
@@ -0,0 +1,18 @@
+/**
+ * @module ui/table.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class TableLayout
+ * @extends Component
+ */
+exports.TableLayout = Component.specialize({
+ enterDocument: {
+ value: function () {
+ if (!!this.contentMaxHeight) {
+ this.scrollview.style.maxHeight = this.contentMaxHeight + "em";
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/loading-message.info/sample/index.html b/blue-shark/ui/loading-message.info/sample/index.html
new file mode 100644
index 0000000000..731c3c04d2
--- /dev/null
+++ b/blue-shark/ui/loading-message.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Loading Message Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/loading-message.info/sample/package.json b/blue-shark/ui/loading-message.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/loading-message.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/loading-message.info/sample/ui/main.reel/_main.css b/blue-shark/ui/loading-message.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/loading-message.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.css b/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.html b/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..6474c6bafd
--- /dev/null
+++ b/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
Loading Message
+
Default
+
+
+
+
+
diff --git a/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.js b/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..3fa4e9daf1
--- /dev/null
+++ b/blue-shark/ui/loading-message.info/sample/ui/main.reel/main.js
@@ -0,0 +1,36 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ options: {
+ value: [
+ {
+ "value": "none",
+ "label": "None"
+ },
+ {
+ "value": "optimal",
+ "label": "Optimal"
+ },
+ {
+ "value": "virtualization",
+ "label": "Virtualization"
+ },
+ {
+ "value": "backups",
+ "label": "Backups"
+ },
+ {
+ "value": "media",
+ "label": "Media"
+ }
+ ]
+ }
+});
diff --git a/blue-shark/ui/loading-message.reel/_loading-message.css b/blue-shark/ui/loading-message.reel/_loading-message.css
new file mode 100644
index 0000000000..c0b5f27a69
--- /dev/null
+++ b/blue-shark/ui/loading-message.reel/_loading-message.css
@@ -0,0 +1,51 @@
+.LoadingMessage {
+ display: none;
+ align-items: center;
+ justify-content: center;
+ min-height: 3rem;
+
+ &.is-loading { display: flex; }
+
+ &.has-background {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+
+ &:before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: rgba(0,0,0,.5);
+ background-image: repeating-linear-gradient(-45deg, rgba(43,156,216,0.25), rgba(43,156,216,0.25) 1px, transparent 1px, transparent 10px);
+ background-size: 28px 28px;
+ }
+ }
+}
+
+.LoadingMessage-message {
+ margin-right: .5em;
+ font-weight: 200;
+
+ @nest .LoadingMessage.has-background & {
+ position: relative;
+ z-index: 1;
+ }
+}
+
+.LoadingMessage-spinner {
+
+ & svg {
+ height: 2em !important;
+ width: 2em !important;
+ }
+
+ @nest .LoadingMessage.has-background & {
+ position: relative;
+ z-index: 1;
+ }
+}
diff --git a/blue-shark/ui/loading-message.reel/loading-message.css b/blue-shark/ui/loading-message.reel/loading-message.css
new file mode 100644
index 0000000000..023f7aa372
--- /dev/null
+++ b/blue-shark/ui/loading-message.reel/loading-message.css
@@ -0,0 +1 @@
+.LoadingMessage{display:none;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;min-height:48px;min-height:3rem}.LoadingMessage.is-loading{display:-webkit-box;display:-ms-flexbox;display:flex}.LoadingMessage.has-background,.LoadingMessage.has-background:before{position:absolute;top:0;left:0;right:0;bottom:0}.LoadingMessage.has-background:before{content:"";background-color:rgba(0,0,0,.5);background-image:-webkit-repeating-linear-gradient(135deg,rgba(43,156,216,.25),rgba(43,156,216,.25) 1px,transparent 0,transparent 10px);background-image:repeating-linear-gradient(-45deg,rgba(43,156,216,.25),rgba(43,156,216,.25) 1px,transparent 0,transparent 10px);background-size:28px 28px}.LoadingMessage-message{margin-right:.5em;font-weight:200}.LoadingMessage.has-background .LoadingMessage-message{position:relative;z-index:1}.LoadingMessage-spinner svg{height:2em!important;width:2em!important}.LoadingMessage.has-background .LoadingMessage-spinner{position:relative;z-index:1}
\ No newline at end of file
diff --git a/blue-shark/ui/loading-message.reel/loading-message.html b/blue-shark/ui/loading-message.reel/loading-message.html
new file mode 100644
index 0000000000..e0eb9b92bc
--- /dev/null
+++ b/blue-shark/ui/loading-message.reel/loading-message.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/loading-message.reel/loading-message.js b/blue-shark/ui/loading-message.reel/loading-message.js
new file mode 100644
index 0000000000..84c65bad7c
--- /dev/null
+++ b/blue-shark/ui/loading-message.reel/loading-message.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/loading-message.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class LoadingMessage
+ * @extends Component
+ */
+exports.LoadingMessage = Component.specialize();
diff --git a/blue-shark/ui/main.reel/_main.css b/blue-shark/ui/main.reel/_main.css
new file mode 100644
index 0000000000..214f94752b
--- /dev/null
+++ b/blue-shark/ui/main.reel/_main.css
@@ -0,0 +1,85 @@
+.Main {
+ padding: 0 2em;
+}
+
+.Main ul {
+ list-style: none;
+ padding: 0;
+}
+
+.Main a {
+ color: var(--blue-lighten-1);
+
+ &:hover {
+ color: color(var(--blue-lighten-1) l(+ 10%));
+ }
+}
+
+.color {
+ display: inline-block;
+ width: 8em;
+ height: 3em;
+
+ &:before {
+ display: inline-block;
+ padding: var(--space-half);
+ font-weight: 200;
+ font-family: 'lato';
+ font-size: .8em;
+ color: var(--white);
+ };
+}
+
+/* blue */
+
+.color.color-blue:nth-child(1) {
+ background: var(--blue-lighten-2);
+ &:before { content: '--blue-lighten-2'; };
+}
+
+.color.color-blue:nth-child(2) {
+ background: var(--blue-lighten-1);
+ &:before { content: '--blue-lighten-1'; };
+}
+
+.color.color-blue:nth-child(3) {
+ background: var(--blue);
+ &:before { content: '--blue'; };
+}
+
+.color.color-blue:nth-child(4) {
+ background: var(--blue-darken-1);
+ &:before { content: '--blue-darken-1'; };
+}
+
+.color.color-blue:nth-child(5) {
+ background: var(--blue-darken-2);
+ &:before { content: '--blue-darken-2'; };
+}
+
+/* orange */
+
+.color.color-orange:nth-child(1) {
+ background: var(--orange-lighten-2);
+ &:before { content: '--orange-lighten-2'; };
+}
+
+.color.color-orange:nth-child(2) {
+ background: var(--orange-lighten-1);
+ &:before { content: '--orange-lighten-1'; };
+}
+
+.color.color-orange:nth-child(3) {
+ background: var(--orange);
+ &:before { content: '--orange'; };
+}
+
+.color.color-orange:nth-child(4) {
+ background: var(--orange-darken-1);
+ &:before { content: '--orange-darken-1'; };
+}
+
+.color.color-orange:nth-child(5) {
+ background: var(--orange-darken-2);
+ &:before { content: '--orange-darken-2'; };
+}
diff --git a/blue-shark/ui/main.reel/main.css b/blue-shark/ui/main.reel/main.css
new file mode 100644
index 0000000000..8b444362d9
--- /dev/null
+++ b/blue-shark/ui/main.reel/main.css
@@ -0,0 +1 @@
+.Main{padding:0 2em}.Main ul{list-style:none;padding:0}.Main a{color:#0d65a0}.Main a:hover{color:#1183d0}.color{width:8em;height:3em}.color,.color:before{display:inline-block}.color:before{padding:.5em;font-weight:200;font-family:lato;font-size:.8em;color:#fff}.color.color-blue:first-child{background:#2089d3}.color.color-blue:first-child:before{content:"--blue-lighten-2"}.color.color-blue:nth-child(2){background:#0d65a0}.color.color-blue:nth-child(2):before{content:"--blue-lighten-1"}.color.color-blue:nth-child(3){background:#0c5688}.color.color-blue:nth-child(3):before{content:"--blue"}.color.color-blue:nth-child(4){background:#093a51}.color.color-blue:nth-child(4):before{content:"--blue-darken-1"}.color.color-blue:nth-child(5){background:#0b1e29}.color.color-blue:nth-child(5):before{content:"--blue-darken-2"}.color.color-orange:first-child{background:#d78f2a}.color.color-orange:first-child:before{content:"--orange-lighten-2"}.color.color-orange:nth-child(2){background:#de7225}.color.color-orange:nth-child(2):before{content:"--orange-lighten-1"}.color.color-orange:nth-child(3){background:#d95b1b}.color.color-orange:nth-child(3):before{content:"--orange"}.color.color-orange:nth-child(4){background:#c35118}.color.color-orange:nth-child(4):before{content:"--orange-darken-1"}.color.color-orange:nth-child(5){background:#ac4815}.color.color-orange:nth-child(5):before{content:"--orange-darken-2"}
\ No newline at end of file
diff --git a/blue-shark/ui/main.reel/main.html b/blue-shark/ui/main.reel/main.html
new file mode 100644
index 0000000000..3c4dbaeb41
--- /dev/null
+++ b/blue-shark/ui/main.reel/main.html
@@ -0,0 +1,94 @@
+
+
+
+
+
Main
+
+
+
+
+
+
+
+
+
Blue Shark
+
Base Widgets
+
+
+
+
+
+ Colors
+ Blue
+
+ Orange
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/main.reel/main.js b/blue-shark/ui/main.reel/main.js
new file mode 100644
index 0000000000..de3171b166
--- /dev/null
+++ b/blue-shark/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/modal.info/sample/index.html b/blue-shark/ui/modal.info/sample/index.html
new file mode 100644
index 0000000000..012f0e7f3b
--- /dev/null
+++ b/blue-shark/ui/modal.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Modal Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/modal.info/sample/package.json b/blue-shark/ui/modal.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/modal.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/modal.info/sample/ui/main.reel/_main.css b/blue-shark/ui/modal.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/modal.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/modal.info/sample/ui/main.reel/main.css b/blue-shark/ui/modal.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/modal.info/sample/ui/main.reel/main.html b/blue-shark/ui/modal.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..56a30443a9
--- /dev/null
+++ b/blue-shark/ui/modal.info/sample/ui/main.reel/main.html
@@ -0,0 +1,54 @@
+
+
+
+
+
+
+
+
+
+
+ This is the contents of the modal
+
+
+
Loading Message
+ Default
+
+
+
+
+
diff --git a/blue-shark/ui/modal.info/sample/ui/main.reel/main.js b/blue-shark/ui/modal.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..c67d046956
--- /dev/null
+++ b/blue-shark/ui/modal.info/sample/ui/main.reel/main.js
@@ -0,0 +1,17 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ handleTriggerAction: {
+ value: function() {
+ this.modal.isShown = true;
+ }
+ }
+});
diff --git a/blue-shark/ui/modal.reel/_modal.css b/blue-shark/ui/modal.reel/_modal.css
new file mode 100644
index 0000000000..14c3f9ed2e
--- /dev/null
+++ b/blue-shark/ui/modal.reel/_modal.css
@@ -0,0 +1,30 @@
+.Modal {
+ opacity: 0;
+ visibility: hidden;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 5000;
+ background-color: color(var(--primary--9) a(50%));
+ display: flex;
+ justify-content: top;
+ align-items: center;
+ flex-direction: column;
+ transition: opacity .25s ease-in-out,
+ visibility .25s ease-in-out;
+
+ &.is-active {
+ display: flex !important;
+ opacity: 1;
+ visibility: visible;
+ }
+}
+
+.Modal-close {
+ position: absolute;
+ top: 0;
+ right: 0;
+ font-size: 1rem !important;
+}
diff --git a/blue-shark/ui/modal.reel/modal.css b/blue-shark/ui/modal.reel/modal.css
new file mode 100644
index 0000000000..354a5beb56
--- /dev/null
+++ b/blue-shark/ui/modal.reel/modal.css
@@ -0,0 +1 @@
+.Modal{opacity:0;visibility:hidden;position:absolute;top:0;left:0;right:0;bottom:0;z-index:5000;background-color:rgba(14,17,21,.5);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:top;-ms-flex-pack:top;justify-content:top;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-transition:opacity .25s ease-in-out,visibility .25s ease-in-out;transition:opacity .25s ease-in-out,visibility .25s ease-in-out}.Modal.is-active{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;opacity:1;visibility:visible}.Modal-close{position:absolute;top:0;right:0;font-size:16px!important;font-size:1rem!important}
\ No newline at end of file
diff --git a/blue-shark/ui/modal.reel/modal.html b/blue-shark/ui/modal.reel/modal.html
new file mode 100644
index 0000000000..23b5ac2c23
--- /dev/null
+++ b/blue-shark/ui/modal.reel/modal.html
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/modal.reel/modal.js b/blue-shark/ui/modal.reel/modal.js
new file mode 100644
index 0000000000..e8f833f56a
--- /dev/null
+++ b/blue-shark/ui/modal.reel/modal.js
@@ -0,0 +1,73 @@
+var AbstractControl = require("montage/ui/base/abstract-control").AbstractControl,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer;
+
+exports.Modal = AbstractControl.specialize({
+ isShown: {
+ value: false
+ },
+
+ templateDidLoad: {
+ value: function() {
+ this.super();
+ this.isShown = false;
+ }
+ },
+
+ enterDocument: {
+ value: function() {
+ this.element.addEventListener('click', this);
+ }
+ },
+
+ // FIXME: not working??
+ prepareForActivationEvents: {
+ value: function() {
+ KeyComposer.createKey(this, "enter", "enter").addEventListener("keyPress", this);
+ KeyComposer.createKey(this, "escape", "escape").addEventListener("keyPress", this);
+ }
+ },
+
+ close: {
+ value: function() {
+ this.isShown = false;
+ }
+ },
+
+ toggle: {
+ value: function() {
+ this.isShown = !this.isShown;
+ }
+ },
+
+ handleEscapeKeyPress: {
+ value: function() {
+ if (this.controller && typeof this.controller.handleCloseAction === 'function') {
+ this.controller.handleCloseAction()
+ } else {
+ this.close();
+ }
+ }
+ },
+
+ handleClick: {
+ value: function (e) {
+ if(e.target == this.element) {
+ if (this.controller && typeof this.controller.handleCloseAction === 'function') {
+ this.controller.handleCloseAction()
+ } else {
+ this.close();
+ }
+ }
+ }
+ },
+
+ handleCloseButtonAction: {
+ value: function() {
+ if (this.controller && typeof this.controller.handleCloseAction === 'function') {
+ this.controller.handleCloseAction()
+ } else {
+ this.close();
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/multiple-select-grid.info/sample/index.html b/blue-shark/ui/multiple-select-grid.info/sample/index.html
new file mode 100644
index 0000000000..d014b638f2
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.info/sample/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
Multiple Select Grid Sample
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select-grid.info/sample/package.json b/blue-shark/ui/multiple-select-grid.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/_main.css b/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.css b/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.html b/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..e2f264cde6
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.html
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
Multiple Select Grid
+
+
Results:
+
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.js b/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..cf79bbbe49
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.info/sample/ui/main.reel/main.js
@@ -0,0 +1,55 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+ minutesContent: {
+ value: null
+ },
+ daysContent: {
+ value: null
+ },
+
+ selection: {
+ value: null
+ },
+
+ templateDidLoad: {
+ value: function() {
+ var minutes = [];
+ for (var i = 0; i < 60; i++) {
+ minutes.push({"label": ''+i, "value": i});
+ }
+ this.minutesContent = minutes;/*[
+ {"index": 1, "label": "M", "value": "monday"},
+ {"index": 0, "label": "S", "value": "sunday"},
+ {"index": 2, "label": "T", "value": "tuesday"},
+ {"index": 3, "label": "W", "value": "wednesday"},
+ {"index": 4, "label": "Th", "value": "thursday"},
+ {"index": 5, "label": "F", "value": "friday"},
+ {"index": 6, "label": "S", "value": "saturday"}
+ ];*/
+
+ this.daysContent = [
+ {"index": 1, "label": "M", "value": "monday"},
+ {"index": 0, "label": "S", "value": "sunday"},
+ {"index": 2, "label": "T", "value": "tuesday"},
+ {"index": 3, "label": "W", "value": "wednesday"},
+ {"index": 4, "label": "Th", "value": "thursday"},
+ {"index": 5, "label": "F", "value": "friday"},
+ {"index": 6, "label": "S", "value": "saturday"}
+ ];
+ this.selectedOnOpen = ['monday', 'wednesday'];
+ }
+ },
+
+ enterDocument: {
+ value: function (isFirstTime) {
+ }
+ }
+});
diff --git a/blue-shark/ui/multiple-select-grid.reel/_multiple-select-grid.css b/blue-shark/ui/multiple-select-grid.reel/_multiple-select-grid.css
new file mode 100644
index 0000000000..ad8d6853b4
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.reel/_multiple-select-grid.css
@@ -0,0 +1,73 @@
+.MultipleSelectGrid {
+
+}
+
+.MultipleSelectGrid-options {
+ display: flex;
+ justify-content: flex-start;
+ flex-wrap: wrap;
+}
+
+.MultipleSelectGrid-option {
+ flex: 1;
+ position: relative;
+ padding: .5em;
+ height: 2.5em;
+ line-height: 1.5em;
+ text-align: center;
+ color: var(--grey-1);
+ cursor: pointer;
+}
+
+.MultipleSelectGrid-option:first-child:nth-last-child(n+8),
+.MultipleSelectGrid-option:first-child:nth-last-child(n+8) ~ .MultipleSelectGrid-option {
+ flex: 0;
+ min-width: 2.5em;
+}
+
+.MultipleSelectGrid-option:hover {
+ color: var(--white);
+ background-color: rgba(255,255,255,.1);
+}
+
+.MultipleSelectGrid-option.selected {
+ color: var(--white);
+ background-color: var(--color-selected);
+}
+
+.MultipleSelectGrid-option:before {
+ position: absolute;
+ content: '';
+ top: 1px;
+ left: 1px;
+ right: 0px;
+ bottom: 0px;
+ outline: 1px solid #888;
+}
+
+/* iterator */
+
+.MultipleSelectGrid-iterator {
+ display: none;
+ margin-top: 1rem;
+ justify-content: space-between;
+
+ @nest .MultipleSelectGrid.has-iterator & {
+ display: flex;
+ }
+
+}
+
+.MultipleSelectGrid-control {
+ display: flex;
+ align-items: center;
+
+ & .MultipleSelectGrid-label {
+ margin-right: 1em;
+ font-weight: 300;
+ }
+
+ & .MultipleSelectGrid-numberIterator {
+ max-width: 6.5em;
+ }
+}
diff --git a/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.css b/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.css
new file mode 100644
index 0000000000..79ba3ec5f2
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.css
@@ -0,0 +1 @@
+.MultipleSelectGrid-options{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;-ms-flex-wrap:wrap;flex-wrap:wrap}.MultipleSelectGrid-option{-webkit-box-flex:1;-ms-flex:1;flex:1;position:relative;padding:.5em;height:2.5em;line-height:1.5em;text-align:center;color:#939e9f;cursor:pointer}.MultipleSelectGrid-option:first-child:nth-last-child(n+8),.MultipleSelectGrid-option:first-child:nth-last-child(n+8)~.MultipleSelectGrid-option{-webkit-box-flex:0;-ms-flex:0;flex:0;min-width:2.5em}.MultipleSelectGrid-option:hover{color:#fff;background-color:hsla(0,0%,100%,.1)}.MultipleSelectGrid-option.selected{color:#fff;background-color:#0c5688}.MultipleSelectGrid-option:before{position:absolute;content:"";top:1px;left:1px;right:0;bottom:0;outline:1px solid #888}.MultipleSelectGrid-iterator{display:none;margin-top:16px;margin-top:1rem;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.MultipleSelectGrid-control,.MultipleSelectGrid.has-iterator .MultipleSelectGrid-iterator{display:-webkit-box;display:-ms-flexbox;display:flex}.MultipleSelectGrid-control{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.MultipleSelectGrid-control .MultipleSelectGrid-label{margin-right:1em;font-weight:300}.MultipleSelectGrid-control .MultipleSelectGrid-numberIterator{max-width:6.5em}
\ No newline at end of file
diff --git a/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.html b/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.html
new file mode 100644
index 0000000000..47876be72e
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.html
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.js b/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.js
new file mode 100644
index 0000000000..43347352c5
--- /dev/null
+++ b/blue-shark/ui/multiple-select-grid.reel/multiple-select-grid.js
@@ -0,0 +1,143 @@
+/**
+ * @module ui/multiple-select-grid.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class MultipleSelectGrid
+ * @extends Component
+ */
+exports.MultipleSelectGrid = Component.specialize(/** @lends MultipleSelectGrid# */ {
+
+ _sorter: {
+ value: null
+ },
+
+ _sortedSelection: {
+ get: function() {
+ if (!this._sorter && this.controller && this.controller.selection && this.controller.selection.length > 0) {
+ this._sorter = typeof this.controller.selection[0].index !== 'undefined' ?
+ this.constructor._indexSorter : this.constructor._valueSorter;
+ }
+
+ var collection = this.controller && this.controller.selection ?
+ this.controller.selection.slice().map(function(x) { return x.value; }) : [];
+
+ return this._sorter ? collection.sort(this._sorter) : collection;
+ }
+ },
+
+ _selectedValues: {
+ value: null
+ },
+
+ selectedValues: {
+ get: function() {
+ return this._sortedSelection;
+ }, set: function(selectedValues) {
+ this._selectedValues = selectedValues;
+ if (selectedValues) {
+ if (this.options && this.controller) {
+ this.controller.selection = this.options.filter(function(x) {
+ return selectedValues.indexOf(x.value) != -1;
+ });
+ } else {
+ this._needsToSetData = true;
+ }
+ }
+ }
+ },
+
+ enterDocument: {
+ value: function() {
+ if (this._needsToSetData) {
+ this.selectedValues = this._selectedValues;
+ this._needsToSetData = false;
+ }
+ this.addPathChangeListener("frequency", this, "_handleFrequencyChange");
+ this._cancelSelectionListener = this.addRangeAtPathChangeListener("controller.selection", this, "_handleSelectionChange");
+ }
+ },
+
+ exitDocument: {
+ value: function() {
+ if (this.getPathChangeDescriptor("frequency", this)) {
+ this.removePathChangeListener("frequency", this);
+ }
+ if (typeof this._cancelSelectionListener === 'function') {
+ this._cancelSelectionListener();
+ this._cancelSelectionListener = null;
+ }
+ }
+ },
+
+ handleClearSelectionButtonAction: {
+ value: function () {
+ this.controller.clearSelection();
+ this.frequency = null;
+ }
+ },
+
+ _handleSelectionChange: {
+ value: function() {
+ if (this.hasIterator) {
+ this.frequency = this._getSelectionFrequency();
+ }
+ this.dispatchOwnPropertyChange("selectedValues", this._sortedSelection);
+ }
+ },
+
+ _handleFrequencyChange: {
+ value: function() {
+ if (this.frequency > 0) {
+ if (this._getSelectionFrequency() !== this.frequency) {
+ var options = this.controller.organizedContent,
+ selection = [];
+ for (var i = 0, length = options.length; i < length; i = i + this.frequency) {
+ selection.push(options[i]);
+ }
+ this.controller.selection = selection;
+ }
+ } else if (typeof this.frequency === 'number') {
+ this.frequency = null;
+ }
+ }
+ },
+
+ _getSelectionFrequency: {
+ value: function() {
+ if (this._selectedIndexes.length > 0 && this._selectedIndexes[0] === 0) {
+ if (this._selectedIndexes.length === 1) {
+ return this.options.length;
+ } else if (this._selectedIndexes.length > 1) {
+ var i, length,
+ referenceInterval = this._selectedIndexes[1] - this._selectedIndexes[0];
+ for (i = 0, length = this._selectedIndexes.length-1; i < length; i++) {
+ if (this._selectedIndexes[i+1] - this._selectedIndexes[i] !== referenceInterval) {
+ return 0;
+ }
+ }
+ var intervalToEnd = this.options.length - this._selectedIndexes[length];
+ if (intervalToEnd > 1 && intervalToEnd !== referenceInterval) {
+ return 0;
+ }
+ return referenceInterval;
+ }
+ }
+ return 0;
+ }
+ }
+
+
+}, {
+ _indexSorter: {
+ value: function(a, b) {
+ return a.index - b.index;
+ }
+ },
+ _valueSorter: {
+ value: function(a, b) {
+ return a.value < b.value ? -1 : a.value > b.value ? 1 : 0;
+ }
+ }
+});
diff --git a/blue-shark/ui/multiple-select.info/sample/index.html b/blue-shark/ui/multiple-select.info/sample/index.html
new file mode 100644
index 0000000000..d61e04cede
--- /dev/null
+++ b/blue-shark/ui/multiple-select.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Multiple Select Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select.info/sample/package.json b/blue-shark/ui/multiple-select.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/multiple-select.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/multiple-select.info/sample/ui/main.reel/_main.css b/blue-shark/ui/multiple-select.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/multiple-select.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.css b/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.html b/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..363c51f1d6
--- /dev/null
+++ b/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.html
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Multiple Select
+
Default
+
+
Disabled
+
+
Additional Options
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.js b/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..90669567fd
--- /dev/null
+++ b/blue-shark/ui/multiple-select.info/sample/ui/main.reel/main.js
@@ -0,0 +1,32 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ fakeConverter: {
+ value: {
+ revert: function(value) {
+ console.log('revert');
+ var result = {
+ name: value.toUpperCase()
+ };
+ return result;
+ },
+ validator: {
+ validate: function(value) {
+ var isValid = true;
+ if (typeof value === 'string') {
+ isValid = value.indexOf("INVALID") == -1;
+ }
+ return isValid;
+ }
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/multiple-select.reel/_multiple-select.css b/blue-shark/ui/multiple-select.reel/_multiple-select.css
new file mode 100644
index 0000000000..cd5529456a
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/_multiple-select.css
@@ -0,0 +1,196 @@
+.MultipleSelect {
+ min-width: 16em;
+ margin-bottom: 2em;
+ border-radius: 4px;
+
+ &.is-disabled {
+ opacity: .5;
+ cursor: not-allowed;
+ }
+}
+
+.MultipleSelect-title {
+ font-family: 'lato';
+ line-height: 1.5;
+ font-weight: 300;
+ font-weight: 400;
+
+ @nest .MultipleSelect-input & {
+ /* adjustment for extra 1px on outline */
+ height: calc(2em - 1px);
+ line-height: 1.4;
+ }
+}
+
+.MultipleSelect-input-controls {
+ margin-bottom: .5rem;
+
+ & .Field { margin-bottom: .5em;}
+}
+
+/* default input */
+
+.MultipleSelect-input-default {
+ position: relative;
+ margin-right: .25rem;
+ display: inline-block;
+ /* magic # */
+ width: calc(100% - 5.1rem);
+ vertical-align: middle;
+}
+
+.MultipleSelect-input-field {
+ padding-right: 0 !Important;
+
+ @nest .MultipleSelect-input-default.has-value & {
+ padding-right: 1.7rem !important;
+ }
+}
+
+.MultipleSelect-input-clearButton.Button {
+ position: absolute;
+ height: 1.25rem;
+ width: 1.25rem;
+ top: 50%;
+ right: .25rem;
+ margin-top: -.625rem;
+ background-color: var(--primary--4);
+ color: var(--primary--1);
+ border: none;
+ border-radius: .75rem;
+ visibility: hidden;
+ opacity: 0;
+ transition-property: visibility, opacity;
+ transition-duration: .2s;
+
+ &:hover { color: var(--white); }
+
+ &:active { background-color: var(--primary--6); }
+
+ & svg {
+ transform: rotate(45deg);
+ padding: 2px;
+ }
+
+ @nest .MultipleSelect-input-default.has-value & {
+ visibility: visible;
+ opacity: 1;
+ }
+}
+
+/* buttons */
+
+.MultipleSelect-input-buttons {
+ flex: 0;
+ display: flex;
+ justify-content: flex-end;
+
+ @nest .MultipleSelect-input-default + & {
+ display: inline-block;
+ vertical-align: middle;
+ }
+}
+
+.MultipleSelect-input-add { height: 2rem; }
+
+.MultipleSelect-input-options {
+ /* Fix - should I have to do this? */
+ display: none;
+ position: absolute !important;
+ top: 2em;
+ left: 0;
+ right: 0;
+ height: 8.2em;
+ border-bottom-right-radius: 3px;
+ border-bottom-left-radius: 3px;
+ color: var(--grey);
+ background-color: var(--grey-3);
+ border: 1px solid var(--blue-lighten-2);
+ border-top: none;
+ box-shadow: 0 2px 4px rgba(0,0,0,.3);
+ z-index: 100;
+ overflow-x: hidden;
+}
+
+.MultipleSelect-input-error {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background: var(--red);
+ color: var(--white);
+ font-weight: 300;
+ padding: .5em;
+ transform: translateY(100%);
+ z-index: 1;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0,0,0,.3);
+ visibility: hidden;
+ opacity: 0;
+ transition-property: visibility, opacity;
+ transition-duration: .2s;
+}
+.MultipleSelect-values { padding: .25rem; }
+
+.MultipleSelect-valuesContainer {
+ border: 1px solid var(--input-border-color);
+ border-radius: var(--border-radius);
+ position: relative;
+ box-sizing: border-box;
+ display: flex;
+ color: var(--white);
+ height: 7.25em;
+ width: 100%;
+ transition-property: border-color, background-color, opacity;
+ transition-duration: .25s;
+
+ @nest .MultipleSelect.is-disabled & {
+ pointer-events: none;
+ }
+}
+
+/* Empty State */
+
+.MultipleSelect-values-emptyState {
+ position: absolute;
+ color: var(--primary--3);
+ height: 1em;
+ line-height: 1em;
+ left: .5em;
+ right: .5em;
+ top: 50%;
+ text-align: center;
+ margin-top: -.5em;
+
+ @nest .MultipleSelect.disabled & {
+ display: none;
+ }
+}
+
+/*
+
+States
+
+*/
+
+.MultipleSelect-input-field.has-options:focus + .MultipleSelect-input-options.has-content,
+.MultipleSelect-input-options:active,
+.MultipleSelect-input.has-error .MultipleSelect-input-error {
+ display: block;
+}
+
+.MultipleSelect-input.has-error .MultipleSelect-input-field {
+ border-color: var(--red);
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+/* disabled */
+
+.MultipleSelect.disabled .MultipleSelect-valuesContainer {
+ border-color: transparent;
+ opacity: .5;
+ background-color: rgba(0,0,0,.1);
+}
+
+
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/_multiple-select-option.css b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/_multiple-select-option.css
new file mode 100644
index 0000000000..d7f7aec825
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/_multiple-select-option.css
@@ -0,0 +1,14 @@
+.MultipleSelectOption {
+ cursor: pointer;
+ padding: .25em .5em .35em;
+ font-family: 'lato';
+ font-weight: 200;
+}
+
+/*
+.MultipleSelectOption:hover,
+*/
+.MultipleSelectOption.selected {
+ background: var(--blue-lighten-2);
+ color: var(--white);
+}
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.css b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.css
new file mode 100644
index 0000000000..8a6d7a4c2f
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.css
@@ -0,0 +1 @@
+.MultipleSelectOption{cursor:pointer;padding:.25em .5em .35em;font-family:lato;font-weight:200}.MultipleSelectOption.selected{background:#2089d3;color:#fff}
\ No newline at end of file
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.html b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.html
new file mode 100644
index 0000000000..8a6d48a45d
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.js b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.js
new file mode 100644
index 0000000000..9113af288b
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-option.reel/multiple-select-option.js
@@ -0,0 +1,34 @@
+/**
+ * @module ui/multiple-select-option.reel
+ */
+var Component = require("montage/ui/component").Component,
+ PressComposer = require("montage/composer/press-composer").PressComposer;
+
+/**
+ * @class MultipleSelectOption
+ * @extends Component
+ */
+exports.MultipleSelectOption = Component.specialize(/** @lends MultipleSelectOption# */ {
+ prepareForActivationEvents: {
+ value: function() {
+ var pressComposer = new PressComposer();
+ this.addComposer(pressComposer);
+ pressComposer.addEventListener("press", this);
+ this.element.addEventListener("mouseover", this);
+ }
+ },
+
+ handlePress: {
+ value: function() {
+ this.dispatchEventNamed("multipleOptionSelected", true, true, this.option);
+ }
+ },
+
+ handleMouseover: {
+ value: function() {
+ if (this.selected != this.option) {
+ this.selected = this.option;
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/_multiple-select-value.css b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/_multiple-select-value.css
new file mode 100644
index 0000000000..257666c750
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/_multiple-select-value.css
@@ -0,0 +1,134 @@
+.MultipleSelectValue {
+ position: relative;
+ display: flex;
+ flex-wrap: wrap;
+ background: none;
+ margin: -1px;
+}
+
+.MultipleSelectValue:nth-child(even) {
+ background-color: var(--transparent--darken);
+}
+
+.MultipleSelectValue-label.TextField {
+ flex: 1;
+ background: none;
+ border-color: transparent;
+ font-family: 'lato', sans-serif;
+ font-weight: 200;
+ font-size: 1em;
+ color: var(--grey-3);
+ padding: .25em .5em .35em;
+ margin-right: .25em;
+ width: auto;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ cursor: pointer;
+ border-radius: 0;
+
+ &:hover {
+ /* background-color: var(--transparent--lighten); */
+ cursor: text;
+ }
+
+ &:focus {
+ cursor: text;
+ color: var(--white);
+ background: none;
+ }
+}
+
+
+.MultipleSelectValue-delete {
+ align-self: center;
+ height: 1.2rem;
+ width: 1.2rem;
+ padding: .25rem;
+ color: var(--red);
+ cursor: pointer;
+ border: 1px solid var(--red);
+ border-radius: 50%;
+ border: none;
+ background: none;
+ outline: none;
+ margin-right: .25em;
+
+ & svg {
+ transform: rotate(45deg);
+ }
+
+ &:hover {
+ background: var(--red);
+ color: var(--white);
+ }
+}
+
+
+.MultipleSelectValue-error {
+ position: relative;
+ z-index: 1;
+ padding: .5em;
+ width: 100%;
+ font-family: 'lato';
+ font-weight: 200;
+ display: none;
+ margin-bottom: .5em;
+}
+
+/* States */
+
+.MultipleSelectValue.has-error .MultipleSelectValue-label {
+ border-color: var(--red) !important;
+ border-bottom: none !important;
+ border-bottom-right-radius: 0;
+ border-bottom-left-radius: 0;
+}
+
+.MultipleSelectValue.has-error .MultipleSelectValue-error {
+ display: block;
+}
+
+.MultipleSelectValue.has-error .MultipleSelectValue-error:before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: -.25em;
+ right: -.25em;
+ bottom: 0;
+ background: var(--red);
+ z-index: -1;
+}
+
+/* $fix - Temporary Styles ---------------------------------- */
+
+.MultipleSelect-values:empty { display: none; }
+
+.MultipleSelectValue-handler {
+ cursor: move;
+ cursor: grab;
+ padding: 0 0.5em;
+ background: var(--grey-blue-1);
+ display: none;
+}
+
+.MultipleSelectValue.draggable .MultipleSelectValue-handler {
+ display: block;
+ background-image: radial-gradient(rgba(255,255,255,.5), rgba(255,255,255,0) 30%);
+ background-size:8px 8px;
+ border-radius: 2px;
+}
+
+.MultipleSelectValue.draggable .MultipleSelectValue-handler:hover {
+ background-image: radial-gradient(rgba(255,255,255,1), rgba(255,255,255,0) 30%);
+}
+
+.MultipleSelectValue.dragged {
+ opacity: 0.5;
+ user-select: none;
+}
+
+.MultipleSelectValue.dragOver {
+ border-top: 5px solid var(--blue-lighten-2);
+ user-select: none;
+}
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.css b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.css
new file mode 100644
index 0000000000..afe18911d8
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.css
@@ -0,0 +1 @@
+.MultipleSelectValue{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;background:none;margin:-1px}.MultipleSelectValue:nth-child(2n){background-color:rgba(0,0,0,.1)}.MultipleSelectValue-label.TextField{-webkit-box-flex:1;-ms-flex:1;flex:1;background:none;border-color:transparent;font-family:lato,sans-serif;font-weight:200;font-size:1em;color:#e0e5e5;padding:.25em .5em .35em;margin-right:.25em;width:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;cursor:pointer;border-radius:0}.MultipleSelectValue-label.TextField:hover{cursor:text}.MultipleSelectValue-label.TextField:focus{cursor:text;color:#fff;background:none}.MultipleSelectValue-delete{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center;height:19.2px;height:1.2rem;width:19.2px;width:1.2rem;padding:4px;padding:.25rem;color:#cf324f;cursor:pointer;border:1px solid #cf324f;border-radius:50%;border:none;background:none;outline:none;margin-right:.25em}.MultipleSelectValue-delete svg{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.MultipleSelectValue-delete:hover{background:#cf324f;color:#fff}.MultipleSelectValue-error{position:relative;z-index:1;padding:.5em;width:100%;font-family:lato;font-weight:200;display:none;margin-bottom:.5em}.MultipleSelectValue.has-error .MultipleSelectValue-label{border-color:#cf324f!important;border-bottom:none!important;border-bottom-right-radius:0;border-bottom-left-radius:0}.MultipleSelectValue.has-error .MultipleSelectValue-error{display:block}.MultipleSelectValue.has-error .MultipleSelectValue-error:before{content:"";position:absolute;top:0;left:-.25em;right:-.25em;bottom:0;background:#cf324f;z-index:-1}.MultipleSelect-values:empty{display:none}.MultipleSelectValue-handler{cursor:move;cursor:-webkit-grab;cursor:grab;padding:0 .5em;background:#2a2e33;display:none}.MultipleSelectValue.draggable .MultipleSelectValue-handler{display:block;background-image:-webkit-radial-gradient(hsla(0,0%,100%,.5),hsla(0,0%,100%,0) 30%);background-image:radial-gradient(hsla(0,0%,100%,.5),hsla(0,0%,100%,0) 30%);background-size:8px 8px;border-radius:2px}.MultipleSelectValue.draggable .MultipleSelectValue-handler:hover{background-image:-webkit-radial-gradient(#fff,hsla(0,0%,100%,0) 30%);background-image:radial-gradient(#fff,hsla(0,0%,100%,0) 30%)}.MultipleSelectValue.dragged{opacity:.5}.MultipleSelectValue.dragged,.MultipleSelectValue.dragOver{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.MultipleSelectValue.dragOver{border-top:5px solid #2089d3}
\ No newline at end of file
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.html b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.html
new file mode 100644
index 0000000000..ea1ba559b8
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.js b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.js
new file mode 100644
index 0000000000..61518ffd22
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select-value.reel/multiple-select-value.js
@@ -0,0 +1,78 @@
+/**
+ * @module ui/multiple-select-value.reel
+ */
+var AbstractDraggableComponent = require("core/drag-drop/abstract-draggable-component").AbstractDraggableComponent,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer;
+
+/**
+ * @class MultipleSelectValue
+ * @extends Component
+ */
+exports.MultipleSelectValue = AbstractDraggableComponent.specialize(/** @lends MultipleSelectValue# */ {
+ converter: {
+ value: null
+ },
+
+ _inputError: {
+ value: null
+ },
+
+ invalidValue: {
+ value: null
+ },
+
+ isGhostImageCenter: {
+ value: false
+ },
+
+ placeHolderStrategy: {
+ value: AbstractDraggableComponent.PLACE_HOLDER_STRATEGY.remove
+ },
+
+ prepareForActivationEvents: {
+ value: function() {
+ AbstractDraggableComponent.prototype.prepareForActivationEvents.call(this);
+
+ this.valueField.delegate = {
+ shouldAcceptValue: function() {
+ return true;
+ }
+ };
+
+ KeyComposer.createKey(this.valueField, "escape", "undo").addEventListener("keyPress", this);
+ KeyComposer.createKey(this.valueField, "enter", "save").addEventListener("keyPress", this);
+ }
+ },
+
+ handleSaveKeyPress: {
+ value: function() {
+ var value = this.valueField.value,
+ isValid = true;
+ if (this.converter) {
+ if (this.converter.validator && typeof this.converter.validator.validate === 'function') {
+ isValid = this.converter.validator.validate(value);
+ }
+ if (isValid) {
+ this.invalidValue = null;
+ if (typeof this.converter.revert === 'function') {
+ value = this.converter.revert(value);
+ }
+ } else {
+ this.invalidValue = value;
+ }
+ }
+ if (isValid) {
+ this.valueField.element.blur();
+ this.object = value;
+ }
+ }
+ },
+
+ handleUndoKeyPress: {
+ value: function () {
+ this.valueField.element.blur();
+ this.valueField.value = this.object.label;
+ }
+ }
+
+});
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select.css b/blue-shark/ui/multiple-select.reel/multiple-select.css
new file mode 100644
index 0000000000..79b3024499
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select.css
@@ -0,0 +1 @@
+.MultipleSelect{min-width:16em;margin-bottom:2em;border-radius:4px}.MultipleSelect.is-disabled{opacity:.5;cursor:not-allowed}.MultipleSelect-title{font-family:lato;line-height:1.5;font-weight:300;font-weight:400}.MultipleSelect-input .MultipleSelect-title{height:calc(2em - 1px);line-height:1.4}.MultipleSelect-input-controls{margin-bottom:8px;margin-bottom:.5rem}.MultipleSelect-input-controls .Field{margin-bottom:.5em}.MultipleSelect-input-default{position:relative;margin-right:4px;margin-right:.25rem;display:inline-block;width:calc(100% - 5.1rem);vertical-align:middle}.MultipleSelect-input-field{padding-right:0 !Important}.MultipleSelect-input-default.has-value .MultipleSelect-input-field{padding-right:27.2px!important;padding-right:1.7rem!important}.MultipleSelect-input-clearButton.Button{position:absolute;height:20px;height:1.25rem;width:20px;width:1.25rem;top:50%;right:4px;right:.25rem;margin-top:-10px;margin-top:-.625rem;background-color:#384049;color:#9ca0a4;border:none;border-radius:.75rem;visibility:hidden;opacity:0;-webkit-transition-property:visibility,opacity;transition-property:visibility,opacity;-webkit-transition-duration:.2s;transition-duration:.2s}.MultipleSelect-input-clearButton.Button:hover{color:#fff}.MultipleSelect-input-clearButton.Button:active{background-color:#1d252d}.MultipleSelect-input-clearButton.Button svg{-webkit-transform:rotate(45deg);transform:rotate(45deg);padding:2px}.MultipleSelect-input-default.has-value .MultipleSelect-input-clearButton.Button{visibility:visible;opacity:1}.MultipleSelect-input-buttons{-webkit-box-flex:0;-ms-flex:0;flex:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.MultipleSelect-input-default+.MultipleSelect-input-buttons{display:inline-block;vertical-align:middle}.MultipleSelect-input-add{height:32px;height:2rem}.MultipleSelect-input-options{display:none;position:absolute!important;top:2em;left:0;right:0;height:8.2em;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:#2f3233;background-color:#e0e5e5;border:1px solid #2089d3;border-top:none;box-shadow:0 2px 4px rgba(0,0,0,.3);z-index:100;overflow-x:hidden}.MultipleSelect-input-error{position:absolute;bottom:0;width:100%;background:#cf324f;color:#fff;font-weight:300;padding:.5em;-webkit-transform:translateY(100%);transform:translateY(100%);z-index:1;border-bottom-left-radius:4px;border-bottom-right-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,.3);visibility:hidden;opacity:0;-webkit-transition-property:visibility,opacity;transition-property:visibility,opacity;-webkit-transition-duration:.2s;transition-duration:.2s}.MultipleSelect-values{padding:4px;padding:.25rem}.MultipleSelect-valuesContainer{border:1px solid #535a61;border-radius:4px;position:relative;box-sizing:border-box;display:-webkit-box;display:-ms-flexbox;display:flex;color:#fff;height:7.25em;width:100%;-webkit-transition-property:border-color,background-color,opacity;transition-property:border-color,background-color,opacity;-webkit-transition-duration:.25s;transition-duration:.25s}.MultipleSelect.is-disabled .MultipleSelect-valuesContainer{pointer-events:none}.MultipleSelect-values-emptyState{position:absolute;color:#535a61;height:1em;line-height:1em;left:.5em;right:.5em;top:50%;text-align:center;margin-top:-.5em}.MultipleSelect.disabled .MultipleSelect-values-emptyState{display:none}.MultipleSelect-input-field.has-options:focus+.MultipleSelect-input-options.has-content,.MultipleSelect-input-options:active,.MultipleSelect-input.has-error .MultipleSelect-input-error{display:block}.MultipleSelect-input.has-error .MultipleSelect-input-field{border-color:#cf324f;border-bottom-left-radius:0;border-bottom-right-radius:0}.MultipleSelect.disabled .MultipleSelect-valuesContainer{border-color:transparent;opacity:.5;background-color:rgba(0,0,0,.1)}
\ No newline at end of file
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select.html b/blue-shark/ui/multiple-select.reel/multiple-select.html
new file mode 100644
index 0000000000..247fbe1c99
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select.html
@@ -0,0 +1,218 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/multiple-select.reel/multiple-select.js b/blue-shark/ui/multiple-select.reel/multiple-select.js
new file mode 100644
index 0000000000..d6d6c3b420
--- /dev/null
+++ b/blue-shark/ui/multiple-select.reel/multiple-select.js
@@ -0,0 +1,362 @@
+/**
+ * @module ui/multiple-select.reel
+ */
+var AbstractDropZoneComponent = require("core/drag-drop/abstract-dropzone-component").AbstractDropZoneComponent,
+ MultipleSelectValue = require("./multiple-select-value.reel").MultipleSelectValue,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer;
+
+/**
+ * @class MultipleSelect
+ * @extends Component
+ */
+exports.MultipleSelect = AbstractDropZoneComponent.specialize(/** @lends MultipleSelect# */ {
+
+ enabled: {
+ value: true
+ },
+
+ values: {
+ value: null
+ },
+
+ options: {
+ value: null
+ },
+
+ converter: {
+ value: null
+ },
+
+ isDraggable: {
+ value: false
+ },
+
+ __inputError: {
+ value: null
+ },
+
+
+ _inputError: {
+ get: function() {
+ return this.__inputError;
+ },
+ set: function(inputError) {
+ if (!inputError) {
+ this.invalidValue = null;
+ }
+ this.__inputError = inputError;
+ }
+ },
+
+ __selectedOption: {
+ value: null
+ },
+
+ invalidValue: {
+ value: null
+ },
+
+ _selectedOption: {
+ get: function() {
+ return this.__selectedOption;
+ },
+ set: function(option) {
+ if (option && this.__selectedOption != option) {
+ this.__selectedOption = option;
+ this._selectOption(option);
+ }
+ }
+ },
+
+ _addOption: {
+ value: function(value) {
+ if (value) {
+ this._addValueToContent(value, true);
+ this._clearInput();
+ this._stopScrollingOptions();
+ this._blurInputField();
+ }
+ }
+ },
+
+ handleMultipleOptionSelected: {
+ value: function (option) {
+ this._addOption(option.detail);
+ }
+ },
+
+ enterDocument: {
+ value: function (firstTime) {
+ AbstractDropZoneComponent.prototype.enterDocument.call(this, firstTime);
+
+ if (!this.values) {
+ this.values = [];
+ }
+ if (!this.options) {
+ this.options = [];
+ }
+
+ if (isFinite(this.valuesHeight)) {
+ this.valuesContainer.style.height = this.valuesHeight + 'rem';
+ }
+ }
+ },
+
+ prepareForActivationEvents: {
+ value: function() {
+ this._inputField.delegate = {
+ shouldAcceptValue: function() {
+ return true;
+ }
+ };
+ KeyComposer.createKey(this._inputField, "down", "down").addEventListener("keyPress", this);
+ KeyComposer.createKey(this._inputField, "up", "up").addEventListener("keyPress", this);
+ }
+ },
+
+ _shouldAcceptComponent: {
+ value: function (draggableComponent) {
+ return this.element.contains(draggableComponent.element);
+ }
+ },
+
+ handleComponentDragOver: {
+ value: function (draggableComponent, dragEvent) {
+ var pointerPositionX = dragEvent.startPositionX + dragEvent.translateX,
+ pointerPositionY = dragEvent.startPositionY + dragEvent.translateY,
+ multipleSelectValue = this._findMultipleSelectValueComponentFromPoint(pointerPositionX, pointerPositionY);
+
+ if (multipleSelectValue) {
+ if (draggableComponent !== multipleSelectValue && multipleSelectValue !== this._previousOverMultipleSelectValue) {
+ this._clearPreviousOverMultipleSelectValueIfNeeded();
+ this._previousOverMultipleSelectValue = multipleSelectValue;
+ multipleSelectValue.classList.add("dragOver");
+ }
+ } else if (this._previousOverMultipleSelectValue) {
+ this._clearPreviousOverMultipleSelectValueIfNeeded();
+ }
+ }
+ },
+
+ didComponentDrop: {
+ value: function (draggableComponent) {
+ var draggedObject;
+
+ if (this._previousOverMultipleSelectValue) {
+ draggedObject = this.valuesController.content[draggableComponent.index];
+ this.valuesController.splice(this._previousOverMultipleSelectValue.index, 0, draggedObject);
+ this.valuesController.splice(draggableComponent.index, 1);
+ } else {
+ this.valuesController.push(this.valuesController.splice(draggableComponent.index, 1)[0]);
+ }
+ }
+ },
+
+ didComponentDragEnd: {
+ value: function () {
+ this._clearPreviousOverMultipleSelectValueIfNeeded();
+ }
+ },
+
+ handleClearButtonAction: {
+ value: function () {
+ this._clearInput();
+ }
+ },
+
+ _clearPreviousOverMultipleSelectValueIfNeeded: {
+ value: function () {
+ if (this._previousOverMultipleSelectValue) {
+ this._previousOverMultipleSelectValue.classList.remove("dragOver");
+ this._previousOverMultipleSelectValue = null;
+ }
+ }
+ },
+
+ _findMultipleSelectValueComponentFromPoint: {
+ value: function (pointerPositionX, pointerPositionY) {
+ var element = document.elementFromPoint(pointerPositionX, pointerPositionY);
+ return element ? this._findMultipleSelectValueComponentFromElement(element) : null;
+ }
+ },
+
+
+ _findMultipleSelectValueComponentFromElement: {
+ value: function (element) {
+ var component = this._findCloserComponentFromElement(element),
+ multipleSelectValueComponent;
+
+ while (component && !multipleSelectValueComponent && component !== this) {
+ if (component instanceof MultipleSelectValue) {
+ multipleSelectValueComponent = component;
+ } else {
+ component = component.parentComponent;
+ }
+ }
+
+ return multipleSelectValueComponent;
+ }
+ },
+
+ _findCloserComponentFromElement: {
+ value: function _findCloserComponentFromElement (element) {
+ var component;
+
+ while (element && !(component = element.component) && element !== this.element) {
+ element = element.parentNode;
+ }
+
+ return component;
+ }
+ },
+
+ _blurInputField: {
+ value: function () {
+ this._inputField.blur();
+ }
+ },
+
+ handleInputAction: {
+ value: function (event) {
+ if (this._inputField.value) {
+ if (this._addValueToContent(this._inputField.value)) {
+ this._blurInputField();
+ this._clearInput();
+ }
+ } else {
+ this._addOption(this._selectedOption);
+ this._blurInputField();
+ }
+ }
+ },
+
+ handleDownKeyPress: {
+ value: function(event) {
+ switch (event.target.component) {
+ case this._inputField:
+ if (this.options && this.options.length > 0) {
+ this._navigateInOptions(1)
+ }
+ break;
+ }
+ }
+ },
+
+ handleUpKeyPress: {
+ value: function(event) {
+ switch (event.target.component) {
+ case this._inputField:
+ if (this.options && this.options.length > 0) {
+ this._navigateInOptions(-1);
+ }
+ break;
+ }
+ }
+ },
+
+ _selectOption: {
+ value: function (option) {
+ if (!this._typedValue) {
+ this._typedValue = this._inputField.value;
+ }
+ this.optionsController.select(option);
+ this._inputField.value = this.optionsController.selection[0].label;
+ this._selectedOption = option;
+ }
+ },
+
+ _stopScrollingOptions: {
+ value: function () {
+ this.optionsController.clearSelection();
+ this._selectedOption = null;
+ this._inputField.value = this._typedValue;
+ this._typedValue = null;
+ }
+ },
+
+ _navigateInOptions: {
+ value: function(distance) {
+ var currentIndex = this.optionsController.organizedContent.indexOf(this.optionsController.selection[0]),
+ newIndex = currentIndex + distance,
+ contentLength = this.optionsController.organizedContent.length;
+ if (newIndex < -1) {
+ newIndex = contentLength -1;
+ }
+ if (newIndex == -1 || newIndex == contentLength) {
+ this._inputField.value = this._typedValue;
+ this._stopScrollingOptions();
+ } else {
+ this._selectOption(this.optionsController.organizedContent[newIndex % contentLength]);
+ }
+ }
+ },
+
+ _clearInput: {
+ value: function() {
+ this._typedValue = null;
+ this._inputField.value = null;
+ }
+ },
+
+ _addValueToContent: {
+ value: function(value, isFromOptions) {
+ var shouldMultipleSelectAcceptValue = this.callDelegateMethod("shouldMultipleSelectAcceptValue", this, value),
+ isValid = typeof shouldMultipleSelectAcceptValue === "boolean" ? shouldMultipleSelectAcceptValue : true;
+
+ if (isValid && this.converter) {
+ if (!isFromOptions && this.converter.validator && typeof this.converter.validator.validate === 'function') {
+ isValid = this.converter.validator.validate(value);
+ }
+
+ if (isValid && !isFromOptions && typeof this.converter.revert === 'function') {
+ value = this.converter.revert(value);
+ }
+ }
+
+ if (isValid && value !== null && value !== void 0) {
+ this.invalidValue = null;
+
+ if (this.values.indexOf(value) === -1) {
+ this.values.unshift(value);
+ this._inputField.focus();
+ }
+
+ } else {
+ this.invalidValue = value;
+ }
+
+ return isValid;
+ }
+ },
+
+ handleAddButtonAction: {
+ value: function (event) {
+ if (this.controller && typeof this.controller.handleMultipleSelectAddAction === "function") {
+ this.controller.handleMultipleSelectAddAction(this, this._inputField.value);
+ } else if (this._inputField.value) {
+ if (this._addValueToContent(this._inputField.value)) {
+ this._blurInputField();
+ this._clearInput();
+ }
+ }
+ }
+ },
+
+ handleDeleteButtonAction: {
+ value: function (event) {
+ var element = event.target ? event.target.element : null;
+
+ if (element) {
+ var multipleSelectComponent = this._findMultipleSelectValueComponentFromElement(element);
+
+ if (multipleSelectComponent) {
+ if (this.controller && typeof this.controller.handleMultipleSelectDeleteAction === "function") {
+ this.controller.handleMultipleSelectDeleteAction(this, multipleSelectComponent, multipleSelectComponent.object);
+ } else {
+ this.valuesController.delete(multipleSelectComponent.object);
+ }
+ }
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/number-input.info/sample/index.html b/blue-shark/ui/number-input.info/sample/index.html
new file mode 100644
index 0000000000..f7d2884af3
--- /dev/null
+++ b/blue-shark/ui/number-input.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Number Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/number-input.info/sample/package.json b/blue-shark/ui/number-input.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/number-input.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/number-input.info/sample/ui/main.reel/_main.css b/blue-shark/ui/number-input.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/number-input.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/number-input.info/sample/ui/main.reel/main.css b/blue-shark/ui/number-input.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/number-input.info/sample/ui/main.reel/main.html b/blue-shark/ui/number-input.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..612f4d9a87
--- /dev/null
+++ b/blue-shark/ui/number-input.info/sample/ui/main.reel/main.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
Number
+
Default Number Field
+
+
+
+
+
diff --git a/blue-shark/ui/number-input.info/sample/ui/main.reel/main.js b/blue-shark/ui/number-input.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..3fa4e9daf1
--- /dev/null
+++ b/blue-shark/ui/number-input.info/sample/ui/main.reel/main.js
@@ -0,0 +1,36 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ options: {
+ value: [
+ {
+ "value": "none",
+ "label": "None"
+ },
+ {
+ "value": "optimal",
+ "label": "Optimal"
+ },
+ {
+ "value": "virtualization",
+ "label": "Virtualization"
+ },
+ {
+ "value": "backups",
+ "label": "Backups"
+ },
+ {
+ "value": "media",
+ "label": "Media"
+ }
+ ]
+ }
+});
diff --git a/blue-shark/ui/number-input.reel/_number-input.css b/blue-shark/ui/number-input.reel/_number-input.css
new file mode 100644
index 0000000000..9e8a6c9d09
--- /dev/null
+++ b/blue-shark/ui/number-input.reel/_number-input.css
@@ -0,0 +1,59 @@
+.NumberInput { display: flex; max-width: 8em;}
+
+.NumberInput.montage--disabled { pointer-events: none; }
+
+.NumberInput-input.TextField {
+ border-radius: 0;
+ text-align: center;
+ padding-left: 0;
+ padding-right: 0;
+ border-color: transparent;
+}
+
+.NumberInput-control {
+ min-width: 2em;
+ height: 2em;
+ font-size: 1em;
+ line-height: 1.7em;
+ margin: 0;
+ padding: 0;
+ text-align: center;
+ background-color: var(--grey-1);
+ border: none;
+ color: var(--white);
+ border-bottom: 1px solid rgba(0, 0, 0, .4);
+ border-top: 1px solid rgba(255, 255, 255, .05);
+ outline: none;
+ transition: opacity .25s ease-in-out;
+ cursor: pointer;
+
+ &:hover {
+ background-color: rgba(255,255,255,.2);
+ color: var(--white);
+ }
+
+ &:first-child {
+ border-bottom-left-radius: 4px;
+ border-top-left-radius: 4px;
+ }
+
+ &:last-child {
+ border-bottom-right-radius: 4px;
+ border-top-right-radius: 4px;
+ }
+
+ &.montage--disabled {
+ cursor: not-allowed;
+ opacity: .5;
+ color: var(--grey-1);
+
+ &:hover {
+ color: var(--grey-1);
+ background-color: var(--grey-1);
+ }
+ }
+}
+
+.NumberInput.montage--disabled .NumberInput-control {
+ opacity: .3;
+}
diff --git a/blue-shark/ui/number-input.reel/number-input.css b/blue-shark/ui/number-input.reel/number-input.css
new file mode 100644
index 0000000000..5be1cdc52c
--- /dev/null
+++ b/blue-shark/ui/number-input.reel/number-input.css
@@ -0,0 +1 @@
+.NumberInput{display:-webkit-box;display:-ms-flexbox;display:flex;max-width:8em}.NumberInput.montage--disabled{pointer-events:none}.NumberInput-input.TextField{border-radius:0;text-align:center;padding-left:0;padding-right:0;border-color:transparent}.NumberInput-control{min-width:2em;height:2em;font-size:1em;line-height:1.7em;margin:0;padding:0;text-align:center;background-color:#939e9f;border:none;color:#fff;border-bottom:1px solid rgba(0,0,0,.4);border-top:1px solid hsla(0,0%,100%,.05);outline:none;-webkit-transition:opacity .25s ease-in-out;transition:opacity .25s ease-in-out;cursor:pointer}.NumberInput-control:hover{background-color:hsla(0,0%,100%,.2);color:#fff}.NumberInput-control:first-child{border-bottom-left-radius:4px;border-top-left-radius:4px}.NumberInput-control:last-child{border-bottom-right-radius:4px;border-top-right-radius:4px}.NumberInput-control.montage--disabled{cursor:not-allowed;opacity:.5;color:#939e9f}.NumberInput-control.montage--disabled:hover{color:#939e9f;background-color:#939e9f}.NumberInput.montage--disabled .NumberInput-control{opacity:.3}
\ No newline at end of file
diff --git a/blue-shark/ui/number-input.reel/number-input.html b/blue-shark/ui/number-input.reel/number-input.html
new file mode 100644
index 0000000000..f6055463f5
--- /dev/null
+++ b/blue-shark/ui/number-input.reel/number-input.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+ −
+
+ +
+
+
+
diff --git a/blue-shark/ui/number-input.reel/number-input.js b/blue-shark/ui/number-input.reel/number-input.js
new file mode 100644
index 0000000000..6a041b9872
--- /dev/null
+++ b/blue-shark/ui/number-input.reel/number-input.js
@@ -0,0 +1,16 @@
+/**
+ * @module ui/number-input.reel
+ */
+var AbstractNumberField = require("montage/ui/base/abstract-number-field").AbstractNumberField;
+
+/**
+ * @class NumberInput
+ * @extends Component
+ */
+exports.NumberInput = AbstractNumberField.specialize({
+ handleInputAction: {
+ value: function () {
+ this._numberFieldTextFieldComponent.element.blur();
+ }
+ }
+});
diff --git a/blue-shark/ui/number-unit.reel/_number-unit.css b/blue-shark/ui/number-unit.reel/_number-unit.css
new file mode 100644
index 0000000000..c94d66d15d
--- /dev/null
+++ b/blue-shark/ui/number-unit.reel/_number-unit.css
@@ -0,0 +1,16 @@
+.NumberUnit {
+ display: flex;
+ max-width: 11rem;
+}
+
+.NumberUnit .NumberUnit-count { margin-right: .5em; }
+
+.NumberUnit.is-read-only .NumberUnit-count,
+.NumberUnit.is-read-only .NumberUnit-unit {
+ background: transparent;
+ border: none;
+}
+
+.NumberUnit.is-read-only .NumberUnit-unit .Select-icon {
+ display: none;
+}
diff --git a/blue-shark/ui/number-unit.reel/number-unit.css b/blue-shark/ui/number-unit.reel/number-unit.css
new file mode 100644
index 0000000000..9f44e1cb0d
--- /dev/null
+++ b/blue-shark/ui/number-unit.reel/number-unit.css
@@ -0,0 +1 @@
+.NumberUnit{display:-webkit-box;display:-ms-flexbox;display:flex;max-width:176px;max-width:11rem}.NumberUnit .NumberUnit-count{margin-right:.5em}.NumberUnit.is-read-only .NumberUnit-count,.NumberUnit.is-read-only .NumberUnit-unit{background:transparent;border:none}.NumberUnit.is-read-only .NumberUnit-unit .Select-icon{display:none}
\ No newline at end of file
diff --git a/blue-shark/ui/number-unit.reel/number-unit.html b/blue-shark/ui/number-unit.reel/number-unit.html
new file mode 100644
index 0000000000..1f8331b14c
--- /dev/null
+++ b/blue-shark/ui/number-unit.reel/number-unit.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/number-unit.reel/number-unit.js b/blue-shark/ui/number-unit.reel/number-unit.js
new file mode 100644
index 0000000000..b5d4499b1b
--- /dev/null
+++ b/blue-shark/ui/number-unit.reel/number-unit.js
@@ -0,0 +1,72 @@
+var Component = require("montage/ui/component").Component;
+
+exports.NumberUnit = Component.specialize({
+
+ unit: {
+ value: null
+ },
+
+ count: {
+ value: ''
+ },
+
+ _value: {
+ value: null
+ },
+
+ value: {
+ value: null
+ },
+
+ enterDocument: {
+ value: function(isFirstTime) {
+ if (!this.unit && Array.isArray(this.units) && this.units.length > 0) {
+ this.unit = this.units[0].value;
+ }
+ if (isFirstTime) {
+ this.addPathChangeListener("unit", this, "_handleInputChange");
+ this.addPathChangeListener("count", this, "_handleInputChange");
+ this.addPathChangeListener("value", this, "_handleValueChange");
+ }
+ }
+ },
+
+ _handleValueChange: {
+ value: function (value) {
+ if (value != this._value) {
+ this._splitValue();
+ this._value = value;
+ }
+ }
+ },
+
+ _handleInputChange: {
+ value: function () {
+ if (isNaN(this.value) || this.value === this._value) {
+ this._getValue();
+ }
+ }
+ },
+
+ _getValue: {
+ value: function() {
+ this._value = this.unit * this.count;
+ this.value = this._value;
+ }
+ },
+
+ _splitValue: {
+ value: function() {
+ for (var i = 1, length = this.units.length; i < length; i++) {
+ var count = this.value / this.units[i].value;
+ if (count < 1 || Math.round(count) !== count) {
+ break;
+ }
+ }
+
+ this.unit = this.units[i-1].value;
+ var count = this.unit ? this.value / this.unit : null;
+ this.count = isNaN(count) ? '' : count;
+ }
+ }
+});
diff --git a/blue-shark/ui/panel.info/sample/index.html b/blue-shark/ui/panel.info/sample/index.html
new file mode 100644
index 0000000000..5d0baad86a
--- /dev/null
+++ b/blue-shark/ui/panel.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Panel Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/panel.info/sample/package.json b/blue-shark/ui/panel.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/panel.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/panel.info/sample/ui/main.reel/_main.css b/blue-shark/ui/panel.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/panel.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/panel.info/sample/ui/main.reel/main.css b/blue-shark/ui/panel.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/panel.info/sample/ui/main.reel/main.html b/blue-shark/ui/panel.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..700d339261
--- /dev/null
+++ b/blue-shark/ui/panel.info/sample/ui/main.reel/main.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
Panel
+
Default Panel
+
+
Container Panel
+
+ Element injected into component
+
+
+
+
+
diff --git a/blue-shark/ui/panel.info/sample/ui/main.reel/main.js b/blue-shark/ui/panel.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..de3171b166
--- /dev/null
+++ b/blue-shark/ui/panel.info/sample/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/panel.reel/_panel.css b/blue-shark/ui/panel.reel/_panel.css
new file mode 100644
index 0000000000..e2e4d5a41c
--- /dev/null
+++ b/blue-shark/ui/panel.reel/_panel.css
@@ -0,0 +1,18 @@
+.Panel {
+ width: 100%;
+ position: relative;
+ border: 1px solid var(--accent);
+ background-color: color(var(--accent) a(5%));
+ padding: 1em;
+ border-radius: 4px;
+
+ &.is-warning {
+ border-color: var(--orange);
+ background-color: color(var(--orange) a(5%));
+ }
+
+ &.is-error {
+ border-color: var(--red);
+ background-color: color(var(--red) a(5%));
+ }
+}
diff --git a/blue-shark/ui/panel.reel/panel.css b/blue-shark/ui/panel.reel/panel.css
new file mode 100644
index 0000000000..fa74d6d148
--- /dev/null
+++ b/blue-shark/ui/panel.reel/panel.css
@@ -0,0 +1 @@
+.Panel{width:100%;position:relative;border:1px solid #2089d3;background-color:rgba(32,137,211,.05);padding:1em;border-radius:4px}.Panel.is-warning{border-color:#d95b1b;background-color:rgba(217,91,27,.05)}.Panel.is-error{border-color:#cf324f;background-color:rgba(207,50,79,.05)}
\ No newline at end of file
diff --git a/blue-shark/ui/panel.reel/panel.html b/blue-shark/ui/panel.reel/panel.html
new file mode 100644
index 0000000000..6a6e672811
--- /dev/null
+++ b/blue-shark/ui/panel.reel/panel.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/panel.reel/panel.js b/blue-shark/ui/panel.reel/panel.js
new file mode 100644
index 0000000000..996fb43183
--- /dev/null
+++ b/blue-shark/ui/panel.reel/panel.js
@@ -0,0 +1,41 @@
+/**
+ * @module ui/panel.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Panel
+ * @extends Component
+ */
+exports.Panel = Component.specialize(/** @lends Panel# */ {
+ _status: {
+ value: null
+ },
+
+ status: {
+ get: function() {
+ return this._status;
+ },
+ set: function(value) {
+ if (value != this._status) {
+ switch(value) {
+ case 'warn':
+ this.classList.add('is-warning');
+ this.classList.remove('is-error');
+ this._status = value;
+ break;
+ case 'error':
+ this.classList.add('is-error');
+ this.classList.remove('is-warning');
+ this._status = value;
+ break;
+ case 'default':
+ this.classList.remove('is-error');
+ this.classList.remove('is-warning');
+ this._status = value;
+ break;
+ }
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/password.info/sample/index.html b/blue-shark/ui/password.info/sample/index.html
new file mode 100644
index 0000000000..8b7ae2be98
--- /dev/null
+++ b/blue-shark/ui/password.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Password Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/password.info/sample/package.json b/blue-shark/ui/password.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/password.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/password.info/sample/ui/main.reel/_main.css b/blue-shark/ui/password.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/password.info/sample/ui/main.reel/main.css b/blue-shark/ui/password.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/password.info/sample/ui/main.reel/main.html b/blue-shark/ui/password.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..7df52a9db0
--- /dev/null
+++ b/blue-shark/ui/password.info/sample/ui/main.reel/main.html
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
Password
+
Default Password
+
+
+
+
+
diff --git a/blue-shark/ui/password.info/sample/ui/main.reel/main.js b/blue-shark/ui/password.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..8182d0dd9e
--- /dev/null
+++ b/blue-shark/ui/password.info/sample/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {});
diff --git a/blue-shark/ui/password.reel/_password.css b/blue-shark/ui/password.reel/_password.css
new file mode 100644
index 0000000000..9b14a2729f
--- /dev/null
+++ b/blue-shark/ui/password.reel/_password.css
@@ -0,0 +1,3 @@
+.Password {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/password.reel/password.css b/blue-shark/ui/password.reel/password.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/password.reel/password.html b/blue-shark/ui/password.reel/password.html
new file mode 100644
index 0000000000..59e80211ea
--- /dev/null
+++ b/blue-shark/ui/password.reel/password.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/password.reel/password.js b/blue-shark/ui/password.reel/password.js
new file mode 100644
index 0000000000..6e14500829
--- /dev/null
+++ b/blue-shark/ui/password.reel/password.js
@@ -0,0 +1,45 @@
+/**
+ * @module ui/password.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Password
+ * @extends Component
+ */
+exports.Password = Component.specialize({
+
+ //FIXME: workaround
+ enabled: {
+ value: true
+ },
+
+ __password: {
+ value: null
+ },
+
+ _password: {
+ get: function() {
+ return this.__password;
+ },
+ set: function(strPassword) {
+ if (this.__password !== strPassword) {
+ this.__password = strPassword;
+ this.dispatchOwnPropertyChange('password', this.password);
+ }
+ }
+ },
+
+ password: {
+ get: function() {
+ return this._password ? { $password: this._password } : null;
+ },
+ set: function(password) {
+ if (typeof password === 'object') password = password ? password['$password'] : null;
+ if (this.__password !== password) {
+ this.__password = password;
+ this.dispatchOwnPropertyChange('_password', this._password);
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/progress.info/sample/index.html b/blue-shark/ui/progress.info/sample/index.html
new file mode 100644
index 0000000000..d61e04cede
--- /dev/null
+++ b/blue-shark/ui/progress.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Multiple Select Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/progress.info/sample/package.json b/blue-shark/ui/progress.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/progress.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/progress.info/sample/ui/main.reel/_main.css b/blue-shark/ui/progress.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/progress.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/progress.info/sample/ui/main.reel/main.css b/blue-shark/ui/progress.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/progress.info/sample/ui/main.reel/main.html b/blue-shark/ui/progress.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..9ae65d74a0
--- /dev/null
+++ b/blue-shark/ui/progress.info/sample/ui/main.reel/main.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/progress.info/sample/ui/main.reel/main.js b/blue-shark/ui/progress.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..90669567fd
--- /dev/null
+++ b/blue-shark/ui/progress.info/sample/ui/main.reel/main.js
@@ -0,0 +1,32 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ fakeConverter: {
+ value: {
+ revert: function(value) {
+ console.log('revert');
+ var result = {
+ name: value.toUpperCase()
+ };
+ return result;
+ },
+ validator: {
+ validate: function(value) {
+ var isValid = true;
+ if (typeof value === 'string') {
+ isValid = value.indexOf("INVALID") == -1;
+ }
+ return isValid;
+ }
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/progress.reel/_progress.css b/blue-shark/ui/progress.reel/_progress.css
new file mode 100644
index 0000000000..6a8eb4ea22
--- /dev/null
+++ b/blue-shark/ui/progress.reel/_progress.css
@@ -0,0 +1,65 @@
+.Progress {
+ display: flex;
+ align-items: center;
+ overflow: hidden;
+ position: relative;
+
+ & svg {
+ right: 0;
+ width: 1.4em;
+ height: 1.4em;
+ }
+}
+
+.Progress-wrapper {
+ flex: 1;
+ height: .5em;
+ position: relative;
+ background-color: var(--grey-3);
+}
+
+.Progress-bar {
+ position: absolute;
+ top: 0;
+ left: -1px;
+ right: -1px;
+ bottom: 0;
+ background-color: var(--accent);
+ transition: transform .25s ease-in-out;
+
+ @nest .Progress.has-success & {
+ background-color: var(--green);
+ }
+
+ @nest .Progress.has-error & {
+ background-color: var(--red);
+ }
+}
+
+.Progress-statusIcon {
+ margin-left: .5rem;
+ display: flex;
+
+ @nest .Progress.has-error & {
+ color: var(--red);
+ }
+}
+
+.Progress-active .Spinner svg {
+ width: 1.1rem;
+ height: 1.1rem;
+}
+
+#pending-l,
+#pending-c,
+#pending-r {
+ animation: pulse .5s linear infinite alternate;
+}
+
+#pending-c { animation-delay: .1s; }
+
+#pending-r { animation-delay: .2s; }
+
+.Progress-success {
+ color: var(--green);
+}
diff --git a/blue-shark/ui/progress.reel/progress.css b/blue-shark/ui/progress.reel/progress.css
new file mode 100644
index 0000000000..bf6412b18c
--- /dev/null
+++ b/blue-shark/ui/progress.reel/progress.css
@@ -0,0 +1 @@
+.Progress{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;overflow:hidden;position:relative}.Progress svg{right:0;width:1.4em;height:1.4em}.Progress-wrapper{-webkit-box-flex:1;-ms-flex:1;flex:1;height:.5em;position:relative;background-color:#e0e5e5}.Progress-bar{position:absolute;top:0;left:-1px;right:-1px;bottom:0;background-color:#2089d3;-webkit-transition:-webkit-transform .25s ease-in-out;transition:-webkit-transform .25s ease-in-out;transition:transform .25s ease-in-out;transition:transform .25s ease-in-out,-webkit-transform .25s ease-in-out}.Progress.has-success .Progress-bar{background-color:#1e963f}.Progress.has-error .Progress-bar{background-color:#cf324f}.Progress-statusIcon{margin-left:8px;margin-left:.5rem;display:-webkit-box;display:-ms-flexbox;display:flex}.Progress.has-error .Progress-statusIcon{color:#cf324f}.Progress-active .Spinner svg{width:17.6px;width:1.1rem;height:17.6px;height:1.1rem}#pending-c,#pending-l,#pending-r{-webkit-animation:pulse .5s linear infinite alternate;animation:pulse .5s linear infinite alternate}#pending-c{-webkit-animation-delay:.1s;animation-delay:.1s}#pending-r{-webkit-animation-delay:.2s;animation-delay:.2s}.Progress-success{color:#1e963f}
\ No newline at end of file
diff --git a/blue-shark/ui/progress.reel/progress.html b/blue-shark/ui/progress.reel/progress.html
new file mode 100644
index 0000000000..c09b559462
--- /dev/null
+++ b/blue-shark/ui/progress.reel/progress.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ menu
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/progress.reel/progress.js b/blue-shark/ui/progress.reel/progress.js
new file mode 100644
index 0000000000..490f4f81dd
--- /dev/null
+++ b/blue-shark/ui/progress.reel/progress.js
@@ -0,0 +1,94 @@
+/**
+ * @module ui/progress.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Progress
+ * @extends Component
+ */
+exports.Progress = Component.specialize(/** @lends Progress# */ {
+
+ _percentageComplete: {
+ value: null
+ },
+
+ statusClassMap: {
+ value: {
+ "success": "has-success",
+ "error": "has-error",
+ "active": "is-active",
+ "pending": "is-pending"
+ }
+ },
+
+ _status: {
+ value: null
+ },
+
+ status: {
+ get: function () {
+ return this._status;
+ },
+ set: function (value) {
+ if (value != this._status) {
+ this._status = value;
+ this._oldStatusClasses.push(this._statusClass);
+
+ this._statusClass = this.statusClassMap[value];
+
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ percentageComplete: {
+ set: function (value) {
+ this._percentageComplete = value;
+ this.needsDraw = true;
+ },
+ get: function () {
+ return this._percentageComplete;
+ }
+ },
+
+ constructor: {
+ value: function () {
+ this._oldStatusClasses = [];
+ }
+ },
+
+ draw: {
+ value: function () {
+ this.bar.style.transform = "translateX(" + (this._percentageComplete - 100) + "%)";
+
+ this._cleanupClasses();
+
+ if (this._statusClass) {
+ this.classList.add(this._statusClass);
+ }
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ this._cleanupClasses(true);
+ }
+ },
+
+ _cleanupClasses: {
+ value: function (removeCurrent) {
+ var oldClass;
+
+ if (this._oldStatusClasses && this._oldStatusClasses.length > 0) {
+ while (oldClass = this._oldStatusClasses.pop()) {
+ this.classList.remove(oldClass);
+ }
+ }
+
+ if (removeCurrent && this._statusClass) {
+ this.classList.remove(this._statusClass);
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/radio-button-field-group.info/sample/index.html b/blue-shark/ui/radio-button-field-group.info/sample/index.html
new file mode 100644
index 0000000000..cfc8088803
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Radio Button Field Group Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/radio-button-field-group.info/sample/package.json b/blue-shark/ui/radio-button-field-group.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/_main.css b/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.css b/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.html b/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..bd90c27c99
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.html
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
Radio Button Field Group
+
Default
+
+
Disabled
+
+
Block
+
+
+
+
+
diff --git a/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.js b/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..f4400783eb
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.info/sample/ui/main.reel/main.js
@@ -0,0 +1,7 @@
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/radio-button-field-group.reel/_radio-button-field-group.css b/blue-shark/ui/radio-button-field-group.reel/_radio-button-field-group.css
new file mode 100644
index 0000000000..6fbe6ccb2b
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/_radio-button-field-group.css
@@ -0,0 +1,11 @@
+.RadioButtonFieldGroup.RadioButtonFieldGroup--block {
+ margin-top: 0;
+
+ & .RadioButtonFieldGroup-option {
+ display: block;
+ }
+}
+
+.RadioButtonFieldGroup-option:not(:last-child) {
+ margin-right: 1rem;
+}
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.css b/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.css
new file mode 100644
index 0000000000..e40941ca85
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.css
@@ -0,0 +1 @@
+.RadioButtonFieldGroup.RadioButtonFieldGroup--block{margin-top:0}.RadioButtonFieldGroup.RadioButtonFieldGroup--block .RadioButtonFieldGroup-option{display:block}.RadioButtonFieldGroup-option:not(:last-child){margin-right:16px;margin-right:1rem}
\ No newline at end of file
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.html b/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.html
new file mode 100644
index 0000000000..9f8c4ac5f9
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.js b/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.js
new file mode 100644
index 0000000000..9d82a488b8
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field-group.js
@@ -0,0 +1,14 @@
+/**
+ * @module ui/radio-button-field-group.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class RadioButtonFieldGroup
+ * @extends Component
+ */
+exports.RadioButtonFieldGroup = Component.specialize(/** @lends RadioButtonFieldGroup# */ {
+ enabled: {
+ value: true
+ }
+});
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/_radio-button-field.css b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/_radio-button-field.css
new file mode 100644
index 0000000000..bf2cc54560
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/_radio-button-field.css
@@ -0,0 +1,31 @@
+.RadioButtonField {
+ display: inline-block;
+ cursor: pointer;
+ padding: .25rem 0;
+
+ &.montage--disabled {
+ cursor: not-allowed;
+ opacity: .5;
+ }
+
+ &:hover {
+ & .RadioButtonField-control {
+ border-color: var(--primary--1);
+ background-color: var(--input-bg-color);
+ }
+ }
+
+ & label { cursor: pointer; }
+
+ &.montage--disabled label { cursor: not-allowed; }
+}
+
+/* Control */
+
+.RadioButtonField-control { margin-right: .25em; }
+
+/* Block Modifier */
+
+.FieldRadioGroup--block .RadioButtonField {
+ display: block;
+}
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.css b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.css
new file mode 100644
index 0000000000..a832cfde9b
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.css
@@ -0,0 +1 @@
+.RadioButtonField{display:inline-block;cursor:pointer;padding:4px 0;padding:.25rem 0}.RadioButtonField.montage--disabled{cursor:not-allowed;opacity:.5}.RadioButtonField:hover .RadioButtonField-control{border-color:#9ca0a4;background-color:#222b35}.RadioButtonField label{cursor:pointer}.RadioButtonField.montage--disabled label{cursor:not-allowed}.RadioButtonField-control{margin-right:.25em}.FieldRadioGroup--block .RadioButtonField{display:block}
\ No newline at end of file
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.html b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.html
new file mode 100644
index 0000000000..11189236fa
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.html
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.js b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.js
new file mode 100644
index 0000000000..f2bedfcd45
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button-field.js
@@ -0,0 +1,30 @@
+var Component = require("montage/ui/component").Component,
+ PressComposer = require("montage/composer/press-composer").PressComposer;
+
+/**
+ * @class RadioButtonField
+ * @extends Component
+ */
+exports.RadioButtonField = Component.specialize({
+ constructor: {
+ value: function RadioButtonField () {
+ this._pressComposer = new PressComposer();
+ this.addComposerForElement(this._pressComposer, this.labelElement);
+ this._pressComposer.addEventListener("press", this, false);
+ }
+ },
+
+ _pressComposer: {
+ value: null
+ },
+
+ handlePress: {
+ value: function() {
+ var radioButton = this.templateObjects.radioButton;
+
+ if (!radioButton.checked) {
+ radioButton.checked = true;
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/_radio-button.css b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/_radio-button.css
new file mode 100644
index 0000000000..641160a984
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/_radio-button.css
@@ -0,0 +1,35 @@
+:root {
+ --radio-size: 1.5rem;
+}
+
+.RadioButton {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ width: var(--radio-size);
+ height: var(--radio-size);
+ border-radius: 1rem;
+ -webkit-tap-highlight-color: transparent;
+ border: 1px solid var(--primary--2);
+ transition-property: opacity, border-color;
+ transition-duration: .25s;
+
+ /* States */
+
+ &.montage--active:not(.montage--disabled):before,
+ &.montage-RadioButton--checked:not(.montage--disabled):before {
+ content: '';
+ position: absolute;
+ height: calc(var(--radio-size) / 2);
+ width: calc(var(--radio-size) / 2);
+ top: 50%;
+ left: 50%;
+ margin-top: -calc(var(--radio-size) / 4);
+ margin-left: -calc(var(--radio-size) / 4);
+ border-radius: 50%;
+ background-color: var(--accent);
+ transition: background-color.25s;
+ }
+}
+
+
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.css b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.css
new file mode 100644
index 0000000000..7849a3bdd0
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.css
@@ -0,0 +1 @@
+.RadioButton{position:relative;display:inline-block;vertical-align:middle;width:24px;width:1.5rem;height:24px;height:1.5rem;border-radius:1rem;-webkit-tap-highlight-color:transparent;border:1px solid #6f757c;-webkit-transition-property:opacity,border-color;transition-property:opacity,border-color;-webkit-transition-duration:.25s;transition-duration:.25s}.RadioButton.montage--active:not(.montage--disabled):before,.RadioButton.montage-RadioButton--checked:not(.montage--disabled):before{content:"";position:absolute;height:12px;height:.75rem;width:12px;width:.75rem;top:50%;left:50%;margin-top:-6px;margin-top:-.375rem;margin-left:-6px;margin-left:-.375rem;border-radius:50%;background-color:#2089d3;-webkit-transition:background-color.25s;transition:background-color.25s}
\ No newline at end of file
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.html b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.html
new file mode 100644
index 0000000000..42079c3d6d
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.js b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.js
new file mode 100644
index 0000000000..0219820e29
--- /dev/null
+++ b/blue-shark/ui/radio-button-field-group.reel/radio-button-field.reel/radio-button.reel/radio-button.js
@@ -0,0 +1,8 @@
+var AbstractRadioButton = require("montage/ui/base/abstract-radio-button").AbstractRadioButton;
+
+CLASS_PREFIX = "RadioButton";
+/**
+ * @class RadioButton
+ * @extends Component
+ */
+exports.RadioButton = AbstractRadioButton.specialize();
diff --git a/blue-shark/ui/scrollable-list.info/sample/index.html b/blue-shark/ui/scrollable-list.info/sample/index.html
new file mode 100644
index 0000000000..cc0d5b97b4
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Scrollable List
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/scrollable-list.info/sample/package.json b/blue-shark/ui/scrollable-list.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/_main.css b/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.css b/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.html b/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..c1ddfc2113
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.html
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
Scrollable List
+
Default
+
+
+
+
+
diff --git a/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.js b/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..f4400783eb
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.info/sample/ui/main.reel/main.js
@@ -0,0 +1,7 @@
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/scrollable-list.reel/_scrollable-list.css b/blue-shark/ui/scrollable-list.reel/_scrollable-list.css
new file mode 100644
index 0000000000..c438793b87
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.reel/_scrollable-list.css
@@ -0,0 +1,21 @@
+.ScrollableList {
+ display: flex;
+ flex-direction: column;
+ height: 10em;
+ border: 1px solid var(--black);
+ background: var(--grey-blue);
+ border-radius: 4px;
+}
+
+.ScrollableList-items {
+ margin: .25em .5em;
+ margin-bottom: .5em;
+ list-style: none;
+ padding: 0;
+}
+
+.ScrollableList-item {
+ font-weight: 300;
+ margin-bottom: .25em;
+ color: var(--white);
+}
diff --git a/blue-shark/ui/scrollable-list.reel/scrollable-list.css b/blue-shark/ui/scrollable-list.reel/scrollable-list.css
new file mode 100644
index 0000000000..e27389801d
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.reel/scrollable-list.css
@@ -0,0 +1 @@
+.ScrollableList{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:10em;border:1px solid #0f1213;background:#242628;border-radius:4px}.ScrollableList-items{margin:.25em .5em;margin-bottom:.5em;list-style:none;padding:0}.ScrollableList-item{font-weight:300;margin-bottom:.25em;color:#fff}
\ No newline at end of file
diff --git a/blue-shark/ui/scrollable-list.reel/scrollable-list.html b/blue-shark/ui/scrollable-list.reel/scrollable-list.html
new file mode 100644
index 0000000000..e0d1ddbced
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.reel/scrollable-list.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/scrollable-list.reel/scrollable-list.js b/blue-shark/ui/scrollable-list.reel/scrollable-list.js
new file mode 100644
index 0000000000..82d9022aff
--- /dev/null
+++ b/blue-shark/ui/scrollable-list.reel/scrollable-list.js
@@ -0,0 +1,26 @@
+/**
+ * @module ui/scrollable-list.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class ScrollableList
+ * @extends Component
+ */
+exports.ScrollableList = Component.specialize(/** @lends ScrollableList# */ {
+
+ _height: {
+ value: null
+ },
+
+ height: {
+ get: function () {
+ return this.height;
+ },
+ set: function (height) {
+ if (this._height != height) {
+ this.element.style.height = height + "em";
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/scrollbar.reel/_scrollbar.css b/blue-shark/ui/scrollbar.reel/_scrollbar.css
new file mode 100755
index 0000000000..7b765a4943
--- /dev/null
+++ b/blue-shark/ui/scrollbar.reel/_scrollbar.css
@@ -0,0 +1,43 @@
+.Scrollbar {
+ border-radius: 9999px;
+ z-index: 2;
+}
+
+.ScrollbarHandle {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ transition: opacity 300ms, width 200ms, height 200ms;
+}
+
+.Scrollbar.isAnimating .ScrollbarHandle {
+ transition: width 200ms, height 200ms, transform 200ms;
+}
+
+/* animating size and position changes */
+
+.Scrollbar.isAnimating .ScrollbarHandle:before,
+.is-scrolling .ScrollbarHandle:before {
+ opacity: 1;
+ transition: opacity .2s;
+}
+
+.ScrollbarHandle:before {
+ content: "";
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ border-radius: 9999px;
+ background-color: var(--grey-2);
+ border: 1px solid color(var(--grey) shade(25%));
+ opacity: 0;
+ transition: opacity .5s 1s;
+}
+
+.ScrollbarHandle:active:before {
+ background-color: var(--grey-2);
+}
diff --git a/blue-shark/ui/scrollbar.reel/scrollbar.css b/blue-shark/ui/scrollbar.reel/scrollbar.css
new file mode 100755
index 0000000000..70e26e4771
--- /dev/null
+++ b/blue-shark/ui/scrollbar.reel/scrollbar.css
@@ -0,0 +1 @@
+.Scrollbar{border-radius:9999px;z-index:2}.ScrollbarHandle{position:absolute;top:0;left:0;right:0;bottom:0;-webkit-transition:opacity .3s,width .2s,height .2s;transition:opacity .3s,width .2s,height .2s}.Scrollbar.isAnimating .ScrollbarHandle{-webkit-transition:width .2s,height .2s,-webkit-transform .2s;transition:width .2s,height .2s,-webkit-transform .2s;transition:width .2s,height .2s,transform .2s;transition:width .2s,height .2s,transform .2s,-webkit-transform .2s}.is-scrolling .ScrollbarHandle:before,.Scrollbar.isAnimating .ScrollbarHandle:before{opacity:1;-webkit-transition:opacity .2s;transition:opacity .2s}.ScrollbarHandle:before{content:"";position:absolute;top:0;left:0;right:0;bottom:0;border-radius:9999px;border:1px solid #232626;opacity:0;-webkit-transition:opacity .5s 1s;transition:opacity .5s 1s}.ScrollbarHandle:active:before,.ScrollbarHandle:before{background-color:#b1bcbe}
\ No newline at end of file
diff --git a/blue-shark/ui/scrollbar.reel/scrollbar.html b/blue-shark/ui/scrollbar.reel/scrollbar.html
new file mode 100755
index 0000000000..1aa1e83dc3
--- /dev/null
+++ b/blue-shark/ui/scrollbar.reel/scrollbar.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/scrollbar.reel/scrollbar.js b/blue-shark/ui/scrollbar.reel/scrollbar.js
new file mode 100755
index 0000000000..14c1cd13d4
--- /dev/null
+++ b/blue-shark/ui/scrollbar.reel/scrollbar.js
@@ -0,0 +1,461 @@
+var Component = require("montage/ui/component").Component,
+ TranslateComposer = require("montage/composer/translate-composer").TranslateComposer;
+
+exports.Scrollbar = Component.specialize({
+
+ _type: {
+ value: "vertical"
+ },
+
+ type: {
+ get: function () {
+ return this._type;
+ },
+ set: function (value) {
+ value = value === "horizontal" ? "horizontal" : "vertical";
+
+ if (this._type !== value) {
+ this._translateComposer.axis = this._type = value;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _animationTimeout: {
+ value: null
+ },
+
+ _length: {
+ value: 1
+ },
+
+ length: {
+ get: function () {
+ return this._length;
+ },
+ set: function (value) {
+ if (this._length !== value) {
+ this._length = value;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _drag: {
+ value: 0
+ },
+
+ drag: {
+ get: function () {
+ return this._drag;
+ },
+ set: function (value) {
+ if (this._type === "horizontal") {
+ this._drag = this.dragX = value;
+
+ } else if (this._type === "vertical") {
+ this._drag = this.dragY = value;
+ }
+ }
+ },
+
+ _dragX: {
+ value: 0
+ },
+
+ dragX: {
+ get: function () {
+ return this._dragX;
+ },
+ set: function (value) {
+ if (this.isRounding) {
+ value = Math.round(value);
+ }
+
+ if (this._dragX !== value) {
+ if (value < this.minDragX) {
+ value = this.minDragX;
+ } else if (value > this.maxDragX) {
+ value = this.maxDragX;
+ }
+
+ this._dragX = value;
+
+ if (this._isOwnUpdate) {//changes that has occurred by its own translateComposer
+ //need to dispatch changes for the scrollView
+ this.drag = this._dragX;
+ this._isOwnUpdate = false;
+ } else {
+ this._translateComposer.translateX = this._dragX / this.dragYMultiplier;
+ }
+
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _dragY: {
+ value: 0
+ },
+
+ dragY: {
+ get: function () {
+ return this._dragY;
+ },
+ set: function (value) {
+ if (this.isRounding) {
+ value = Math.round(value);
+ }
+
+ if (this._dragY !== value) {
+ if (value < this.minDragY) {
+ value = this.minDragY;
+ } else if (value > this.maxDragY) {
+ value = this.maxDragY;
+ }
+
+ this._dragY = value;
+
+ if (this._isOwnUpdate) {//changes that has occurred by its own translateComposer
+ //need to dispatch changes for the scrollView
+ this.drag = this._dragY;
+ this._isOwnUpdate = false;
+ } else {
+ this._translateComposer.translateY = this._dragY / this.dragYMultiplier;
+ }
+
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ dragYMultiplier: {
+ value: 1
+ },
+
+ dragXMultiplier: {
+ value: 1
+ },
+
+ _minDragX: {
+ value: 0
+ },
+
+ minDragX: {
+ get: function () {
+ return this._minDragX;
+ },
+ set: function (value) {
+ if (this._minDragX !== value) {
+ this._minDragX = value;
+ this._translateComposer.minTranslateX = this._minDragX/this.dragXMultiplier;
+ }
+ }
+ },
+
+ _maxDragX: {
+ value: 0
+ },
+
+ maxDragX: {
+ get: function () {
+ return this._maxDragX;
+ },
+ set: function (value) {
+ if (this._maxDragX !== value) {
+ this._maxDragX = value;
+ this._translateComposer.maxTranslateX = this._maxDragX/this.dragXMultiplier;
+ }
+ }
+ },
+
+ _minDragY: {
+ value: 0
+ },
+
+ minDragY: {
+ get: function () {
+ return this._minDragY;
+ },
+ set: function (value) {
+ this._minDragY = value;
+ this._translateComposer.minTranslateY = this._minDragY/this.dragYMultiplier;
+ }
+ },
+
+ _maxDragY: {
+ value: 0
+ },
+
+ maxDragY: {
+ get: function () {
+ return this._maxDragY;
+ },
+ set: function (value) {
+ this._maxDragY = value;
+ this._translateComposer.maxTranslateY = this._maxDragY/this.dragYMultiplier;
+ }
+ },
+
+ isRounding: {
+ value: true
+ },
+
+ __translateComposer: {
+ value: null
+ },
+
+
+ _translateComposer: {
+ get: function () {
+ if (!this.__translateComposer) {
+ this.__translateComposer = new TranslateComposer();
+ this.__translateComposer.hasMomentum = false;
+ this.__translateComposer.axis = this.type;
+ this.__translateComposer.minTranslateX = this._minDragX;
+ this.__translateComposer.minTranslateY = this._minDragY;
+ }
+
+ return this.__translateComposer;
+ }
+ },
+
+
+ _handleLength: {
+ value: 1
+ },
+
+ handleLength: {
+ get: function () {
+ return this._handleLength;
+ },
+ set: function (value) {
+ var self = this;
+
+ if (this._handleLength !== value) {
+ this._handleLength = value;
+ this.classList.add("isAnimating");
+
+ if (this._animationTimeout) {
+ clearTimeout(this._animationTimeout);
+ }
+
+ this._animationTimeout = setTimeout(function () {
+ self.classList.remove("isAnimating");
+ }, 330);
+ }
+ }
+ },
+
+ handleResize: {
+ value: function () {
+ this.needsDraw = true;
+ }
+ },
+
+ minHandlePixelSize: {
+ value: 16
+ },
+
+ enterDocument: {
+ value: function (isFirstTime) {
+ if (isFirstTime && !this.constructor.transform) {
+ if("webkitTransform" in this.element.style) {
+ this.constructor.transform = "webkitTransform";
+ } else if("MozTransform" in this.element.style) {
+ this.constructor.transform = "MozTransform";
+ } else if("msTransform" in this.element.style) {
+ this.constructor.transform = "msTransform";
+ } else if("OTransform" in this.element.style) {
+ this.constructor.transform = "OTransform";
+ } else {
+ this.constructor.transform = "transform";
+ }
+ }
+
+ window.addEventListener("resize", this, false);
+ this._addEventListenerIfNeeded();
+ }
+ },
+
+ prepareForActivationEvents: {
+ value: function () {
+ this.addComposerForElement(this._translateComposer, this._handleElement);
+ this._addEventListener();
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ window.removeEventListener("resize", this, false);
+ this._removeEventListenerIfNeeded();
+ }
+ },
+
+ _enterScrollbar: {
+ value: function () {
+ this.classList.add("isAnimating");
+ }
+ },
+
+ _leaveScrollbar: {
+ value: function (event) {
+ if (event.target === this.element && !this._isDragging) {
+ this.classList.remove("isAnimating");
+ }
+ }
+ },
+
+ handleMouseenter: {
+ value: function () {
+ this._enterScrollbar();
+ }
+ },
+
+ handlePointerenter: {
+ value: function () {
+ this.classList.add("isAnimating");
+ }
+ },
+
+ handlePointerleave: {
+ value: function (event) {
+ this._leaveScrollbar(event);
+ }
+ },
+
+ handleMouseleave: {
+ value: function (event) {
+ this._leaveScrollbar(event);
+ }
+ },
+
+ handleTranslateStart: {
+ value: function () {
+ this._isDragging = true;
+ this.classList.add("isAnimating");
+ }
+ },
+
+ handleTranslate: {
+ value: function (event) {
+ this._isOwnUpdate = true;
+
+ if (this.type === "horizontal") {
+ this.dragX = event.translateX * this.dragXMultiplier;
+ } else if (this.type === "vertical") {
+ this.dragY = event.translateY * this.dragYMultiplier;
+ }
+ }
+ },
+
+ handleTranslateEnd: {
+ value: function () {
+ this._isDragging = false;
+ this.classList.remove("isAnimating");
+ }
+ },
+
+ _addEventListenerIfNeeded: {
+ value: function () {
+ if (this.preparedForActivationEvents) {
+ this._addEventListener();
+ }
+ }
+ },
+
+ _addEventListener: {
+ value: function () {
+ this._translateComposer.addEventListener("translateStart", this, false);
+ this._translateComposer.addEventListener("translate", this, false);
+ this._translateComposer.addEventListener("translateEnd", this, false);
+
+ if (window.PointerEvent) {
+ this._element.addEventListener("pointerenter", this, false);
+ this._element.addEventListener("pointerleave", this, false);
+
+ } else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ this._element.addEventListener("MSPointerEnter", this, false);
+ this._element.addEventListener("MSPointerLeave", this, false);
+
+ } else {
+ this._element.addEventListener("mouseenter", this, false);
+ this._element.addEventListener("mouseleave", this, false);
+ }
+ }
+ },
+
+ _removeEventListenerIfNeeded: {
+ value: function () {
+ if (this.preparedForActivationEvents) {
+ this._translateComposer.removeEventListener("translateStart", this, false);
+ this._translateComposer.removeEventListener("translate", this, false);
+ this._translateComposer.removeEventListener("translateEnd", this, false);
+
+ if (window.PointerEvent) {
+ this._element.removeEventListener("pointerenter", this, false);
+ this._element.removeEventListener("pointerleave", this, false);
+
+ } else if (window.MSPointerEvent && window.navigator.msPointerEnabled) {
+ this._element.removeEventListener("MSPointerEnter", this, false);
+ this._element.removeEventListener("MSPointerLeave", this, false);
+
+ } else {
+ this._element.removeEventListener("mouseenter", this, false);
+ this._element.removeEventListener("mouseleave", this, false);
+ }
+ }
+ }
+ },
+
+
+ willDraw: {
+ value: function () {
+ this._width = this._element.offsetWidth;
+ this._height = this._element.offsetHeight;
+
+ if (this.type === "horizontal") {
+ this.maxDragX = this._length - this._handleLength;
+ this.dragXMultiplier = this._length / (this._width - this.minHandlePixelSize);
+ } else {
+ this.maxDragY = this._length - this._handleLength;
+ this.dragYMultiplier = this._length / (this._height - this.minHandlePixelSize);
+ }
+ }
+ },
+
+ draw: {
+ value: function () {
+ if (this._length <= this._handleLength) {
+ this._handleElement.style.opacity = 0;
+
+ } else {
+ this._handleElement.style.opacity = 1;
+
+ if (this._type === "horizontal") {
+ var handlePixelWidth = this.minHandlePixelSize +
+ Math.floor((this._width - this.minHandlePixelSize) * this._handleLength / this._length);
+
+ if (handlePixelWidth > this._width) {
+ handlePixelWidth = this._width;
+ }
+
+ this._handleElement.style.width = handlePixelWidth + "px";
+ this._handleElement.style[this.constructor.transform] = "translate3d(" + (this._dragX/this.dragXMultiplier) + "px,0,0)";
+
+ } else {
+ var handlePixelHeight = this.minHandlePixelSize +
+ Math.floor((this._height - this.minHandlePixelSize) * this._handleLength / this._length);
+
+ if (handlePixelHeight > this._height) {
+ handlePixelHeight = this._height;
+ }
+
+ this._handleElement.style.height = handlePixelHeight + "px";
+ this._handleElement.style[this.constructor.transform] = "translate3d(0," + (this._dragY/this.dragYMultiplier) + "px,0)";
+ }
+ }
+ }
+ }
+
+});
diff --git a/blue-shark/ui/scroller.info/sample/index.html b/blue-shark/ui/scroller.info/sample/index.html
new file mode 100644
index 0000000000..83e0ca7a1f
--- /dev/null
+++ b/blue-shark/ui/scroller.info/sample/index.html
@@ -0,0 +1,20 @@
+
+
+
+
+
Scroller
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/scroller.info/sample/package.json b/blue-shark/ui/scroller.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/scroller.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/scroller.info/sample/ui/main.reel/_main.css b/blue-shark/ui/scroller.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..1a5b19e517
--- /dev/null
+++ b/blue-shark/ui/scroller.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,6 @@
+.Main {
+ & .default {
+ height: 30rem;
+ outline: 1px solid red;
+ }
+}
diff --git a/blue-shark/ui/scroller.info/sample/ui/main.reel/main.css b/blue-shark/ui/scroller.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..cd844224b9
--- /dev/null
+++ b/blue-shark/ui/scroller.info/sample/ui/main.reel/main.css
@@ -0,0 +1 @@
+.Main .default{height:480px;height:30rem;outline:1px solid red}
\ No newline at end of file
diff --git a/blue-shark/ui/scroller.info/sample/ui/main.reel/main.html b/blue-shark/ui/scroller.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..bc4fee645e
--- /dev/null
+++ b/blue-shark/ui/scroller.info/sample/ui/main.reel/main.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
Scroller
+
Default
+
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Recusandae ipsam at deserunt veritatis nemo facilis eveniet est asperiores animi magnam, doloribus, voluptatibus inventore, dignissimos laudantium omnis, laborum incidunt temporibus! Quas!
+
Excepturi quia nisi tempora mollitia consequatur similique ullam nihil, molestiae qui et suscipit, eos vitae officiis repellat, animi incidunt. Numquam veniam, amet assumenda explicabo ullam mollitia officia dolorum tempora quibusdam?
+
Excepturi doloribus tenetur voluptate nulla accusamus numquam commodi veritatis asperiores, quidem consequatur ex animi optio exercitationem, illo quibusdam rerum maiores, iure? Temporibus delectus voluptates, tempora dignissimos ipsam mollitia voluptatem atque?
+
Blanditiis facilis deserunt debitis quam quo illo perferendis, laboriosam sapiente atque dolorem voluptate tempore deleniti porro quidem temporibus explicabo ex dicta, ut repellat sed aperiam. Est, dolore fuga officia natus.
+
Quisquam illo autem, iusto magni nostrum quia cumque quas quaerat repellendus accusantium ab neque quo similique enim minima labore expedita distinctio est quam eos, porro repudiandae animi amet. Ex, obcaecati!
+
Voluptatum rerum, minus fugiat laboriosam, fuga distinctio culpa numquam, tempora, repellat hic vero ad possimus eius accusantium maiores earum maxime similique ratione nisi voluptates. Nesciunt voluptatum quos animi vel illum?
+
Quae sit earum atque tenetur quas necessitatibus recusandae asperiores quo, error beatae veritatis. Ut, ea porro sapiente quam fugiat repellendus veniam consequuntur necessitatibus. Atque amet laudantium accusamus recusandae impedit voluptates.
+
Dolorum tenetur, omnis dicta dolor mollitia eum modi quam incidunt ipsum unde, quia, similique obcaecati aspernatur, architecto porro veritatis est atque consectetur! Rem repellat laudantium et, cupiditate, atque obcaecati ipsa?
+
Laboriosam autem, esse alias voluptate iusto ab non atque. Architecto deleniti, omnis nihil, illum, dignissimos totam ipsum laborum molestias quaerat corporis, beatae tempora obcaecati velit eos doloribus veniam vitae necessitatibus.
+
Sunt aspernatur, deleniti natus, recusandae suscipit numquam. Corrupti laudantium optio nostrum iusto expedita, nemo laborum accusantium voluptatibus! Unde officia delectus eveniet porro, minus dolor voluptatem itaque, deserunt aliquid, quo est?
+
Nihil magnam atque odit maxime placeat ab mollitia commodi amet optio voluptatibus repudiandae perspiciatis assumenda quos illum earum illo, tempore. Ducimus quas sed quia voluptas praesentium porro repellendus voluptatem officiis!
+
Reprehenderit earum commodi minima in ratione deserunt dolorum perspiciatis inventore, quos sint cumque veritatis culpa, voluptate hic laudantium! Fugiat facilis nihil, distinctio quibusdam optio possimus labore amet, odio impedit aspernatur?
+
Cupiditate animi hic eaque autem, nobis perspiciatis odio provident rerum delectus optio saepe est inventore, quidem vitae illo minima eligendi nisi distinctio veritatis. Voluptatibus quasi, sit, velit ab error voluptatem.
+
Modi repellat impedit vero quis! Dolor molestias pariatur cumque expedita explicabo. Porro error, aliquam quasi repellendus debitis sint accusamus quaerat, quo adipisci, reprehenderit sed, vero nobis qui dolorem aspernatur. Delectus.
+
Magnam nostrum sequi minima inventore sed velit in sit soluta quo quos rem expedita et commodi dolorem exercitationem illo delectus facilis culpa quibusdam ipsam iusto dolore, voluptatum? Saepe, nisi ab!
+
Quos quisquam perferendis in voluptate, consequatur sit fugit illo, nisi quis, suscipit ex praesentium? Mollitia laboriosam cumque error fugit assumenda provident fuga itaque incidunt, blanditiis obcaecati, perspiciatis distinctio cum non.
+
Expedita ducimus tempora dolor commodi dignissimos, perferendis aut eius eveniet accusantium, voluptates ipsam placeat nam nisi, inventore voluptatibus aspernatur voluptatem velit! Veritatis voluptates nisi, quaerat aliquid tempore amet asperiores aut.
+
Eveniet, esse dolores molestiae quasi sed reprehenderit reiciendis eius temporibus, itaque dicta, maxime blanditiis possimus, repellat molestias. Porro, enim! A rerum distinctio animi, quisquam rem soluta at delectus dolores debitis?
+
Nisi hic sint fugiat quidem totam illum adipisci dignissimos modi ut ipsum blanditiis dolorem a aspernatur quisquam quis aperiam atque vitae sit quas eligendi molestias, eum optio. Quod, rerum, quae.
+
Reiciendis minus quo vero tempora porro harum eligendi, ducimus fuga molestiae consequuntur id. Odio laudantium molestias error neque tempore eum soluta beatae nemo voluptate, quaerat nulla quasi tempora quas minima.
+
+
+
+
+
diff --git a/blue-shark/ui/scroller.info/sample/ui/main.reel/main.js b/blue-shark/ui/scroller.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..f4400783eb
--- /dev/null
+++ b/blue-shark/ui/scroller.info/sample/ui/main.reel/main.js
@@ -0,0 +1,7 @@
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/scroller.reel/_scroller.css b/blue-shark/ui/scroller.reel/_scroller.css
new file mode 100644
index 0000000000..d81b57dcaf
--- /dev/null
+++ b/blue-shark/ui/scroller.reel/_scroller.css
@@ -0,0 +1,4 @@
+.Scroller {
+ flex: 1;
+ overflow: auto;
+}
diff --git a/blue-shark/ui/scroller.reel/scroller.css b/blue-shark/ui/scroller.reel/scroller.css
new file mode 100644
index 0000000000..9c6c05a8b9
--- /dev/null
+++ b/blue-shark/ui/scroller.reel/scroller.css
@@ -0,0 +1 @@
+.Scroller{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:auto}
\ No newline at end of file
diff --git a/blue-shark/ui/scroller.reel/scroller.html b/blue-shark/ui/scroller.reel/scroller.html
new file mode 100644
index 0000000000..2c81ec8e69
--- /dev/null
+++ b/blue-shark/ui/scroller.reel/scroller.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/scroller.reel/scroller.js b/blue-shark/ui/scroller.reel/scroller.js
new file mode 100644
index 0000000000..22be1537ff
--- /dev/null
+++ b/blue-shark/ui/scroller.reel/scroller.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/scroller.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Scroller
+ * @extends Component
+ */
+exports.Scroller = Component.specialize();
diff --git a/blue-shark/ui/search-multiple.info/sample/index.html b/blue-shark/ui/search-multiple.info/sample/index.html
new file mode 100755
index 0000000000..82f5ed93d6
--- /dev/null
+++ b/blue-shark/ui/search-multiple.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Search Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/search-multiple.info/sample/package.json b/blue-shark/ui/search-multiple.info/sample/package.json
new file mode 100755
index 0000000000..c951fee5be
--- /dev/null
+++ b/blue-shark/ui/search-multiple.info/sample/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
diff --git a/blue-shark/ui/search-multiple.info/sample/ui/main.reel/_main.css b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/_main.css
new file mode 100755
index 0000000000..03dd0140e6
--- /dev/null
+++ b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,16 @@
+/* Setup code */
+
+body,
+html {
+ height: 100%;
+}
+
+body {
+ display: flex;
+ flex-direction: column;
+}
+
+.Main {
+ flex: 1;
+ @apply --flex-column;
+}
diff --git a/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.css b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.css
new file mode 100755
index 0000000000..17609751fd
--- /dev/null
+++ b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.css
@@ -0,0 +1 @@
+body,html{height:100%}body{-ms-flex-direction:column;flex-direction:column}.Main,body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal}.Main{-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;min-height:0}
\ No newline at end of file
diff --git a/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.html b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.html
new file mode 100755
index 0000000000..c995d03d1c
--- /dev/null
+++ b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
Select
+
Default Select
+
+
+
+
+
diff --git a/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.js b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.js
new file mode 100755
index 0000000000..de3171b166
--- /dev/null
+++ b/blue-shark/ui/search-multiple.info/sample/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/search-multiple.reel/search-multiple.css b/blue-shark/ui/search-multiple.reel/search-multiple.css
new file mode 100644
index 0000000000..37a27f5855
--- /dev/null
+++ b/blue-shark/ui/search-multiple.reel/search-multiple.css
@@ -0,0 +1,8 @@
+.SearchMultiple {
+
+}
+
+.SearchMultiple .MultipleSelect-title,
+.SearchMultiple .MultipleSelect-input-controls {
+ display: none;
+}
diff --git a/blue-shark/ui/search-multiple.reel/search-multiple.html b/blue-shark/ui/search-multiple.reel/search-multiple.html
new file mode 100644
index 0000000000..4903d15888
--- /dev/null
+++ b/blue-shark/ui/search-multiple.reel/search-multiple.html
@@ -0,0 +1,146 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/search-multiple.reel/search-multiple.js b/blue-shark/ui/search-multiple.reel/search-multiple.js
new file mode 100644
index 0000000000..8b9e69556c
--- /dev/null
+++ b/blue-shark/ui/search-multiple.reel/search-multiple.js
@@ -0,0 +1,51 @@
+/**
+ * @module ui/search-multiple.reel
+ */
+var Search = require("../search.reel").Search,
+ _ = require("lodash");
+
+/**
+ * @class SearchMultiple
+ * @extends Component
+ */
+exports.SearchMultiple = Search.specialize(/** @lends SearchMultiple# */ {
+
+ controller: {
+ value: null
+ },
+
+ handleAction: {
+ value: function (event) {
+ var target = event.target;
+
+ if (target === this._searchButton || target === this._searchInput) {
+ this._search(this._searchInput.value);
+ } else if (target === this._addButton) {
+ this.switchValue = 'write';
+ this._selectComponent.selectedValues = null;
+ this._results = this.initialOptions;
+ this._searchInput.focus();
+
+ } else if (target === this._cancelButton || target === this._validButton) {
+ if (target === this._validButton) {
+ var self = this;
+
+ this.values = _.uniqWith(
+ _.concat(this.values || [],
+ _.difference(this._results,
+ _.differenceWith(this._results, this._selectComponent.selectedValues, function (object, value) {
+ return object[self.valuePath] === value;
+ })
+ )
+ )
+ , function (a, b) {
+ return a.id === b.id;
+ });
+ }
+
+ this._resetState();
+ }
+ }
+ }
+
+});
diff --git a/blue-shark/ui/search.info/sample/index.html b/blue-shark/ui/search.info/sample/index.html
new file mode 100755
index 0000000000..82f5ed93d6
--- /dev/null
+++ b/blue-shark/ui/search.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Search Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/search.info/sample/package.json b/blue-shark/ui/search.info/sample/package.json
new file mode 100755
index 0000000000..c951fee5be
--- /dev/null
+++ b/blue-shark/ui/search.info/sample/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
diff --git a/blue-shark/ui/search.info/sample/ui/main.reel/_main.css b/blue-shark/ui/search.info/sample/ui/main.reel/_main.css
new file mode 100755
index 0000000000..03dd0140e6
--- /dev/null
+++ b/blue-shark/ui/search.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,16 @@
+/* Setup code */
+
+body,
+html {
+ height: 100%;
+}
+
+body {
+ display: flex;
+ flex-direction: column;
+}
+
+.Main {
+ flex: 1;
+ @apply --flex-column;
+}
diff --git a/blue-shark/ui/search.info/sample/ui/main.reel/main.css b/blue-shark/ui/search.info/sample/ui/main.reel/main.css
new file mode 100755
index 0000000000..17609751fd
--- /dev/null
+++ b/blue-shark/ui/search.info/sample/ui/main.reel/main.css
@@ -0,0 +1 @@
+body,html{height:100%}body{-ms-flex-direction:column;flex-direction:column}.Main,body{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal}.Main{-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-direction:column;flex-direction:column;min-height:0}
\ No newline at end of file
diff --git a/blue-shark/ui/search.info/sample/ui/main.reel/main.html b/blue-shark/ui/search.info/sample/ui/main.reel/main.html
new file mode 100755
index 0000000000..2ff4724649
--- /dev/null
+++ b/blue-shark/ui/search.info/sample/ui/main.reel/main.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
+
Select
+
Default Select
+
+
+
+
+
diff --git a/blue-shark/ui/search.info/sample/ui/main.reel/main.js b/blue-shark/ui/search.info/sample/ui/main.reel/main.js
new file mode 100755
index 0000000000..de3171b166
--- /dev/null
+++ b/blue-shark/ui/search.info/sample/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/search.reel/_search.css b/blue-shark/ui/search.reel/_search.css
new file mode 100644
index 0000000000..43b2c277b2
--- /dev/null
+++ b/blue-shark/ui/search.reel/_search.css
@@ -0,0 +1,14 @@
+.Search-results {
+ position: relative;
+}
+
+.Search-results-message {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
diff --git a/blue-shark/ui/search.reel/search.css b/blue-shark/ui/search.reel/search.css
new file mode 100644
index 0000000000..6afb4f4a6b
--- /dev/null
+++ b/blue-shark/ui/search.reel/search.css
@@ -0,0 +1 @@
+.Search-results{position:relative}.Search-results-message{position:absolute;top:0;left:0;right:0;bottom:0;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}
\ No newline at end of file
diff --git a/blue-shark/ui/search.reel/search.html b/blue-shark/ui/search.reel/search.html
new file mode 100644
index 0000000000..545946a6ba
--- /dev/null
+++ b/blue-shark/ui/search.reel/search.html
@@ -0,0 +1,154 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/search.reel/search.js b/blue-shark/ui/search.reel/search.js
new file mode 100644
index 0000000000..6dcd4c9e8c
--- /dev/null
+++ b/blue-shark/ui/search.reel/search.js
@@ -0,0 +1,125 @@
+/**
+ * @module ui/search.reel
+ */
+var Component = require("montage/ui/component").Component
+ _ = require("lodash");
+
+/**
+ * @class Search
+ * @extends Component
+ */
+exports.Search = Component.specialize(/** @lends Search# */ {
+
+ _value: {
+ value: null
+ },
+
+ value: {
+ set: function (value) {
+ this._value = value ? this.valuePath ? value[this.valuePath] || value : value : null;
+ this.displayedValue = value ? this.labelPath ? value[this.labelPath] || value : value : 'none';
+ },
+ get: function () {
+ return this._value;
+ }
+ },
+
+ enterDocument: {
+ value: function (firstTime) {
+ if (!this.controller || typeof this.controller.search !== 'function') {
+ throw new Error('Search component needs a controller that implements an `search` method.');
+ }
+
+ if (firstTime) {
+ this.addPathChangeListener("_searchInput.value", this, "handleSearchChange");
+ }
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ this._resetState();
+ }
+ },
+
+ handleSearchChange: {
+ value: function (value) {
+ if (value !== null && value !== void 0 && !value.length) {
+ this._results = this.initialOptions;
+ }
+ }
+ },
+
+ handleAction: {
+ value: function (event) {
+ var target = event.target;
+
+ if (target === this._searchButton || target === this._searchInput) {
+ this._search(this._searchInput.value);
+ } else if (target === this._changeButton) {
+ this.switchValue = 'write';
+ this._selectComponent.selectedValues = null;
+ this._results = this.initialOptions;
+ this._searchInput.focus();
+
+ } else if (target === this._cancelButton || target === this._validButton || target === this._noneButton) {
+ if (target === this._validButton) {
+ var self = this,
+ selectedValue = this._selectComponent.selectedValues[0];
+
+ this.value = _.find(this._results, function (result) {
+ return result[self.valuePath] === selectedValue;
+ });
+ }
+
+ if (target === this._noneButton) {
+ this.value = null;
+ }
+
+ this._resetState();
+ }
+ }
+ },
+
+ controller: {
+ value: null
+ },
+
+ _resetState: {
+ value: function () {
+ this._searchInput.value = this._results = null;
+ this.isSearching = false;
+ this.switchValue = 'read';
+ }
+ },
+
+ _search: {
+ value: function (value) {
+ if (typeof value === 'string' && value.length) {
+ this._handleSearchAction(this.controller.search(value));
+ }
+ }
+ },
+
+ _handleSearchAction: {
+ value: function (searchAction) {
+ this.isSearching = true;
+
+ if (Promise.is(searchAction)) {
+ var self = this;
+
+ searchAction.then(function (results) {
+ if (self._inDocument) {
+ self._results = results;
+ }
+ }).finally(function () {
+ self.isSearching = false;
+ });
+ } else {
+ this._results = searchAction;
+ this.isSearching = false;
+ }
+ }
+ }
+
+});
diff --git a/blue-shark/ui/select-filter-item.reel/_select-filter-item.css b/blue-shark/ui/select-filter-item.reel/_select-filter-item.css
new file mode 100644
index 0000000000..fd553babb5
--- /dev/null
+++ b/blue-shark/ui/select-filter-item.reel/_select-filter-item.css
@@ -0,0 +1,20 @@
+.SelectFilterItem {
+ &:not(:last-child) {
+ margin-bottom: .5em;
+ }
+
+ &:hover .SelectFilterItem-checkbox label:before {
+ box-shadow: 0 0 2px 2px rgba(255,255,255,.85);
+ }
+}
+
+.SelectFilterItem-checkbox {
+ display: block;
+
+ & label {
+ white-space: nowrap;
+ display: block;
+ color: var(--white);
+ }
+}
+
diff --git a/blue-shark/ui/select-filter-item.reel/select-filter-item.css b/blue-shark/ui/select-filter-item.reel/select-filter-item.css
new file mode 100644
index 0000000000..79977bb1c7
--- /dev/null
+++ b/blue-shark/ui/select-filter-item.reel/select-filter-item.css
@@ -0,0 +1 @@
+.SelectFilterItem:not(:last-child){margin-bottom:.5em}.SelectFilterItem:hover .SelectFilterItem-checkbox label:before{box-shadow:0 0 2px 2px hsla(0,0%,100%,.85)}.SelectFilterItem-checkbox{display:block}.SelectFilterItem-checkbox label{white-space:nowrap;display:block;color:#fff}
\ No newline at end of file
diff --git a/blue-shark/ui/select-filter-item.reel/select-filter-item.html b/blue-shark/ui/select-filter-item.reel/select-filter-item.html
new file mode 100644
index 0000000000..5dc64e192d
--- /dev/null
+++ b/blue-shark/ui/select-filter-item.reel/select-filter-item.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-filter-item.reel/select-filter-item.js b/blue-shark/ui/select-filter-item.reel/select-filter-item.js
new file mode 100644
index 0000000000..fe323ea529
--- /dev/null
+++ b/blue-shark/ui/select-filter-item.reel/select-filter-item.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/select-filter-item.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class SelectFilterItem
+ * @extends Component
+ */
+exports.SelectFilterItem = Component.specialize();
diff --git a/blue-shark/ui/select-filter-items.reel/_select-filter-items.css b/blue-shark/ui/select-filter-items.reel/_select-filter-items.css
new file mode 100644
index 0000000000..18b431be01
--- /dev/null
+++ b/blue-shark/ui/select-filter-items.reel/_select-filter-items.css
@@ -0,0 +1,17 @@
+.SelectFilterItems {
+ position: absolute;
+ visibility: hidden;
+ opacity: 0;
+ background: var(--grey);
+ padding: .5rem .75rem;
+ border-radius: var(--border-radius);
+ box-shadow: 0 2px 2px 2px var(--shadow-1);
+
+ &.montage-Overlay--visible {
+ visibility: visible;
+ opacity: 1;
+ transition-delay: 0s, 0s;
+ z-index: 1000;
+ }
+}
+
diff --git a/blue-shark/ui/select-filter-items.reel/select-filter-items.css b/blue-shark/ui/select-filter-items.reel/select-filter-items.css
new file mode 100644
index 0000000000..2bdae63781
--- /dev/null
+++ b/blue-shark/ui/select-filter-items.reel/select-filter-items.css
@@ -0,0 +1 @@
+.SelectFilterItems{position:absolute;visibility:hidden;opacity:0;background:#2f3233;padding:8px 12px;padding:.5rem .75rem;border-radius:4px;box-shadow:0 2px 2px 2px rgba(0,0,0,.3)}.SelectFilterItems.montage-Overlay--visible{visibility:visible;opacity:1;-webkit-transition-delay:0s,0s;transition-delay:0s,0s;z-index:1000}
\ No newline at end of file
diff --git a/blue-shark/ui/select-filter-items.reel/select-filter-items.html b/blue-shark/ui/select-filter-items.reel/select-filter-items.html
new file mode 100644
index 0000000000..23b9e03b29
--- /dev/null
+++ b/blue-shark/ui/select-filter-items.reel/select-filter-items.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-filter-items.reel/select-filter-items.js b/blue-shark/ui/select-filter-items.reel/select-filter-items.js
new file mode 100644
index 0000000000..97b9d3bb99
--- /dev/null
+++ b/blue-shark/ui/select-filter-items.reel/select-filter-items.js
@@ -0,0 +1,16 @@
+/**
+ * @module ui/select-filter-items.reel
+ */
+var SelectOptions = require("blue-shark/ui/select.reel/select-options.reel").SelectOptions;
+
+/**
+ * @class SelectFilterItems
+ * @extends Component
+ */
+exports.SelectFilterItems = SelectOptions.specialize({
+ hasTemplate: {
+ value: true
+ }
+});
+
+
diff --git a/blue-shark/ui/select-filter.info/sample/index.html b/blue-shark/ui/select-filter.info/sample/index.html
new file mode 100644
index 0000000000..643ab114b7
--- /dev/null
+++ b/blue-shark/ui/select-filter.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Select Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-filter.info/sample/package.json b/blue-shark/ui/select-filter.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/select-filter.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/select-filter.info/sample/ui/main.reel/_main.css b/blue-shark/ui/select-filter.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..416e089ebb
--- /dev/null
+++ b/blue-shark/ui/select-filter.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
diff --git a/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.css b/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.html b/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..dc98de3d21
--- /dev/null
+++ b/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Select Filter
+
+
filter results:
+
+
+
+
+
diff --git a/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.js b/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..de3171b166
--- /dev/null
+++ b/blue-shark/ui/select-filter.info/sample/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/select-filter.reel/_select-filter.css b/blue-shark/ui/select-filter.reel/_select-filter.css
new file mode 100644
index 0000000000..ee3c1feeb2
--- /dev/null
+++ b/blue-shark/ui/select-filter.reel/_select-filter.css
@@ -0,0 +1,36 @@
+.SelectFilter {
+ position: relative;
+ display: flex;
+}
+
+.SelectFilter-filter {
+ position: relative;
+}
+
+.SelectFilter-displayAll.Button {
+ margin-right: .5rem;
+}
+
+.SelectFilter-filterButton.Button {
+ padding-right: .75em;
+
+ & svg {
+ order: 1;
+ margin-right: 0 !important;
+ max-height: 1.2em;
+ max-width: 1.1em;
+
+ @nest .SelectFilter.filters-are-visible & {
+ transform: rotate(180deg);
+ }
+ }
+
+ & .Button-label { margin-right: .5em; }
+}
+
+.SelectFilter-items {
+
+ @nest .SelectFilter.filters-are-visible & {
+ display: block;
+ }
+}
diff --git a/blue-shark/ui/select-filter.reel/select-filter.css b/blue-shark/ui/select-filter.reel/select-filter.css
new file mode 100644
index 0000000000..f287d5447f
--- /dev/null
+++ b/blue-shark/ui/select-filter.reel/select-filter.css
@@ -0,0 +1 @@
+.SelectFilter{display:-webkit-box;display:-ms-flexbox;display:flex}.SelectFilter,.SelectFilter-filter{position:relative}.SelectFilter-displayAll.Button{margin-right:8px;margin-right:.5rem}.SelectFilter-filterButton.Button{padding-right:.75em}.SelectFilter-filterButton.Button svg{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1;margin-right:0!important;max-height:1.2em;max-width:1.1em}.SelectFilter.filters-are-visible .SelectFilter-filterButton.Button svg{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.SelectFilter-filterButton.Button .Button-label{margin-right:.5em}.SelectFilter.filters-are-visible .SelectFilter-items{display:block}
\ No newline at end of file
diff --git a/blue-shark/ui/select-filter.reel/select-filter.html b/blue-shark/ui/select-filter.reel/select-filter.html
new file mode 100644
index 0000000000..0c8fc6cdd1
--- /dev/null
+++ b/blue-shark/ui/select-filter.reel/select-filter.html
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-filter.reel/select-filter.js b/blue-shark/ui/select-filter.reel/select-filter.js
new file mode 100644
index 0000000000..a4b98765de
--- /dev/null
+++ b/blue-shark/ui/select-filter.reel/select-filter.js
@@ -0,0 +1,31 @@
+/**
+ * @module ui/select-filter.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class SelectFilter
+ * @extends Component
+ */
+exports.SelectFilter = Component.specialize(/** @lends SelectFilter# */ {
+
+ handleDisplayAllButtonAction: {
+ value: function () {
+ this.options.forEach(function(filter){
+ filter.checked = true;
+ });
+ }
+ },
+
+ handleFilterButtonAction: {
+ value: function () {
+ this._toggleFilterOverlay();
+ }
+ },
+
+ _toggleFilterOverlay: {
+ value: function () {
+ this.filterOverlayComponent.isShown ? this.filterOverlayComponent.hide() : this.filterOverlayComponent.show();
+ }
+ }
+});
diff --git a/blue-shark/ui/select-multiple.info/sample/index.html b/blue-shark/ui/select-multiple.info/sample/index.html
new file mode 100644
index 0000000000..643ab114b7
--- /dev/null
+++ b/blue-shark/ui/select-multiple.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Select Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-multiple.info/sample/package.json b/blue-shark/ui/select-multiple.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/select-multiple.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/select-multiple.info/sample/ui/main.reel/_main.css b/blue-shark/ui/select-multiple.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/select-multiple.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.css b/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.html b/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..6e6448cbff
--- /dev/null
+++ b/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.html
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
Select
+
Default Select
+
+
+
+
+
diff --git a/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.js b/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..0833df543e
--- /dev/null
+++ b/blue-shark/ui/select-multiple.info/sample/ui/main.reel/main.js
@@ -0,0 +1,42 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ options: {
+ value: [
+ {
+ "value": "option1",
+ "label": "Option 1"
+ },
+ {
+ "value": "optimal",
+ "label": "Optimal"
+ },
+ {
+ "value": "virtualization",
+ "label": "Virtualization"
+ },
+ {
+ "value": "backups",
+ "label": "Backups"
+ },
+ {
+ "value": "media",
+ "label": "Media"
+ }
+ ]
+ },
+
+ selected: {
+ value: [
+ "optimal", "backups"
+ ]
+ }
+});
diff --git a/blue-shark/ui/select-multiple.reel/_select-multiple.css b/blue-shark/ui/select-multiple.reel/_select-multiple.css
new file mode 100644
index 0000000000..119aac646d
--- /dev/null
+++ b/blue-shark/ui/select-multiple.reel/_select-multiple.css
@@ -0,0 +1,39 @@
+.SelectMultiple {
+ @apply --input-field;
+ min-width: 10rem;
+}
+
+.SelectMultiple option {
+ position: relative;
+ font-family: 'lato';
+ font-weight: 300;
+ color: var(--grey-3);
+ padding: .25em .5em;
+ z-index: 1;
+
+ &:checked {
+ &:before {
+ content: "\2713 ";
+ width: 1rem;
+ margin-right: .5em;
+ color: var(--white);
+ z-index: 1;
+ }
+ &:after {
+ content: '';
+ position: absolute;
+ top:0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background-color: var(--accent);
+ z-index: -1;
+ pointer-events:none;
+ }
+ }
+}
+
+.SelectMultiple.is-disabled {
+ opacity: .5;
+ pointer-events: none;
+}
diff --git a/blue-shark/ui/select-multiple.reel/select-multiple.css b/blue-shark/ui/select-multiple.reel/select-multiple.css
new file mode 100644
index 0000000000..f3fc480e98
--- /dev/null
+++ b/blue-shark/ui/select-multiple.reel/select-multiple.css
@@ -0,0 +1 @@
+.SelectMultiple{font-weight:300;font-family:Lato,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:1em;color:#fff;width:100%;-webkit-tap-highlight-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;border:1px solid #535a61;background-color:#222b35;border-radius:4px;-webkit-transition-property:background-color,border-color,opacity;transition-property:background-color,border-color,opacity;-webkit-transition-duration:.25s;transition-duration:.25s;min-width:160px;min-width:10rem}.SelectMultiple:hover{background-color:#29313b;border-color:#9ca0a4}.SelectMultiple:focus{background-color:#29313b;border-color:#2089d3}.SelectMultiple.montage--disabled{border-color:transparent;opacity:.5;cursor:not-allowed}.SelectMultiple.montage--disabled:hover{background-color:#222b35;border-color:transparent}.SelectMultiple.montage--invalidText{border-color:#cf324f}.SelectMultiple[readonly=readonly]{background-color:transparent;border:none;padding:0}.SelectMultiple option{position:relative;font-family:lato;font-weight:300;color:#e0e5e5;padding:.25em .5em;z-index:1}.SelectMultiple option:checked:before{content:"\2713 ";width:16px;width:1rem;margin-right:.5em;color:#fff;z-index:1}.SelectMultiple option:checked:after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;background-color:#2089d3;z-index:-1;pointer-events:none}.SelectMultiple.is-disabled{opacity:.5;pointer-events:none}
\ No newline at end of file
diff --git a/blue-shark/ui/select-multiple.reel/select-multiple.html b/blue-shark/ui/select-multiple.reel/select-multiple.html
new file mode 100644
index 0000000000..215d1878e1
--- /dev/null
+++ b/blue-shark/ui/select-multiple.reel/select-multiple.html
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-multiple.reel/select-multiple.js b/blue-shark/ui/select-multiple.reel/select-multiple.js
new file mode 100644
index 0000000000..da8e7b4c7f
--- /dev/null
+++ b/blue-shark/ui/select-multiple.reel/select-multiple.js
@@ -0,0 +1,194 @@
+var Component = require("montage/ui/component").Component;
+
+exports.SelectMultiple = Component.specialize({
+
+ enterDocument: {
+ value: function (isFirstTime) {
+ if (isFirstTime) {
+ this._element.addEventListener("change", this, false);
+ }
+ }
+ },
+
+ allowMultiple: {
+ value: true
+ },
+
+ handleChange: {
+ value: function () {
+ var children = this._element.children,
+ selectedMap = new Map(),
+ i;
+
+ if (this._selectedValues) {
+ for (i = 0; i < this._selectedValues.length; i++) {
+ selectedMap.set(this._selectedValues[i], true);
+ }
+ } else {
+ this.selectedValues = [];
+ }
+ for (i = 0; i < children.length; i++) {
+ if (children[i].selected) {
+ if (!selectedMap.has(this._options[i][this._valuePropertyName] || this._options[i])) {
+ this.selectedValues.push(this._options[i][this._valuePropertyName] || this._options[i]);
+ }
+ } else {
+ if (selectedMap.has(this._options[i][this._valuePropertyName] || this._options[i])) {
+ this.selectedValues.splice(
+ this.selectedValues.indexOf(this._options[i][this._valuePropertyName] || this._options[i]),
+ 1
+ );
+ }
+ }
+ }
+ }
+ },
+
+ _options: {
+ value: null
+ },
+
+ options: {
+ get: function () {
+ return this._options;
+ },
+ set: function (value) {
+ if (this._options !== value) {
+ if (this._cancelOptionsRangeChangeListener) {
+ this._cancelOptionsRangeChangeListener();
+ }
+ if (value && value instanceof Array) {
+ this._options = value;
+ } else {
+ this._options = [];
+ }
+ this._cancelOptionsRangeChangeListener = this.addRangeAtPathChangeListener(
+ "_options",
+ this,
+ "handleRangeChange"
+ );
+ this._needsUpdateOptions = true;
+ this._selectedValues = [];
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _needsUpdateOptions: {
+ value: false
+ },
+
+ _labelPropertyName: {
+ value: "label"
+ },
+
+ labelPropertyName: {
+ get: function () {
+ return this._labelPropertyName;
+ },
+ set: function (value) {
+ if (this._labelPropertyName !== value) {
+ if (value) {
+ this._labelPropertyName = value + "";
+ } else {
+ this._labelPropertyName = "label";
+ }
+ this._needsUpdateOptions = true;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _valuePropertyName: {
+ value: "value"
+ },
+
+ valuePropertyName: {
+ get: function () {
+ return this._valuePropertyName;
+ },
+ set: function (value) {
+ if (this._valuePropertyName !== value) {
+ if (value) {
+ this._valuePropertyName = value + "";
+ } else {
+ this._valuePropertyName = "value";
+ }
+ this._needsUpdateOptions = true;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _selectedValues: {
+ value: null
+ },
+
+ selectedValues: {
+ get: function () {
+ if (!this._selectedValues) {
+ this._selectedValues = [];
+ }
+ return this._selectedValues;
+ },
+ set: function (value) {
+ if (this._selectedValues !== value) {
+ if (this._cancelSelectedValuesRangeChangeListener) {
+ this._cancelSelectedValuesRangeChangeListener();
+ }
+ if (value && value instanceof Array) {
+ this._selectedValues = value;
+ } else {
+ this._selectedValues = [];
+ }
+ this._cancelSelectedValuesRangeChangeListener = this.addRangeAtPathChangeListener(
+ "_selectedValues",
+ this,
+ "handleRangeChange"
+ );
+ this._needsUpdateOptions = true;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ handleRangeChange: {
+ value: function () {
+ this._needsUpdateOptions = true;
+ this.needsDraw = true;
+ }
+ },
+
+ draw: {
+ value: function() {
+ var optionsFragment,
+ optionElement,
+ selectedMap,
+ i;
+
+ if (this._needsUpdateOptions) {
+ selectedMap = new Map();
+ if (this._selectedValues) {
+ for (i = 0; i < this._selectedValues.length; i++) {
+ selectedMap.set(this._selectedValues[i], true);
+ }
+ }
+ optionsFragment = document.createDocumentFragment();
+
+ if (this._options) {
+ for (i = 0; i < this._options.length; i++) {
+ optionElement = document.createElement("option");
+ optionElement.selected = selectedMap.has(this._options[i][this._valuePropertyName] || this._options[i]);
+ optionElement.textContent = this._options[i][this._labelPropertyName] || this._options[i];
+ optionsFragment.appendChild(optionElement);
+ }
+ }
+
+ this._element.innerHTML = "";
+ this._element.appendChild(optionsFragment);
+ this._needsUpdateOptions = false;
+ }
+ }
+ }
+
+});
diff --git a/blue-shark/ui/select-search.info/sample/index.html b/blue-shark/ui/select-search.info/sample/index.html
new file mode 100644
index 0000000000..10d2deadb1
--- /dev/null
+++ b/blue-shark/ui/select-search.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Search Select Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-search.info/sample/package.json b/blue-shark/ui/select-search.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/select-search.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/select-search.info/sample/ui/main.reel/_main.css b/blue-shark/ui/select-search.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/select-search.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/select-search.info/sample/ui/main.reel/main.css b/blue-shark/ui/select-search.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/select-search.info/sample/ui/main.reel/main.html b/blue-shark/ui/select-search.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..32d07f26cb
--- /dev/null
+++ b/blue-shark/ui/select-search.info/sample/ui/main.reel/main.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
+
Select
+
Default Select Search
+
+
+
+
+
diff --git a/blue-shark/ui/select-search.info/sample/ui/main.reel/main.js b/blue-shark/ui/select-search.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..0833df543e
--- /dev/null
+++ b/blue-shark/ui/select-search.info/sample/ui/main.reel/main.js
@@ -0,0 +1,42 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ options: {
+ value: [
+ {
+ "value": "option1",
+ "label": "Option 1"
+ },
+ {
+ "value": "optimal",
+ "label": "Optimal"
+ },
+ {
+ "value": "virtualization",
+ "label": "Virtualization"
+ },
+ {
+ "value": "backups",
+ "label": "Backups"
+ },
+ {
+ "value": "media",
+ "label": "Media"
+ }
+ ]
+ },
+
+ selected: {
+ value: [
+ "optimal", "backups"
+ ]
+ }
+});
diff --git a/blue-shark/ui/select-search.reel/_select-search.css b/blue-shark/ui/select-search.reel/_select-search.css
new file mode 100644
index 0000000000..7a32cf7633
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/_select-search.css
@@ -0,0 +1,206 @@
+.SelectSearch {
+ position: relative;
+ margin-bottom: 1em;
+ border-radius: 4px;
+ font-size: 1em;
+}
+
+.SelectSearch.disabled { cursor: not-allowed; }
+
+.SelectSearch:focus {
+ outline: none;
+ box-shadow: 0 0 1px 1px var(--blue-lighten-2);
+}
+
+.SelectSearch-button {
+ position: relative;
+ font-family: 'lato';
+ font-size: inherit;
+ line-height: inherit;
+ font-weight: 200;
+ height: 2em;
+ width: 100%;
+ text-align: left;
+ padding: .3em 2.5em 0em .5em;
+ border-radius: 4px;
+ background: var(--grey-blue);
+ border: none;
+ border-width: 1px;
+ border-style: solid;
+ border-color: transparent;
+ border-bottom-color: rgba(0, 0, 0, .15);
+ border-top-color: rgba(255, 255, 255, .1);
+ outline: none;
+ color: var(--grey-3);
+ user-select: none;
+ cursor: pointer;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.SelectSearch-button:hover {
+ background-image: linear-gradient(rgba(255,255,255,0.025), rgba(255,255,255,0.025));
+}
+
+.SelectSearch.disabled .SelectSearch-button {
+ border-color: transparent;
+ background: var(--grey-blue);
+ opacity: .5;
+ color: var(--grey-1);
+ pointer-events: none;
+}
+
+.SelectSearch.isExpanded .SelectSearch-button {
+ border-color: var(--blue-lighten-2);
+ border-bottom-color: transparent;
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}
+
+/* container */
+
+.SelectSearch-input {
+ position: absolute;
+ width: 100%;
+ padding: .25em;
+ padding-top: 0;
+ top: calc(2em - 1px);
+ background: var(--grey-blue);
+ border-left: 1px solid var(--blue-lighten-2);
+ border-right: 1px solid var(--blue-lighten-2);
+ opacity: 0;
+ visibility: hidden;
+}
+
+.SelectSearch-input-field {
+ border-radius: 3px;
+ background: var(--grey-3);
+ color: var(--main-bg-color);
+}
+
+/* icons */
+
+.SelectSearch-input-clearButton,
+.SelectSearch-input-triangle,
+.SelectSearch-input-search {
+ position: absolute;
+}
+
+.SelectSearch-input-clearButton {
+ height: 1.3em;
+ width: 1.3em;
+ top: 50%;
+ right: .5em;
+ margin-top: -.75em;
+ padding: .25em;
+ color: var(--grey-3);
+ transform: rotate(45deg);
+ background: var(--grey-blue);
+ border-radius: 2em;
+ cursor: pointer;
+ outline: none;
+ visibility: hidden;
+ opacity: 0;
+ border-radius: 1em;
+}
+
+/* add icon */
+
+.SelectSearch-input-triangle {
+ height: 1em;
+ width: 1em;
+ top: 50%;
+ right: .5em;
+ margin-top: -.5em;
+ color: rgba(255,255,255,.8);
+ opacity: 1;
+}
+
+.SelectSearch-input-search {
+ height: 1.5em;
+ width: 1.5em;
+ top: 50%;
+ right: .4em;
+ margin-top: -.8em;
+ color: var(--main-bg-color);
+ padding: .1em;
+}
+
+.SelectSearch.disabled .SelectSearch-input-triangle { opacity: .5; }
+
+.SelectSearch-input-options {
+ position: absolute;
+ top: 2.25em;
+ left: -1px;
+ right: -1px;
+ height: 8.2em;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+ color: var(--grey-2);
+ background-color: var(--grey-blue);
+ border: 1px solid var(--blue-lighten-2);
+ border-top: none;
+ box-shadow: 0 2px 4px rgba(0,0,0,.3);
+ z-index: 100;
+ overflow-x: hidden;
+}
+
+.SelectSearch-input-error {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ background: var(--red);
+ color: var(--white);
+ font-weight: 300;
+ padding: .5em;
+ transform: translateY(100%);
+ z-index: 1;
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ box-shadow: 0 2px 4px rgba(0,0,0,.3);
+ visibility: hidden;
+ opacity: 0;
+ transition-property: visibility, opacity;
+ transition-duration: .2s;
+}
+
+/*
+
+States
+
+*/
+
+.SelectSearch.isExpanded .SelectSearch-input {
+ opacity: 1;
+ visibility: visible;
+}
+
+.SelectSearch.isExpanded .SelectSearch-input-triangle {
+ transform: rotate(180deg);
+}
+
+/*.SelectSearch-input-field.has-options:focus + .SelectSearch-input-options.has-content,
+.SelectSearch-input-options:active,
+.SelectSearch-input.has-error .SelectSearch-input-error {
+ visibility: visible;
+ opacity: 1;
+}*/
+
+.SelectSearch.isExpanded .SelectSearch-input.has-value .SelectSearch-input-clearButton {
+ z-index: 1;
+ visibility: visible;
+ opacity: 1;
+}
+
+.SelectSearch-input.has-value .SelectSearch-input-search {
+ /*opacity: 0;*/
+}
+
+/*.SelectSearch-input.has-error .SelectSearch-input-field {
+ border-color: var(--red);
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+}*/
+
+
diff --git a/blue-shark/ui/select-search.reel/select-search-option.reel/_select-search-option.css b/blue-shark/ui/select-search.reel/select-search-option.reel/_select-search-option.css
new file mode 100644
index 0000000000..c2fca5f870
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/select-search-option.reel/_select-search-option.css
@@ -0,0 +1,11 @@
+.SelectSearchOption {
+ cursor: pointer;
+ padding: .25em .5em .35em;
+ font-family: 'lato';
+ font-weight: 200;
+}
+
+.SelectSearchOption.selected {
+ background: var(--blue-lighten-2);
+ color: var(--white);
+}
diff --git a/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.css b/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.css
new file mode 100644
index 0000000000..15f7c1da31
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.css
@@ -0,0 +1 @@
+.SelectSearchOption{cursor:pointer;padding:.25em .5em .35em;font-family:lato;font-weight:200}.SelectSearchOption.selected{background:#2089d3;color:#fff}
\ No newline at end of file
diff --git a/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.html b/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.html
new file mode 100644
index 0000000000..7dfd05111f
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.js b/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.js
new file mode 100644
index 0000000000..b48c5edaec
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/select-search-option.reel/select-search-option.js
@@ -0,0 +1,34 @@
+/**
+ * @module ui/multiple-select-option.reel
+ */
+var Component = require("montage/ui/component").Component,
+ PressComposer = require("montage/composer/press-composer").PressComposer;
+
+/**
+ * @class MultipleSelectOption
+ * @extends Component
+ */
+exports.SelectSearchOption = Component.specialize(/** @lends MultipleSelectOption# */ {
+ prepareForActivationEvents: {
+ value: function() {
+ var pressComposer = new PressComposer();
+ this.addComposer(pressComposer);
+ pressComposer.addEventListener("press", this);
+ this.element.addEventListener("mouseover", this);
+ }
+ },
+
+ handlePress: {
+ value: function() {
+ this.valueToAdd = this.option;
+ }
+ },
+
+ handleMouseover: {
+ value: function() {
+ if (this.selected != this.option) {
+ this.selected = this.option;
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/select-search.reel/select-search.css b/blue-shark/ui/select-search.reel/select-search.css
new file mode 100644
index 0000000000..3bb8413f93
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/select-search.css
@@ -0,0 +1 @@
+.SelectSearch{position:relative;margin-bottom:1em;border-radius:4px;font-size:1em}.SelectSearch.disabled{cursor:not-allowed}.SelectSearch:focus{outline:none;box-shadow:0 0 1px 1px #2089d3}.SelectSearch-button{position:relative;font-family:lato;font-size:inherit;line-height:inherit;font-weight:200;height:2em;width:100%;text-align:left;padding:.3em 2.5em 0 .5em;border-radius:4px;background:#242628;border:none;border:1px solid transparent;border-bottom-color:rgba(0,0,0,.15);border-top-color:hsla(0,0%,100%,.1);outline:none;color:#e0e5e5;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;cursor:pointer;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.SelectSearch-button:hover{background-image:-webkit-linear-gradient(hsla(0,0%,100%,.025),hsla(0,0%,100%,.025));background-image:linear-gradient(hsla(0,0%,100%,.025),hsla(0,0%,100%,.025))}.SelectSearch.disabled .SelectSearch-button{border-color:transparent;background:#242628;opacity:.5;color:#939e9f;pointer-events:none}.SelectSearch.isExpanded .SelectSearch-button{border-color:#2089d3;border-bottom-color:transparent;border-bottom-left-radius:0;border-bottom-right-radius:0}.SelectSearch-input{position:absolute;width:100%;padding:.25em;padding-top:0;top:calc(2em - 1px);background:#242628;border-left:1px solid #2089d3;border-right:1px solid #2089d3;opacity:0;visibility:hidden}.SelectSearch-input-field{border-radius:3px;background:#e0e5e5;color:#16171a}.SelectSearch-input-clearButton,.SelectSearch-input-search,.SelectSearch-input-triangle{position:absolute}.SelectSearch-input-clearButton{height:1.3em;width:1.3em;top:50%;right:.5em;margin-top:-.75em;padding:.25em;color:#e0e5e5;-webkit-transform:rotate(45deg);transform:rotate(45deg);background:#242628;border-radius:2em;cursor:pointer;outline:none;visibility:hidden;opacity:0;border-radius:1em}.SelectSearch-input-triangle{height:1em;width:1em;top:50%;right:.5em;margin-top:-.5em;color:hsla(0,0%,100%,.8);opacity:1}.SelectSearch-input-search{height:1.5em;width:1.5em;top:50%;right:.4em;margin-top:-.8em;color:#16171a;padding:.1em}.SelectSearch.disabled .SelectSearch-input-triangle{opacity:.5}.SelectSearch-input-options{position:absolute;top:2.25em;left:-1px;right:-1px;height:8.2em;border-bottom-right-radius:4px;border-bottom-left-radius:4px;color:#b1bcbe;background-color:#242628;border:1px solid #2089d3;border-top:none;box-shadow:0 2px 4px rgba(0,0,0,.3);z-index:100;overflow-x:hidden}.SelectSearch-input-error{position:absolute;bottom:0;width:100%;background:#cf324f;color:#fff;font-weight:300;padding:.5em;-webkit-transform:translateY(100%);transform:translateY(100%);z-index:1;border-bottom-left-radius:4px;border-bottom-right-radius:4px;box-shadow:0 2px 4px rgba(0,0,0,.3);visibility:hidden;opacity:0;-webkit-transition-property:visibility,opacity;transition-property:visibility,opacity;-webkit-transition-duration:.2s;transition-duration:.2s}.SelectSearch.isExpanded .SelectSearch-input{opacity:1;visibility:visible}.SelectSearch.isExpanded .SelectSearch-input-triangle{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.SelectSearch.isExpanded .SelectSearch-input.has-value .SelectSearch-input-clearButton{z-index:1;visibility:visible;opacity:1}
\ No newline at end of file
diff --git a/blue-shark/ui/select-search.reel/select-search.html b/blue-shark/ui/select-search.reel/select-search.html
new file mode 100644
index 0000000000..dc04e37f19
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/select-search.html
@@ -0,0 +1,135 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select-search.reel/select-search.js b/blue-shark/ui/select-search.reel/select-search.js
new file mode 100644
index 0000000000..af14677f08
--- /dev/null
+++ b/blue-shark/ui/select-search.reel/select-search.js
@@ -0,0 +1,188 @@
+/**
+ * @module ui/select-search.reel
+ */
+var Component = require("montage/ui/component").Component,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer;
+
+/**
+ * @class SelectSearch
+ * @extends Component
+ */
+exports.SelectSearch = Component.specialize(/** @lends SelectSearch# */ {
+ enabled: {
+ value: true
+ },
+
+ options: {
+ value: null
+ },
+
+ isDraggable: {
+ value: false
+ },
+
+ converter: {
+ value: null
+ },
+
+ __selectedOption: {
+ value: null
+ },
+
+ isExpanded: {
+ value: false
+ },
+
+ _selectedOption: {
+ get: function() {
+ return this.__selectedOption;
+ },
+ set: function(option) {
+ if (option && this.__selectedOption != option) {
+ this.__selectedOption = option;
+ this._selectOption(option);
+ }
+ }
+ },
+
+ enterDocument: {
+ value: function (firstTime) {
+
+ if (!this.values) {
+ this.values = [];
+ }
+ if (!this.options) {
+ this.options = [];
+ }
+ }
+ },
+
+ prepareForActivationEvents: {
+ value: function() {
+ this._inputField.delegate = {
+ shouldAcceptValue: function() {
+ return true;
+ }
+ };
+ KeyComposer.createKey(this._inputField, "down", "down").addEventListener("keyPress", this);
+ KeyComposer.createKey(this._inputField, "up", "up").addEventListener("keyPress", this);
+ }
+ },
+
+ handleButtonAction: {
+ value: function () {
+ this.isExpanded = !this.isExpanded;
+ }
+ },
+
+ handleClearButtonAction: {
+ value: function () {
+ this._clearInput();
+ }
+ },
+
+ _valueToAdd: {
+ get: function() {
+ return null;
+ },
+ set: function(value) {
+ if (value) {
+ this.value = value;
+ this.isExpanded = !this.isExpanded;
+ }
+ }
+ },
+
+ _findCloserComponentFromElement: {
+ value: function _findCloserComponentFromElement (element) {
+ var component;
+
+ while (element && !(component = element.component) && element !== this.element) {
+ element = element.parentNode;
+ }
+
+ return component;
+ }
+ },
+
+ _blurInputField: {
+ value: function () {
+ this._inputField.element.blur();
+ }
+ },
+
+ handleInputAction: {
+ value: function() {
+ this._inputField.value = this._selectedOption.name;
+ this._blurInputField();
+ }
+ },
+
+ handleDownKeyPress: {
+ value: function(event) {
+ switch (event.target.component) {
+ case this._inputField:
+ if (this.options && this.options.length > 0) {
+ this._navigateInOptions(1)
+ }
+ break;
+ }
+ }
+ },
+
+ handleUpKeyPress: {
+ value: function(event) {
+ switch (event.target.component) {
+ case this._inputField:
+ if (this.options && this.options.length > 0) {
+ this._navigateInOptions(-1);
+ }
+ break;
+ }
+ }
+ },
+
+ _selectOption: {
+ value: function (option) {
+ if (!this._typedValue) {
+ this._typedValue = this._inputField.value;
+ }
+ this._optionsController.select(option);
+ this._inputField.value = this._optionsController.selection[0].label;
+ this._selectedOption = option;
+ }
+ },
+
+ _stopScrollingOptions: {
+ value: function () {
+ this._optionsController.clearSelection();
+ this._selectedOption = null;
+ this._inputField.value = this._typedValue;
+ this._typedValue = null;
+ }
+ },
+
+ _navigateInOptions: {
+ value: function(distance) {
+ var currentIndex = this._optionsController.organizedContent.indexOf(this._optionsController.selection[0]),
+ newIndex = currentIndex + distance,
+ contentLength = this._optionsController.organizedContent.length;
+ if (newIndex < -1) {
+ newIndex = contentLength -1;
+ }
+ if (newIndex == -1 || newIndex == contentLength) {
+ this._inputField.value = this._typedValue;
+ this._stopScrollingOptions();
+ } else {
+ this._selectOption(this._optionsController.organizedContent[newIndex % contentLength]);
+ }
+ }
+ },
+
+ _clearInput: {
+ value: function() {
+ this._typedValue = null;
+ this._inputField.value = null;
+ }
+ }
+});
diff --git a/blue-shark/ui/select.info/sample/index.html b/blue-shark/ui/select.info/sample/index.html
new file mode 100644
index 0000000000..643ab114b7
--- /dev/null
+++ b/blue-shark/ui/select.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Select Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select.info/sample/package.json b/blue-shark/ui/select.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/select.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/select.info/sample/ui/main.reel/_main.css b/blue-shark/ui/select.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..f2f7edef66
--- /dev/null
+++ b/blue-shark/ui/select.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,14 @@
+.Main {
+
+}
+
+h3 {
+ /* margin-bottom: 20em; */
+}
+
+.scrollView-container {
+ display: flex;
+ position: relative;
+ min-width: 15em;
+ outline: 1px solid red;
+}
diff --git a/blue-shark/ui/select.info/sample/ui/main.reel/main.css b/blue-shark/ui/select.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e3f15a3909
--- /dev/null
+++ b/blue-shark/ui/select.info/sample/ui/main.reel/main.css
@@ -0,0 +1 @@
+.scrollView-container{display:-webkit-box;display:-ms-flexbox;display:flex;position:relative;min-width:15em;outline:1px solid red}
\ No newline at end of file
diff --git a/blue-shark/ui/select.info/sample/ui/main.reel/main.html b/blue-shark/ui/select.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..c9d81e99ae
--- /dev/null
+++ b/blue-shark/ui/select.info/sample/ui/main.reel/main.html
@@ -0,0 +1,101 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
Select
+
Default Select
+
+
+
+
+
+
diff --git a/blue-shark/ui/select.info/sample/ui/main.reel/main.js b/blue-shark/ui/select.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..90669567fd
--- /dev/null
+++ b/blue-shark/ui/select.info/sample/ui/main.reel/main.js
@@ -0,0 +1,32 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ fakeConverter: {
+ value: {
+ revert: function(value) {
+ console.log('revert');
+ var result = {
+ name: value.toUpperCase()
+ };
+ return result;
+ },
+ validator: {
+ validate: function(value) {
+ var isValid = true;
+ if (typeof value === 'string') {
+ isValid = value.indexOf("INVALID") == -1;
+ }
+ return isValid;
+ }
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/select.reel/_select.css b/blue-shark/ui/select.reel/_select.css
new file mode 100644
index 0000000000..a062142b1f
--- /dev/null
+++ b/blue-shark/ui/select.reel/_select.css
@@ -0,0 +1,137 @@
+.Select {
+ @apply --input-field;
+ user-select: none;
+
+ &:not(.montage--disabled, .is-read-only):focus { @apply --input-focus; }
+
+ &:hover:not(:focus) {
+ border-color: var(--primary--1);
+ }
+
+ /* Naked Select Style overrides */
+ &.Select--naked,
+ &.is-read-only {
+ background: none;
+ border: none;
+
+ &:hover { background: none; }
+
+ & .Select-icon {
+ background: none;
+ border: none;
+ }
+
+ & .Select-currentOption { flex: none; }
+ }
+
+ /* Disabled State */
+ @nest .Field.is-disabled & {
+ background: rgba(0, 0, 0, .1);
+ border-color: transparent;
+ opacity: .5;
+ pointer-events: none;
+ }
+}
+
+.Select > button {
+ display: flex;
+ box-sizing: border-box;
+ position: relative;
+ border: none;
+ font-size: 1em;
+ line-height: 1.2;
+ /* handles border */
+ height: calc(2rem - 2px);
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ font-weight: inherit;
+ width: 100%;
+ text-align: left;
+ background: none;
+ outline: none;
+ padding: 0;
+ padding: 0 .25em 0 .5em;
+ color: var(--grey-3);
+ appearance: none;
+ border-radius: inherit;
+ cursor: initial;
+
+ &:not(.montage--disabled, .is-read-only) {
+ cursor: pointer;
+ }
+}
+
+.Select.is-read-only > button { display: none; }
+
+.Select-currentOption {
+ position: absolute;
+ left: .5rem;
+ right: 2rem;
+ top: 50%;
+ transform: translateY(-50%);
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+}
+
+.Select-icon {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ position: absolute;
+ right: .25rem;
+ top: 50%;
+ margin-top: -.7rem;
+ width: 1.4rem;
+ height: 1.4rem;
+
+ & svg {
+ display: inline-block;
+ width: .9em;
+ height: .9em;
+ }
+
+ @nest .montage--disabled & {
+ opacity: 0;
+ width: 0;
+ }
+}
+
+/* Options Drop Down */
+
+.Select-options { background-color: var(--primary--3); }
+
+.Select-option {
+ padding: .25em .5em .25em 2em;
+ font-weight: inherit;
+ font-size: inherit;
+ line-height: 1.25em;
+ color: var(--white);
+ margin-top: -.05em;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ white-space: nowrap;
+
+ &:active { background: var(--color-selected); }
+
+ &.highlighted { background: var(--color-selected); }
+
+ &.selected {
+ padding-left: .7em;
+
+ &:before {
+ content: "\2713 ";
+ margin-right: .5em;
+ }
+ }
+}
+
+.Select-readOnly {
+ display: none;
+ color: var(--main-text-color);
+
+ @nest .Select.is-read-only & {
+ display: block;
+ }
+}
diff --git a/blue-shark/ui/select.reel/select-options.reel/_select-options.css b/blue-shark/ui/select.reel/select-options.reel/_select-options.css
new file mode 100644
index 0000000000..6293147afb
--- /dev/null
+++ b/blue-shark/ui/select.reel/select-options.reel/_select-options.css
@@ -0,0 +1,31 @@
+.SelectOptions {
+ position: absolute;
+ display: flex;
+ flex-direction: column;
+ visibility: hidden;
+ opacity: 0;
+ font-weight: inherit;
+ font-size: inherit;
+ line-height: inherit;
+ cursor: pointer;
+ z-index: 1000;
+ border-radius: 3px;
+ overflow: hidden;
+ transition: visibility .25s ease-in-out,
+ opacity .25s ease-in-out;
+ flex: 1;
+ transition-delay: .1s, .1s;
+ box-shadow: 0 0 6px rgba(0, 0, 0, .5);
+ /* places overlay overtop select */
+ transform: translateY(calc(-2.25em))
+}
+
+.SelectOptions.is-below-middle {
+ transform: translateY(calc(-100%));
+}
+
+.SelectOptions.montage-Overlay--visible {
+ visibility: visible;
+ opacity: 1;
+ transition-delay: 0s, 0s;
+}
diff --git a/blue-shark/ui/select.reel/select-options.reel/select-options.css b/blue-shark/ui/select.reel/select-options.reel/select-options.css
new file mode 100644
index 0000000000..7b49ae7ba4
--- /dev/null
+++ b/blue-shark/ui/select.reel/select-options.reel/select-options.css
@@ -0,0 +1 @@
+.SelectOptions{position:absolute;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;visibility:hidden;opacity:0;font-weight:inherit;font-size:inherit;line-height:inherit;cursor:pointer;z-index:1000;border-radius:3px;overflow:hidden;-webkit-transition:visibility .25s ease-in-out,opacity .25s ease-in-out;transition:visibility .25s ease-in-out,opacity .25s ease-in-out;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-transition-delay:.1s,.1s;transition-delay:.1s,.1s;box-shadow:0 0 6px rgba(0,0,0,.5);-webkit-transform:translateY(-2.25em);transform:translateY(-2.25em)}.SelectOptions.is-below-middle{-webkit-transform:translateY(-100%);transform:translateY(-100%)}.SelectOptions.montage-Overlay--visible{visibility:visible;opacity:1;-webkit-transition-delay:0s,0s;transition-delay:0s,0s}
\ No newline at end of file
diff --git a/blue-shark/ui/select.reel/select-options.reel/select-options.html b/blue-shark/ui/select.reel/select-options.reel/select-options.html
new file mode 100644
index 0000000000..3a0aa4c8de
--- /dev/null
+++ b/blue-shark/ui/select.reel/select-options.reel/select-options.html
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select.reel/select-options.reel/select-options.js b/blue-shark/ui/select.reel/select-options.reel/select-options.js
new file mode 100644
index 0000000000..f885a5102e
--- /dev/null
+++ b/blue-shark/ui/select.reel/select-options.reel/select-options.js
@@ -0,0 +1,242 @@
+/**
+ * @module ui/select-options.reel
+ */
+var Overlay = require("montage/ui/overlay.reel").Overlay,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer,
+ Composer = require("montage/composer/composer").Composer;
+
+/**
+ * @class SelectOptions
+ * @extends Overlay
+ */
+var SelectOptions = exports.SelectOptions = Overlay.specialize(/** @lends SelectOptions# */ {
+
+ optionsRepetition: {
+ value: null
+ },
+
+ _optionsHeight: {
+ value: null
+ },
+
+ __optionsHeight: {
+ get: function () {
+ return this._optionsHeight;
+ },
+ set: function (height) {
+ this._optionsHeight = height;
+ return this._optionsHeight;
+ }
+ },
+
+ __optionsMaxHeight: {
+ value: null
+ },
+
+ _optionsMaxHeight: {
+ get: function () {
+ return this.__optionsMaxHeight;
+ },
+ set: function (maxHeight) {
+ this.__optionsMaxHeight = maxHeight;
+ this.element.style.maxHeight = maxHeight - 16 + "px";
+ }
+ },
+
+ optionsMaxHeight: {
+ get: function () {
+ return this._optionsMaxHeight;
+ },
+ set: function (value) {
+ if (this._optionsMaxHeight !== value) {
+ this._optionsMaxHeight = value;
+ this.needsDraw = true;
+ }
+ }
+ },
+
+ _needsComputeBoundaries: {
+ value: false
+ },
+
+ enterDocument: {
+ value: function (isFirstTime) {
+ if (isFirstTime) {
+ this.addPathChangeListener("selectedValue", this, "handleSelectedValueChange");
+
+ var keyIdentifiers = this.constructor.KEY_IDENTIFIERS;
+
+ this._keyComposerMap = new Map();
+
+ this._keyComposerMap.set(
+ keyIdentifiers.escape,
+ KeyComposer.createKey(this, keyIdentifiers.escape, keyIdentifiers.escape)
+ );
+ }
+
+ Overlay.prototype.enterDocument.call(this, isFirstTime);
+ }
+ },
+
+ exitDocument: {
+ value: function () {
+ Overlay.prototype.exitDocument.call(this);
+ }
+ },
+
+ show: {
+ value: function () {
+ if (!this.isShown) {
+ this._keyComposerMap.get(this.constructor.KEY_IDENTIFIERS.escape).addEventListener("keyPress", this);
+ this.element.ownerDocument.defaultView.addEventListener("wheel", this, true);
+ this._saveInitialCenterPosition();
+ // remove class each time to calculate position from same spot
+ this.classList.remove("is-below-middle");
+ this._needsComputeBoundaries = true;
+
+ }
+
+ Overlay.prototype.show.call(this);
+ }
+ },
+
+ hide: {
+ value: function () {
+ if (this.isShown) {
+ this._keyComposerMap.get(this.constructor.KEY_IDENTIFIERS.escape).removeEventListener("keyPress", this);
+ this.element.ownerDocument.defaultView.removeEventListener("wheel", this, true);
+ }
+
+ Overlay.prototype.hide.call(this);
+ }
+ },
+
+ captureWheel: {
+ value: function (event) {
+ if (!this.element.contains(event.target) && this._isPositionChanged(event)) {
+ this.hide();
+ }
+ }
+ },
+
+ _saveInitialCenterPosition: {
+ value: function () {
+ if (this.anchor instanceof HTMLElement) {
+ var boundingClientRect = this.anchor.getBoundingClientRect();
+
+ this._initialCenterPositionX = boundingClientRect.left + (boundingClientRect.width / 2);
+ this._initialCenterPositionY = boundingClientRect.top + (boundingClientRect.height / 2);
+ }
+ }
+ },
+
+ _isPositionChanged: {
+ value: function (event) {
+ // debugger;
+ if (this.anchor instanceof HTMLElement) {
+ var boundingClientRect = this.anchor.getBoundingClientRect(),
+ newCenterPositionX = boundingClientRect.left + (boundingClientRect.width / 2),
+ newCenterPositionY = boundingClientRect.top + (boundingClientRect.height / 2);
+
+ if (this._initialCenterPositionX !== newCenterPositionX || this._initialCenterPositionY !== newCenterPositionY) {
+ var deltaX = Math.abs(this._initialCenterPositionX - newCenterPositionX),
+ deltaY = Math.abs(this._initialCenterPositionY - newCenterPositionY),
+ radius = 1; // todo implement touchmove + pointermove
+
+ return Composer.isCoordinateOutsideRadius(deltaX, deltaY, radius);
+ }
+ }
+
+ return false;
+ }
+ },
+
+ willDraw: {
+ value: function () {
+ Overlay.prototype.willDraw.call(this);
+
+ if (this.isShown) {
+ var optionsRepetitionBoundingClientRect = this.optionsRepetition.element.getBoundingClientRect();
+
+ this.__optionsHeight = optionsRepetitionBoundingClientRect.height;
+ this._anchorRect = this.anchor.getBoundingClientRect();
+ this._anchorWidth = this._anchorRect.width;
+
+ if (!this._needsComputeBoundaries) {
+
+ var documentHeight = this.element.ownerDocument.documentElement.clientHeight;
+ this._optionsMaxHeight = 100;
+ this._optionsMaxHeight = documentHeight - optionsRepetitionBoundingClientRect.top;
+
+ // check if the options would go outside the viewport
+ // if the bottom of the options is greater than document height
+ if (optionsRepetitionBoundingClientRect.bottom > documentHeight) {
+
+ // will the options fit above select?
+ if (this._anchorRect.top - this.__optionsHeight < 0) {
+ // is there more room above or below?
+ // check the middle point of the anchor to see if it's above or below the middle of documentHeight
+ if(documentHeight - (this._anchorRect.top - this._anchorRect.height / 2) > (documentHeight / 2)) {
+ // more room below
+ this._optionsMaxHeight = documentHeight - optionsRepetitionBoundingClientRect.top;
+ } else {
+ // more room above
+ this._optionsMaxHeight = this._anchorRect.top;
+ this.classList.add("is-below-middle");
+ }
+ } else {
+ // the options fit
+ this.classList.add("is-below-middle");
+ }
+
+ }
+
+ }
+ }
+ }
+ },
+
+ //@override super draw overlay method.
+ draw: {
+ value: function () {
+ var overlayElementStyle = this.element.style;
+
+ if (this.isShown) {
+ var position = this._drawPosition;
+
+ overlayElementStyle.top = position.top + "px";
+ overlayElementStyle.left = position.left + "px";
+
+ // set options minWidth
+ overlayElementStyle.minWidth = this._anchorWidth + "px";
+ overlayElementStyle.maxWidth = this._anchorWidth > 600 ? this._anchorWidth + "px" : 600 + "px";
+
+ if (this._needsComputeBoundaries) {
+ this._needsComputeBoundaries = false;
+ this.needsDraw = true;
+ }
+ }
+ }
+ }
+
+}, {
+
+ STYLE_VISIBILITY: {
+ value: {
+ hidden: "hidden",
+ visible: "visible"
+ }
+ },
+
+ KEY_IDENTIFIERS: {
+ value: {
+ escape: "escape"
+ }
+ }
+
+});
+
+
+SelectOptions.prototype.handleEscapeKeyPress = SelectOptions.prototype.hide;
+SelectOptions.prototype.handleSelectedValueChange = SelectOptions.prototype.hide;
+SelectOptions.prototype.handleResize = SelectOptions.prototype.hide;
diff --git a/blue-shark/ui/select.reel/select.css b/blue-shark/ui/select.reel/select.css
new file mode 100644
index 0000000000..451f58d279
--- /dev/null
+++ b/blue-shark/ui/select.reel/select.css
@@ -0,0 +1 @@
+.Select{font-weight:300;font-family:Lato,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:1em;color:#fff;width:100%;-webkit-tap-highlight-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;border:1px solid #535a61;background-color:#222b35;border-radius:4px;-webkit-transition-property:background-color,border-color,opacity;transition-property:background-color,border-color,opacity;-webkit-transition-duration:.25s;transition-duration:.25s;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.Select:hover{border-color:#9ca0a4}.Select:focus,.Select:hover{background-color:#29313b}.Select:focus{border-color:#2089d3}.Select.montage--disabled{border-color:transparent;opacity:.5;cursor:not-allowed}.Select.montage--disabled:hover{background-color:#222b35;border-color:transparent}.Select.montage--invalidText{border-color:#cf324f}.Select[readonly=readonly]{background-color:transparent;border:none;padding:0}.Select:not(.montage--disabled):not(.is-read-only):focus{outline:none;box-shadow:inset 0 0 0 1px #2089d3}.Select:hover:not(:focus){border-color:#9ca0a4}.Select.is-read-only,.Select.Select--naked{background:none;border:none}.Select.is-read-only:hover,.Select.Select--naked:hover{background:none}.Select.is-read-only .Select-icon,.Select.Select--naked .Select-icon{background:none;border:none}.Select.is-read-only .Select-currentOption,.Select.Select--naked .Select-currentOption{-webkit-box-flex:0;-ms-flex:none;flex:none}.Field.is-disabled .Select{background:rgba(0,0,0,.1);border-color:transparent;opacity:.5;pointer-events:none}.Select>button{display:-webkit-box;display:-ms-flexbox;display:flex;box-sizing:border-box;position:relative;border:none;font-size:1em;line-height:1.2;height:calc(2rem - 2px);font-family:inherit;font-size:inherit;line-height:inherit;font-weight:inherit;width:100%;text-align:left;background:none;outline:none;padding:0;padding:0 .25em 0 .5em;color:#e0e5e5;-webkit-appearance:none;-moz-appearance:none;appearance:none;border-radius:inherit;cursor:auto}.Select>button:not(.montage--disabled):not(.is-read-only){cursor:pointer}.Select.is-read-only>button{display:none}.Select-currentOption{position:absolute;left:8px;left:.5rem;right:32px;right:2rem;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.Select-icon{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:absolute;right:4px;right:.25rem;top:50%;margin-top:-11.2px;margin-top:-.7rem;width:22.4px;width:1.4rem;height:22.4px;height:1.4rem}.Select-icon svg{display:inline-block;width:.9em;height:.9em}.montage--disabled .Select-icon{opacity:0;width:0}.Select-options{background-color:#535a61}.Select-option{padding:.25em .5em .25em 2em;font-weight:inherit;font-size:inherit;line-height:1.25em;color:#fff;margin-top:-.05em;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.Select-option.highlighted,.Select-option:active{background:#0c5688}.Select-option.selected{padding-left:.7em}.Select-option.selected:before{content:"\2713 ";margin-right:.5em}.Select-readOnly{display:none;color:#bdbfc2}.Select.is-read-only .Select-readOnly{display:block}
\ No newline at end of file
diff --git a/blue-shark/ui/select.reel/select.html b/blue-shark/ui/select.reel/select.html
new file mode 100644
index 0000000000..2856bb69f1
--- /dev/null
+++ b/blue-shark/ui/select.reel/select.html
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/select.reel/select.js b/blue-shark/ui/select.reel/select.js
new file mode 100644
index 0000000000..6f8f9f49fb
--- /dev/null
+++ b/blue-shark/ui/select.reel/select.js
@@ -0,0 +1,347 @@
+/**
+ * @module ui/select.reel
+ */
+var Component = require("montage/ui/component").Component,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer,
+ SelectOptions = require("blue-shark/ui/select.reel/select-options.reel").SelectOptions;
+
+
+/**
+ * @class Select
+ * @extends Component
+ */
+var Select = exports.Select = Component.specialize({
+
+ converter: {
+ value: null
+ },
+
+ optionsOverlayComponent: {
+ value: null
+ },
+
+ _options: {
+ value: null
+ },
+
+ __highlightedOption: {
+ value: null
+ },
+
+ _highlightedOption: {
+ get: function () {
+ return this.__highlightedOption;
+ },
+ set: function (option) {
+ if (option !== this.__highlightedOption) {
+ if (this.__highlightedOption) {
+ this.__highlightedOption._childComponents[0].classList.remove("highlighted");
+ }
+
+ if (option) {
+ option._childComponents[0].classList.add("highlighted");
+ this.__highlightedOption = option;
+ } else {
+ this.__highlightedOption = null;
+ }
+ }
+ }
+ },
+
+ options: {
+ set: function (content) {
+ this._originalContent = content;
+ },
+ get: function () {
+ return this._options;
+ }
+ },
+
+ _originalContent: {
+ value: null
+ },
+
+ __selectedValue: {
+ value: null
+ },
+
+ _selectedValue: {
+ set: function (_selectedValue) {
+ this.__selectedValue = _selectedValue;
+ this.dispatchOwnPropertyChange("selectedValue", this.selectedValue, false);
+ },
+ get: function () {
+ return this.__selectedValue;
+ }
+ },
+
+ selectedValue: {
+ set: function (selectedValue) {
+ this.__selectedValue = this._hasOptionalValue && selectedValue === null ? NONE_OPTION_VALUE : selectedValue;
+ this.dispatchOwnPropertyChange("_selectedValue", selectedValue, false);
+ },
+ get: function () {
+ return this._hasOptionalValue && this.__selectedValue === NONE_OPTION_VALUE ? null : this._selectedValue;
+ }
+ },
+
+ _hasOptionalValue: {
+ value: false
+ },
+
+ hasOptionalValue: {
+ set: function (hasOptionalValue) {
+ hasOptionalValue = !!hasOptionalValue;
+ if (hasOptionalValue !== this._hasOptionalValue) {
+ this._hasOptionalValue = hasOptionalValue;
+ this._updateOptionsIfNeeded();
+ }
+ },
+ get: function () {
+ return this._hasOptionalValue;
+ }
+ },
+
+ enterDocument: {
+ value: function (isFirstTime) {
+ if (isFirstTime) {
+ this.addRangeAtPathChangeListener("_originalContent", this, "_handleOriginalContentChange");
+ }
+ }
+ },
+
+ prepareForActivationEvents: {
+ value: function () {
+ var keyboardIdentifiers = this.constructor.KEY_IDENTIFIERS,
+ keyboardIdentifiersKeys = Object.keys(keyboardIdentifiers),
+ keyboardIdentifier;
+
+ this._keyComposerMap = new Map();
+
+ for (var i = 0, length = keyboardIdentifiersKeys.length; i < length; i++) {
+ keyboardIdentifier = keyboardIdentifiers[keyboardIdentifiersKeys[i]];
+
+ this._keyComposerMap.set(
+ keyboardIdentifier,
+ KeyComposer.createKey(this, keyboardIdentifier, keyboardIdentifier)
+ );
+
+ this._keyComposerMap.get(keyboardIdentifier).addEventListener("keyPress", this);
+ }
+ }
+ },
+
+ handleKeyPress: {
+ value: function (event) {
+ var keyIdentifiers = this.constructor.KEY_IDENTIFIERS;
+
+ if (event.identifier === keyIdentifiers.tab && this.optionsOverlayComponent.isShown) {
+ event.preventDefault();
+ }
+ }
+ },
+
+ _toggleOptionsOverlay: {
+ value: function () {
+ this.element.focus();
+ this.optionsOverlayComponent.isShown ? this._hideOptionsOverlay() : this._showOptionsOverlay();
+ }
+ },
+
+ _showOptionsOverlay: {
+ value: function () {
+ if (!this.disabled) {
+ this.optionsOverlayComponent.element.focus();
+
+ if (!this.optionsOverlayComponent.isShown) {
+ this.optionsOverlayComponent.show();
+ this._highlightedOption = this.optionsOverlayComponent.templateObjects.options.selectedIterations[0];
+ }
+ this.optionsOverlayComponent.element.addEventListener("mouseover", this);
+ this.optionsOverlayComponent.element.addEventListener("mouseup", this);
+ }
+ }
+ },
+
+ _hasHighlightedOptionChanged: {
+ value: function () {
+ return (this.optionsOverlayComponent.isShown && this._highlightedOption == this.optionsOverlayComponent.templateObjects.options.selectedIterations[0]);
+ }
+ },
+
+ handleMouseup: {
+ value: function() {
+ this._hasHighlightedOptionChanged() ? this._toggleOptionsOverlay() : this._selectOption();
+ }
+ },
+
+ _hideOptionsOverlay: {
+ value: function () {
+ if (this.optionsOverlayComponent.isShown) {
+ this.optionsOverlayComponent.hide();
+ }
+ this.optionsOverlayComponent.element.removeEventListener("mouseover", this);
+ this.optionsOverlayComponent.element.removeEventListener("mouseup", this);
+ }
+ },
+
+ _handleOriginalContentChange: {
+ value: function() {
+ var options = null;
+
+ if (this._originalContent) {
+ if (this.converter) {
+ options = this.converter.convert(this._originalContent);
+ } else {
+ var isConverterMissing = false;
+ options = this._originalContent.map(function(x) {
+ if (typeof x === 'string') {
+ isConverterMissing = true;
+ return {
+ label: x,
+ value: x
+ };
+ }
+ return x;
+ });
+ if (isConverterMissing) {
+ console.warn('Usage of strings array in select component is deprecated, please use a converter instead.');
+ }
+ }
+
+ var indexNoneOption = options.indexOf(NONE_SELECT_OPTION);
+
+ if (this._hasOptionalValue && indexNoneOption === -1) { // missing
+ options.unshift(NONE_SELECT_OPTION)
+
+ } else if (!this._hasOptionalValue && indexNoneOption > -1) { //
+ options.splice(indexNoneOption, 1)
+ }
+ }
+
+ this._options = options;
+ }
+ },
+
+ _updateOptionsIfNeeded: {
+ value: function () {
+ if (this._options) {
+ this.options = this._originalContent; // trigger setter.
+ }
+ }
+ },
+
+ _nextOption: {
+ value: function (event) {
+ if (this._options && this._options.length > 0) {
+ this._navigateInOptions(1);
+ }
+ }
+ },
+
+ _previousOption: {
+ value: function () {
+ if (this._options && this._options.length > 0) {
+ this._navigateInOptions(-1);
+ }
+ }
+ },
+
+ _selectOption: {
+ value: function (e) {
+ if (this.optionsOverlayComponent.isShown && this._highlightedOption) {
+ this.optionsOverlayComponent.templateObjects.options.selection = [this._highlightedOption.object];
+ }
+ }
+ },
+
+ _navigateInOptions: {
+ value: function(distance) {
+ var currentIndex = this.optionsOverlayComponent.templateObjects.options.iterations.indexOf(this._highlightedOption),
+ newIndex = currentIndex + distance,
+ contentLength = this.optionsOverlayComponent.templateObjects.options.iterations.length;
+
+ if (newIndex < -1) {
+ newIndex = contentLength -1;
+ }
+ if (newIndex != -1 && newIndex != contentLength) {
+ this._highlightedOption = this.optionsOverlayComponent.templateObjects.options.iterations[newIndex % contentLength];
+ }
+ }
+ },
+
+ _handledUpKeyPress: {
+ value: function (e) {
+ if (!this.optionsOverlayComponent.isShown) {
+ this._toggleOptionsOverlay();
+ } else {
+ this._previousOption();
+ e.preventDefault();
+ }
+ }
+ },
+
+ _handleDownKeyPress: {
+ value: function (e) {
+ if (!this.optionsOverlayComponent.isShown) {
+ this._toggleOptionsOverlay();
+ } else {
+ this._nextOption();
+ e.preventDefault();
+ }
+ }
+ },
+
+ _handleSpaceKeyPress: {
+ value: function () {
+ if (!this.optionsOverlayComponent.isShown || this._highlightedOption == this.optionsOverlayComponent.templateObjects.options.selectedIterations[0]) {
+ this._toggleOptionsOverlay();
+ } else {
+ this._selectOption();
+ }
+ }
+ },
+
+ handleMouseover: {
+ value: function(event) {
+ if (event.target.component) {
+ var target = event.target.component.iteration;
+
+ if (target !== this._highlightedOption) {
+ this._highlightedOption = target;
+ }
+ }
+ }
+ },
+
+ _handleEnterKeyPress: {
+ value: function () {
+ this._hasHighlightedOptionChanged() ? this._toggleOptionsOverlay() : this._selectOption();
+ }
+ }
+
+}, {
+
+ KEY_IDENTIFIERS: {
+ value: {
+ space: "space",
+ enter: "enter",
+ up: "up",
+ down: "down",
+ tab: "tab"
+ }
+ }
+});
+
+
+Select.prototype.handleSpaceKeyPress = Select.prototype._handleSpaceKeyPress;
+Select.prototype.handleUpKeyPress = Select.prototype._handledUpKeyPress;
+Select.prototype.handleDownKeyPress = Select.prototype._handleDownKeyPress;
+Select.prototype.handleSelectButtonAction = Select.prototype._toggleOptionsOverlay;
+Select.prototype.handleEnterKeyPress = Select.prototype._handleEnterKeyPress;
+Select.prototype.exitDocument = Select.prototype._hideOptionsOverlay;
+
+
+var NONE_OPTION_LABEL = "none",
+ NONE_OPTION_VALUE = "_none",
+ NONE_SELECT_OPTION = {label: NONE_OPTION_LABEL, value: NONE_OPTION_VALUE};
diff --git a/blue-shark/ui/sink.info/sample/index.html b/blue-shark/ui/sink.info/sample/index.html
new file mode 100644
index 0000000000..c2d98428eb
--- /dev/null
+++ b/blue-shark/ui/sink.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Widget Examples
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/sink.info/sample/package.json b/blue-shark/ui/sink.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/sink.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/sink.info/sample/ui/main.reel/_main.css b/blue-shark/ui/sink.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..fd2f5e9d2b
--- /dev/null
+++ b/blue-shark/ui/sink.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,8 @@
+.Main {}
+
+.scrollContainer {
+ display: flex;
+ flex-direction: column;
+ height: 300px;
+ width: 300px;
+}
diff --git a/blue-shark/ui/sink.info/sample/ui/main.reel/main.css b/blue-shark/ui/sink.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..fc571b4c94
--- /dev/null
+++ b/blue-shark/ui/sink.info/sample/ui/main.reel/main.css
@@ -0,0 +1 @@
+.scrollContainer{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:300px;width:300px}
\ No newline at end of file
diff --git a/blue-shark/ui/sink.info/sample/ui/main.reel/main.html b/blue-shark/ui/sink.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..e83e98dd07
--- /dev/null
+++ b/blue-shark/ui/sink.info/sample/ui/main.reel/main.html
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
Widget Examples
+
Default
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/sink.info/sample/ui/main.reel/main.js b/blue-shark/ui/sink.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..de3171b166
--- /dev/null
+++ b/blue-shark/ui/sink.info/sample/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/spinner.info/sample/index.html b/blue-shark/ui/spinner.info/sample/index.html
new file mode 100644
index 0000000000..3ce00a9b28
--- /dev/null
+++ b/blue-shark/ui/spinner.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
tree-view.info
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/spinner.info/sample/package.json b/blue-shark/ui/spinner.info/sample/package.json
new file mode 100644
index 0000000000..777e14850c
--- /dev/null
+++ b/blue-shark/ui/spinner.info/sample/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
diff --git a/blue-shark/ui/spinner.info/sample/ui/main.reel/main.html b/blue-shark/ui/spinner.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..64377ec238
--- /dev/null
+++ b/blue-shark/ui/spinner.info/sample/ui/main.reel/main.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/spinner.info/sample/ui/main.reel/main.js b/blue-shark/ui/spinner.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..2bac0d7cfe
--- /dev/null
+++ b/blue-shark/ui/spinner.info/sample/ui/main.reel/main.js
@@ -0,0 +1,3 @@
+var Component = require("montage/ui/component").Component;
+
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/spinner.reel/_spinner.css b/blue-shark/ui/spinner.reel/_spinner.css
new file mode 100644
index 0000000000..97b09d56b5
--- /dev/null
+++ b/blue-shark/ui/spinner.reel/_spinner.css
@@ -0,0 +1,43 @@
+@keyframes flash {
+ 0% { fill: var(--white);}
+ 35% { fill: #238EC2;}
+}
+
+.Spinner {
+
+ &.center-in-container {
+ display: flex;
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ justify-content: center;
+ align-items: center;
+ z-index: 100;
+ background-color: var(--primary--7)
+ }
+}
+
+.Spinner svg {
+ width: 4rem;
+ height: 4rem;
+
+ & polyline { fill: #238EC2; }
+
+ & #corral-1,
+ & #corral-2,
+ & #corral-3,
+ & #corral-4,
+ & #corral-5,
+ & #corral-6 {
+ animation: flash .6s infinite linear;
+ }
+
+ & #corral-6 { animation-delay: -.3s; }
+ & #corral-5 { animation-delay: -.2s; }
+ & #corral-4 { animation-delay: -.1s; }
+ & #corral-3 { animation-delay: 0s; }
+ & #corral-2 { animation-delay: .1s; }
+ & #corral-1 { animation-delay: .2s; }
+}
diff --git a/blue-shark/ui/spinner.reel/spinner.css b/blue-shark/ui/spinner.reel/spinner.css
new file mode 100644
index 0000000000..bbd872ddc0
--- /dev/null
+++ b/blue-shark/ui/spinner.reel/spinner.css
@@ -0,0 +1 @@
+@-webkit-keyframes flash{0%{fill:#fff}35%{fill:#238ec2}}@keyframes flash{0%{fill:#fff}35%{fill:#238ec2}}.Spinner.center-in-container{display:-webkit-box;display:-ms-flexbox;display:flex;position:absolute;top:0;left:0;right:0;bottom:0;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;z-index:100;background-color:#181e25}.Spinner svg{width:64px;width:4rem;height:64px;height:4rem}.Spinner svg polyline{fill:#238ec2}.Spinner svg #corral-1,.Spinner svg #corral-2,.Spinner svg #corral-3,.Spinner svg #corral-4,.Spinner svg #corral-5,.Spinner svg #corral-6{-webkit-animation:flash .6s infinite linear;animation:flash .6s infinite linear}.Spinner svg #corral-6{-webkit-animation-delay:-.3s;animation-delay:-.3s}.Spinner svg #corral-5{-webkit-animation-delay:-.2s;animation-delay:-.2s}.Spinner svg #corral-4{-webkit-animation-delay:-.1s;animation-delay:-.1s}.Spinner svg #corral-3{-webkit-animation-delay:0s;animation-delay:0s}.Spinner svg #corral-2{-webkit-animation-delay:.1s;animation-delay:.1s}.Spinner svg #corral-1{-webkit-animation-delay:.2s;animation-delay:.2s}
\ No newline at end of file
diff --git a/blue-shark/ui/spinner.reel/spinner.html b/blue-shark/ui/spinner.reel/spinner.html
new file mode 100644
index 0000000000..478069723e
--- /dev/null
+++ b/blue-shark/ui/spinner.reel/spinner.html
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/spinner.reel/spinner.js b/blue-shark/ui/spinner.reel/spinner.js
new file mode 100644
index 0000000000..0d8447dca0
--- /dev/null
+++ b/blue-shark/ui/spinner.reel/spinner.js
@@ -0,0 +1,3 @@
+var Component = require("montage/ui/component").Component;
+
+exports.Spinner = Component.specialize();
diff --git a/blue-shark/ui/tables/table-editable.info/sample/index.html b/blue-shark/ui/tables/table-editable.info/sample/index.html
new file mode 100644
index 0000000000..91682c15c5
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Table Editable Example
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tables/table-editable.info/sample/package.json b/blue-shark/ui/tables/table-editable.info/sample/package.json
new file mode 100644
index 0000000000..7f24763f62
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../../node_modules/montage",
+ "blue-shark": "../../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.css b/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..2e1e2279f8
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.css
@@ -0,0 +1,24 @@
+.Main {
+ /* only for demo */
+ padding: 5em;
+ font-family: Lato,Helvetica,Arial,sans-serif;
+}
+
+/*
+
+Layout Code
+
+*/
+
+/* Header & Body Cell widths */
+
+.sampleTable .Table-cells > div:nth-child(1),
+.TableHeaderLayout-row .TableHeaderLayout-cell:nth-child(1) {}
+
+.sampleTable .Table-cells > div:nth-child(2),
+.TableHeaderLayout-row .TableHeaderLayout-cell:nth-child(2) {}
+
+.sampleTable .Table-cells > div:nth-child(3),
+.TableHeaderLayout-row .TableHeaderLayout-cell:nth-child(3) {
+ min-width: 6em;
+}
diff --git a/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.html b/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..1fea4459d4
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.html
@@ -0,0 +1,140 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.js b/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..58f7a6cb08
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/ui/main.reel/main.js
@@ -0,0 +1,52 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ prepareForActivationEvents: {
+ value: function () {
+ this.addEventListener("action", this);
+ }
+ },
+
+ handleAddButtonAction: {
+ value: function () {
+ this.editableTable.showNewEntryRow();
+ }
+ },
+
+ handleDeleteButtonAction: {
+ value: function () {
+ this.editableTable.deleteSelectedRows();
+ }
+ },
+
+ tableDidCancelEditingNewEntry: {
+ value: function (table, object, row) {
+ console.log("table cancel adding object: ", object)
+ }
+ },
+
+ tableWillAddNewEntry: {
+ value: function (table, object, contentController) {
+ console.log("table will add object: ", object)
+ }
+ },
+
+ tableWillStartEditingNewEntry: {
+ value: function (table, object, contentController) {
+ console.log("table will edit object: ", object)
+
+ if (!contentController.has(object)) {
+ this.newObject = object;
+ }
+ }
+ }
+
+});
diff --git a/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.css b/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.css
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.css
@@ -0,0 +1 @@
+
diff --git a/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.html b/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.html
new file mode 100644
index 0000000000..b363507d72
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.html
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.js b/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.js
new file mode 100644
index 0000000000..d0cd68cb2c
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.info/sample/ui/table-new-row.reel/table-new-row.js
@@ -0,0 +1,32 @@
+/**
+ * @module ui/table-new-row.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class TableNewRow
+ * @extends Component
+ */
+exports.TableNewRow = Component.specialize({
+
+ fakeConverter: {
+ value: {
+ convert: function(value) {
+ return value;
+ },
+ revert: function(value) {
+ if (this.validator(value)) {
+ return value;
+ }
+ },
+ validator: function (value) {
+ if (+value === parseInt(value)) {
+ return true;
+ }
+ else {
+ throw new Error("Value must be an integer.");
+ }
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/tables/table-editable.reel/_table-editable.css b/blue-shark/ui/tables/table-editable.reel/_table-editable.css
new file mode 100644
index 0000000000..38a3917de6
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.reel/_table-editable.css
@@ -0,0 +1,172 @@
+:root {
+ --table-newRow-bg: var(--black);
+}
+
+.TableEditable { position: relative; }
+
+.Table-row-group {
+ position: relative;
+
+ /* row dimmer */
+ &:after {
+ display: none;
+ content: '';
+ position: absolute;
+ background: rgba(0,0,0,.6);
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ pointer-events: none;
+ }
+
+ /* inactive row dimmer */
+ &.is-active:after {
+ display: block;
+ pointer-events: all;
+ }
+}
+
+.Table-row-fields {
+
+ &.is-active {
+ position: relative;
+ z-index: 100;
+
+ &:after {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ border: 1px solid var(--primary--3);
+ border-bottom: none;
+ pointer-events: none;
+ }
+ }
+}
+
+.Table-row {
+ position: relative;
+ z-index: 0;
+ transition: all .5s ease-in-out;
+ flex-wrap: wrap;
+
+ &.is-active {
+ z-index: 20;
+ }
+}
+
+/* Select Cells */
+
+.Table-selectAll,
+.Table-selectRow {
+ display: none !important;
+ align-self: stretch;
+ align-items: center;
+ flex-grow: 0;
+ padding: .25em;
+ padding-left: .5em;
+ padding-right: 0;
+ border-right: 1px solid var(--table-border-color);
+}
+
+.Table.has-multipleSelection .Table-selectAll,
+.Table.has-multipleSelection .Table-selectRow {
+ display: flex !important;
+}
+
+/* Controls */
+.TableEditable-rowControls {
+ max-height: 0;
+ position: relative;
+ width: 100%;
+ background: var(--primary);
+ border: 1px solid var(--primary--3);
+ border-top: none;
+ box-shadow: 0 4px 4px var(--shadow-1);
+ visibility: hidden;
+ overflow: hidden;
+
+ &.is-active {
+ max-height: 10rem;
+ visibility: visible;
+ }
+}
+
+.Table-row-info {
+ display: flex;
+ background-color: var(--red);
+ color: var(--white);
+ max-height: 0px;
+ overflow: hidden;
+
+ &.has-errors {
+ max-height: 10rem;
+ transition: max-height 0.5s ease-in-out;
+ transition-delay: .25s;
+ }
+
+ & .Table-row-info-messages { align-self: center; }
+
+ & svg {
+ margin-left: 1rem;
+ margin-top: .5rem;
+ width: 2rem;
+ height: 2rem;
+ color: color(var(--red) shade(15%));
+ }
+}
+
+.actions {
+ border-top: 1px solid var(--table-border-color);
+ display: flex;
+ justify-content: flex-end;
+ padding: .5rem;
+}
+
+/* New Row */
+
+.Table-body-top {
+ border: 1px solid var(--primary--3);
+ border-bottom: none;
+}
+
+.TableEditable .Table-body-top.Table-row-group {
+ /* magic # based on checkbox width */
+ background-color: var(--primary--7);
+}
+
+.TableEditable .Table.has-multipleSelection .Table-body-top.Table-row-group .Table-cells {
+ padding-left: 2.55em;
+}
+
+
+/* Header Cells */
+
+.TableHeaderLayout-row { display: flex; }
+
+/*
+
+BODY
+
+*/
+
+/* Row Cells */
+
+.TableEditable .Table-cells {
+ flex: 1;
+ display: flex;
+ align-items: stretch;
+
+ /* Row Cell */
+
+ & > div {
+ position: relative;
+ padding: .5em;
+ flex: 1;
+ display: flex;
+ align-items: center;
+ }
+}
diff --git a/blue-shark/ui/tables/table-editable.reel/table-editable.css b/blue-shark/ui/tables/table-editable.reel/table-editable.css
new file mode 100644
index 0000000000..7d207212b0
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.reel/table-editable.css
@@ -0,0 +1 @@
+.Table-row-group,.TableEditable{position:relative}.Table-row-group:after{display:none;content:"";position:absolute;background:rgba(0,0,0,.6);top:0;left:0;right:0;bottom:0;pointer-events:none}.Table-row-group.is-active:after{display:block;pointer-events:all}.Table-row-fields.is-active{position:relative;z-index:100}.Table-row-fields.is-active:after{content:"";position:absolute;top:0;left:0;right:0;bottom:0;border:1px solid #535a61;border-bottom:none;pointer-events:none}.Table-row{position:relative;z-index:0;-webkit-transition:all .5s ease-in-out;transition:all .5s ease-in-out;-ms-flex-wrap:wrap;flex-wrap:wrap}.Table-row.is-active{z-index:20}.Table-selectAll,.Table-selectRow{display:none!important;-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;padding:.25em;padding-left:.5em;padding-right:0;border-right:1px solid #181e25}.Table.has-multipleSelection .Table-selectAll,.Table.has-multipleSelection .Table-selectRow{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important}.TableEditable-rowControls{max-height:0;position:relative;width:100%;background:#222b35;border:1px solid #535a61;border-top:none;box-shadow:0 4px 4px rgba(0,0,0,.3);visibility:hidden;overflow:hidden}.TableEditable-rowControls.is-active{max-height:160px;max-height:10rem;visibility:visible}.Table-row-info{display:-webkit-box;display:-ms-flexbox;display:flex;background-color:#cf324f;color:#fff;max-height:0;overflow:hidden}.Table-row-info.has-errors{max-height:160px;max-height:10rem;-webkit-transition:max-height .5s ease-in-out;transition:max-height .5s ease-in-out;-webkit-transition-delay:.25s;transition-delay:.25s}.Table-row-info .Table-row-info-messages{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.Table-row-info svg{margin-left:16px;margin-left:1rem;margin-top:8px;margin-top:.5rem;width:32px;width:2rem;height:32px;height:2rem;color:#b02b43}.actions{border-top:1px solid #181e25;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;padding:8px;padding:.5rem}.Table-body-top{border:1px solid #535a61;border-bottom:none}.TableEditable .Table-body-top.Table-row-group{background-color:#181e25}.TableEditable .Table.has-multipleSelection .Table-body-top.Table-row-group .Table-cells{padding-left:2.55em}.TableHeaderLayout-row{display:-webkit-box;display:-ms-flexbox;display:flex}.TableEditable .Table-cells{-webkit-box-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch}.TableEditable .Table-cells>div{position:relative;padding:.5em;-webkit-box-flex:1;-ms-flex:1;flex:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}
\ No newline at end of file
diff --git a/blue-shark/ui/tables/table-editable.reel/table-editable.html b/blue-shark/ui/tables/table-editable.reel/table-editable.html
new file mode 100644
index 0000000000..d6aaecae9c
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.reel/table-editable.html
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tables/table-editable.reel/table-editable.js b/blue-shark/ui/tables/table-editable.reel/table-editable.js
new file mode 100644
index 0000000000..ae74de79b9
--- /dev/null
+++ b/blue-shark/ui/tables/table-editable.reel/table-editable.js
@@ -0,0 +1,421 @@
+/**
+ * @module ui/table-editable.reel
+ */
+var Component = require("montage/ui/component").Component,
+ Checkbox = require("montage/ui/checkbox.reel").Checkbox,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer,
+ Composer = require("montage/composer/composer").Composer,
+ _ = require("lodash");
+
+function RowEntry(object) {
+ this.object = object;
+ this.selected = false;
+}
+
+
+function findRowElement(el) {
+ while (el) {
+ if (el.getAttribute("data-montage-id") == 'rowEntry') {
+ break;
+ }
+ el = el.parentElement;
+ }
+ return el;
+}
+
+/**
+ * @class TableEditable
+ * @extends Component
+ */
+var TableEditable = exports.TableEditable = Component.specialize({
+
+ showRowActions: {
+ value: true
+ },
+
+ canAddWithError: {
+ value: true
+ },
+
+ isMultiSelectionEnabled: {
+ value: true
+ },
+
+ rows: {
+ set: function (rows) {
+ this._rows = rows;
+ },
+ get: function () {
+ if (!this._rows) {
+ this._rows = []
+ }
+
+ return this._rows;
+ }
+ },
+
+ templateDidLoad: {
+ value: function () {
+ this.addRangeAtPathChangeListener("rows", this, "handleRowsChange");
+ }
+ },
+
+ _shouldShowNewEntryRow: {
+ set: function (shouldShowNewEntryRow) {
+ shouldShowNewEntryRow = !!shouldShowNewEntryRow;
+
+ if (this.__shouldShowNewEntryRow !== shouldShowNewEntryRow) {
+ document.addEventListener("wheel", this, true);
+ this.__shouldShowNewEntryRow = shouldShowNewEntryRow;
+ this._canShowNewEntryRow = true;
+ this.needsDraw = true;
+ }
+ },
+ get: function () {
+ return this.__shouldShowNewEntryRow;
+ }
+ },
+
+ _shouldHideNewEntryRow: {
+ set: function (shouldHideNewEntryRow) {
+ shouldHideNewEntryRow = !!shouldHideNewEntryRow;
+
+ if (this.__shouldHideNewEntryRow !== shouldHideNewEntryRow) {
+ this.__shouldHideNewEntryRow = shouldHideNewEntryRow;
+ this._canShowNewEntryRow = false;
+ this.needsDraw = true;
+ }
+ },
+ get: function () {
+ return this.__shouldHideNewEntryRow;
+ }
+ },
+
+ //Public API
+
+ isAddingNewEntry: {
+ get: function () {
+ return !!this._canShowNewEntryRow;
+ }
+ },
+
+ currentNewEntry: {
+ get: function () {
+ if (!this.isAddingNewEntry) {
+ this._currentNewEntry = null;
+ }
+
+ return this._currentNewEntry;
+ }
+ },
+
+ hideNewEntryRow: {
+ value: function () {
+ this._cancelAddingNewEntry();
+ }
+ },
+
+ showNewEntryRow: {
+ value: function () {
+ this._shouldShowNewEntryRow = true;
+ }
+ },
+
+ deleteSelectedRows: {
+ value: function () {
+ var rowEntry,
+ index;
+
+ while (this.selectedRows.length) {
+ rowEntry = this.selectedRows[0];
+
+ if ((index = this.rows.indexOf(rowEntry.object)) > -1) {
+ this.callDelegateMethod(
+ "tableWillDeleteEntry",
+ rowEntry.object
+ );
+ this.rows.splice(index, 1);
+ }
+ }
+ }
+ },
+
+ findRowIterationContainingElement: {
+ value: function (element) {
+ return this._rowRepetitionComponent._findIterationContainingElement(element);
+ }
+ },
+
+ //END Public API
+
+ prepareForActivationEvents: {
+ value: function () {
+ this.addEventListener("action", this);
+ this.element.addEventListener("focusin", this);
+
+ var keyboardIdentifiers = this.constructor.KEY_IDENTIFIERS,
+ keyboardIdentifiersKeys = Object.keys(keyboardIdentifiers),
+ keyboardIdentifier;
+
+ this._keyComposerMap = new Map();
+
+ for (var i = 0, length = keyboardIdentifiersKeys.length; i < length; i++) {
+ keyboardIdentifier = keyboardIdentifiers[keyboardIdentifiersKeys[i]];
+
+ this._keyComposerMap.set(
+ keyboardIdentifier,
+ KeyComposer.createKey(this, keyboardIdentifier, keyboardIdentifier)
+ );
+
+ this._keyComposerMap.get(keyboardIdentifier).addEventListener("keyPress", this);
+ }
+ if (this.showRowActions) {
+ this._rowRepetitionComponent.element.addEventListener("click", this);
+ }
+ }
+ },
+
+ handleFocusin: {
+ value: function(e) {
+ this.handleClick(e);
+ }
+ },
+
+ exitDocument: {
+ value: function() {
+ this._cancelAddingNewEntry();
+ if(this.showRowActions) {
+ this._rowRepetitionComponent.element.removeEventListener("click", this);
+ }
+ }
+ },
+
+ handleKeyPress: {
+ value: function (event) {
+ var keyIdentifiers = this.constructor.KEY_IDENTIFIERS;
+ }
+ },
+
+ _activeRow: {
+ value: null
+ },
+
+ _activeRowEntry: {
+ value: null
+ },
+
+ _showControls: {
+ value: function() {
+ if (this._activeRow) {
+ this._activeRow.classList.add('is-active');
+ this._activeRow.appendChild(this.rowControls);
+ } else {
+ this._tableBodyTopElement.appendChild(this.rowControls);
+ }
+ this._rowRepetitionComponent.element.classList.add('is-active');
+ this.rowControls.classList.add('is-active');
+ }
+ },
+
+ _hideControls: {
+ value: function() {
+ if(this._activeRow) {
+ this._activeRow.classList.remove('is-active');
+ this._activeRow = this._activeRowEntry = null;
+ }
+ this.rowControls.classList.remove('is-active');
+ this._rowRepetitionComponent.element.classList.remove('is-active');
+ }
+ },
+
+ handleClick: {
+ value: function(e) {
+ if(this.showRowActions) {
+ var element = findRowElement(e.target);
+ if (element && element.component !== this._activeRowEntry) {
+ if (this._activeRow) {
+ this._activeRow.classList.remove('is-active');
+ }
+ this._activeRow = this.findRowIterationContainingElement(element).firstElement;
+ this._activeRowEntry = element.component;
+ this._activeRowOriginalObject = _.cloneDeep(this._activeRowEntry.object);
+ this._showControls();
+
+ // if the event target is not in the row or the row controls
+ } else if(this._activeRow && !this._activeRow.contains(e.target) && !this.rowControls.contains(e.target)) {
+ this.handleCancelAction();
+ }
+ }
+ }
+ },
+
+ handleRowsChange: {
+ value: function () {
+ if (this._inDocument) {
+ this._toggleAllComponent.checked = this.rows.length > 0 && this.selectedRows &&
+ this.selectedRows.length === this.rows.length;
+ }
+ }
+ },
+
+ handleCancelAction: {
+ value: function () {
+ if(this._activeRow) {
+ this._activeRowEntry.object = this._activeRowOriginalObject;
+ }
+ document.activeElement.blur();
+ this._cancelAddingNewEntry();
+ this._hideControls();
+ }
+ },
+
+ handleDoneAction: {
+ value: function () {
+ if (this._stopAddingNewEntry()) {
+ document.activeElement.blur();
+ this._hideControls();
+ }
+ }
+ },
+
+ handleAction: {
+ value: function (event) {
+ var target = event.target;
+ if (this._toggleAllComponent.element.contains(target.element)) {
+ this._handleToggleAllAction(event);
+ } else if (target instanceof Checkbox && this._rowRepetitionComponent.element.contains(target.element)) {
+ this._toggleAllComponent.checked = this.selectedRows && this.selectedRows.length === this.rows.length;
+ }
+ }
+ },
+
+ _getNewEntry: {
+ value: function () {
+ var defaultNewEntry = {};
+
+ defaultNewEntry = this.callDelegateMethod(
+ "tableWillUseNewEntry",
+ this,
+ defaultNewEntry
+ ) || defaultNewEntry;
+
+ if (Promise.is(defaultNewEntry)) {
+ return defaultNewEntry.then(function (NewEntry) {
+ return new RowEntry(NewEntry);
+ });
+ }
+
+ return Promise.resolve(new RowEntry(defaultNewEntry));
+ }
+ },
+
+ _handleToggleAllAction: {
+ value: function() {
+ var self = this;
+
+ this._rowEntries.forEach(function (rowEntry) {
+ rowEntry.selected = !!self._toggleAllComponent.checked;
+ });
+ }
+ },
+
+ _cancelAddingNewEntry: {
+ value: function () {
+ if (this.isAddingNewEntry) {
+ this.callDelegateMethod(
+ "tableDidCancelEditingNewEntry",
+ this,
+ this.currentNewEntry.object,
+ this.contentController
+ );
+
+ this._shouldHideNewEntryRow = true;
+ }
+
+ }
+ },
+
+ _stopAddingNewEntry: {
+ value: function () {
+ var isValid = true;
+ if (!this.canAddWithError &&
+ this._activeRowEntry &&
+ this._activeRowEntry.templateObjects.errorController &&
+ typeof this._activeRowEntry.templateObjects.errorController.checkIsValid === 'function') {
+ isValid = this._activeRowEntry.templateObjects.errorController.checkIsValid();
+ }
+ if (isValid && this.isAddingNewEntry) {
+ this._activeRowEntry = null;
+ var shouldAddNewEntry = this.callDelegateMethod(
+ "tableWillAddNewEntry",
+ this,
+ this.currentNewEntry.object,
+ this.contentController
+ );
+
+ if (shouldAddNewEntry !== void 0 ? !!shouldAddNewEntry : true) {
+ this.contentController.add(this.currentNewEntry.object);
+ this.callDelegateMethod(
+ "tableDidAddNewEntry",
+ this,
+ this.currentNewEntry.object,
+ this.contentController
+ );
+ }
+
+ this._shouldHideNewEntryRow = true;
+ }
+ return isValid;
+ }
+ },
+
+ _startAddingNewEntry: {
+ value: function () {
+ var self = this;
+
+ return this._getNewEntry().then(function (newEntry) {
+ self._currentNewEntry = newEntry;
+ self._activeRowEntry = self.element.querySelector('[data-montage-id=newEntry]').component;
+
+ self.callDelegateMethod(
+ "tableWillStartEditingNewEntry",
+ self,
+ self.currentNewEntry.object,
+ self.contentController
+ );
+ self._showControls();
+
+ self.dispatchOwnPropertyChange("isAddingNewEntry", self.isAddingNewEntry);
+ self.dispatchOwnPropertyChange("currentNewEntry", self.currentNewEntry);
+ });
+ }
+ },
+
+ draw: {
+ value: function () {
+ if (this._shouldShowNewEntryRow) {
+ this.__shouldShowNewEntryRow = false;
+ this._startAddingNewEntry();
+
+ } else if (this._shouldHideNewEntryRow) {
+ this._shouldHideNewEntryRow = false;
+ this.dispatchOwnPropertyChange("isAddingNewEntry", this.isAddingNewEntry);
+ this.dispatchOwnPropertyChange("currentNewEntry", this.currentNewEntry);
+ this._hideControls();
+ }
+ }
+ }
+
+}, {
+
+ KEY_IDENTIFIERS: {
+ value: {
+ enter: "enter",
+ escape: "escape"
+ }
+ }
+});
+
+TableEditable.prototype.handleEnterKeyPress = TableEditable.prototype.handleDoneAction;
+TableEditable.prototype.handleEscapeKeyPress = TableEditable.prototype.handleCancelAction;
+
diff --git a/blue-shark/ui/tables/table-read-only.info/sample/index.html b/blue-shark/ui/tables/table-read-only.info/sample/index.html
new file mode 100644
index 0000000000..5ecd65a821
--- /dev/null
+++ b/blue-shark/ui/tables/table-read-only.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Table Example
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tables/table-read-only.info/sample/package.json b/blue-shark/ui/tables/table-read-only.info/sample/package.json
new file mode 100644
index 0000000000..7f24763f62
--- /dev/null
+++ b/blue-shark/ui/tables/table-read-only.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../../node_modules/montage",
+ "blue-shark": "../../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/_main.css b/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.css b/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.html b/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..565ec4ef70
--- /dev/null
+++ b/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.html
@@ -0,0 +1,65 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.js b/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..3fa4e9daf1
--- /dev/null
+++ b/blue-shark/ui/tables/table-read-only.info/sample/ui/main.reel/main.js
@@ -0,0 +1,36 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ options: {
+ value: [
+ {
+ "value": "none",
+ "label": "None"
+ },
+ {
+ "value": "optimal",
+ "label": "Optimal"
+ },
+ {
+ "value": "virtualization",
+ "label": "Virtualization"
+ },
+ {
+ "value": "backups",
+ "label": "Backups"
+ },
+ {
+ "value": "media",
+ "label": "Media"
+ }
+ ]
+ }
+});
diff --git a/blue-shark/ui/tables/table-read-only.reel/table-read-only.css b/blue-shark/ui/tables/table-read-only.reel/table-read-only.css
new file mode 100644
index 0000000000..bc4577a11b
--- /dev/null
+++ b/blue-shark/ui/tables/table-read-only.reel/table-read-only.css
@@ -0,0 +1,13 @@
+.TableReadOnly {}
+
+.TableReadOnly .Table-row > div {
+ position: relative;
+ padding: .5em;
+ flex: 1;
+ display: flex;
+ align-items: center;
+}
+
+.TableReadOnly .Table-cell {
+ padding: 0;
+}
diff --git a/blue-shark/ui/tables/table-read-only.reel/table-read-only.html b/blue-shark/ui/tables/table-read-only.reel/table-read-only.html
new file mode 100644
index 0000000000..d0359a1085
--- /dev/null
+++ b/blue-shark/ui/tables/table-read-only.reel/table-read-only.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tables/table-read-only.reel/table-read-only.js b/blue-shark/ui/tables/table-read-only.reel/table-read-only.js
new file mode 100644
index 0000000000..57f4f82457
--- /dev/null
+++ b/blue-shark/ui/tables/table-read-only.reel/table-read-only.js
@@ -0,0 +1,22 @@
+/**
+ * @module ui/table-read-only.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class TableReadOnly
+ * @extends Component
+ */
+exports.TableReadOnly = Component.specialize({
+
+ isSelectionEnabled: {
+ value: false
+ },
+
+ clearSelection: {
+ value: function () {
+ this._tableComponent.rowRepetitionComponent.contentController.clearSelection();
+ }
+ }
+
+});
diff --git a/blue-shark/ui/tabs.info/sample/index.html b/blue-shark/ui/tabs.info/sample/index.html
new file mode 100644
index 0000000000..ba94210614
--- /dev/null
+++ b/blue-shark/ui/tabs.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Tabs Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tabs.info/sample/package.json b/blue-shark/ui/tabs.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/tabs.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/tabs.info/sample/ui/main.reel/_main.css b/blue-shark/ui/tabs.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/tabs.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/tabs.info/sample/ui/main.reel/main.css b/blue-shark/ui/tabs.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/tabs.info/sample/ui/main.reel/main.html b/blue-shark/ui/tabs.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..714146eadc
--- /dev/null
+++ b/blue-shark/ui/tabs.info/sample/ui/main.reel/main.html
@@ -0,0 +1,55 @@
+
+
+
+
+
+
+
+
+
+
Tabs
+
Default
+
+
Controlling a Substitution
+
+
day
+
week
+
month
+
year
+
+
+
+
+
diff --git a/blue-shark/ui/tabs.info/sample/ui/main.reel/main.js b/blue-shark/ui/tabs.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..dace91507d
--- /dev/null
+++ b/blue-shark/ui/tabs.info/sample/ui/main.reel/main.js
@@ -0,0 +1,30 @@
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize({
+ _currentView: {
+ value: null
+ },
+
+ currentView: {
+ get: function() {
+ console.log(this._currentView);
+ return this._currentView;
+ },
+ set: function(currentView) {
+ if (this._currentView !== currentView) {
+ console.log(currentView);
+ this._currentView = currentView;
+ }
+ }
+ },
+
+ enterDocument: {
+ value: function() {
+ this.currentView = "day";
+ }
+ }
+});
diff --git a/blue-shark/ui/tabs.reel/_tabs.css b/blue-shark/ui/tabs.reel/_tabs.css
new file mode 100644
index 0000000000..8fa2d0086f
--- /dev/null
+++ b/blue-shark/ui/tabs.reel/_tabs.css
@@ -0,0 +1,34 @@
+.Tabs-group { display: flex; }
+
+.Tabs-tab {
+ font-size: 1em;
+ height: 2em;
+ font-weight: 200;
+ border-radius: 0;
+ padding: .25em .75em .35em;
+ outline: none;
+ border: 1px solid var(--black);
+ cursor: pointer;
+ background-color: var(--grey-blue);
+ color: var(--grey-3);
+ min-width: 5em;
+}
+
+.Tabs-tab:hover { background-color: color(var(--grey-blue) tint(15%)); }
+
+.Tabs-tab + .Tabs-tab { border-left: none; }
+
+.Tabs-tab:first-child {
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+}
+
+.Tabs-tab:last-child {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+
+.Tabs-tab.selected {
+ background: var(--color-selected);
+ color: var(--white);
+}
diff --git a/blue-shark/ui/tabs.reel/tabs.css b/blue-shark/ui/tabs.reel/tabs.css
new file mode 100644
index 0000000000..4cae307286
--- /dev/null
+++ b/blue-shark/ui/tabs.reel/tabs.css
@@ -0,0 +1 @@
+.Tabs-group{display:-webkit-box;display:-ms-flexbox;display:flex}.Tabs-tab{font-size:1em;height:2em;font-weight:200;border-radius:0;padding:.25em .75em .35em;outline:none;border:1px solid #0f1213;cursor:pointer;background-color:#242628;color:#e0e5e5;min-width:5em}.Tabs-tab:hover{background-color:#454748}.Tabs-tab+.Tabs-tab{border-left:none}.Tabs-tab:first-child{border-top-left-radius:4px;border-bottom-left-radius:4px}.Tabs-tab:last-child{border-top-right-radius:4px;border-bottom-right-radius:4px}.Tabs-tab.selected{background:#0c5688;color:#fff}
\ No newline at end of file
diff --git a/blue-shark/ui/tabs.reel/tabs.html b/blue-shark/ui/tabs.reel/tabs.html
new file mode 100644
index 0000000000..d80d37a1fd
--- /dev/null
+++ b/blue-shark/ui/tabs.reel/tabs.html
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/tabs.reel/tabs.js b/blue-shark/ui/tabs.reel/tabs.js
new file mode 100644
index 0000000000..c7ee3af5d7
--- /dev/null
+++ b/blue-shark/ui/tabs.reel/tabs.js
@@ -0,0 +1,44 @@
+/**
+ * @module ui/tabs.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Tabs
+ * @extends Component
+ */
+exports.Tabs = Component.specialize({
+ _selectedTab: {
+ value: null
+ },
+
+ selectedTab: {
+ get: function() {
+ return this._selectedTab;
+ },
+ set: function(selectedTab) {
+ if (this._selectedTab !== selectedTab) {
+ this._selectedTab = selectedTab;
+ if (selectedTab) {
+ this.selection = selectedTab.value;
+ }
+ }
+ }
+ },
+
+ _selection: {
+ value: null
+ },
+
+ selection: {
+ get: function() {
+ return this._selection;
+ },
+ set: function(selection) {
+ if (this._selection !== selection) {
+ this._selection = selection;
+ this.selectedTab = this.options.filter(function(x) { return x.value == selection; })[0];
+ }
+ }
+ }
+});
diff --git a/blue-shark/ui/text-area.info/sample/index.html b/blue-shark/ui/text-area.info/sample/index.html
new file mode 100644
index 0000000000..436ecbf682
--- /dev/null
+++ b/blue-shark/ui/text-area.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Text Area Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/text-area.info/sample/package.json b/blue-shark/ui/text-area.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/text-area.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/text-area.info/sample/ui/main.reel/_main.css b/blue-shark/ui/text-area.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/text-area.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/text-area.info/sample/ui/main.reel/main.css b/blue-shark/ui/text-area.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/text-area.info/sample/ui/main.reel/main.html b/blue-shark/ui/text-area.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..03cb98dab3
--- /dev/null
+++ b/blue-shark/ui/text-area.info/sample/ui/main.reel/main.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
Text Area
+
Default
+
+
+
+
+
diff --git a/blue-shark/ui/text-area.info/sample/ui/main.reel/main.js b/blue-shark/ui/text-area.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..3fa4e9daf1
--- /dev/null
+++ b/blue-shark/ui/text-area.info/sample/ui/main.reel/main.js
@@ -0,0 +1,36 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ options: {
+ value: [
+ {
+ "value": "none",
+ "label": "None"
+ },
+ {
+ "value": "optimal",
+ "label": "Optimal"
+ },
+ {
+ "value": "virtualization",
+ "label": "Virtualization"
+ },
+ {
+ "value": "backups",
+ "label": "Backups"
+ },
+ {
+ "value": "media",
+ "label": "Media"
+ }
+ ]
+ }
+});
diff --git a/blue-shark/ui/text-area.reel/_text-area.css b/blue-shark/ui/text-area.reel/_text-area.css
new file mode 100644
index 0000000000..0169eaefa4
--- /dev/null
+++ b/blue-shark/ui/text-area.reel/_text-area.css
@@ -0,0 +1,8 @@
+.TextArea {
+ @apply --input-field;
+ font-size: 100%;
+ height: 5em;
+ padding: 0.25em .5em;
+ resize: vertical;
+ -webkit-tap-highlight-color: transparent;
+}
diff --git a/blue-shark/ui/text-area.reel/text-area.css b/blue-shark/ui/text-area.reel/text-area.css
new file mode 100644
index 0000000000..e82c2e3f13
--- /dev/null
+++ b/blue-shark/ui/text-area.reel/text-area.css
@@ -0,0 +1 @@
+.TextArea{font-weight:300;font-family:Lato,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:1em;color:#fff;width:100%;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;border:1px solid #535a61;background-color:#222b35;border-radius:4px;-webkit-transition-property:background-color,border-color,opacity;transition-property:background-color,border-color,opacity;-webkit-transition-duration:.25s;transition-duration:.25s;font-size:100%;height:5em;padding:.25em .5em;resize:vertical;-webkit-tap-highlight-color:transparent}.TextArea:hover{background-color:#29313b;border-color:#9ca0a4}.TextArea:focus{background-color:#29313b;border-color:#2089d3}.TextArea.montage--disabled{border-color:transparent;opacity:.5;cursor:not-allowed}.TextArea.montage--disabled:hover{background-color:#222b35;border-color:transparent}.TextArea.montage--invalidText{border-color:#cf324f}.TextArea[readonly=readonly]{background-color:transparent;border:none;padding:0}
\ No newline at end of file
diff --git a/blue-shark/ui/text-area.reel/text-area.html b/blue-shark/ui/text-area.reel/text-area.html
new file mode 100644
index 0000000000..52c8ef4b8b
--- /dev/null
+++ b/blue-shark/ui/text-area.reel/text-area.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/text-area.reel/text-area.js b/blue-shark/ui/text-area.reel/text-area.js
new file mode 100644
index 0000000000..9924ca1528
--- /dev/null
+++ b/blue-shark/ui/text-area.reel/text-area.js
@@ -0,0 +1,7 @@
+var AbstractTextArea = require("montage/ui/base/abstract-text-area").AbstractTextArea;
+
+exports.TextArea = AbstractTextArea.specialize({
+ hasTemplate: {
+ value: true
+ }
+});
diff --git a/blue-shark/ui/text-field.info/sample/index.html b/blue-shark/ui/text-field.info/sample/index.html
new file mode 100644
index 0000000000..df9b635a17
--- /dev/null
+++ b/blue-shark/ui/text-field.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Text Field Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/text-field.info/sample/package.json b/blue-shark/ui/text-field.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/text-field.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/text-field.info/sample/ui/main.reel/_main.css b/blue-shark/ui/text-field.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/text-field.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/text-field.info/sample/ui/main.reel/main.css b/blue-shark/ui/text-field.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/text-field.info/sample/ui/main.reel/main.html b/blue-shark/ui/text-field.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..2524cf4128
--- /dev/null
+++ b/blue-shark/ui/text-field.info/sample/ui/main.reel/main.html
@@ -0,0 +1,51 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/text-field.info/sample/ui/main.reel/main.js b/blue-shark/ui/text-field.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..3fa4e9daf1
--- /dev/null
+++ b/blue-shark/ui/text-field.info/sample/ui/main.reel/main.js
@@ -0,0 +1,36 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+
+ options: {
+ value: [
+ {
+ "value": "none",
+ "label": "None"
+ },
+ {
+ "value": "optimal",
+ "label": "Optimal"
+ },
+ {
+ "value": "virtualization",
+ "label": "Virtualization"
+ },
+ {
+ "value": "backups",
+ "label": "Backups"
+ },
+ {
+ "value": "media",
+ "label": "Media"
+ }
+ ]
+ }
+});
diff --git a/blue-shark/ui/text-field.reel/_text-field.css b/blue-shark/ui/text-field.reel/_text-field.css
new file mode 100644
index 0000000000..ac7b4434c6
--- /dev/null
+++ b/blue-shark/ui/text-field.reel/_text-field.css
@@ -0,0 +1,10 @@
+.TextField {
+
+ @apply --input-field;
+
+ line-height: 2rem;
+ height: 2rem;
+ padding: 0 .25rem .1rem .5rem;
+
+}
+
diff --git a/blue-shark/ui/text-field.reel/text-field.css b/blue-shark/ui/text-field.reel/text-field.css
new file mode 100644
index 0000000000..782445af87
--- /dev/null
+++ b/blue-shark/ui/text-field.reel/text-field.css
@@ -0,0 +1 @@
+.TextField{font-weight:300;font-family:Lato,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:1em;color:#fff;width:100%;-webkit-tap-highlight-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none;outline:none;border:1px solid #535a61;background-color:#222b35;border-radius:4px;-webkit-transition-property:background-color,border-color,opacity;transition-property:background-color,border-color,opacity;-webkit-transition-duration:.25s;transition-duration:.25s;line-height:32px;line-height:2rem;height:32px;height:2rem;padding:0 4px 1.6px 8px;padding:0 .25rem .1rem .5rem}.TextField:hover{background-color:#29313b;border-color:#9ca0a4}.TextField:focus{background-color:#29313b;border-color:#2089d3}.TextField.montage--disabled{border-color:transparent;opacity:.5;cursor:not-allowed}.TextField.montage--disabled:hover{background-color:#222b35;border-color:transparent}.TextField.montage--invalidText{border-color:#cf324f}.TextField[readonly=readonly]{background-color:transparent;border:none;padding:0}
\ No newline at end of file
diff --git a/blue-shark/ui/text-field.reel/text-field.html b/blue-shark/ui/text-field.reel/text-field.html
new file mode 100644
index 0000000000..993cbe90fe
--- /dev/null
+++ b/blue-shark/ui/text-field.reel/text-field.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/text-field.reel/text-field.js b/blue-shark/ui/text-field.reel/text-field.js
new file mode 100644
index 0000000000..674d459476
--- /dev/null
+++ b/blue-shark/ui/text-field.reel/text-field.js
@@ -0,0 +1,95 @@
+var TextField = require("montage/ui/text-field.reel").TextField,
+ Translator = require("core/translator").Translator;
+
+exports.TextField = TextField.specialize({
+
+ hasTemplate: {
+ value: true
+ },
+
+ _placeholder: {
+ value: void 0
+ },
+
+ placeholder: {
+ get: function() {
+ return this._placeholder;
+ },
+ set: function(placeholder) {
+ var self = this;
+ Translator.translate(placeholder).then(function(translated) {
+ self._placeholder = self.element.placeholder = translated;
+ });
+ }
+ },
+
+ value: {
+ get: function () {
+ return this._value;
+ },
+ set: function (value, fromInput) {
+ if (value !== this._value) {
+ var shouldAcceptValue;
+ if (!this.delegate || (shouldAcceptValue = this.callDelegateMethod("shouldAcceptValue", this, value) ) === undefined ? true : shouldAcceptValue ){
+ if (this.converter) {
+ var convertedValue;
+ try {
+ //Where is the matching convert?
+ convertedValue = this.converter.revert(value);
+ this.error = null;
+ this._value = convertedValue;
+ } catch (e) {
+ // unable to convert - maybe error
+ this._value = value;
+ //FIXME: we don't handle required field.
+ this.error = value !== "" && value !== void 0 && value !== null ? e : null;
+ }
+ } else {
+ this._value = value;
+ this.error = null;
+ }
+
+ this.callDelegateMethod("didChange", this);
+ this._elementAttributeValues["value"] = value;
+ this.needsDraw = true;
+ }
+ }
+ }
+ },
+
+ enterDocument: {
+ value: function(isFirstTime) {
+ this.super(isFirstTime);
+ this.element.placeholder = this.placeholder || '';
+ }
+ },
+
+ handleChange: {
+ enumerable: false,
+ value: function(event) {
+ this.takeValueFromElement();
+ this._hasFocus = false;
+ }
+ },
+
+ handleBlur: {
+ enumerable: false,
+ value: function (event) {
+ this.error = null;
+ if (this.isMandatory && (!this.value || this.value.length === 0)) {
+ this.error = new Error('Value is mandatory');
+ }
+ if (!this.error && this.validator && typeof this.validator.validate === "function") {
+ try {
+ this.validator.validate(this.value);
+ }
+ catch (e) {
+ this.error = e;
+ }
+ }
+ this.hasFocus = false;
+ this.callDelegateMethod("didEndEditing", this);
+ }
+ }
+
+});
diff --git a/blue-shark/ui/text-input-edit.info/sample/index.html b/blue-shark/ui/text-input-edit.info/sample/index.html
new file mode 100644
index 0000000000..d6b77c801e
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Text Input Edit Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/text-input-edit.info/sample/package.json b/blue-shark/ui/text-input-edit.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/_main.css b/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.css b/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.html b/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..009eb9b110
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.html
@@ -0,0 +1,39 @@
+
+
+
+
+
+
+
+
+
+
Text Field
+
Text Field
+
+
+
+
+
diff --git a/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.js b/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..de3171b166
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.info/sample/ui/main.reel/main.js
@@ -0,0 +1,10 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize();
diff --git a/blue-shark/ui/text-input-edit.reel/_text-input-edit.css b/blue-shark/ui/text-input-edit.reel/_text-input-edit.css
new file mode 100644
index 0000000000..9c1709ba3b
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.reel/_text-input-edit.css
@@ -0,0 +1,32 @@
+.TextInputEdit {
+ display: flex;
+ flex: 1;
+}
+
+.TextInputEdit-editButton {
+ @nest .TextInputEdit.is-editing & {
+ display: none;
+ }
+}
+
+.TextInputEdit-cancelButton {
+ display: none;
+ margin-right: .5em !important;
+
+ @nest .TextInputEdit.is-editing & {
+ display: block;
+ }
+}
+
+.TextInputEdit-submitButton {
+ display: none;
+
+ @nest .TextInputEdit.is-editing & {
+ display: block;
+ }
+}
+
+.TextInputEdit-actions {
+ margin-left: .5em;
+ display: flex;
+}
diff --git a/blue-shark/ui/text-input-edit.reel/text-input-edit.css b/blue-shark/ui/text-input-edit.reel/text-input-edit.css
new file mode 100644
index 0000000000..97e13ddc3f
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.reel/text-input-edit.css
@@ -0,0 +1 @@
+.TextInputEdit{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1}.TextInputEdit.is-editing .TextInputEdit-editButton{display:none}.TextInputEdit-cancelButton{display:none;margin-right:.5em!important}.TextInputEdit.is-editing .TextInputEdit-cancelButton{display:block}.TextInputEdit-submitButton{display:none}.TextInputEdit.is-editing .TextInputEdit-submitButton{display:block}.TextInputEdit-actions{margin-left:.5em;display:-webkit-box;display:-ms-flexbox;display:flex}
\ No newline at end of file
diff --git a/blue-shark/ui/text-input-edit.reel/text-input-edit.html b/blue-shark/ui/text-input-edit.reel/text-input-edit.html
new file mode 100644
index 0000000000..a9e22a5c78
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.reel/text-input-edit.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/text-input-edit.reel/text-input-edit.js b/blue-shark/ui/text-input-edit.reel/text-input-edit.js
new file mode 100644
index 0000000000..2597c4884b
--- /dev/null
+++ b/blue-shark/ui/text-input-edit.reel/text-input-edit.js
@@ -0,0 +1,87 @@
+/**
+ * @module ui/text-input-edit.reel
+ */
+var AbstractControl = require("montage/ui/base/abstract-control").AbstractControl,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer;
+
+/**
+ * @class TextInputEdit
+ * @extends Component
+ */
+var TextInputEdit = exports.TextInputEdit = AbstractControl.specialize(/** @lends TextInputEdit# */ {
+
+ prepareForActivationEvents: {
+ value: function () {
+ var keyboardIdentifiers = this.constructor.KEY_IDENTIFIERS,
+ keyboardIdentifier;
+
+ this._keyComposerMap = new Map();
+
+ for (var i = 0, length = keyboardIdentifiers.length; i < length; i++) {
+ keyboardIdentifier = keyboardIdentifiers[i];
+
+ this._keyComposerMap.set(
+ keyboardIdentifier,
+ KeyComposer.createKey(this, keyboardIdentifier, keyboardIdentifier)
+ );
+
+ this._keyComposerMap.get(keyboardIdentifier).addEventListener("keyPress", this);
+ }
+ }
+ },
+
+ _originalValue: {
+ value: null
+ },
+
+ isEditEnabled: {
+ value: false
+ },
+
+ _deselectText: {
+ value: function () {
+ this.input.element.selectionEnd = this.input.element.selectionStart;
+ }
+ },
+
+ handleEditButtonAction: {
+ value: function () {
+ this.isEditEnabled = true;
+ this._originalValue = this.input.value;
+ this.input.focus();
+ this.input.select();
+ }
+ },
+
+ handleSubmitButtonAction: {
+ value: function () {
+ this.isEditEnabled = false;
+ this._deselectText();
+ if(this._originalValue != this.input.value) {
+ this.detail.set('eventName', 'textValueChanged');
+ this.dispatchActionEvent();
+ }
+ }
+ },
+
+ handleCancelButtonAction: {
+ value: function () {
+ this.input.value = this._originalValue;
+ this.isEditEnabled = false;
+ this._deselectText();
+ }
+ }
+},
+{
+
+ KEY_IDENTIFIERS: {
+ value: [
+ "enter",
+ "escape"
+ ]
+ }
+});
+
+TextInputEdit.prototype.handleEnterKeyPress = TextInputEdit.prototype.handleSubmitButtonAction;
+TextInputEdit.prototype.handleEscapeKeyPress = TextInputEdit.prototype.handleCancelButtonAction;
+
diff --git a/blue-shark/ui/text.reel/text.js b/blue-shark/ui/text.reel/text.js
new file mode 100644
index 0000000000..80e8ab0540
--- /dev/null
+++ b/blue-shark/ui/text.reel/text.js
@@ -0,0 +1,60 @@
+var Component = require("montage/ui/component").Component,
+ Translator = require("core/translator").Translator;
+
+exports.Text = Component.specialize({
+ hasTemplate: {
+ value: false
+ },
+
+ result: {
+ value: void 0
+ },
+
+ _value: {
+ value: void 0
+ },
+
+ value: {
+ get: function() {
+ return this._value;
+ }, set: function(value) {
+ if (this._value !== value) {
+ this._value = value;
+ this._refreshResult();
+ }
+ }
+ },
+
+ _args: {
+ value: void 0
+ },
+
+ args: {
+ get: function() {
+ return this._args;
+ }, set: function(args) {
+ if (this._args !== args) {
+ this._args = args;
+ this._refreshResult();
+ }
+ }
+ },
+
+ _refreshResult: {
+ value: function() {
+ var self = this,
+ promise = this.disableTranslation ? Promise.resolve(this._value) : Translator.translate(this._value, this._args);
+ promise.then(function(result) {
+ self.result = result;
+ self.needsDraw = true;
+ });
+ }
+ },
+
+ draw: {
+ value: function() {
+ this.element.innerHTML = (this.converter ? this.converter.convert(this.result) : this.result) || '';
+ }
+ }
+});
+
diff --git a/blue-shark/ui/theme.css b/blue-shark/ui/theme.css
new file mode 100644
index 0000000000..e9c2446851
--- /dev/null
+++ b/blue-shark/ui/theme.css
@@ -0,0 +1,3 @@
+:root {
+/* --red: #F02; */
+}
diff --git a/blue-shark/ui/time.info/sample/index.html b/blue-shark/ui/time.info/sample/index.html
new file mode 100644
index 0000000000..c611570228
--- /dev/null
+++ b/blue-shark/ui/time.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Time Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/time.info/sample/package.json b/blue-shark/ui/time.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/time.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/time.info/sample/ui/main.reel/_main.css b/blue-shark/ui/time.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/time.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/time.info/sample/ui/main.reel/main.css b/blue-shark/ui/time.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/time.info/sample/ui/main.reel/main.html b/blue-shark/ui/time.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..b6ef886a30
--- /dev/null
+++ b/blue-shark/ui/time.info/sample/ui/main.reel/main.html
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ Arrow Icon
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/time.info/sample/ui/main.reel/main.js b/blue-shark/ui/time.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..b0f870f952
--- /dev/null
+++ b/blue-shark/ui/time.info/sample/ui/main.reel/main.js
@@ -0,0 +1,14 @@
+/**
+ * @module ui/main.reel
+ */
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+ date: {
+ value: new Date()
+ }
+});
diff --git a/blue-shark/ui/time.reel/_time.css b/blue-shark/ui/time.reel/_time.css
new file mode 100644
index 0000000000..f5a10d313c
--- /dev/null
+++ b/blue-shark/ui/time.reel/_time.css
@@ -0,0 +1,75 @@
+.Time-container {
+ position: relative;
+ user-select: none;
+}
+
+/* Time Controls ---------------------------------- */
+
+.Time-controls {
+ position: absolute;
+ right: 0;
+ top: 0;
+ bottom: 1px;
+ display: flex;
+ cursor: default;
+}
+
+.Time-controls .Button {
+
+ & svg {
+ height: 2rem;
+ width: 2rem;
+ opacity: .5;
+ color: var(--white);
+ }
+
+ &:hover {
+ background-color: rgba(255,255,255,.1);
+
+ & svg {
+ opacity: 1;
+ }
+ }
+
+}
+
+.Time-input-decrement {
+ transform: rotate(180deg);
+}
+
+.Time-input-increment {
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+}
+
+
+/* Options ---------------------------------- */
+
+.Time-optionsContainer {
+ display: none;
+ position: absolute;
+ height: 7em;
+ top: 2em;
+ width: 100%;
+ font-family: lato;
+ font-weight: 200;
+ color: var(--grey-1);
+ background: var(--grey-blue);
+ z-index: 100;
+ box-shadow: 0 1px 2px rgba(0,0,0,.2);
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ overflow: hidden;
+}
+
+.Time-options {
+ cursor: pointer;
+ border-bottom-right-radius: 4px;
+ border-bottom-left-radius: 4px;
+ overflow: hidden;
+}
+
+.Time.has-options .Time-input-field:focus + .Time-optionsContainer,
+.Time-optionsContainer:active {
+ display: block;
+}
diff --git a/blue-shark/ui/time.reel/time-option.reel/_time-option.css b/blue-shark/ui/time.reel/time-option.reel/_time-option.css
new file mode 100644
index 0000000000..dae80a24f8
--- /dev/null
+++ b/blue-shark/ui/time.reel/time-option.reel/_time-option.css
@@ -0,0 +1,17 @@
+.TimeOption {
+ line-height: 1em;
+ padding: .25em .5em;
+ user-select: none;
+}
+
+
+.TimeOption:hover {
+ color: var(--white);
+ background-color: var(--transparent--lighten);
+}
+
+.TimeOption.selected {
+ background-color: var(--color-selected);
+ color: var(--white);
+ pointer-events: none;
+}
diff --git a/blue-shark/ui/time.reel/time-option.reel/time-option.css b/blue-shark/ui/time.reel/time-option.reel/time-option.css
new file mode 100644
index 0000000000..c70be55d9d
--- /dev/null
+++ b/blue-shark/ui/time.reel/time-option.reel/time-option.css
@@ -0,0 +1 @@
+.TimeOption{line-height:1em;padding:.25em .5em;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.TimeOption:hover{color:#fff;background-color:hsla(0,0%,100%,.1)}.TimeOption.selected{background-color:#0c5688;color:#fff;pointer-events:none}
\ No newline at end of file
diff --git a/blue-shark/ui/time.reel/time-option.reel/time-option.html b/blue-shark/ui/time.reel/time-option.reel/time-option.html
new file mode 100644
index 0000000000..5b2d6bca75
--- /dev/null
+++ b/blue-shark/ui/time.reel/time-option.reel/time-option.html
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/time.reel/time-option.reel/time-option.js b/blue-shark/ui/time.reel/time-option.reel/time-option.js
new file mode 100644
index 0000000000..368ed631a4
--- /dev/null
+++ b/blue-shark/ui/time.reel/time-option.reel/time-option.js
@@ -0,0 +1,26 @@
+/**
+ * @module ui/time-option.reel
+ */
+var Component = require("montage/ui/component").Component,
+ PressComposer = require("montage/composer/press-composer").PressComposer;
+
+/**
+ * @class TimeOption
+ * @extends Component
+ */
+exports.TimeOption = Component.specialize(/** @lends TimeOption# */ {
+ prepareForActivationEvents: {
+ value: function() {
+ var pressComposer = new PressComposer();
+ this.addComposer(pressComposer);
+ pressComposer.addEventListener("press", this);
+ this.element.addEventListener("mouseover", this);
+ }
+ },
+
+ handlePress: {
+ value: function() {
+ this.selected = this.option;
+ }
+ }
+});
diff --git a/blue-shark/ui/time.reel/time.css b/blue-shark/ui/time.reel/time.css
new file mode 100644
index 0000000000..87d56a9669
--- /dev/null
+++ b/blue-shark/ui/time.reel/time.css
@@ -0,0 +1 @@
+.Time-container{position:relative;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.Time-controls{position:absolute;right:0;top:0;bottom:1px;display:-webkit-box;display:-ms-flexbox;display:flex;cursor:default}.Time-controls .Button svg{height:32px;height:2rem;width:32px;width:2rem;opacity:.5;color:#fff}.Time-controls .Button:hover{background-color:hsla(0,0%,100%,.1)}.Time-controls .Button:hover svg{opacity:1}.Time-input-decrement{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.Time-input-increment{border-top-right-radius:4px;border-bottom-right-radius:4px}.Time-optionsContainer{display:none;position:absolute;height:7em;top:2em;width:100%;font-family:lato;font-weight:200;color:#939e9f;background:#242628;z-index:100;box-shadow:0 1px 2px rgba(0,0,0,.2)}.Time-options,.Time-optionsContainer{border-bottom-left-radius:4px;border-bottom-right-radius:4px;overflow:hidden}.Time-options{cursor:pointer}.Time-optionsContainer:active,.Time.has-options .Time-input-field:focus+.Time-optionsContainer{display:block}
\ No newline at end of file
diff --git a/blue-shark/ui/time.reel/time.html b/blue-shark/ui/time.reel/time.html
new file mode 100644
index 0000000000..7051b6da7b
--- /dev/null
+++ b/blue-shark/ui/time.reel/time.html
@@ -0,0 +1,112 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/time.reel/time.js b/blue-shark/ui/time.reel/time.js
new file mode 100644
index 0000000000..fe55d118b6
--- /dev/null
+++ b/blue-shark/ui/time.reel/time.js
@@ -0,0 +1,213 @@
+/**
+ * @module ui/time.reel
+ */
+var Component = require("montage/ui/component").Component,
+ KeyComposer = require("montage/composer/key-composer").KeyComposer;
+
+/**
+ * @class Time
+ * @extends Component
+ */
+exports.Time = Component.specialize(/** @lends Time# */ {
+ __selectedOption: {
+ value: null
+ },
+
+ _selectedOption: {
+ get: function() {
+ return this.__selectedOption;
+ },
+ set: function(option) {
+ if (this.__selectedOption != option) {
+ if (option) {
+ this.__selectedOption = option;
+ this._optionsController.select(option);
+ this.value = option;
+ } else {
+ this._optionsController.clearSelection();
+ }
+ }
+ }
+ },
+
+ enterDocument: {
+ value: function() {
+ if (!this.options) {
+ this.options = [];
+ if (this.intervalInSeconds) {
+ var maxValue = new Date(0, 0, 0, 23, 59, 59),
+ seconds = 0,
+ nextOption = new Date(0, 0, 0, 0, 0, seconds);
+ while (nextOption <= maxValue) {
+ this.options.push(nextOption);
+ seconds += this.intervalInSeconds;
+ nextOption = new Date(0, 0, 0, 0, 0, seconds);
+ }
+ }
+ }
+ if (this.isDefaultNow) {
+ this.options.unshift(new Date());
+ }
+ if (!this.allowEmpty && !this.value) {
+ this._selectedOption = this.options[0];
+ }
+
+ this.addPathChangeListener("value", this, "_handleValueChange");
+ }
+ },
+
+ exitDocument: {
+ value: function() {
+ if (this.getPathChangeDescriptor("value", this)) {
+ this.removePathChangeListener("value", this);
+ }
+ }
+ },
+
+ prepareForActivationEvents: {
+ value: function() {
+ this._inputField.delegate = {
+ shouldAcceptValue: function() {
+ return true;
+ }
+ };
+ KeyComposer.createKey(this._inputField, "down", "down").addEventListener("keyPress", this);
+ KeyComposer.createKey(this._inputField, "up", "up").addEventListener("keyPress", this);
+ }
+ },
+
+ handleInputAction: {
+ value: function() {
+ if (this._inputField.value) {
+ this.value = this._inputField.value;
+ this._selectedOption = this._findMatchingOption();
+ this._blurInputField();
+ }
+ }
+ },
+
+ handleDownKeyPress: {
+ value: function(event) {
+ this._handleDirectionKeyPress(event, 1);
+ }
+ },
+
+ handleUpKeyPress: {
+ value: function(event) {
+ this._handleDirectionKeyPress(event, -1);
+ }
+ },
+
+ _handleDirectionKeyPress: {
+ value: function(event, direction) {
+ if (event.target.component === this._inputField && this.options && this.options.length > 0) {
+ this._navigateInOptions(direction);
+ }
+ }
+ },
+
+ _handleValueChange: {
+ value: function() {
+ if (this.value) {
+ this._selectedOption = this._findMatchingOption();
+ this._nextOptionComponent = this._findNextMatchingIndex();
+ }
+ }
+ },
+
+ _blurInputField: {
+ value: function () {
+ this._inputField.element.blur();
+ }
+ },
+
+ _findMatchingOption: {
+ value: function() {
+ var i, length, option;
+ for (i = 0, length = this.options.length; i < length; i++) {
+ option = this.options[i];
+ if (option === this.value) {
+ return option;
+ }
+ }
+ return null;
+ }
+ },
+
+ _findNextMatchingIndex: {
+ value: function() {
+ var option = this._findNextOption();
+ return this.options.indexOf(option);
+ }
+ },
+
+ _stopScrollingOptions: {
+ value: function () {
+ this._optionsController.clearSelection();
+ this._selectedOption = null;
+ this._inputField.value = this._typedValue;
+ this._typedValue = null;
+ }
+ },
+
+ _navigateInOptions: {
+ value: function(distance) {
+ if (distance > 0) {
+ this._selectedOption = this._findNextOption();
+ } else {
+ this._selectedOption = this._findPreviousOption();
+ }
+ }
+ },
+
+ _findPreviousOption: {
+ value: function() {
+ var option,
+ i = 0,
+ length = this.options.length;
+ for (; i < length; i++) {
+ option = this.options[i];
+ if (option.getHours() > this.value.getHours() ||
+ option.getHours() === this.value.getHours() && option.getMinutes() >= this.value.getMinutes()) {
+ break;
+ }
+ }
+ if (i === 0) {
+ i = this.options.length;
+ }
+ return this.options[i-1];
+ }
+ },
+
+ _findNextOption: {
+ value: function() {
+ var option,
+ max = this.options.length - 1,
+ i = max;
+ for (; i >= 0; i--) {
+ option = this.options[i];
+ if (option.getHours() < this.value.getHours() ||
+ option.getHours() === this.value.getHours() && option.getMinutes() <= this.value.getMinutes()) {
+ break;
+ }
+ }
+ if (i === max) {
+ i = -1;
+ }
+ return this.options[i+1];
+ }
+ },
+
+ handleIncrementAction: {
+ value: function (e) {
+ this._navigateInOptions(1);
+ }
+ },
+
+ handleDecrementAction: {
+ value: function (e) {
+ this._navigateInOptions(-1);
+ }
+ }
+});
+
diff --git a/blue-shark/ui/toggle-switch.info/sample/index.html b/blue-shark/ui/toggle-switch.info/sample/index.html
new file mode 100644
index 0000000000..c3375b369e
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.info/sample/index.html
@@ -0,0 +1,21 @@
+
+
+
+
+
Toggle Switch Sample
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/toggle-switch.info/sample/package.json b/blue-shark/ui/toggle-switch.info/sample/package.json
new file mode 100644
index 0000000000..0f02d74d94
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.info/sample/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "button-sample",
+ "version": "0.1.0",
+ "dependencies": {
+ "blue-shark": "*",
+ "montage": "*"
+ },
+ "mappings": {
+ "montage": "../../../node_modules/montage",
+ "blue-shark": "../../../"
+ }
+}
+
+
diff --git a/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/_main.css b/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/_main.css
new file mode 100644
index 0000000000..94d42e7e31
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/_main.css
@@ -0,0 +1,3 @@
+.Main {
+
+}
\ No newline at end of file
diff --git a/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.css b/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.css
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.html b/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.html
new file mode 100644
index 0000000000..51199537c2
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.js b/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.js
new file mode 100644
index 0000000000..508b3c7b61
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.info/sample/ui/main.reel/main.js
@@ -0,0 +1,11 @@
+var Component = require("montage/ui/component").Component;
+
+/**
+ * @class Main
+ * @extends Component
+ */
+exports.Main = Component.specialize(/** @lends Main# */ {
+ foo: {
+ value: true
+ }
+});
diff --git a/blue-shark/ui/toggle-switch.reel/_toggle-switch.css b/blue-shark/ui/toggle-switch.reel/_toggle-switch.css
new file mode 100644
index 0000000000..436e8093d8
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.reel/_toggle-switch.css
@@ -0,0 +1,77 @@
+.ToggleSwitch {
+ font-size: 0.8em;
+ position: relative;
+ display: block;
+ width: 4em;
+ height: 2em;
+ border-radius: 2em;
+ vertical-align: middle;
+ border: 1px solid var(--grey-2);
+ color: var(--grey-2);
+ cursor: pointer;
+ user-select: none;
+ -webkit-tap-highlight-color: transparent;
+ transition: background-color .2s cubic-bezier(.5,.15,.2,1);
+ transition-property: opacity, background-color, border-color;
+ transition-duration: .25s;
+
+ /* Thumb --------------------- */
+
+ &:before {
+ content: '';
+ position: absolute;
+ box-sizing: border-box;
+ display: inline-block;
+ left: 0;
+ margin: -1px;
+ width: 2em;
+ height: inherit;
+ border-radius: inherit;
+ border: 4px solid transparent;
+ background-clip: content-box;
+ background-color: currentColor;
+ will-change: transform;
+ transition: transform .2s cubic-bezier(.5,.15,.2,1);
+ z-index: 1;
+ }
+
+ /* Text --------------------- */
+
+ &:after {
+ content: 'off';
+ position: absolute;
+ display: block;
+ font-family: 'helvetica-neue', arial;
+ right: .7em;
+ top: 0;
+ bottom: 0;
+ font-weight: 500;
+ -webkit-font-smoothing: antialiased;
+ line-height: 1.8em;
+ }
+
+ &.montage--disabled {
+ opacity: .5;
+ background: transparent;
+ border-color: var(--grey-1);
+ }
+}
+
+/* States --------------------- */
+
+.montage-ToggleSwitch--checked {
+ background-color: var(--accent);
+ border-color: var(--accent);
+
+ &:before {
+ background-color: var(--white);
+ transform: translate3d(100%,0,0);
+ }
+
+ &:after {
+ content: 'on';
+ right: auto;
+ left: .6em;
+ color: var(--white);
+ }
+}
diff --git a/blue-shark/ui/toggle-switch.reel/toggle-switch.css b/blue-shark/ui/toggle-switch.reel/toggle-switch.css
new file mode 100644
index 0000000000..950676885b
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.reel/toggle-switch.css
@@ -0,0 +1 @@
+.ToggleSwitch{font-size:.8em;position:relative;display:block;width:4em;height:2em;border-radius:2em;vertical-align:middle;border:1px solid #b1bcbe;color:#b1bcbe;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;-webkit-transition:background-color .2s cubic-bezier(.5,.15,.2,1);transition:background-color .2s cubic-bezier(.5,.15,.2,1);-webkit-transition-property:opacity,background-color,border-color;transition-property:opacity,background-color,border-color;-webkit-transition-duration:.25s;transition-duration:.25s}.ToggleSwitch:before{content:"";position:absolute;box-sizing:border-box;display:inline-block;left:0;margin:-1px;width:2em;height:inherit;border-radius:inherit;border:4px solid transparent;background-clip:content-box;background-color:currentColor;will-change:transform;-webkit-transition:-webkit-transform .2s cubic-bezier(.5,.15,.2,1);transition:-webkit-transform .2s cubic-bezier(.5,.15,.2,1);transition:transform .2s cubic-bezier(.5,.15,.2,1);transition:transform .2s cubic-bezier(.5,.15,.2,1),-webkit-transform .2s cubic-bezier(.5,.15,.2,1);z-index:1}.ToggleSwitch:after{content:"off";position:absolute;display:block;font-family:helvetica-neue,arial;right:.7em;top:0;bottom:0;font-weight:500;-webkit-font-smoothing:antialiased;line-height:1.8em}.ToggleSwitch.montage--disabled{opacity:.5;background:transparent;border-color:#939e9f}.montage-ToggleSwitch--checked{background-color:#2089d3;border-color:#2089d3}.montage-ToggleSwitch--checked:before{background-color:#fff;-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.montage-ToggleSwitch--checked:after{content:"on";right:auto;left:.6em;color:#fff}
\ No newline at end of file
diff --git a/blue-shark/ui/toggle-switch.reel/toggle-switch.html b/blue-shark/ui/toggle-switch.reel/toggle-switch.html
new file mode 100644
index 0000000000..52737078be
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.reel/toggle-switch.html
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/blue-shark/ui/toggle-switch.reel/toggle-switch.js b/blue-shark/ui/toggle-switch.reel/toggle-switch.js
new file mode 100644
index 0000000000..8d970bbe6b
--- /dev/null
+++ b/blue-shark/ui/toggle-switch.reel/toggle-switch.js
@@ -0,0 +1,3 @@
+var AbstractToggleSwitch = require("montage/ui/base/abstract-toggle-switch").AbstractToggleSwitch;
+
+exports.ToggleSwitch = AbstractToggleSwitch.specialize();
diff --git a/gulpfile.js b/gulpfile.js
index 71bf2e2b91..fb24c39602 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -49,7 +49,7 @@ var tsProject = ts.createProject('tsconfig.json'),
cssnano({autoprefixer: false, safe: true})
],
gulpDir = process.cwd(),
- cssConfig = gulpDir + "/node_modules/blue-shark/ui/_config.css",
+ cssConfig = gulpDir + "/blue-shark/ui/_config.css",
rollbarDevConfig = "window._FREENAS_ENVIRONMENT = 'development';\n" +
"window._FREENAS_GIT_SHA = 'master';",
rollbarProdConfig = "window._FREENAS_ENVIRONMENT = 'production';\n" +
diff --git a/index.html b/index.html
index 773b6e7316..5fa08b315d 100644
--- a/index.html
+++ b/index.html
@@ -8,7 +8,7 @@
FreeNAS Corral
-
+
diff --git a/package.json b/package.json
index c002b1f386..bf2ddcd1ef 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,6 @@
"name": "freenas-10-gui",
"version": "10.0.3-RELEASE",
"dependencies": {
- "blue-shark": "freenas/blue-shark#master",
"bytes": "^2.4.0",
"change-case": "^3.0.0",
"collections": "montagejs/collections#90210529c7b01ed373b65d4a60409f5edd36a93a",
@@ -11,6 +10,9 @@
"digit": "montagejs/digit",
"frb": "montagejs/frb#66ba657ae8e7ada7658df3beb6e924c500b7259c",
"hasher": "^1.2.0",
+ "i18next": "^7.1.3",
+ "i18next-browser-languagedetector": "^1.0.1",
+ "i18next-xhr-backend": "^1.4.1",
"immutable": "^3.8.1",
"lodash": "^4.17.2",
"maphilight": "~1.2.3",
@@ -22,13 +24,13 @@
"numeral": "^2.0.4",
"plottable": "~2.7.0",
"redux": "^3.6.0",
+ "smoothscroll-polyfill": "^0.3.4",
"systemjs": "^0.19.41",
"systemjs-plugin-json": "^0.2.2",
+ "url-join": "^1.1.0",
"uuid": "^3.0.1",
"validators": "~0.3.1",
- "xterm": "^1.0.0",
- "smoothscroll-polyfill": "^0.3.4",
- "url-join": "^1.1.0"
+ "xterm": "^1.0.0"
},
"redirects": {
"redux": "redux/dist/redux.min.js",
diff --git a/src/core.js b/src/core.js
new file mode 100644
index 0000000000..1ef4bf6f4e
--- /dev/null
+++ b/src/core.js
@@ -0,0 +1,25 @@
+exports.bindPropertyToClassName = function bindPropertyToClassName (constructor, propertyName, className, isReversed) {
+ var privatePropertyName = "_" + propertyName;
+
+ constructor.prototype["_" + privatePropertyName] = false;
+
+ Object.defineProperty(constructor.prototype, propertyName, {
+ set: function (value) {
+ if (typeof value === "boolean" && this[privatePropertyName] !== value) {
+ this[privatePropertyName] = value;
+
+ if ((value && !isReversed) || (isReversed && !value)) {
+ this.classList.add(className);
+ } else {
+ this.classList.remove(className);
+ }
+ } else {
+ this.classList.remove(className);
+ this[privatePropertyName] = null;
+ }
+ },
+ get: function () {
+ return this[privatePropertyName];
+ }
+ });
+};
diff --git a/src/drag-drop/abstract-draggable-component.js b/src/drag-drop/abstract-draggable-component.js
new file mode 100644
index 0000000000..1a6e070ae7
--- /dev/null
+++ b/src/drag-drop/abstract-draggable-component.js
@@ -0,0 +1,461 @@
+var Component = require("montage/ui/component").Component,
+ DragDropComponentManager = require('core/drag-drop/drag-drop-component-manager').defaultDragDropComponentManager,
+ TranslateComposer = require("montage/composer/translate-composer").TranslateComposer;
+
+/**
+ * @class AbstractDraggableComponent
+ * @extends Component
+ */
+var AbstractDraggableComponent = exports.AbstractDraggableComponent = Component.specialize(/** @lends AbstractDraggableComponent# */ {
+
+
+ parentContainer: {
+ value: null
+ },
+
+
+ isOutsideParentContainer: {
+ get: function () {
+ return this._isOutsideParentContainer;
+ }
+ },
+
+
+ zIndexDragElement: {
+ value: 999999
+ },
+
+
+ _placeHolderStrategy: {
+ value: null
+ },
+
+
+ placeHolderStrategy: {
+ set: function (value) {
+ if (typeof value === "string" && typeof AbstractDraggableComponent.PLACE_HOLDER_STRATEGY[value]) {
+ this._placeHolderStrategy = AbstractDraggableComponent.PLACE_HOLDER_STRATEGY[value];
+ }
+ },
+ get: function () {
+ if (!this._placeHolderStrategy) {
+ this._placeHolderStrategy = AbstractDraggableComponent.PLACE_HOLDER_STRATEGY.copy;
+ }
+
+ return this._placeHolderStrategy;
+ }
+ },
+
+
+ _enabled: {
+ value: true
+ },
+
+
+ enabled: {
+ set: function (boolean) {
+ boolean = !!boolean;
+
+ if (this._enabled !== boolean) {
+ this._enabled = boolean;
+
+ if (boolean && this._inDocument) {
+ this._load();
+ } else {
+ this._unload();
+ }
+
+ if (this._translateComposer) {
+ this._translateComposer.enabled = boolean;
+ }
+ }
+ },
+ get: function () {
+ return this._enabled;
+ }
+ },
+
+
+ isGhostImageCenter: {
+ value: true
+ },
+
+
+ ghostImageElement: {
+ value: null
+ },
+
+
+ dropZoneDropped: {
+ value: null
+ },
+
+
+ hasBeenDropped: {
+ value: false
+ },
+
+
+ shouldCancelDrop: {
+ value: false
+ },
+
+
+ _isOutsideParentContainer: {
+ value: false
+ },
+
+
+ _isDragging: {
+ value: false
+ },
+
+
+ _previousDisplayRule: {
+ value: null
+ },
+
+
+ _translateX: {
+ value: null
+ },
+
+
+ _translateY: {
+ value: null
+ },
+
+
+ _startPositionX: {
+ value: null
+ },
+
+
+ _startPositionY: {
+ value: null
+ },
+
+
+ _translateComposer: {
+ value: null
+ },
+
+
+ _cloneElement: {
+ value: null
+ },
+
+
+ _boundingRect: {
+ value: null
+ },
+
+
+ _containerBoundingRect: {
+ value: null
+ },
+
+ _uid: {
+ value: null
+ },
+
+
+ uid: {
+ get: function () {
+ return this._uid || (this._uid = DragDropComponentManager.constructor.generateUID());
+ }
+ },
+
+
+ enterDocument: {
+ value: function (firstTime) {
+ if (firstTime) {
+ this.classList.add("montage--Draggable");
+
+ if (!AbstractDraggableComponent.cssTransform) {// check for transform support
+ if("webkitTransform" in this._element.style) {
+ AbstractDraggableComponent.cssTransform = "webkitTransform";
+ } else if("MozTransform" in this._element.style) {
+ AbstractDraggableComponent.cssTransform = "MozTransform";
+ } else if("oTransform" in this._element.style) {
+ AbstractDraggableComponent.cssTransform= "oTransform";
+ } else {
+ AbstractDraggableComponent.cssTransform = "transform";
+ }
+ }
+ }
+ }
+ },
+
+
+ exitDocument: {
+ value: function () {
+ this._resetIfNeeded();
+
+ //if (this._enabled) {
+ // this._unload();
+ //}
+ }
+ },
+
+
+ prepareForActivationEvents: {
+ value: function() {
+ this._load();
+ }
+ },
+
+
+ handleTranslateStart: {
+ value: function (event) {
+ var startPosition = this._translateComposer.pointerStartEventPosition;
+ this._startPositionX = startPosition.pageX;
+ this._startPositionY = startPosition.pageY;
+
+ if (typeof this.shouldAcceptDrag === "function" && !this.shouldAcceptDrag(event)) {
+ return void 0;
+ }
+
+ if (DragDropComponentManager.registerDraggableComponent(this)) {
+ this._translateComposer.addEventListener('translate', this, false);
+ this._translateComposer.addEventListener('translateEnd', this, false);
+ this._translateComposer.addEventListener('translateCancel', this, false);
+
+ if (typeof this.didDragStart === "function") {
+ this.didDragStart(event);
+ }
+
+ DragDropComponentManager.dispatchComponentDragStart(this, event);
+ }
+ }
+ },
+
+
+ handleTranslate: {
+ value: function (event) {
+ this._translateX = event.translateX;
+ this._translateY = event.translateY;
+
+ //fixme: could be passed by translate composer.
+ event.startPositionX = this._startPositionX;
+ event.startPositionY = this._startPositionY;
+
+ this._isDragging = true;
+
+ if (typeof this.handleDrag === "function") {
+ this.handleDrag(event);
+ }
+
+ DragDropComponentManager.dispatchComponentDrag(this, event);
+
+ this.needsDraw = true;
+ }
+ },
+
+
+ handleTranslateEnd: {
+ value: function (event) {
+ this._isDragging = false;
+ this._translateX = 0;
+ this._translateY = 0;
+ this._translateComposer.translateX = 0;
+ this._translateComposer.translateY = 0;
+
+ DragDropComponentManager.dispatchComponentDragEnd(this, event);
+
+ if (typeof this.didDragEnd === "function") {
+ this.didDragEnd(event);
+ }
+
+ this.hasBeenDropped = false;
+ this.dropZoneDropped = null;
+ this.shouldCancelDrop = false;
+
+ DragDropComponentManager.releaseDraggableComponentWithUUID(this.uid);
+
+ this._translateComposer.removeEventListener('translate', this, false);
+ this._translateComposer.removeEventListener('translateEnd', this, false);
+ this._translateComposer.removeEventListener('translateCancel', this, false);
+
+ this.needsDraw = true;
+ }
+ },
+
+
+ handleTranslateCancel: {
+ value: function (event) {
+
+ //todo
+ this.needsDraw = true;
+ }
+ },
+
+
+ _load: {
+ value: function () {
+ if (this._enabled) {
+ if (!this._translateComposer) {
+ this._translateComposer = new TranslateComposer();
+ this._translateComposer.hasMomentum = false;
+
+ this.addComposer(this._translateComposer);
+ }
+
+ this._translateComposer.addEventListener('translateStart', this, false);
+ }
+ }
+ },
+
+
+ _unload: {
+ value: function () {
+ if (this._translateComposer) {
+ this._translateComposer.removeEventListener('translateStart', this, false);
+ }
+ }
+ },
+
+
+ _resetIfNeeded: {
+ value: function () {
+ if (this._cloneElement && !this._isDragging) {
+ document.body.removeChild(this._cloneElement);
+
+ if (this._placeHolderStrategy === AbstractDraggableComponent.PLACE_HOLDER_STRATEGY.hidden) {
+ this._element.style.visibility = this._previousDisplayRule;
+ } else if (this.placeHolderStrategy === AbstractDraggableComponent.PLACE_HOLDER_STRATEGY.remove) {
+ this._element.style.display = this._previousDisplayRule;
+ }
+
+ this._boundingRect = null;
+ this._containerBoundingRect = null;
+ this._cloneElement = null;
+ }
+ }
+ },
+
+
+ willDraw: {
+ value: function () {
+ if (this._isDragging) {
+ if (!this._cloneElement && this.ghostImageElement instanceof HTMLElement) {
+ var shouldRemoveGhostImageElement = false;
+
+ if (this.ghostImageElement.parentNode) {
+ this.ghostImageElement.style.position = "absolute";
+ this.ghostImageElement.style.zIndex = "-1";
+
+ document.body.appendChild(this.ghostImageElement);
+ shouldRemoveGhostImageElement = true;
+ }
+
+ this._boundingRect = this.ghostImageElement.getBoundingClientRect();
+
+ if (shouldRemoveGhostImageElement) {
+ document.body.removeChild(this.ghostImageElement);
+ }
+ } else if (this._cloneElement) {
+ this._boundingRect = this._element.getBoundingClientRect();
+ this._boundingCloneElementRect = this._cloneElement.getBoundingClientRect();
+ }
+
+ if (this.parentContainer && !this._containerBoundingRect) {
+ this._containerBoundingRect = this.parentContainer._element.getBoundingClientRect();
+ }
+ }
+ }
+ },
+
+
+ draw: {
+ value: function () {
+ if (!this._enabled && !this.classList.contains("disabled")) {
+ this._element.classList.add("disabled");
+ } else if (this._enabled && this._element.classList.contains("disabled")) {
+ this._element.classList.remove("disabled");
+ }
+
+ if (this._isDragging) {
+ if (!this._cloneElement) {
+ this._cloneElement = this.ghostImageElement instanceof HTMLElement ?
+ this.ghostImageElement.cloneNode(true) : this._element.cloneNode(true);
+
+ this._cloneElement.style.visibility = "hidden";
+ this._cloneElement.style.pointerEvents = "none";
+ this._cloneElement.style.zIndex = this.zIndexDragElement;
+ this._cloneElement.style.position = "absolute";
+ this._cloneElement.style.margin = "0px";
+ this._cloneElement.classList.add("isDragging");
+
+ document.body.appendChild(this._cloneElement);
+
+ this._needToWaitforBoundaries = true;
+ this.needsDraw = true;
+
+ return void 0;
+ }
+
+ if (this._needToWaitforBoundaries) {
+ var positionTop,
+ positionLeft;
+
+ if (this.isGhostImageCenter) {
+ positionTop = this._startPositionY - this._boundingCloneElementRect.height/2;
+ positionLeft = this._startPositionX - this._boundingCloneElementRect.width/2;
+ } else {
+ positionTop = this._boundingRect.top;
+ positionLeft = this._boundingRect.left;
+ }
+
+ // Needs to call the placeHolderStrategy's getter at least once.
+ if (this.placeHolderStrategy === AbstractDraggableComponent.PLACE_HOLDER_STRATEGY.hidden) {
+ this._previousDisplayRule = this._element.style.visibility;
+ this._element.style.visibility = "hidden";
+ } else if (this.placeHolderStrategy === AbstractDraggableComponent.PLACE_HOLDER_STRATEGY.remove) {
+ this._previousDisplayRule = this._element.style.display;
+ this._element.style.display = "none";
+ }
+
+ this._cloneElement.style.top = positionTop + "px";
+ this._cloneElement.style.left = positionLeft + "px";
+ this._cloneElement.style.visibility = "visible";
+
+ this._needToWaitforBoundaries = false;
+ }
+
+ if (this.parentContainer && this._containerBoundingRect) {
+ var newPositionY = this._startPositionY + this._translateY,
+ newPositionX = this._startPositionX + this._translateX;
+
+ if (newPositionY < this._containerBoundingRect.top || // top
+ newPositionY > this._containerBoundingRect.top + this._containerBoundingRect.height || // bottom,
+ newPositionX < this._containerBoundingRect.left || // left
+ newPositionX > this._containerBoundingRect.left + this._containerBoundingRect.width // right
+ ) {
+ this._isOutsideParentContainer = true;
+ this._cloneElement.classList.add("isOutside");
+ } else {
+ this._cloneElement.classList.remove("isOutside");
+ this._isOutsideParentContainer = false;
+ }
+ }
+
+ this._cloneElement.style[AbstractDraggableComponent.cssTransform] = "translate3d(" + this._translateX + "px," + this._translateY + "px,0)";
+ }
+
+ this._resetIfNeeded();
+ }
+ }
+
+
+}, {
+
+ PLACE_HOLDER_STRATEGY: {
+ value: {
+ remove: "remove",
+ copy: "copy",
+ hidden: "hidden"
+ }
+ }
+
+});
diff --git a/src/drag-drop/abstract-dropzone-component.js b/src/drag-drop/abstract-dropzone-component.js
new file mode 100644
index 0000000000..f189760535
--- /dev/null
+++ b/src/drag-drop/abstract-dropzone-component.js
@@ -0,0 +1,355 @@
+/*global require, exports, document, Error*/
+
+var Component = require("montage/ui/component").Component,
+ DragDropComponentManager = require('core/drag-drop/drag-drop-component-manager').defaultDragDropComponentManager;
+
+/**
+ * @class AbstractDropZoneComponent
+ * @abstract
+ *
+ * @extends Component
+ *
+ */
+exports.AbstractDropZoneComponent = Component.specialize( /** @lends AbstractDropZoneComponent# */ {
+
+
+ _acceptDrop: {
+ value: false
+ },
+
+
+ acceptDrop: {
+ set: function (value) {
+ if (typeof value === "boolean" && this._acceptDrop !== value) {
+ this._acceptDrop = value;
+
+ this.needsDraw = true;
+ }
+ },
+ get: function () {
+ return this._acceptDrop;
+ }
+ },
+
+
+ _uid: {
+ value: null
+ },
+
+
+ uid: {
+ get: function () {
+ return this._uid || (this._uid = DragDropComponentManager.constructor.generateUID());
+ }
+ },
+
+ scrollThreshold: {
+ value: 60
+ },
+
+ _willAcceptDrop: {
+ value: false
+ },
+
+
+ willAcceptDrop: {
+ set: function (value) {
+ if (typeof value === "boolean" && this._willAcceptDrop !== value) {
+ this._willAcceptDrop = value;
+
+ this.needsDraw = true;
+ }
+ },
+ get: function () {
+ return this._willAcceptDrop;
+ }
+ },
+
+
+ _boundingRect: {
+ value: null
+ },
+
+
+ enterDocument: {
+ value: function (firstime) {
+ if (firstime) {
+ this.classList.add("montage--DropZone");
+ }
+
+ DragDropComponentManager.registerDropZoneComponent(this);
+ }
+ },
+
+
+ exitDocument: {
+ value: function () {
+ DragDropComponentManager.releaseDropZoneComponent(this);
+ }
+ },
+
+
+ handleComponentDragStart: {
+ value: function (draggableComponent, dragStartEvent) {
+ this.willAcceptDrop = this._shouldAcceptComponent(draggableComponent, dragStartEvent);
+ }
+ },
+
+ handleComponentDrop: {
+ value: function (draggableComponent) {
+ if (this._acceptDrop) {
+ draggableComponent.hasBeenDropped = true;
+ draggableComponent.dropZoneDropped = this;
+
+ if (typeof this.didComponentDrop === "function") {
+ this.didComponentDrop(draggableComponent);
+ }
+ }
+ }
+ },
+
+
+ handleComponentDragEnd: {
+ value: function (draggableComponent, dragEndEvent) {
+ if (this._willAcceptDrop || this._acceptDrop) {
+ if (typeof this.didComponentDragEnd === "function") {
+ this.didComponentDragEnd(draggableComponent, dragEndEvent);
+ }
+
+ this.willAcceptDrop = false;
+ this.acceptDrop = false;
+ this._boundingRect = null;
+ this._spacerElementBoundingRect = null;
+ }
+ }
+ },
+
+
+ handleFilesDragStart: {
+ value: function (dragStartEvent) {
+ this.willAcceptDrop = this._shouldAcceptFiles(dragStartEvent);
+
+ if (this._willAcceptDrop) {
+ this._element.addEventListener("dragover", this, false);
+ }
+ }
+ },
+
+
+ handleDragover: {
+ value: function (event) {
+ var dataTransfer = event.dataTransfer;
+
+ if (!this._acceptDrop) {
+ if (this._willAcceptDrop) {
+ event.preventDefault();
+
+ dataTransfer.dropEffect = dataTransfer.effectAllowed;
+ this.acceptDrop = true;
+
+ this._element.addEventListener("dragleave", this, false);
+ this._element.addEventListener("drop", this, false);
+ } else {
+ dataTransfer.dropEffect = "none";
+ }
+ } else { // Component is already accepting drop.
+ event.preventDefault();
+
+ }
+ }
+ },
+
+
+ handleDrop: {
+ value: function (event) {
+ var dataTransfer = event.dataTransfer;
+
+ if (this._acceptDrop) {
+ if (dataTransfer && dataTransfer.types && dataTransfer.types.has("Files")) {
+ event.preventDefault();
+
+ if (typeof this.didFilesDrop === "function") {
+ this.didFilesDrop(dataTransfer.files, event);
+ }
+ }
+
+ this.acceptDrop = false;
+ this.willAcceptDrop = false;
+
+ this._element.removeEventListener("dragover", this, false);
+ this._removeFileListeners();
+ }
+ }
+ },
+
+
+ handleDragleave: {
+ value: function (event) {
+ if (typeof this.didDragFileLeave === "function") {
+ this.didDragFileLeave(event);
+ }
+
+ this.acceptDrop = false;
+ this._removeFileListeners();
+ }
+ },
+
+
+ handleFilesDragEnd: {
+ value: function (event) {
+ if (this._willAcceptDrop || this._acceptDrop) {
+ if (typeof this.didDragFileEnd === "function") {
+ this.didDragFileEnd(event);
+ }
+
+ this.willAcceptDrop = false;
+ this.acceptDrop = false;
+ this._boundingRect = null;
+
+ this._element.removeEventListener("dragover", this, false);
+ }
+ }
+ },
+
+
+ _removeFileListeners: {
+ value: function () {
+ this._element.removeEventListener("dragleave", this, false);
+ this._element.removeEventListener("drop", this, false);
+ }
+ },
+
+
+ _shouldAcceptComponent: {
+ value: function (component, event) {
+ var shouldAcceptComponent = true;
+
+ if (typeof this.shouldAcceptComponent === "function") {
+ shouldAcceptComponent = this.shouldAcceptComponent(component, event);
+ }
+
+ return shouldAcceptComponent;
+ }
+ },
+
+
+ _shouldAcceptFiles: {
+ value: function (event) {
+ var dataTransfer = event.dataTransfer,
+ shouldAcceptFile = false;
+
+ if (dataTransfer) {
+ var mimeTypes = dataTransfer.types;
+
+ if (mimeTypes && mimeTypes.has("Files") && typeof this.shouldAcceptFiles === "function") {
+ shouldAcceptFile = this.shouldAcceptFiles(event);
+ }
+ }
+
+ return shouldAcceptFile;
+ }
+ },
+
+ willDraw: {
+ value: function () {
+ if (this._willAcceptDrop && !this._boundingRect) {
+ this._boundingRect = this._element.getBoundingClientRect();
+ }
+
+ if (this.acceptDrop && this.autoScrollView) {
+ this._scrollviewElementBoundingRect = this.scrollView.element.getBoundingClientRect();
+ }
+ }
+ },
+
+ draw: {
+ value: function () {
+ if (this._willAcceptDrop && this._acceptDrop) {
+ this._element.classList.remove("willAcceptDrop");
+ this._element.classList.add("acceptDrop");
+
+ } else if (this._willAcceptDrop) {
+ this._element.classList.remove("acceptDrop");
+ this._element.classList.add("willAcceptDrop");
+
+ } else {
+ this._element.classList.remove("acceptDrop");
+ this._element.classList.remove("willAcceptDrop");
+ }
+
+ if (this.acceptDrop && this.scrollView) {
+ var scrollViewBoundingRect = this._scrollviewElementBoundingRect,
+ scrollThreshold = this.scrollThreshold,
+ scrollViewElement = this.scrollView.element;
+
+ if (this.autoScrollView) {
+ if(scrollViewElement.scrollHeight > scrollViewElement.offsetHeight) {
+ this.multiplierY = 0;
+
+ if (scrollViewBoundingRect.top <= this.scrollViewPointerPositionY &&
+ scrollViewBoundingRect.top + scrollThreshold > this.scrollViewPointerPositionY) {
+ this.multiplierY = scrollThreshold / (this.scrollViewPointerPositionY - scrollViewBoundingRect.top);
+
+ } else if (scrollViewBoundingRect.bottom >= this.scrollViewPointerPositionY &&
+ this.scrollViewPointerPositionY >= scrollViewBoundingRect.bottom - scrollThreshold ) {
+
+ this.multiplierY = scrollThreshold / (scrollViewBoundingRect.bottom - this.scrollViewPointerPositionY);
+ }
+ // Change the algorithm for speed scrolling.
+ this.multiplierY = this.multiplierY * 2;
+ }
+
+ if(scrollViewElement.scrollWidth > scrollViewElement.offsetWidth) {
+ this.multiplierX = 0;
+
+ if (scrollViewBoundingRect.left <= this.scrollViewPointerPositionX &&
+ scrollViewBoundingRect.left + scrollThreshold > this.scrollViewPointerPositionX) {
+
+ this.multiplierX = scrollThreshold / (this.scrollViewPointerPositionX - scrollViewBoundingRect.left);
+
+ } else if (scrollViewBoundingRect.right >= this.scrollViewPointerPositionY &&
+ this.scrollViewPointerPositionX >= scrollViewBoundingRect.right - scrollThreshold ) {
+
+ this.multiplierX = scrollThreshold / (scrollViewBoundingRect.right - this.scrollViewPointerPositionX);
+ }
+
+ this.multiplierX = this.multiplierX * 2;
+ }
+
+ this.autoScrollView = false;
+ this.needsUpdateScrollView = !!this.multiplierY || !!this.multiplierX;
+ }
+
+ if (this.needsUpdateScrollView) {
+ if (scrollViewElement.scrollHeight > scrollViewElement.offsetHeight) {
+ this.needsUpdateScrollView = false;
+
+ if (scrollViewBoundingRect.top + scrollThreshold > this.scrollViewPointerPositionY) {
+ scrollViewElement.scrollTop = scrollViewElement.scrollTop - (1 * this.multiplierY);
+ this.needsUpdateScrollView = scrollViewElement.scrollTop !== 0;
+ } else if (this.scrollViewPointerPositionY >= scrollViewBoundingRect.bottom - scrollThreshold ) {
+ scrollViewElement.scrollTop = scrollViewElement.scrollTop + (1 * this.multiplierY);
+ this.needsUpdateScrollView = (scrollViewElement.scrollTop + scrollViewElement.offsetHeight) < scrollViewElement.scrollHeight;
+ }
+ }
+
+ if (scrollViewElement.scrollWidth > scrollViewElement.offsetWidth) {
+ this.needsUpdateScrollView = this.needsUpdateScrollView || false;
+
+ if (spacerElementBoundingRect.left + scrollThreshold > this.scrollViewPointerPositionX) {
+ scrollViewElement.scrollLeft = scrollViewElement.scrollLeft - (1 * multiplier);
+ this.needsUpdateScrollView = scrollViewElement.scrollLeft !== 0;
+ } else if (scrollViewElementPointerPositionX >= spacerElementBoundingRect.right - scrollThreshold ) {
+ scrollViewElement.scrollLeft = scrollViewElement.scrollLeft + (1 * multiplier);
+ this.needsUpdateScrollView = (scrollViewElement.scrollLeft + scrollViewElement.offsetWidth) < scrollViewElement.scrollWidth;
+ }
+ }
+ }
+
+ if (this.needsUpdateScrollView ) {
+ this.needsDraw = true;
+ }
+ }
+ }
+ }
+});
diff --git a/src/drag-drop/drag-drop-component-manager.js b/src/drag-drop/drag-drop-component-manager.js
new file mode 100644
index 0000000000..42ba5879a6
--- /dev/null
+++ b/src/drag-drop/drag-drop-component-manager.js
@@ -0,0 +1,239 @@
+/*global require, exports, document, Error*/
+
+/**
+ * Inject needed css Rule.
+ */
+var sheet = (document.styleSheets[0] || (function() {
+
+ // Create the