uniform-ui 2.3.6 → 3.0.0.beta2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/lib/assets/javascripts/uniform.es5.js +1 -1
  3. data/lib/assets/javascripts/uniform.js +8 -21
  4. data/lib/assets/javascripts/uniform/checkbox.js +59 -16
  5. data/lib/assets/javascripts/uniform/component.js +20 -4
  6. data/lib/assets/javascripts/uniform/dropdown.js +78 -209
  7. data/lib/assets/javascripts/uniform/floating-label-input.js +63 -0
  8. data/lib/assets/javascripts/uniform/icons.js +12 -3
  9. data/lib/assets/javascripts/uniform/modal.js +13 -12
  10. data/lib/assets/javascripts/uniform/popover.js +45 -26
  11. data/lib/assets/javascripts/uniform/resizer.js +26 -30
  12. data/lib/assets/javascripts/uniform/select.js +188 -220
  13. data/lib/assets/javascripts/uniform/tooltip.js +11 -11
  14. data/lib/assets/stylesheets/uniform.scss +3 -7
  15. data/lib/assets/stylesheets/uniform/base.scss +20 -1
  16. data/lib/assets/stylesheets/uniform/components/buttons.scss +171 -184
  17. data/lib/assets/stylesheets/uniform/components/checkbox.scss +104 -0
  18. data/lib/assets/stylesheets/uniform/components/container.scss +3 -2
  19. data/lib/assets/stylesheets/uniform/components/dropdown.scss +8 -5
  20. data/lib/assets/stylesheets/uniform/components/floating-label-input.scss +29 -0
  21. data/lib/assets/stylesheets/uniform/components/input-group.scss +30 -0
  22. data/lib/assets/stylesheets/uniform/components/label.scss +21 -16
  23. data/lib/assets/stylesheets/uniform/components/loaders.scss +28 -51
  24. data/lib/assets/stylesheets/uniform/components/nav.scss +50 -87
  25. data/lib/assets/stylesheets/uniform/components/pointer.scss +83 -0
  26. data/lib/assets/stylesheets/uniform/components/select.scss +97 -107
  27. data/lib/assets/stylesheets/uniform/components/table.scss +31 -138
  28. data/lib/assets/stylesheets/uniform/components/thumb.scss +40 -25
  29. data/lib/assets/stylesheets/uniform/components/z-input.scss +20 -0
  30. data/lib/assets/stylesheets/uniform/defaults.scss +31 -7
  31. data/lib/assets/stylesheets/uniform/functions.scss +32 -7
  32. data/lib/assets/stylesheets/uniform/mixins.scss +110 -57
  33. data/lib/assets/stylesheets/uniform/utilities.scss +53 -0
  34. data/lib/assets/stylesheets/uniform/utilities/background.scss +9 -0
  35. data/lib/assets/stylesheets/uniform/utilities/borders.scss +85 -0
  36. data/lib/assets/stylesheets/uniform/utilities/effects.scss +172 -0
  37. data/lib/assets/stylesheets/uniform/utilities/layout.scss +174 -0
  38. data/lib/assets/stylesheets/uniform/utilities/position.scss +42 -0
  39. data/lib/assets/stylesheets/uniform/utilities/sizing.scss +54 -0
  40. data/lib/assets/stylesheets/uniform/utilities/spacing.scss +62 -0
  41. data/lib/assets/stylesheets/uniform/utilities/text.scss +158 -0
  42. data/lib/assets/stylesheets/uniform/variables.scss +104 -44
  43. data/lib/uniform/version.rb +1 -1
  44. metadata +24 -48
  45. data/lib/assets/javascripts/uniform.jquery.js +0 -152
  46. data/lib/assets/javascripts/uniform/dom-helpers.js +0 -158
  47. data/lib/assets/javascripts/uniform/floating-label.js +0 -54
  48. data/lib/assets/stylesheets/uniform-print.scss +0 -1
  49. data/lib/assets/stylesheets/uniform/components.scss +0 -11
  50. data/lib/assets/stylesheets/uniform/components/alert.scss +0 -72
  51. data/lib/assets/stylesheets/uniform/components/card.scss +0 -93
  52. data/lib/assets/stylesheets/uniform/components/form.scss +0 -149
  53. data/lib/assets/stylesheets/uniform/components/form/checkbox-collection.scss +0 -103
  54. data/lib/assets/stylesheets/uniform/components/form/checkbox.scss +0 -58
  55. data/lib/assets/stylesheets/uniform/components/form/floating-label.scss +0 -65
  56. data/lib/assets/stylesheets/uniform/components/form/input-group.scss +0 -56
  57. data/lib/assets/stylesheets/uniform/components/form/tristate.scss +0 -88
  58. data/lib/assets/stylesheets/uniform/components/grid.scss +0 -179
  59. data/lib/assets/stylesheets/uniform/components/row.scss +0 -67
  60. data/lib/assets/stylesheets/uniform/components/tooltip.scss +0 -41
  61. data/lib/assets/stylesheets/uniform/helpers.scss +0 -133
  62. data/lib/assets/stylesheets/uniform/helpers/border.scss +0 -28
  63. data/lib/assets/stylesheets/uniform/helpers/colors.scss +0 -24
  64. data/lib/assets/stylesheets/uniform/helpers/margin.scss +0 -27
  65. data/lib/assets/stylesheets/uniform/helpers/padding.scss +0 -9
  66. data/lib/assets/stylesheets/uniform/helpers/position.scss +0 -20
  67. data/lib/assets/stylesheets/uniform/helpers/sizes.scss +0 -38
  68. data/lib/assets/stylesheets/uniform/helpers/text.scss +0 -152
  69. 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" width="1em" height="1em" viewBox="0 0 32 32">
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" width="1em" height="1em" viewBox="0 0 20 20">
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 * as Helpers from './dom-helpers';
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
- Helpers.addClass(this.el, 'uniformModal');
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
- Helpers.addClass(this.overlay, 'uniformModal-overlay');
35
+ addClass(this.overlay, 'uniformModal-overlay');
35
36
 
36
37
  this.blur = document.createElement('div');
37
- Helpers.addClass(this.blur, 'uniformModal-blur');
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(Helpers.css(el, 'zIndex'));
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
- Helpers.addClass(document.body, 'uniformModal-active');
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
- Helpers.addClass(container, 'uniformModal-container');
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
- Helpers.addClass(closeButton, 'uniformModal-close');
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) Helpers.addClass(container, this.options.klass);
81
- if (content.innerHTML) Helpers.trigger(content, 'rendered');
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(Helpers.hasClass(e.target, 'uniformModal-close'))
89
+ if(hasClass(e.target, 'uniformModal-close'))
89
90
  this.close();
90
91
  }
91
92
 
92
93
  close () {
93
- Helpers.removeClass(document.querySelectorAll('uniformModal-active'), 'uniformModal-active');
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 * as Helpers from './dom-helpers';
2
+ import { closest, offset, outerWidth, outerHeight, removeClass, addClass } from 'dolla';
3
3
 
4
4
  /*
5
5
  Requirements
@@ -12,13 +12,14 @@ 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) {
18
19
  this.showing = false;
19
20
  options = options || {};
20
21
  this.options = {
21
- zIndex: 2,
22
+ zIndex: 3,
22
23
  container: document.body,
23
24
  align: 'center bottom',
24
25
  anchor: document.body,
@@ -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 = Helpers.closest(this.options.anchor, 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 () {
@@ -59,7 +63,7 @@ export default class Popover extends Component {
59
63
 
60
64
  resize () {
61
65
  this.setPosition();
62
- const bounds = this.el.getBoundingClientRect();
66
+ let bounds = this.el.getBoundingClientRect();
63
67
  const body_bounds = document.body.getBoundingClientRect();
64
68
  const window_bounds = {
65
69
  top: 0,
@@ -69,10 +73,14 @@ export default class Popover extends Component {
69
73
  };
70
74
 
71
75
  var reposition = false;
72
- if (bounds.bottom > body_bounds.bottom && bounds.bottom > window_bounds.bottom) {
73
- const difference = body_bounds.bottom - bounds.bottom
74
- if(this.el.style.top != null) this.el.style.top = parseInt(this.el.style.top) - difference + "px"
75
- if(this.el.style.bottom != null) this.el.style.bottom = parseInt(this.el.style.bottom) + difference + "px"
76
+ if (bounds.bottom > Math.max(body_bounds.bottom, window_bounds.bottom)) {
77
+ var [leftAlign, topAlign] = this.options.align.split(" ");
78
+ this.setPosition(`${leftAlign} top`);
79
+ bounds = this.el.getBoundingClientRect()
80
+ if(bounds.top < 0) {
81
+ this.setPosition(`${leftAlign} bottom`);
82
+ }
83
+ bounds = this.el.getBoundingClientRect()
76
84
  }
77
85
  if (bounds.top < body_bounds.top) {
78
86
  const difference = body_bounds.top - bounds.top
@@ -83,6 +91,7 @@ export default class Popover extends Component {
83
91
  const difference = body_bounds.left - bounds.left
84
92
  if(this.el.style.left != null) this.el.style.left = parseInt(this.el.style.left) + difference + "px"
85
93
  if(this.el.style.right != null) this.el.style.right = parseInt(this.el.style.right) - difference + "px"
94
+ bounds = this.el.getBoundingClientRect()
86
95
  }
87
96
  if (bounds.right > body_bounds.right) {
88
97
  const difference = body_bounds.right - bounds.right
@@ -96,43 +105,43 @@ export default class Popover extends Component {
96
105
  var [leftAlign, topAlign] = align.split(" ");
97
106
  leftAlign = leftAlign || "bottom";
98
107
 
99
- var offset = Helpers.offset(this.options.anchor);
108
+ var anchorOffset = offset(this.options.anchor);
100
109
  var container = this.options.container;
101
110
  if(getComputedStyle(container)['position'] == "static") container = container.offsetParent;
102
111
  if(!container) container = document.body;
103
112
 
104
- var containerOffset = Helpers.offset(container);
105
- offset = {
106
- top: offset.top - containerOffset.top,
107
- left: offset.left - containerOffset.left
113
+ var containerOffset = offset(container);
114
+ anchorOffset = {
115
+ top: anchorOffset.top - containerOffset.top,
116
+ left: anchorOffset.left - containerOffset.left
108
117
  }
109
118
 
110
119
  var position = {};
111
120
  if(leftAlign == 'left'){
112
- position.right = Helpers.outerWidth(container) - offset.left;
121
+ position.right = outerWidth(container) - anchorOffset.left;
113
122
  } else if(leftAlign == 'center'){
114
- position.left = offset.left + Helpers.outerWidth(this.options.anchor) / 2 - Helpers.outerWidth(this.el) / 2;
123
+ position.left = anchorOffset.left + outerWidth(this.options.anchor) / 2 - outerWidth(this.el) / 2;
115
124
  } else if (leftAlign == 'right'){
116
- position.left = offset.left + Helpers.outerWidth(this.options.anchor);
125
+ position.left = anchorOffset.left + outerWidth(this.options.anchor);
117
126
  } else if (leftAlign.includes("px")){
118
- position.left = offset.left + parseInt(leftAlign);
127
+ position.left = anchorOffset.left + parseInt(leftAlign);
119
128
  }
120
129
 
121
130
  if(topAlign == 'top'){
122
- let height = Helpers.outerHeight(container);
131
+ let height = outerHeight(container);
123
132
  if(container == document.body && getComputedStyle(container)['position'] == "static"){
124
133
  height = window.innerHeight;
125
134
  } else if (container == document.body) {
126
135
  height = Math.max(height, document.body.clientHeight);
127
136
  }
128
- position.bottom = height - offset.top;
137
+ position.bottom = height - anchorOffset.top;
129
138
  } else if(topAlign == 'center'){
130
- position.top = offset.top + Helpers.outerHeight(this.options.anchor) / 2;
139
+ position.top = anchorOffset.top + outerHeight(this.options.anchor) / 2;
131
140
  position.transform = "translateY(-50%)";
132
141
  } else if (topAlign == 'bottom'){
133
- position.top = offset.top + Helpers.outerHeight(this.options.anchor);
142
+ position.top = anchorOffset.top + outerHeight(this.options.anchor);
134
143
  } else if (topAlign.includes("px")){
135
- position.top = offset.top + parseInt(topAlign);
144
+ position.top = anchorOffset.top + parseInt(topAlign);
136
145
  }
137
146
 
138
147
  if(this.options.offset.left) position.left += parseInt(this.options.offset.left);
@@ -145,9 +154,9 @@ export default class Popover extends Component {
145
154
  this.el.style.top = null;
146
155
  this.el.style.bottom = null;
147
156
  this.el.style.transform = null;
148
- Helpers.removeClass(this.el, 'popover-left popover-right popover-center popover-top popover-bottom');
149
- Helpers.addClass(this.el, 'popover-' + topAlign);
150
- Helpers.addClass(this.el, 'popover-' + leftAlign);
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);
151
160
  Object.keys(position).forEach(function(key){
152
161
  this.el.style[key] = position[key] + (key != "transform" ? "px" : "");
153
162
  }, this);
@@ -160,11 +169,13 @@ export default class Popover extends Component {
160
169
  if (e.target == this.options.anchor) return;
161
170
  if (this.el.contains(e.target)) return;
162
171
  if (this.options.anchor.contains(e.target)) return;
172
+ if (this.persisting) return;
163
173
  this.hide();
164
174
  }
165
175
 
166
176
  checkEscape (e) {
167
177
  if(e.which != 27) return;
178
+ if (this.persisting) return;
168
179
  this.hide();
169
180
  }
170
181
 
@@ -193,4 +204,12 @@ export default class Popover extends Component {
193
204
  flag = flag || this.showing;
194
205
  if(flag) this.hide(); else this.show();
195
206
  }
207
+
208
+ persist() {
209
+ this.persisting = true;
210
+ }
211
+
212
+ unpersist() {
213
+ this.persisting = false;
214
+ }
196
215
  }
@@ -1,43 +1,39 @@
1
1
  import Component from './component';
2
- import * as Helpers from './dom-helpers';
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
- Helpers.trigger(window, 'resize');
15
+ this.resize();
9
16
  }
10
17
 
11
18
  resize () {
12
- // breakpoints at 720, 1080, 1440
13
- var width = this.el.offsetWidth;
14
-
15
- if(width > 720 && !Helpers.hasClass(this.el, 'md-size')) {
16
- Helpers.addClass(this.el, 'md-size');
17
- Helpers.trigger(window, 'resized-md');
18
- } else if (width < 720 && Helpers.hasClass(this.el, 'md-size')) {
19
- Helpers.removeClass(this.el, 'md-size');
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(width > 1440 && !Helpers.hasClass(this.el, 'xl-size')) {
30
- Helpers.addClass(this.el, 'xl-size');
31
- Helpers.trigger(window, 'resized-xl');
32
- } else if (width < 1440 && Helpers.hasClass(this.el, 'xl-size')) {
33
- Helpers.removeClass(this.el, 'xl-size');
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,250 +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 * as Helpers from './dom-helpers';
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
- options
9
- class: String, appended to uniformSelect-edit button as class
10
- limit: int | false - number of options to limit to, or false to not limit
11
- showAll: function(button_options) to run if/when "Show All" is clicked
12
- label: string, used for mobile menu
13
- container: selector for where to render dropdown
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
- initialize (options = {}) {
18
- this.options = {
19
- label: false,
20
- class: "",
21
- showAll: function (button_options){
22
- Helpers.removeClass(button_options.querySelectorAll('button.hide'), 'hide');
23
- var button = button_options.querySelector('.uniformSelect-show-all');
24
- button.parentNode.removeChild(button);
25
-
26
- return false;
27
- },
28
- limit: 8,
29
- container: document.body
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
- Object.assign(this.options, this.pick(options, Object.keys(this.options)));
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
- this.listenTo(this.el, 'change', this.renderSelected);
35
- this.listenTo(this.el, 'close', this.hideOptions);
36
- this.el.uniformSelect = this;
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
- this.activeIcon = document.createElement('span');
39
- this.activeIcon.innerHTML = checkIcon;
40
- Helpers.addClass(this.activeIcon, 'uniformSelect-option-icon');
41
- }
67
+ this.indicatorEl = createElement('span', {children: arrowIcon})
68
+ this.indicatorEl.classList.add('uniformSelect-indicator')
69
+ this.el.append(this.indicatorEl);
42
70
 
43
- remove () {
44
- Component.prototype.remove.apply(this, arguments);
45
- this.edit_button.parentNode.removeChild(this.edit_button);
46
- delete this.this.edit_button;
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
- if(this.button_options_popover) this.button_options_popover.remove();
52
- if(this.button_options_modal) this.button_options_modal.remove();
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
- if(this.button_options) {
55
- this.button_options.parentNode.removeChild(this.button_options);
56
- delete this.button_options;
57
- }
58
- }
83
+ this.renderValue();
84
+ return this;
85
+ }
59
86
 
60
- render () {
61
- this.edit_button = Helpers.createElement(`
62
- <button type='button' class='uniformSelect-edit uniformInput outline block ${this.options.class}'>
63
- <span class="text-js"></span>
64
- <span class="uniformSelect-edit-icon">${arrowIcon}</span>
65
- </button>
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
- // Set Min-Width for when empty
75
- const option = this.el.querySelectorAll("option")[0];
76
- this.edit_button.querySelector('.text-js').style.opacity = 0;
77
- this.edit_button.querySelector('.text-js').innerHTML = option.textContent;
78
- const min_width = this.edit_button.querySelector('.text-js').offsetWidth;
79
- this.edit_button.style.minWidth = min_width + "px";
80
- this.edit_button.querySelector('.text-js').innerHTML = "";
81
- this.edit_button.querySelector('.text-js').style.opacity = null;
82
-
83
- this.renderSelected();
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(" ");
84
94
 
85
- this.listenTo(this.edit_button, 'click', this.showOptions);
86
- this.listenTo(this.edit_button, 'click', '.uniformSelect-remove', this.removeSelection);
87
-
88
- 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');
89
102
  }
90
-
91
- renderOptions () {
92
- this.button_options = Helpers.createElement("<div class='uniformSelect-options'>");
93
- if (this.el.name) {
94
- Helpers.addClass(this.button_options, this.el.name.toLowerCase().replace(/[^a-z0-9\-_]+/g, '-'));
95
- }
96
- this.button_options.style.fontSize = Helpers.css(this.el, 'font-size');
103
+ toggleClass(e.target, 'active', makeActive);
104
+ e.target.option.selected = makeActive;
97
105
 
98
- Helpers.each(this.el.querySelectorAll('option'), function(el, index){
99
- var button = Helpers.createElement("<button type='button' class='uniformSelect-option block outline text-left'>");
100
- button.option = el;
101
- button.textContent = el.textContent;
102
- button.value = el.value;
103
- if (button.textContent == "") button.innerHTML = "<span class='text-italic text-muted'>None</span>";
104
- if(el.selected){
105
- Helpers.addClass(button, 'active');
106
- button.append(this.activeIcon.cloneNode(true));
107
- } else if (this.options.limit && index > this.options.limit) {
108
- Helpers.addClass(button, 'hide');
109
- }
110
- this.button_options.append(button);
111
- }.bind(this));
112
-
113
- this.listenTo(this.button_options, 'click', '.uniformSelect-option', this.selectOption);
114
-
115
- const actions_el = Helpers.createElement('<div class="uniformSelect-options-actions"></div>');
116
- if (this.options.limit && this.el.querySelectorAll('option').length > this.options.limit) {
117
- const show_all_button = Helpers.createElement("<button type='button' class='uniformSelect-show-all outline blue' style='display: block; border: none'>Show All</button>");
118
- this.listenTo(show_all_button, 'click', function(e){
119
- Helpers.trigger(this.el, 'show_all');
120
- if (this.options.showAll) this.options.showAll(this.button_options);
121
- e.preventDefault();
122
- e.stopPropagation();
123
- })
124
- actions_el.appendChild(show_all_button);
125
- }
126
- if (this.el.multiple) {
127
- var done_button = Helpers.createElement("<button type='button' class='uniformSelect-done block outline blue'>Done</button>");
128
- this.listenTo(done_button, 'click', this.hideOptions);
129
- actions_el.appendChild(done_button);
130
- }
131
- if (!Helpers.is_empty(actions_el)) {
132
- this.button_options.appendChild(actions_el);
133
- }
106
+ if (!this.options.multiple) {
107
+ this.removeOptions();
134
108
  }
135
-
136
- renderSelected () {
137
- const selected_options = Helpers.filter(this.el.querySelectorAll("option"), function(el){
138
- return el.selected;
139
- });
140
- const html = Helpers.map(selected_options, function(el){
141
- return this.el.multiple ? `<span class="uniformSelect-selection">${el.textContent}<span class="uniformSelect-remove"></span></span>` : el.textContent;
142
- }.bind(this)).join(" ");
143
109
 
144
- if (html == "") {
145
- this.edit_button.querySelector('.text-js').innerHTML = "&nbsp;"
146
- } else {
147
- this.edit_button.querySelector('.text-js').innerHTML = html;
148
- }
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');
149
122
 
150
- if(this.button_options) {
151
- Helpers.each(this.button_options.querySelectorAll('.uniformSelect-option'), function(el) {
152
- if(el.option.selected){
153
- Helpers.addClass(el, 'active');
154
- el.append(this.activeIcon.cloneNode(true));
155
- } else {
156
- Helpers.removeClass(el, 'active');
157
- Helpers.each(el.querySelectorAll('.uniformSelect-option-icon'), Helpers.remove);
158
- }
159
- }.bind(this))
160
- }
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;
161
129
  }
162
-
163
- hideOptions () {
164
- if(!this.button_options) return;
165
- if(this.button_options_modal) this.button_options_modal.close();
166
- if(this.button_options_popover) {
167
- this.button_options_popover.remove();
168
- delete this.button_options_popover;
169
- }
170
- 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()
171
135
  }
136
+ }
172
137
 
173
- showOptions(e) {
174
- if(Helpers.hasClass(e.target, 'uniformSelect-remove')) return;
175
- if(this.button_options_modal) return this.hideOptions();
176
- if(this.button_options_popover) return this.hideOptions();
177
- if(!this.button_options) this.renderOptions();
178
- Helpers.addClass(this.edit_button, 'active');
179
- // For Mobile: Render Full Screen
180
- if(window.innerWidth < 720) {
181
- const content = Helpers.createElement('<div class="uniformSelect-modal">');
182
- content.append(this.button_options);
183
- if (this.options.label) {
184
- content.append(`<div class="uniformSelect-label margin-bottom text-bold">${this.options.label}</div>`);
185
- }
186
- this.button_options_modal = new Modal({
187
- content: content,
188
- klass: '-reset'
189
- }).render();
190
- this.button_options_modal.on('closed', () => {
191
- Helpers.removeClass(this.edit_button, 'active');
192
- delete this.button_options_modal;
193
- });
194
- this.listenTo(content, 'click', function(e){
195
- if(e.target == content) {
196
- this.button_options_modal.close()
197
- }
198
- });
199
- // For Larger: Render Popover
200
- } else {
201
- this.button_options.style.minWidth = this.edit_button.offsetWidth + "px";
202
- this.button_options_popover = new Popover({
203
- offset: {top: 1},
204
- anchor: this.edit_button,
205
- align: '0px bottom',
206
- content: this.button_options,
207
- container: this.options.container
208
- }).render()
209
- this.button_options_popover.on('hidden', () => {
210
- Helpers.removeClass(this.edit_button, 'active');
211
- this.button_options_popover.remove();
212
- delete this.button_options_popover;
213
- })
214
- }
215
- }
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);
216
165
 
217
- selectOption(e) {
218
- if (!this.el.multiple) {
219
- Helpers.each(Helpers.filter(this.el.querySelectorAll("option"), function(el){
220
- return el.selected;
221
- }), function (child) {
222
- child.selected = false;
223
- });
224
- Helpers.each(this.button_options.querySelectorAll('.uniformSelect-option.active .uniformSelect-option-icon'), Helpers.remove);
225
- Helpers.removeClass(this.button_options.querySelectorAll('.uniformSelect-option.active'), 'active');
226
- }
227
- Helpers.toggleClass(e.target, 'active');
228
- e.target.option.selected = Helpers.hasClass(e.target, 'active');
229
- Helpers.each(this.button_options.querySelectorAll("button"), function(button) {
230
- if(!button.option) return;
231
- Helpers.toggleClass(button, 'active', button.option.selected);
232
- if (Helpers.hasClass(button, 'active')) {
233
- button.append(this.activeIcon.cloneNode(true));
234
- } else {
235
- Helpers.each(button.querySelectorAll('.uniformSelect-option-icon'), Helpers.remove);
236
- }
237
- }.bind(this))
238
- Helpers.trigger(this.el, 'change');
239
- }
166
+
167
+ const actions = createElement('div', {
168
+ class: 'uniformSelect-actions'
169
+ });
240
170
 
241
- removeSelection(e) {
242
- e.preventDefault();
243
- var target = Helpers.filter(this.el.querySelectorAll("option"), function(el){
244
- return el.innerText.trim() == e.target.parentNode.innerText.trim();
245
- })[0];
246
- if(!target) return;
247
- target.selected = false;
248
- Helpers.trigger(this.el, 'change');
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);
188
+ }
189
+ if (!isEmpty(actions)) {
190
+ options.append(actions);
249
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
+ }
250
218
  }