uniform-ui 2.4.1 → 3.0.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/assets/javascripts/uniform.js +8 -21
- data/lib/assets/javascripts/uniform/checkbox.js +59 -16
- data/lib/assets/javascripts/uniform/component.js +20 -4
- data/lib/assets/javascripts/uniform/dropdown.js +78 -209
- data/lib/assets/javascripts/uniform/floating-label-input.js +63 -0
- data/lib/assets/javascripts/uniform/icons.js +12 -3
- data/lib/assets/javascripts/uniform/modal.js +13 -12
- data/lib/assets/javascripts/uniform/popover.js +24 -20
- data/lib/assets/javascripts/uniform/resizer.js +26 -30
- data/lib/assets/javascripts/uniform/select.js +188 -222
- data/lib/assets/javascripts/uniform/tooltip.js +11 -11
- data/lib/assets/stylesheets/uniform.scss +3 -7
- data/lib/assets/stylesheets/uniform/base.scss +20 -1
- data/lib/assets/stylesheets/uniform/components/buttons.scss +171 -184
- data/lib/assets/stylesheets/uniform/components/checkbox.scss +104 -0
- data/lib/assets/stylesheets/uniform/components/container.scss +3 -2
- data/lib/assets/stylesheets/uniform/components/dropdown.scss +8 -5
- data/lib/assets/stylesheets/uniform/components/floating-label-input.scss +29 -0
- data/lib/assets/stylesheets/uniform/components/input-group.scss +30 -0
- data/lib/assets/stylesheets/uniform/components/label.scss +21 -16
- data/lib/assets/stylesheets/uniform/components/loaders.scss +28 -51
- data/lib/assets/stylesheets/uniform/components/nav.scss +50 -87
- data/lib/assets/stylesheets/uniform/components/pointer.scss +83 -0
- data/lib/assets/stylesheets/uniform/components/select.scss +97 -107
- data/lib/assets/stylesheets/uniform/components/table.scss +31 -138
- data/lib/assets/stylesheets/uniform/components/thumb.scss +40 -25
- data/lib/assets/stylesheets/uniform/components/z-input.scss +20 -0
- data/lib/assets/stylesheets/uniform/defaults.scss +31 -7
- data/lib/assets/stylesheets/uniform/functions.scss +32 -7
- data/lib/assets/stylesheets/uniform/mixins.scss +110 -57
- data/lib/assets/stylesheets/uniform/utilities.scss +53 -0
- data/lib/assets/stylesheets/uniform/utilities/background.scss +9 -0
- data/lib/assets/stylesheets/uniform/utilities/borders.scss +85 -0
- data/lib/assets/stylesheets/uniform/utilities/effects.scss +172 -0
- data/lib/assets/stylesheets/uniform/utilities/layout.scss +174 -0
- data/lib/assets/stylesheets/uniform/utilities/position.scss +42 -0
- data/lib/assets/stylesheets/uniform/utilities/sizing.scss +54 -0
- data/lib/assets/stylesheets/uniform/utilities/spacing.scss +62 -0
- data/lib/assets/stylesheets/uniform/utilities/text.scss +158 -0
- data/lib/assets/stylesheets/uniform/variables.scss +104 -44
- data/lib/uniform/version.rb +1 -1
- metadata +21 -45
- data/lib/assets/javascripts/uniform.jquery.js +0 -152
- data/lib/assets/javascripts/uniform/dom-helpers.js +0 -158
- data/lib/assets/javascripts/uniform/floating-label.js +0 -54
- data/lib/assets/stylesheets/uniform-print.scss +0 -1
- data/lib/assets/stylesheets/uniform/components.scss +0 -11
- data/lib/assets/stylesheets/uniform/components/alert.scss +0 -72
- data/lib/assets/stylesheets/uniform/components/card.scss +0 -93
- data/lib/assets/stylesheets/uniform/components/form.scss +0 -149
- data/lib/assets/stylesheets/uniform/components/form/checkbox-collection.scss +0 -103
- data/lib/assets/stylesheets/uniform/components/form/checkbox.scss +0 -58
- data/lib/assets/stylesheets/uniform/components/form/floating-label.scss +0 -65
- data/lib/assets/stylesheets/uniform/components/form/input-group.scss +0 -56
- data/lib/assets/stylesheets/uniform/components/form/tristate.scss +0 -88
- data/lib/assets/stylesheets/uniform/components/grid.scss +0 -179
- data/lib/assets/stylesheets/uniform/components/row.scss +0 -67
- data/lib/assets/stylesheets/uniform/components/tooltip.scss +0 -41
- data/lib/assets/stylesheets/uniform/helpers.scss +0 -133
- data/lib/assets/stylesheets/uniform/helpers/border.scss +0 -28
- data/lib/assets/stylesheets/uniform/helpers/colors.scss +0 -24
- data/lib/assets/stylesheets/uniform/helpers/margin.scss +0 -27
- data/lib/assets/stylesheets/uniform/helpers/padding.scss +0 -9
- data/lib/assets/stylesheets/uniform/helpers/position.scss +0 -20
- data/lib/assets/stylesheets/uniform/helpers/sizes.scss +0 -38
- data/lib/assets/stylesheets/uniform/helpers/text.scss +0 -152
- data/lib/assets/stylesheets/uniform/print/grid.scss +0 -50
@@ -0,0 +1,63 @@
|
|
1
|
+
import Component from './component';
|
2
|
+
import { isVisible, isFocus, hasClass, addClass, removeClass, css, createElement } from 'dolla';
|
3
|
+
|
4
|
+
export default class FloatingLabel extends Component {
|
5
|
+
|
6
|
+
initialize(options){
|
7
|
+
if(options.input instanceof Element) {
|
8
|
+
this.input = options.input
|
9
|
+
} else {
|
10
|
+
this.input = createElement('input', Object.assign({}, {
|
11
|
+
type: this.constructor.type
|
12
|
+
}, options.input)) // TODO filter options to dolla.HTML_ATTRIBUTES
|
13
|
+
}
|
14
|
+
this.label = createElement('label', {
|
15
|
+
for: this.input.id,
|
16
|
+
children: [options.label]
|
17
|
+
});
|
18
|
+
this.input.setAttribute('aria-label', options.label);
|
19
|
+
|
20
|
+
addClass(this.el, 'uniformFloatingLabelInput');
|
21
|
+
|
22
|
+
this.listenTo(this.input, 'focus', this.focus);
|
23
|
+
this.listenTo(this.input, 'blur', this.blur);
|
24
|
+
this.listenTo(this.input, 'revealed', this.render);
|
25
|
+
}
|
26
|
+
|
27
|
+
render () {
|
28
|
+
if(!isVisible(this.input)) return;
|
29
|
+
|
30
|
+
let internalHeight = parseInt(css(this.input, 'height')) - parseInt(css(this.input, 'borderTopWidth')) - parseInt(css(this.input, 'borderBottomWidth'));
|
31
|
+
this.input.style.lineHeight = 1;
|
32
|
+
let lineHeight = parseInt(css(this.input, 'lineHeight'));
|
33
|
+
let fontSize = parseInt(css(this.input, 'fontSize'));
|
34
|
+
let padding = internalHeight - lineHeight;
|
35
|
+
|
36
|
+
this.label.style.setProperty('--font-size', css(this.input, 'fontSize'))
|
37
|
+
this.label.style.paddingLeft = css(this.input, 'paddingLeft');
|
38
|
+
this.label.style.lineHeight = lineHeight + "px";
|
39
|
+
this.label.style.paddingTop = (internalHeight/2 - lineHeight) + "px";
|
40
|
+
this.label.style.paddingBottom = (internalHeight/2 - lineHeight) + "px";
|
41
|
+
|
42
|
+
this.input.style.paddingTop = internalHeight/2 - (lineHeight - fontSize) + "px";
|
43
|
+
this.input.style.paddingBottom = (internalHeight/2 - lineHeight) + (lineHeight - fontSize) + "px";
|
44
|
+
|
45
|
+
this.input.parentNode.insertBefore(this.el, this.input.nextSibling);
|
46
|
+
this.el.append(this.input);
|
47
|
+
this.el.append(this.label);
|
48
|
+
|
49
|
+
if(this.input.value != ""){
|
50
|
+
this.focus()
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
focus (e) {
|
55
|
+
addClass(this.el, 'present');
|
56
|
+
}
|
57
|
+
|
58
|
+
blur (e) {
|
59
|
+
if(this.input.value == ""){
|
60
|
+
removeClass(this.el, 'present');
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
@@ -1,16 +1,25 @@
|
|
1
1
|
let check = `
|
2
|
-
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
2
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 32 32">
|
3
3
|
<path d="M28.998 8.531l-2.134-2.134c-0.394-0.393-1.030-0.393-1.423 0l-12.795 12.795-6.086-6.13c-0.393-0.393-1.029-0.393-1.423 0l-2.134 2.134c-0.393 0.394-0.393 1.030 0 1.423l8.924 8.984c0.393 0.393 1.030 0.393 1.423 0l15.648-15.649c0.393-0.392 0.393-1.030 0-1.423z"></path>
|
4
4
|
</svg>
|
5
5
|
`.trim()
|
6
6
|
|
7
7
|
let arrow_down = `
|
8
|
-
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
|
8
|
+
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 20 20">
|
9
9
|
<path d="M13.418 7.601c0.271-0.268 0.709-0.268 0.979 0s0.271 0.701 0 0.969l-3.907 3.83c-0.271 0.268-0.709 0.268-0.979 0l-3.908-3.83c-0.27-0.268-0.27-0.701 0-0.969s0.708-0.268 0.979 0l3.418 3.14 3.418-3.14z"></path>
|
10
10
|
</svg>
|
11
11
|
`.trim()
|
12
12
|
|
13
|
+
let x = `
|
14
|
+
<svg version="1.2" baseProfile="tiny" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="64px" height="64px" viewBox="0 0 64 64" xml:space="preserve">
|
15
|
+
<g><rect x="-2.352" y="29.385" transform="matrix(0.7071 0.7071 -0.7071 0.7071 32.3545 -14.3899)" width="71.799" height="4.95"/></g>
|
16
|
+
<g><rect x="-2.374" y="29.376" transform="matrix(0.7071 -0.7071 0.7071 0.7071 -12.7023 33.0352)" width="71.799" height="4.95"/></g>
|
17
|
+
</svg>
|
18
|
+
|
19
|
+
`.trim()
|
20
|
+
|
13
21
|
export {
|
14
22
|
check,
|
15
|
-
arrow_down
|
23
|
+
arrow_down,
|
24
|
+
x
|
16
25
|
}
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import Component from './component';
|
2
|
-
import
|
2
|
+
import {addClass, hasClass, removeClass, css, trigger} from 'dolla';
|
3
3
|
|
4
4
|
/* UniformModal.initialize
|
5
5
|
Options
|
@@ -14,8 +14,9 @@ export default class Modal extends Component {
|
|
14
14
|
this.options = {};
|
15
15
|
this.options.klass = options.klass || false;
|
16
16
|
this.content = options.content;
|
17
|
+
this.el.removeAttribute('content');
|
17
18
|
|
18
|
-
|
19
|
+
addClass(this.el, 'uniformModal');
|
19
20
|
this.listenTo(document, 'keyup', this.keyup);
|
20
21
|
this.listenTo(this.el, 'click', this.checkCloseButton);
|
21
22
|
}
|
@@ -31,17 +32,17 @@ export default class Modal extends Component {
|
|
31
32
|
|
32
33
|
this.highest_z_index = 0;
|
33
34
|
this.overlay = document.createElement('div');
|
34
|
-
|
35
|
+
addClass(this.overlay, 'uniformModal-overlay');
|
35
36
|
|
36
37
|
this.blur = document.createElement('div');
|
37
|
-
|
38
|
+
addClass(this.blur, 'uniformModal-blur');
|
38
39
|
|
39
40
|
this.original_scroll = window.scrollY;
|
40
41
|
this.blur.style.top = 0 - this.original_scroll + "px";
|
41
42
|
|
42
43
|
if (document.body.querySelectorAll('.uniformModal').length > 0) {
|
43
44
|
this.highest_z_index = Math.max(Array.prototype.map.call(document.body.querySelectorAll('.uniformModal'), function(el){
|
44
|
-
return parseInt(
|
45
|
+
return parseInt(css(el, 'zIndex'));
|
45
46
|
}));
|
46
47
|
this.el.style.zIndex = this.highest_z_index + 2;
|
47
48
|
}
|
@@ -57,12 +58,12 @@ export default class Modal extends Component {
|
|
57
58
|
}
|
58
59
|
}
|
59
60
|
|
60
|
-
|
61
|
+
addClass(document.body, 'uniformModal-active');
|
61
62
|
document.body.appendChild(this.blur);
|
62
63
|
document.body.appendChild(this.el);
|
63
64
|
|
64
65
|
var container = document.createElement('div');
|
65
|
-
|
66
|
+
addClass(container, 'uniformModal-container');
|
66
67
|
if (content instanceof Node) {
|
67
68
|
container.appendChild(content);
|
68
69
|
} else {
|
@@ -70,27 +71,27 @@ export default class Modal extends Component {
|
|
70
71
|
}
|
71
72
|
|
72
73
|
var closeButton = document.createElement('div');
|
73
|
-
|
74
|
+
addClass(closeButton, 'uniformModal-close');
|
74
75
|
this.el.appendChild(closeButton);
|
75
76
|
|
76
77
|
this.el.style.top = window.scrollY;
|
77
78
|
this.listenTo(this.overlay, 'click', this.close);
|
78
79
|
this.el.appendChild(container);
|
79
80
|
|
80
|
-
if (this.options.klass)
|
81
|
-
if (content.innerHTML)
|
81
|
+
if (this.options.klass) addClass(container, this.options.klass);
|
82
|
+
if (content.innerHTML) trigger(content, 'rendered');
|
82
83
|
this.trigger('rendered');
|
83
84
|
|
84
85
|
return this;
|
85
86
|
}
|
86
87
|
|
87
88
|
checkCloseButton (e) {
|
88
|
-
if(
|
89
|
+
if(hasClass(e.target, 'uniformModal-close'))
|
89
90
|
this.close();
|
90
91
|
}
|
91
92
|
|
92
93
|
close () {
|
93
|
-
|
94
|
+
removeClass(document.querySelectorAll('uniformModal-active'), 'uniformModal-active');
|
94
95
|
var elements = this.blur.children;
|
95
96
|
var elementCount = elements.length
|
96
97
|
for(var i=0; i < elementCount; i++){
|
@@ -1,5 +1,5 @@
|
|
1
1
|
import Component from './component';
|
2
|
-
import
|
2
|
+
import { closest, offset, outerWidth, outerHeight, removeClass, addClass } from 'dolla';
|
3
3
|
|
4
4
|
/*
|
5
5
|
Requirements
|
@@ -12,6 +12,7 @@ import * as Helpers from './dom-helpers';
|
|
12
12
|
align: [left|right|center|#px] [top|center|bottom|#px] | default: 'center bottom'
|
13
13
|
zIndex: # | default: unset
|
14
14
|
offset: {left: 0, top: 0}
|
15
|
+
container: element to append popover to. default: document
|
15
16
|
*/
|
16
17
|
export default class Popover extends Component {
|
17
18
|
initialize (options) {
|
@@ -26,7 +27,9 @@ export default class Popover extends Component {
|
|
26
27
|
offset: {left: 0, top: 0}
|
27
28
|
};
|
28
29
|
Object.assign(this.options, this.pick(options, Object.keys(this.options)));
|
30
|
+
this.el.removeAttribute('content');
|
29
31
|
|
32
|
+
this.options.anchor.popover = this
|
30
33
|
this.listenTo(document, 'click', this.checkFocus);
|
31
34
|
this.listenTo(document, 'focusin', this.checkFocus);
|
32
35
|
this.listenTo(document, 'keyup', this.checkEscape);
|
@@ -35,9 +38,10 @@ export default class Popover extends Component {
|
|
35
38
|
});
|
36
39
|
|
37
40
|
if(typeof this.options.container == "string"){
|
38
|
-
this.options.container =
|
39
|
-
this.options.container = this.options.container || document.body
|
41
|
+
this.options.container = closest(this.options.anchor, this.options.container)
|
40
42
|
}
|
43
|
+
this.options.container = this.options.container || document.body
|
44
|
+
|
41
45
|
}
|
42
46
|
|
43
47
|
render () {
|
@@ -101,43 +105,43 @@ export default class Popover extends Component {
|
|
101
105
|
var [leftAlign, topAlign] = align.split(" ");
|
102
106
|
leftAlign = leftAlign || "bottom";
|
103
107
|
|
104
|
-
var
|
108
|
+
var anchorOffset = offset(this.options.anchor);
|
105
109
|
var container = this.options.container;
|
106
110
|
if(getComputedStyle(container)['position'] == "static") container = container.offsetParent;
|
107
111
|
if(!container) container = document.body;
|
108
112
|
|
109
|
-
var containerOffset =
|
110
|
-
|
111
|
-
top:
|
112
|
-
left:
|
113
|
+
var containerOffset = offset(container);
|
114
|
+
anchorOffset = {
|
115
|
+
top: anchorOffset.top - containerOffset.top,
|
116
|
+
left: anchorOffset.left - containerOffset.left
|
113
117
|
}
|
114
118
|
|
115
119
|
var position = {};
|
116
120
|
if(leftAlign == 'left'){
|
117
|
-
position.right =
|
121
|
+
position.right = outerWidth(container) - anchorOffset.left;
|
118
122
|
} else if(leftAlign == 'center'){
|
119
|
-
position.left =
|
123
|
+
position.left = anchorOffset.left + outerWidth(this.options.anchor) / 2 - outerWidth(this.el) / 2;
|
120
124
|
} else if (leftAlign == 'right'){
|
121
|
-
position.left =
|
125
|
+
position.left = anchorOffset.left + outerWidth(this.options.anchor);
|
122
126
|
} else if (leftAlign.includes("px")){
|
123
|
-
position.left =
|
127
|
+
position.left = anchorOffset.left + parseInt(leftAlign);
|
124
128
|
}
|
125
129
|
|
126
130
|
if(topAlign == 'top'){
|
127
|
-
let height =
|
131
|
+
let height = outerHeight(container);
|
128
132
|
if(container == document.body && getComputedStyle(container)['position'] == "static"){
|
129
133
|
height = window.innerHeight;
|
130
134
|
} else if (container == document.body) {
|
131
135
|
height = Math.max(height, document.body.clientHeight);
|
132
136
|
}
|
133
|
-
position.bottom = height -
|
137
|
+
position.bottom = height - anchorOffset.top;
|
134
138
|
} else if(topAlign == 'center'){
|
135
|
-
position.top =
|
139
|
+
position.top = anchorOffset.top + outerHeight(this.options.anchor) / 2;
|
136
140
|
position.transform = "translateY(-50%)";
|
137
141
|
} else if (topAlign == 'bottom'){
|
138
|
-
position.top =
|
142
|
+
position.top = anchorOffset.top + outerHeight(this.options.anchor);
|
139
143
|
} else if (topAlign.includes("px")){
|
140
|
-
position.top =
|
144
|
+
position.top = anchorOffset.top + parseInt(topAlign);
|
141
145
|
}
|
142
146
|
|
143
147
|
if(this.options.offset.left) position.left += parseInt(this.options.offset.left);
|
@@ -150,9 +154,9 @@ export default class Popover extends Component {
|
|
150
154
|
this.el.style.top = null;
|
151
155
|
this.el.style.bottom = null;
|
152
156
|
this.el.style.transform = null;
|
153
|
-
|
154
|
-
|
155
|
-
|
157
|
+
removeClass(this.el, 'popover-left popover-right popover-center popover-top popover-bottom');
|
158
|
+
addClass(this.el, 'popover-' + topAlign);
|
159
|
+
addClass(this.el, 'popover-' + leftAlign);
|
156
160
|
Object.keys(position).forEach(function(key){
|
157
161
|
this.el.style[key] = position[key] + (key != "transform" ? "px" : "");
|
158
162
|
}, this);
|
@@ -1,43 +1,39 @@
|
|
1
1
|
import Component from './component';
|
2
|
-
import
|
2
|
+
import { trigger, toggleClass } from 'dolla';
|
3
3
|
|
4
4
|
export default class Resizer extends Component {
|
5
5
|
|
6
6
|
initialize () {
|
7
|
+
const breakpoints = getComputedStyle(window.document.body).getPropertyValue('--breakpoints')
|
8
|
+
this.breakpoints = {}
|
9
|
+
breakpoints.split(",").forEach(breakpoint => {
|
10
|
+
const [key, value] = breakpoint.split("/")
|
11
|
+
this.breakpoints[key.trim()] = value;
|
12
|
+
})
|
13
|
+
|
7
14
|
this.listenTo(window, 'resize', this.resize);
|
8
|
-
|
15
|
+
this.resize();
|
9
16
|
}
|
10
17
|
|
11
18
|
resize () {
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
if(width > 1080 && !Helpers.hasClass(this.el, 'lg-size')) {
|
23
|
-
Helpers.addClass(this.el, 'lg-size');
|
24
|
-
Helpers.trigger(window, 'resized-lg');
|
25
|
-
} else if (width < 1080 && Helpers.hasClass(this.el, 'lg-size')) {
|
26
|
-
Helpers.removeClass(this.el, 'lg-size');
|
19
|
+
const width = this.el.offsetWidth;
|
20
|
+
Object.keys(this.breakpoints).forEach(size => {
|
21
|
+
const query = this.breakpoints[size]
|
22
|
+
const css_class = size + '-container'
|
23
|
+
let [attribute, value] = query.split(":")
|
24
|
+
if(value.match("px")){
|
25
|
+
value = parseInt(value)
|
26
|
+
} else {
|
27
|
+
throw "unsupported media units"
|
27
28
|
}
|
28
|
-
|
29
|
-
if(
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
if(width < 720 && !Helpers.hasClass(this.el, 'sm-size')) {
|
37
|
-
Helpers.addClass(this.el, 'sm-size');
|
38
|
-
Helpers.trigger(window, 'resized-sm');
|
39
|
-
} else if (width > 720 && Helpers.hasClass(this.el, 'sm-size')) {
|
40
|
-
Helpers.removeClass(this.el, 'sm-size');
|
29
|
+
|
30
|
+
if(attribute == "min-width") {
|
31
|
+
toggleClass(this.el, css_class, width > value)
|
32
|
+
} else if (attribute == "max-width") {
|
33
|
+
toggleClass(this.el, css_class, width < value)
|
34
|
+
} else {
|
35
|
+
throw "unsupported media feature"
|
41
36
|
}
|
37
|
+
});
|
42
38
|
}
|
43
39
|
}
|
@@ -1,252 +1,218 @@
|
|
1
1
|
import Component from './component';
|
2
2
|
import Popover from './popover';
|
3
3
|
import Modal from './modal';
|
4
|
-
import { check as checkIcon, arrow_down as arrowIcon } from './icons';
|
5
|
-
import
|
4
|
+
import { check as checkIcon, arrow_down as arrowIcon, x as xIcon } from './icons';
|
5
|
+
import { createElement, HTML_ATTRIBUTES, filter, css, toggleClass, removeClass, isEmpty, trigger, hasClass, closest } from 'dolla';
|
6
6
|
|
7
7
|
/*
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
options: array of html options, each item can be string | array | object
|
9
|
+
ex. ["Employee", "Manager", "General Manager"]
|
10
|
+
ex. [
|
11
|
+
["Employee", "employee", false],
|
12
|
+
["Manager", "manager", false],
|
13
|
+
["General Manager", "general_manager", true],
|
14
|
+
]
|
15
|
+
ex. [
|
16
|
+
{value: "employee", text: 'Employee', selected: false},
|
17
|
+
{value: "manager", text: 'Manager', selected: false},
|
18
|
+
{value: "general_manager", text: 'General Manager', selected: true}
|
19
|
+
]
|
20
|
+
limit: int | false - number of options to limit to, or false to not limit
|
21
|
+
container: selector for where to render dropdown
|
22
|
+
multiple: false
|
14
23
|
*/
|
15
24
|
export default class Select extends Component {
|
16
25
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
var button = button_options.querySelector('.uniformSelect-show-all');
|
24
|
-
button.parentNode.removeChild(button);
|
25
|
-
|
26
|
-
return false;
|
27
|
-
},
|
28
|
-
limit: 8,
|
29
|
-
container: false
|
26
|
+
initialize (options = {}) {
|
27
|
+
this.htmlOptions = options.options.map(option => {
|
28
|
+
if(typeof option == "string") {
|
29
|
+
return {
|
30
|
+
value: option,
|
31
|
+
text: option
|
30
32
|
}
|
33
|
+
} else if (Array.isArray(option)){
|
34
|
+
return {
|
35
|
+
value: option[1],
|
36
|
+
text: option[0],
|
37
|
+
selected: option[2]
|
38
|
+
}
|
39
|
+
} else if (typeof option == "object") {
|
40
|
+
return option
|
41
|
+
} else {
|
42
|
+
throw "option of unexpected type"
|
43
|
+
}
|
44
|
+
});
|
45
|
+
this.options = {
|
46
|
+
multiple: false,
|
47
|
+
limit: 8,
|
48
|
+
container: false
|
49
|
+
}
|
50
|
+
Object.assign(this.options, this.pick(options, Object.keys(this.options)));
|
31
51
|
|
32
|
-
|
52
|
+
this.el_options = Object.assign({}, this.pick(options, HTML_ATTRIBUTES));
|
53
|
+
this.el = createElement('button', this.el_options);
|
54
|
+
this.el.classList.add('uniformSelect');
|
33
55
|
|
34
|
-
|
35
|
-
|
36
|
-
|
56
|
+
this.listenTo(this.el, 'click', this.toggleOptions);
|
57
|
+
this.listenTo(this.el, 'click', '.uniformSelect-remove', this.removeSelection);
|
58
|
+
this.listenTo(this.el, 'change', 'select', this.renderValue);
|
59
|
+
this.listenTo(this.el, 'close', 'select', this.removeOptions);
|
60
|
+
}
|
61
|
+
|
62
|
+
render () {
|
63
|
+
this.valueEl = createElement('span');
|
64
|
+
this.valueEl.classList.add('uniformSelect-value')
|
65
|
+
this.el.append(this.valueEl);
|
37
66
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
}
|
67
|
+
this.indicatorEl = createElement('span', {children: arrowIcon})
|
68
|
+
this.indicatorEl.classList.add('uniformSelect-indicator')
|
69
|
+
this.el.append(this.indicatorEl);
|
42
70
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
71
|
+
this.select = createElement('select', this.el_options);
|
72
|
+
this.htmlOptions.forEach(option => {
|
73
|
+
this.select.append(createElement('option', Object.assign({}, {children: option.text}, option)))
|
74
|
+
});
|
75
|
+
this.el.append(this.select);
|
47
76
|
|
48
|
-
this.activeIcon.parentNode.removeChild(this.activeIcon);
|
49
|
-
delete this.activeIcon;
|
50
77
|
|
51
|
-
|
52
|
-
|
78
|
+
// Append placeholder of longest option, to set width
|
79
|
+
const longestText = this.htmlOptions.map(x => x.text).sort((a, b) => a.length < b.length)[0]
|
80
|
+
const placeholder = createElement('span', {class: 'uniformSelect-placeholder', children: longestText})
|
81
|
+
this.el.append(placeholder);
|
53
82
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
}
|
58
|
-
}
|
83
|
+
this.renderValue();
|
84
|
+
return this;
|
85
|
+
}
|
59
86
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
if (this.el.name) {
|
69
|
-
Helpers.addClass(this.edit_button, this.el.name.toLowerCase().replace(/[^a-z0-9\-_]+/g, '-'));
|
70
|
-
}
|
71
|
-
this.el.style.display = "none";
|
72
|
-
this.el.insertAdjacentElement('beforebegin', this.edit_button);
|
73
|
-
|
74
|
-
if(!this.options.container) {
|
75
|
-
this.options.container = this.edit_button.parentElement
|
76
|
-
}
|
77
|
-
|
78
|
-
// Set Min-Width for when empty
|
87
|
+
renderValue () {
|
88
|
+
const selectedOptions = filter(this.select.querySelectorAll("option"), el => el.selected);
|
89
|
+
const html = selectedOptions.map(el => this.options.multiple ? `
|
90
|
+
<span class="uniformSelect-selection">
|
91
|
+
<span>${el.textContent}</span><span class="uniformSelect-remove">${xIcon}</span>
|
92
|
+
</span>
|
93
|
+
` : el.textContent).join(" ");
|
79
94
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
this.edit_button.querySelector('.text-js').innerHTML = "";
|
88
|
-
this.edit_button.querySelector('.text-js').style.opacity = null;
|
89
|
-
|
90
|
-
this.renderSelected();
|
91
|
-
|
92
|
-
this.listenTo(this.edit_button, 'click', this.showOptions);
|
93
|
-
this.listenTo(this.edit_button, 'click', '.uniformSelect-remove', this.removeSelection);
|
94
|
-
|
95
|
-
return this;
|
95
|
+
this.valueEl.innerHTML = html;
|
96
|
+
}
|
97
|
+
|
98
|
+
selectOption (e) {
|
99
|
+
const makeActive = !e.target.option.selected;
|
100
|
+
if (!this.options.multiple && makeActive) {
|
101
|
+
removeClass(e.target.offsetParent.querySelectorAll('.active'), 'active');
|
96
102
|
}
|
97
|
-
|
98
|
-
|
99
|
-
this.button_options = Helpers.createElement("<div class='uniformSelect-options'>");
|
100
|
-
if (this.el.name) {
|
101
|
-
Helpers.addClass(this.button_options, this.el.name.toLowerCase().replace(/[^a-z0-9\-_]+/g, '-'));
|
102
|
-
}
|
103
|
-
this.button_options.style.fontSize = Helpers.css(this.el, 'font-size');
|
103
|
+
toggleClass(e.target, 'active', makeActive);
|
104
|
+
e.target.option.selected = makeActive;
|
104
105
|
|
105
|
-
|
106
|
-
|
107
|
-
button.option = el;
|
108
|
-
button.textContent = el.textContent;
|
109
|
-
button.value = el.value;
|
110
|
-
if (button.textContent == "") button.innerHTML = "<span class='text-italic text-muted'>None</span>";
|
111
|
-
if(el.selected){
|
112
|
-
Helpers.addClass(button, 'active');
|
113
|
-
button.append(this.activeIcon.cloneNode(true));
|
114
|
-
} else if (this.options.limit && index > this.options.limit) {
|
115
|
-
Helpers.addClass(button, 'hide');
|
116
|
-
}
|
117
|
-
this.button_options.append(button);
|
118
|
-
}.bind(this));
|
119
|
-
|
120
|
-
this.listenTo(this.button_options, 'click', '.uniformSelect-option', this.selectOption);
|
121
|
-
|
122
|
-
const actions_el = Helpers.createElement('<div class="uniformSelect-options-actions"></div>');
|
123
|
-
if (this.options.limit && this.el.querySelectorAll('option').length > this.options.limit) {
|
124
|
-
const show_all_button = Helpers.createElement("<button type='button' class='uniformSelect-show-all outline blue' style='display: block; border: none'>Show All</button>");
|
125
|
-
this.listenTo(show_all_button, 'click', function(e){
|
126
|
-
Helpers.trigger(this.el, 'show_all');
|
127
|
-
if (this.options.showAll) this.options.showAll(this.button_options);
|
128
|
-
e.preventDefault();
|
129
|
-
e.stopPropagation();
|
130
|
-
})
|
131
|
-
actions_el.appendChild(show_all_button);
|
132
|
-
}
|
133
|
-
if (this.el.multiple) {
|
134
|
-
var done_button = Helpers.createElement("<button type='button' class='uniformSelect-done block outline blue'>Done</button>");
|
135
|
-
this.listenTo(done_button, 'click', this.hideOptions);
|
136
|
-
actions_el.appendChild(done_button);
|
137
|
-
}
|
138
|
-
if (!Helpers.is_empty(actions_el)) {
|
139
|
-
this.button_options.appendChild(actions_el);
|
140
|
-
}
|
106
|
+
if (!this.options.multiple) {
|
107
|
+
this.removeOptions();
|
141
108
|
}
|
142
|
-
|
143
|
-
renderSelected () {
|
144
|
-
const selected_options = Helpers.filter(this.el.querySelectorAll("option"), function(el){
|
145
|
-
return el.selected;
|
146
|
-
});
|
147
|
-
const html = Helpers.map(selected_options, function(el){
|
148
|
-
return this.el.multiple ? `<span class="uniformSelect-selection">${el.textContent}<span class="uniformSelect-remove"></span></span>` : el.textContent;
|
149
|
-
}.bind(this)).join(" ");
|
150
109
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
110
|
+
trigger(this.select, 'change');
|
111
|
+
}
|
112
|
+
|
113
|
+
removeSelection (e) {
|
114
|
+
e.preventDefault();
|
115
|
+
e.stopPropagation();
|
116
|
+
var option = filter(this.select.querySelectorAll("option"), function(el){
|
117
|
+
return el.innerText.trim() == closest(e.target, '.uniformSelect-selection').innerText.trim();
|
118
|
+
})[0];
|
119
|
+
if(!option) return;
|
120
|
+
option.selected = false;
|
121
|
+
option.button.classList.remove('active');
|
156
122
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
Helpers.removeClass(el, 'active');
|
164
|
-
Helpers.each(el.querySelectorAll('.uniformSelect-option-icon'), Helpers.remove);
|
165
|
-
}
|
166
|
-
}.bind(this))
|
167
|
-
}
|
123
|
+
trigger(this.select, 'change');
|
124
|
+
}
|
125
|
+
|
126
|
+
toggleOptions (e) {
|
127
|
+
if(e && (e.target.matches('.uniformSelect-remove') || closest(e.target, '.uniformSelect-remove'))){
|
128
|
+
return;
|
168
129
|
}
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
this.button_options_popover.remove();
|
175
|
-
delete this.button_options_popover;
|
176
|
-
}
|
177
|
-
Helpers.removeClass(this.edit_button, 'active');
|
130
|
+
toggleClass(this.el, 'active')
|
131
|
+
if(hasClass(this.el, 'active')){
|
132
|
+
this.renderOptions()
|
133
|
+
} else {
|
134
|
+
this.removeOptions()
|
178
135
|
}
|
136
|
+
}
|
179
137
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
} else {
|
208
|
-
this.button_options.style.minWidth = this.edit_button.offsetWidth + "px";
|
209
|
-
this.button_options_popover = new Popover({
|
210
|
-
offset: {top: 1},
|
211
|
-
anchor: this.edit_button,
|
212
|
-
align: '0px bottom',
|
213
|
-
content: this.button_options,
|
214
|
-
container: this.options.container
|
215
|
-
}).render()
|
216
|
-
this.button_options_popover.on('hidden', () => {
|
217
|
-
Helpers.removeClass(this.edit_button, 'active');
|
218
|
-
this.button_options_popover.remove();
|
219
|
-
delete this.button_options_popover;
|
220
|
-
})
|
221
|
-
}
|
222
|
-
}
|
138
|
+
renderOptions () {
|
139
|
+
const options = createElement("div", {
|
140
|
+
class: 'uniformSelect-options'
|
141
|
+
});
|
142
|
+
|
143
|
+
options.style.fontSize = css(this.el, 'font-size')
|
144
|
+
|
145
|
+
this.select.querySelectorAll('option').forEach(function(option, index){
|
146
|
+
var button = createElement("button", {
|
147
|
+
type: 'button',
|
148
|
+
class: 'uniformSelect-option'
|
149
|
+
});
|
150
|
+
button.option = option;
|
151
|
+
option.button = button;
|
152
|
+
button.textContent = option.textContent;
|
153
|
+
button.value = option.value;
|
154
|
+
if (button.textContent == "") button.innerHTML = "<span class='text-italic text-muted'>None</span>";
|
155
|
+
toggleClass(button, 'active', option.selected);
|
156
|
+
|
157
|
+
console.log(this.options.limit, index);
|
158
|
+
if (this.options.limit && (index + 1) > this.options.limit) {
|
159
|
+
button.classList.add('hide')
|
160
|
+
}
|
161
|
+
options.append(button);
|
162
|
+
}, this);
|
163
|
+
|
164
|
+
this.listenTo(options, 'click', '.uniformSelect-option', this.selectOption);
|
223
165
|
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
Helpers.removeClass(this.button_options.querySelectorAll('.uniformSelect-option.active'), 'active');
|
229
|
-
}
|
230
|
-
Helpers.toggleClass(e.target, 'active');
|
231
|
-
e.target.option.selected = Helpers.hasClass(e.target, 'active');
|
232
|
-
if (Helpers.hasClass(e.target, 'active')) {
|
233
|
-
e.target.append(this.activeIcon.cloneNode(true));
|
234
|
-
} else {
|
235
|
-
Helpers.each(e.target.querySelectorAll('.uniformSelect-option-icon'), Helpers.remove);
|
236
|
-
}
|
237
|
-
if (!this.el.multiple) {
|
238
|
-
this.hideOptions();
|
239
|
-
}
|
240
|
-
Helpers.trigger(this.el, 'change');
|
241
|
-
}
|
166
|
+
|
167
|
+
const actions = createElement('div', {
|
168
|
+
class: 'uniformSelect-actions'
|
169
|
+
});
|
242
170
|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
171
|
+
if (this.options.limit && this.htmlOptions.length > this.options.limit) {
|
172
|
+
const button = createElement('button', {
|
173
|
+
type: 'button',
|
174
|
+
class: 'uniformSelect-show-all',
|
175
|
+
children: 'Show All'
|
176
|
+
});
|
177
|
+
this.listenTo(button, 'click', this.showAllOptions.bind(this))
|
178
|
+
actions.append(button);
|
179
|
+
}
|
180
|
+
if (this.options.multiple) {
|
181
|
+
const button = createElement('button', {
|
182
|
+
type: 'button',
|
183
|
+
class: 'uniformSelect-done',
|
184
|
+
children: ['Done']
|
185
|
+
});
|
186
|
+
this.listenTo(button, 'click', this.removeOptions.bind(this));
|
187
|
+
actions.append(button);
|
251
188
|
}
|
189
|
+
if (!isEmpty(actions)) {
|
190
|
+
options.append(actions);
|
191
|
+
}
|
192
|
+
|
193
|
+
this.popover = new Popover({
|
194
|
+
offset: {top: 1},
|
195
|
+
align: '0px bottom',
|
196
|
+
anchor: this.el,
|
197
|
+
content: options,
|
198
|
+
container: this.options.container
|
199
|
+
}).render()
|
200
|
+
|
201
|
+
this.listenTo(this.popover, 'hidden', this.removeOptions);
|
202
|
+
}
|
203
|
+
|
204
|
+
removeOptions () {
|
205
|
+
this.el.classList.remove('active')
|
206
|
+
if(!this.popover) return;
|
207
|
+
this.popover.remove()
|
208
|
+
}
|
209
|
+
|
210
|
+
showAllOptions (e) {
|
211
|
+
e.preventDefault();
|
212
|
+
e.stopPropagation();
|
213
|
+
if(!this.popover) return;
|
214
|
+
removeClass(this.popover.el.querySelectorAll('button.hide'), 'hide');
|
215
|
+
var button = this.popover.el.querySelector('.uniformSelect-show-all');
|
216
|
+
button.parentNode.removeChild(button);
|
217
|
+
}
|
252
218
|
}
|