wave-ui 2.32.3 → 2.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-ui",
3
- "version": "2.32.3",
3
+ "version": "2.35.0",
4
4
  "description": "An emerging UI framework for Vue.js (2 & 3) with only the bright side. :sunny:",
5
5
  "author": "Antoni Andre <antoniandre.web@gmail.com>",
6
6
  "main": "./dist/wave-ui.umd.js",
@@ -125,14 +125,6 @@ export default {
125
125
  [item[this.itemColorKey]]: item[this.itemColorKey]
126
126
  }
127
127
  }
128
- },
129
-
130
- watch: {
131
- modelValue (array) {
132
- this.accordionItems.forEach((item, i) => {
133
- item.expanded = (Array.isArray(array) && array[i]) || false
134
- })
135
- }
136
128
  }
137
129
  }
138
130
  </script>
@@ -1,5 +1,5 @@
1
1
  <template lang="pug">
2
- .w-card(:class="classes" :style="styles")
2
+ .w-card(:class="classes")
3
3
  .w-card__title(
4
4
  v-if="$slots.title"
5
5
  :class="{ 'w-card__title--has-toolbar': titleHasToolbar, ...titleClasses }")
@@ -71,10 +71,6 @@ export default {
71
71
  'w-card--tile': this.tile,
72
72
  'w-card--shadow': this.shadow
73
73
  }
74
- },
75
-
76
- styles () {
77
- return false
78
74
  }
79
75
  }
80
76
  }
@@ -107,6 +103,17 @@ export default {
107
103
  &__content {
108
104
  padding: 3 * $base-increment;
109
105
  flex-grow: 1;
106
+
107
+ // Only if there is no title bar.
108
+ &:first-child {
109
+ border-top-left-radius: inherit;
110
+ border-top-right-radius: inherit;
111
+ }
112
+ &:last-child {
113
+ // Only if there is no actions bar.
114
+ border-bottom-left-radius: inherit;
115
+ border-bottom-right-radius: inherit;
116
+ }
110
117
  }
111
118
 
112
119
  &__actions {
@@ -4,12 +4,13 @@ w-overlay.w-dialog(
4
4
  :persistent="persistent"
5
5
  :persistent-no-animation="persistentNoAnimation"
6
6
  @click="onOutsideClick"
7
+ @closed="$emit('closed')"
7
8
  :bg-color="overlayColor"
8
9
  :opacity="overlayOpacity"
9
10
  :class="classes")
10
11
  transition(:name="transition" appear @after-leave="onClose")
11
12
  w-card.w-dialog__content(
12
- v-if="showContent"
13
+ v-show="showContent"
13
14
  no-border
14
15
  :color="color"
15
16
  :bg-color="bgColor"
@@ -18,10 +19,10 @@ w-overlay.w-dialog(
18
19
  :content-class="contentClass"
19
20
  :title="title || undefined"
20
21
  :style="contentStyles")
21
- template(v-if="$slots.title" v-slot:title)
22
+ template(#title v-if="$slots.title")
22
23
  slot(name="title")
23
24
  slot
24
- template(v-if="$slots.actions" v-slot:actions)
25
+ template(#actions v-if="$slots.actions")
25
26
  slot(name="actions")
26
27
  </template>
27
28
 
@@ -47,7 +48,7 @@ export default {
47
48
  overlayOpacity: { type: [Number, String, Boolean] }
48
49
  },
49
50
 
50
- emits: ['input', 'update:modelValue', 'close'],
51
+ emits: ['input', 'update:modelValue', 'close', 'closed'],
51
52
 
52
53
  data () {
53
54
  return {
@@ -87,7 +88,7 @@ export default {
87
88
  this.showWrapper = false
88
89
  this.$emit('update:modelValue', false)
89
90
  this.$emit('input', false)
90
- this.$emit('close', false)
91
+ this.$emit('close')
91
92
  }
92
93
  },
93
94
 
@@ -18,7 +18,7 @@ export default {
18
18
  classes () {
19
19
  return {
20
20
  [`w-divider--has-color ${this.color}`]: this.color,
21
- 'w-divider--vertical': this.vertical,
21
+ [`w-divider--${this.vertical ? 'vertical' : 'horizontal'}`]: true,
22
22
  'w-divider--has-content': this.$slots.default
23
23
  }
24
24
  }
@@ -34,10 +34,14 @@ export default {
34
34
  &--has-color {border-color: currentColor;}
35
35
 
36
36
  &--vertical {
37
+ align-self: stretch; // Fill up the available height.
37
38
  display: flex;
38
39
  border-top-width: 0;
39
40
  border-left-width: 1px;
40
- align-self: stretch;
41
+ }
42
+
43
+ .w-toolbar--vertical > &--horizontal {
44
+ align-self: stretch; // Fill up the available width.
41
45
  }
42
46
 
43
47
  // With a slot.
@@ -1,12 +1,12 @@
1
1
  <template lang="pug">
2
2
  component.w-icon(
3
3
  :is="tag || 'i'"
4
- :class="classes"
5
4
  v-on="$attrs"
5
+ :class="classes"
6
6
  role="icon"
7
7
  aria-hidden="true"
8
- :style="styles")
9
- template(v-if="ligature") {{ ligature.icon }}
8
+ :style="readIcon() /* Always reacting to slot change when called from template. */ && styles")
9
+ template(v-if="hasLigature") {{ icon }}
10
10
  </template>
11
11
 
12
12
  <script>
@@ -41,15 +41,13 @@ export default {
41
41
  emits: [],
42
42
 
43
43
  data: () => ({
44
- icon: ''
44
+ icon: '',
45
+ fontName: ''
45
46
  }),
46
47
 
47
48
  computed: {
48
- ligature () {
49
- if (!config.iconsLigature) return false
50
-
51
- const [fontName, icon] = this.icon.split(' ')
52
- return fontName === config.iconsLigature && { fontName, icon }
49
+ hasLigature () {
50
+ return config.iconsLigature === this.fontName
53
51
  },
54
52
  forcedSize () {
55
53
  return this.size && (!isNaN(this.size) ? `${this.size}px` : this.size)
@@ -66,7 +64,8 @@ export default {
66
64
  },
67
65
  classes () {
68
66
  return {
69
- [this.icon]: true,
67
+ [this.fontName]: true,
68
+ [!this.hasLigature && this.icon]: !this.hasLigature && this.icon,
70
69
  [this.color]: this.color,
71
70
  [`${this.bgColor}--bg`]: this.bgColor,
72
71
  [`size--${this.presetSize}`]: this.presetSize && !this.forcedSize,
@@ -80,8 +79,7 @@ export default {
80
79
  'w-icon--rotate-90': this.rotate90a,
81
80
  'w-icon--rotate-135': this.rotate135a,
82
81
  'w-icon--flip-x': this.flipX,
83
- 'w-icon--flip-y': this.flipY,
84
- [this.ligature && this.ligature.fontName]: this.ligature
82
+ 'w-icon--flip-y': this.flipY
85
83
  }
86
84
  },
87
85
  styles () {
@@ -89,14 +87,13 @@ export default {
89
87
  }
90
88
  },
91
89
 
92
- created () {
93
- this.icon = this.$slots.default && this.$slots.default()[0].children
94
- },
95
-
96
- // Using the slot content directly in the classes computed is not always reacting to changes.
97
- // https://github.com/antoniandre/wave-ui/issues/81
98
- updated () {
99
- this.icon = this.$slots.default && this.$slots.default()[0].children
90
+ methods: {
91
+ readIcon () {
92
+ const { default: slot } = this.$slots
93
+ const [fontName = '', icon = ''] = typeof slot === 'function' && slot()[0].children.trim().split(' ') || []
94
+ this.fontName = fontName
95
+ this.icon = icon
96
+ }
100
97
  }
101
98
  }
102
99
  </script>
@@ -110,6 +107,7 @@ export default {
110
107
  justify-content: center;
111
108
  vertical-align: middle;
112
109
  user-select: none;
110
+ speak: never;
113
111
  line-height: 1;
114
112
  font-size: 1.2em;
115
113
  width: 1em;
@@ -5,6 +5,7 @@
5
5
  .w-menu(
6
6
  v-if="custom && detachableVisible"
7
7
  ref="detachable"
8
+ v-bind="$attrs"
8
9
  @click="hideOnMenuClick && close(true)"
9
10
  @mouseenter="showOnHover && (hoveringMenu = true)"
10
11
  @mouseleave="showOnHover && ((hoveringMenu = false), close())"
@@ -14,6 +15,7 @@
14
15
  w-card.w-menu(
15
16
  v-else-if="detachableVisible"
16
17
  ref="detachable"
18
+ v-bind="$attrs"
17
19
  @click.native="hideOnMenuClick && close(true)"
18
20
  @mouseenter.native="showOnHover && (hoveringMenu = true)"
19
21
  @mouseleave.native="showOnHover && ((hoveringMenu = false), close())"
@@ -134,7 +136,10 @@ export default {
134
136
  },
135
137
 
136
138
  overlayClasses () {
137
- return objectifyClasses(this.overlayClass)
139
+ return {
140
+ ...objectifyClasses(this.overlayClass),
141
+ 'w-overlay--no-pointer-event': this.showOnHover
142
+ }
138
143
  },
139
144
 
140
145
  classes () {
@@ -196,6 +201,7 @@ export default {
196
201
  methods: {
197
202
  /**
198
203
  * Other methods in the `detachable` mixin:
204
+ * - `open`
199
205
  * - `getActivatorCoordinates`
200
206
  * - `computeDetachableCoords`
201
207
  * - `onResize`
@@ -207,7 +213,8 @@ export default {
207
213
  // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
208
214
  toggle (e) {
209
215
  let shouldShowMenu = this.detachableVisible
210
- if ('ontouchstart' in window && this.showOnHover && e.type === 'click') {
216
+ if (typeof window !== 'undefined' && 'ontouchstart' in window &&
217
+ this.showOnHover && e.type === 'click') {
211
218
  shouldShowMenu = !shouldShowMenu
212
219
  }
213
220
  else if (e.type === 'click' && !this.showOnHover) shouldShowMenu = !shouldShowMenu
@@ -226,37 +233,6 @@ export default {
226
233
  else this.close()
227
234
  },
228
235
 
229
- // ! \ This function uses the DOM - NO SSR (only trigger from beforeMount and later).
230
- async open (e) {
231
- // A tiny delay may help positioning the detachable correctly in case of multiple activators
232
- // with different menu contents.
233
- if (this.delay) await new Promise(resolve => setTimeout(resolve, this.delay))
234
-
235
- this.detachableVisible = true
236
-
237
- // If the activator is external, there might be multiple,
238
- // so on open, the activator will be set to the event target.
239
- if (this.activator) this.activatorEl = e.target
240
-
241
- await this.insertInDOM()
242
-
243
- if (this.minWidth === 'activator') this.activatorWidth = this.activatorEl.offsetWidth
244
-
245
- if (!this.noPosition) this.computeDetachableCoords(e)
246
-
247
- // In `getActivatorCoordinates` accessing the menu computed styles takes a few ms (less than 10ms),
248
- // if we don't postpone the Menu apparition it will start transition from a visible menu and
249
- // thus will not transition.
250
- this.timeoutId = setTimeout(() => {
251
- this.$emit('update:modelValue', true)
252
- this.$emit('input', true)
253
- this.$emit('open')
254
- }, 0)
255
-
256
- if (!this.persistent) document.addEventListener('mousedown', this.onOutsideMousedown)
257
- if (!this.noPosition) window.addEventListener('resize', this.onResize)
258
- },
259
-
260
236
  /**
261
237
  * Closes the menu. Can happen on:
262
238
  * - click of activator
@@ -1,7 +1,8 @@
1
1
  <template lang="pug">
2
- transition(name="fade" mode="out-in" appear)
2
+ transition(name="fade" appear @after-leave="onClosed")
3
3
  .w-overlay(
4
- v-if="modelValue"
4
+ v-if="showOverlay"
5
+ v-show="modelValue"
5
6
  :style="(modelValue && styles) || null"
6
7
  @keydown.escape.stop="onClick"
7
8
  @click="onClick"
@@ -24,10 +25,11 @@ export default {
24
25
  persistentNoAnimation: { type: Boolean }
25
26
  },
26
27
 
27
- emits: ['input', 'update:modelValue', 'click', 'close'],
28
+ emits: ['input', 'update:modelValue', 'click', 'close', 'closed'],
28
29
 
29
30
  data: () => ({
30
- persistentAnimate: false
31
+ persistentAnimate: false,
32
+ showOverlay: false
31
33
  }),
32
34
 
33
35
  computed: {
@@ -60,10 +62,29 @@ export default {
60
62
  else if (!this.persistent) {
61
63
  this.$emit('update:modelValue', false)
62
64
  this.$emit('input', false)
63
- this.$emit('close', false)
65
+ this.$emit('close')
64
66
  }
65
67
 
66
68
  this.$emit('click', e)
69
+ },
70
+
71
+ // Wait until the end of the closing transition to unmount the components it contains.
72
+ // This way, in case of w-select in w-dialog, the w-select will only remove its activator
73
+ // element from the DOM once the dialog is completely closed.
74
+ // https://github.com/antoniandre/wave-ui/issues/82
75
+ onClosed () {
76
+ this.showOverlay = false
77
+ this.$emit('closed')
78
+ }
79
+ },
80
+
81
+ created () {
82
+ this.showOverlay = this.modelValue
83
+ },
84
+
85
+ watch: {
86
+ modelValue (bool) {
87
+ if (bool) this.showOverlay = true
67
88
  }
68
89
  }
69
90
  }
@@ -85,6 +106,7 @@ export default {
85
106
  background-color: rgba(0, 0, 0, 0.3);
86
107
 
87
108
  &--persistent-animate {animation: 0.15s w-overlay-pop cubic-bezier(0.6, -0.28, 0.74, 0.05);}
109
+ &--no-pointer-event {pointer-events: none;}
88
110
  }
89
111
 
90
112
  @keyframes w-overlay-pop {
@@ -25,11 +25,12 @@ component(
25
25
  align-left
26
26
  custom
27
27
  min-width="activator"
28
+ @mousedown="isFocused = true, selectingItem = true"
29
+ @mouseup="isFocused = true, selectingItem = false"
28
30
  v-bind="menuProps || {}")
29
31
  template(#activator="{ on }")
30
32
  //- Input wrapper.
31
33
  .w-select__selection-wrap(
32
- ref="selection-wrap"
33
34
  @click="!isDisabled && !isReadonly && (showMenu ? closeMenu : openMenu)()"
34
35
  role="button"
35
36
  aria-haspopup="listbox"
@@ -172,7 +173,9 @@ export default {
172
173
  inputValue: [],
173
174
  showMenu: false,
174
175
  menuMinWidth: 0,
175
- isFocused: false
176
+ isFocused: false,
177
+ selectingItem: false,
178
+ selectionWrapRef: undefined
176
179
  }),
177
180
 
178
181
  computed: {
@@ -209,7 +212,7 @@ export default {
209
212
  'w-select--disabled': this.isDisabled,
210
213
  'w-select--readonly': this.isReadonly,
211
214
  [`w-select--${this.hasValue ? 'filled' : 'empty'}`]: true,
212
- 'w-select--focused': this.isFocused && !this.isReadonly,
215
+ 'w-select--focused': (this.isFocused || this.selectingItem) && !this.isReadonly,
213
216
  'w-select--dark': this.dark,
214
217
  'w-select--floating-label': this.hasLabel && this.labelPosition === 'inside' && !this.staticLabel,
215
218
  'w-select--no-padding': !this.outline && !this.bgColor && !this.shadow && !this.round,
@@ -29,6 +29,10 @@ component(
29
29
  @click="$refs.input.focus();$refs.input.click()"
30
30
  v-on="$attrs"
31
31
  :class="inputClasses")
32
+ .w-switch__track(v-if="$slots.track")
33
+ slot(name="track")
34
+ .w-switch__thumb(v-if="$slots.thumb")
35
+ slot(name="thumb")
32
36
  template(v-if="hasLabel && !labelOnLeft")
33
37
  label.w-switch__label.w-form-el-shakable(v-if="$slots.default" :for="`w-switch--${_.uid}`")
34
38
  slot
@@ -77,6 +81,8 @@ export default {
77
81
  'w-switch--disabled': this.isDisabled,
78
82
  'w-switch--readonly': this.isReadonly,
79
83
  'w-switch--ripple': this.ripple.start,
84
+ 'w-switch--custom-thumb': this.$slots.thumb,
85
+ 'w-switch--custom-track': this.$slots.track,
80
86
  'w-switch--rippled': this.ripple.end
81
87
  }
82
88
  },
@@ -186,8 +192,18 @@ $disabled-color: #ddd;
186
192
  }
187
193
  }
188
194
 
189
- // Thumb.
190
- &__input:after {
195
+ // Track slot, if any.
196
+ &__track {
197
+ position: absolute;
198
+ left: 100%;
199
+ padding: 0 4px;
200
+ transform: translateX(-100%);
201
+ @include default-transition;
202
+ }
203
+ .w-switch--on &__track {left: 0;transform: translateX(0);}
204
+
205
+ // Thumb: show either the thumb slot if any, or :after otherwise.
206
+ &__thumb, &__input:after {
191
207
  content: '';
192
208
  position: absolute;
193
209
  left: 0;
@@ -196,22 +212,28 @@ $disabled-color: #ddd;
196
212
  height: $small-form-el-size;
197
213
  background-color: #fff;
198
214
  border-radius: 100%;
215
+ text-align: center;
199
216
  @include default-transition;
200
217
 
201
218
  .w-switch[class^="bdrs"] &, .w-switch[class*=" bdrs"] & {border-radius: inherit;}
202
219
 
203
- :checked ~ & {transform: translateX(100%);}
220
+ .w-switch--on & {left: 100%;transform: translateX(-100%);}
204
221
 
205
222
  .w-switch--thin & {
206
223
  top: - round(0.15 * $small-form-el-size);
207
224
  transform: scale(1.1);
208
225
  box-shadow: $box-shadow;
209
226
  }
210
- .w-switch--thin :checked ~ & {
211
- transform: translateX(100%) scale(1.1);
227
+ .w-switch--thin.w-switch--on & {
228
+ transform: translateX(-100%) scale(1.1);
212
229
  background-color: currentColor;
213
230
  }
214
231
  }
232
+ &--custom-thumb &__input:after {display: none;}
233
+ &__thumb > * {
234
+ width: inherit;
235
+ height: inherit;
236
+ }
215
237
 
216
238
  // The focus outline & ripple on switch activation.
217
239
  &__input:before {
@@ -223,11 +245,12 @@ $disabled-color: #ddd;
223
245
  height: $small-form-el-size;
224
246
  background-color: currentColor;
225
247
  border-radius: 100%;
226
- transform: translateX(100%) scale(0);
227
248
  opacity: 0;
228
249
  pointer-events: none;
229
250
  transition: 0.25s ease-in-out;
230
251
 
252
+ :checked ~ & {transform: translateX(-100%) scale(0);left: 100%;}
253
+
231
254
  .w-switch[class^="bdrs"] &, .w-switch[class*=" bdrs"] & {border-radius: inherit;}
232
255
  .w-switch--thin & {top: - round(0.15 * $small-form-el-size);}
233
256
  }
@@ -242,14 +265,14 @@ $disabled-color: #ddd;
242
265
  opacity: 0.2;
243
266
  }
244
267
  :focus:checked ~ &__input:before {
245
- transform: translateX(100%) scale(1.8);
268
+ transform: translateX(-100%) scale(1.8);
246
269
  }
247
270
 
248
271
  // After ripple reset to default state, then remove the class via js and the
249
272
  // `:focus ~ &__input:before` will re-transition to normal focused outline.
250
273
  &--rippled &__input:before {
251
274
  transition: none;
252
- transform: translateX(100%) scale(0);
275
+ transform: translateX(-100%) scale(0);
253
276
  opacity: 0;
254
277
  }
255
278
 
@@ -264,7 +287,7 @@ $disabled-color: #ddd;
264
287
  }
265
288
 
266
289
  @keyframes w-switch-ripple {
267
- 0% {opacity: 0.8;transform: translateX(100%) scale(1);background-color: currentColor;} // Start with visible ripple.
268
- 100% {opacity: 0;transform: translateX(100%) scale(2.8);} // Propagate ripple to max radius and fade out.
290
+ 0% {opacity: 0.8;transform: translateX(-100%) scale(1);background-color: currentColor;} // Start with visible ripple.
291
+ 100% {opacity: 0;transform: translateX(-100%) scale(2.8);} // Propagate ripple to max radius and fade out.
269
292
  }
270
293
  </style>
@@ -66,6 +66,7 @@ export default {
66
66
  titleClass: { type: String },
67
67
  activeClass: { type: String, default: 'primary' },
68
68
  noSlider: { type: Boolean },
69
+ pillSlider: { type: Boolean },
69
70
  sliderColor: { type: String, default: 'primary' },
70
71
  contentClass: { type: String },
71
72
  transition: { type: [String, Boolean], default: '' },
@@ -122,6 +123,7 @@ export default {
122
123
  return {
123
124
  'w-tabs--card': this.card,
124
125
  'w-tabs--no-slider': this.noSlider,
126
+ 'w-tabs--pill-slider': this.pillSlider,
125
127
  'w-tabs--fill-bar': this.fillBar,
126
128
  'w-tabs--init': this.init
127
129
  }
@@ -253,11 +255,11 @@ export default {
253
255
  &__bar {
254
256
  position: relative;
255
257
  display: flex;
256
- // align-items: center;
257
258
  overflow-x: auto;
258
259
 
259
260
  &--center {justify-content: center;}
260
261
  &--right {justify-content: flex-end;}
262
+ .w-tabs--pill-slider & {padding-left: $base-increment;}
261
263
 
262
264
  .w-tabs--card &:after {
263
265
  content: '';
@@ -311,6 +313,7 @@ export default {
311
313
  &:active:before {opacity: 0.08;}
312
314
  &--disabled:before {display: none;}
313
315
  }
316
+ &--pill-slider &__bar-item:before {display: none;}
314
317
 
315
318
  // Bar Extra.
316
319
  // ------------------------------------------------------
@@ -331,6 +334,13 @@ export default {
331
334
  background-color: currentColor;
332
335
  transition: $transition-duration ease-in-out;
333
336
  }
337
+ &--pill-slider &__slider {
338
+ opacity: 0.1;
339
+ bottom: 15%;
340
+ height: 70%;
341
+ border-radius: 99em;
342
+ }
343
+
334
344
  &--init &__slider {transition: none;}
335
345
 
336
346
  // Content.
@@ -13,6 +13,10 @@ export default {
13
13
  absolute: { type: Boolean },
14
14
  fixed: { type: Boolean },
15
15
  bottom: { type: Boolean },
16
+ vertical: { type: Boolean },
17
+ left: { type: Boolean },
18
+ right: { type: Boolean },
19
+ width: { type: [Number, String], default: null },
16
20
  height: { type: [Number, String], default: null },
17
21
  noBorder: { type: Boolean },
18
22
  shadow: { type: Boolean }
@@ -21,25 +25,35 @@ export default {
21
25
  emits: [],
22
26
 
23
27
  computed: {
24
- // Return the width or height value if defined, or false otherwise.
28
+ // Return the height value if defined, or false otherwise.
25
29
  toolbarHeight () {
26
30
  const h = this.height
27
31
  // If a number is passed without units, append `px`.
28
32
  return h && parseInt(h) == h ? h + 'px' : h
29
33
  },
34
+ // Return the width value if defined, or false otherwise.
35
+ toolbarWidth () {
36
+ const w = this.width
37
+ // If a number is passed without units, append `px`.
38
+ return w && parseInt(w) == w ? w + 'px' : w
39
+ },
30
40
  classes () {
31
41
  return {
32
42
  [this.color]: !!this.color,
33
43
  [`${this.bgColor}--bg`]: !!this.bgColor,
34
44
  'w-toolbar--absolute': !!this.absolute,
35
45
  'w-toolbar--fixed': !!this.fixed,
36
- [`w-toolbar--${this.bottom ? 'bottom' : 'top'}`]: true,
46
+ [`w-toolbar--${this.bottom ? 'bottom' : 'top'}`]: !this.vertical,
47
+ [`w-toolbar--vertical w-toolbar--${this.right ? 'right' : 'left'}`]: this.vertical,
37
48
  'w-toolbar--no-border': this.noBorder,
38
49
  'w-toolbar--shadow': !!this.shadow
39
50
  }
40
51
  },
41
52
  styles () {
42
- return this.height ? `height: ${this.toolbarHeight}` : false
53
+ return {
54
+ height: this.height && !this.vertical ? this.toolbarHeight : null,
55
+ width: this.width && this.vertical ? this.toolbarWidth : null
56
+ }
43
57
  }
44
58
  }
45
59
  }
@@ -58,16 +72,34 @@ export default {
58
72
  &--absolute, &--fixed {top: 0;left: 0;right: 0;}
59
73
  &--absolute {position: absolute;}
60
74
  &--fixed {position: fixed;}
75
+ &--absolute.w-toolbar--vertical, &--fixed.w-toolbar--vertical {top: 0;bottom: 0;}
76
+ &--absolute.w-toolbar--left, &--fixed.w-toolbar--left {left: 0;right: auto;}
77
+ &--absolute.w-toolbar--right, &--fixed.w-toolbar--right {left: auto;right: 0;}
78
+
79
+ // Horizontal.
61
80
  &--top {border-bottom: $border;}
62
81
  &--bottom {
63
82
  bottom: 0;
64
83
  top: auto;
65
84
  border-top: $border;
66
85
  }
67
- &--no-border, &--shadow {
68
- border-top-width: 0;
69
- border-bottom-width: 0;
86
+
87
+ // Vertical.
88
+ &--vertical {
89
+ padding: (2 * $base-increment);
90
+ flex-direction: column;
91
+ flex-grow: 0;
92
+ flex-shrink: 0;
93
+ }
94
+
95
+ &--left {border-right: $border;}
96
+ &--right {
97
+ right: 0;
98
+ left: auto;
99
+ border-left: $border;
70
100
  }
101
+
102
+ &--no-border, &--shadow {border-width: 0;}
71
103
  &--shadow {box-shadow: $box-shadow;}
72
104
 
73
105
  .w-app > & {z-index: 200;}
@@ -81,5 +113,13 @@ export default {
81
113
  border-bottom-left-radius: inherit;
82
114
  border-bottom-right-radius: inherit;
83
115
  }
116
+ .w-card__content &--left {
117
+ border-top-left-radius: inherit;
118
+ border-bottom-left-radius: inherit;
119
+ }
120
+ .w-card__content &--right {
121
+ border-top-right-radius: inherit;
122
+ border-bottom-right-radius: inherit;
123
+ }
84
124
  }
85
125
  </style>