wave-ui 2.26.0 → 2.29.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.26.0",
3
+ "version": "2.29.0",
4
4
  "description": "An emerging UI framework for Vue.js & Vue 3 with only the bright side. :sunny:",
5
5
  "author": "Antoni Andre <antoniandre.web@gmail.com>",
6
6
  "main": "./dist/wave-ui.umd.js",
@@ -43,29 +43,29 @@
43
43
  "*.vue"
44
44
  ],
45
45
  "devDependencies": {
46
- "@babel/core": "^7.16.0",
47
- "@babel/eslint-parser": "^7.16.0",
48
- "@babel/plugin-proposal-class-properties": "^7.16.0",
46
+ "@babel/core": "^7.16.5",
47
+ "@babel/eslint-parser": "^7.16.5",
48
+ "@babel/plugin-proposal-class-properties": "^7.16.5",
49
49
  "@mdi/font": "^5.9.55",
50
- "@vitejs/plugin-vue": "^1.2.2",
50
+ "@vitejs/plugin-vue": "^1.10.2",
51
51
  "@vue/compiler-sfc": "3.1.5",
52
- "autoprefixer": "^10.2.5",
53
- "axios": "^0.21.1",
54
- "eslint": "^7.28.0",
52
+ "autoprefixer": "^10.4.1",
53
+ "axios": "^0.21.4",
54
+ "eslint": "^7.32.0",
55
55
  "font-awesome": "^4.7.0",
56
- "gsap": "^3.6.1",
56
+ "gsap": "^3.9.1",
57
57
  "ionicons": "^4.6.3",
58
58
  "material-design-icons": "^3.0.1",
59
59
  "rollup-plugin-delete": "^2.0.0",
60
- "sass": "^1.34.0",
61
- "simple-syntax-highlighter": "^2.0.6",
62
- "splitpanes": "^3.0.4",
63
- "vite": "^2.3.3",
60
+ "sass": "^1.45.1",
61
+ "simple-syntax-highlighter": "^2.2.0",
62
+ "splitpanes": "^3.0.6",
63
+ "vite": "^2.7.9",
64
64
  "vite-plugin-pug": "^0.3.0",
65
- "vue": "^3.2.16",
65
+ "vue": "^3.2.26",
66
66
  "vue-cal": "^4.2.0",
67
- "vue-router": "^4.0.8",
68
- "vueperslides": "^3.3.0",
67
+ "vue-router": "^4.0.12",
68
+ "vueperslides": "^3.3.2",
69
69
  "vuex": "^4.0.2"
70
70
  }
71
71
  }
@@ -5,9 +5,10 @@ export { default as WApp } from './w-app.vue'
5
5
  export { default as WBadge } from './w-badge.vue'
6
6
  export { default as WBreadcrumbs } from './w-breadcrumbs.vue'
7
7
  export { default as WButton } from './w-button.vue'
8
+ export { default as WCard } from './w-card.vue'
8
9
  export { default as WCheckbox } from './w-checkbox.vue'
9
10
  export { default as WCheckboxes } from './w-checkboxes.vue'
10
- export { default as WCard } from './w-card.vue'
11
+ export { default as WConfirm } from './w-confirm.vue'
11
12
  export { default as WDatePicker } from './w-date-picker.vue'
12
13
  export { default as WDialog } from './w-dialog.vue'
13
14
  export { default as WDivider } from './w-divider.vue'
@@ -19,7 +19,8 @@
19
19
  :tabindex="-1"
20
20
  text
21
21
  @keypress.stop
22
- @click.stop="!item._disabled && toggleItem(item, $event)")
22
+ @click.stop="!item._disabled && toggleItem(item, $event)"
23
+ :class="{ 'w-accordion__expand-icon--expanded': item._expanded }")
23
24
  //- Title.
24
25
  slot(
25
26
  v-if="$slots[`item-title.${item.id || i + 1}`]"
@@ -34,7 +35,8 @@
34
35
  :icon="(item._expanded && collapseIcon) || expandIcon"
35
36
  text
36
37
  @keypress.stop
37
- @click.stop="!item._disabled && toggleItem(item, $event)")
38
+ @click.stop="!item._disabled && toggleItem(item, $event)"
39
+ :class="{ 'w-accordion__expand-icon--expanded': item._expanded }")
38
40
  //- Content.
39
41
  w-transition-expand(y)
40
42
  .w-accordion__item-content(v-if="item._expanded" :class="contentClass")
@@ -148,8 +150,8 @@ export default {
148
150
  margin-right: $base-increment;
149
151
 
150
152
  .w-accordion--rotate-icon & {@include default-transition;}
151
- .w-accordion--rotate-icon .w-accordion__item--expanded & {transform: rotate(-180deg);}
152
- .w-accordion--rotate-icon.w-accordion--icon-right .w-accordion__item--expanded & {transform: rotate(180deg);}
153
+ &--expanded {transform: rotate(-180deg);}
154
+ .w-accordion--icon-right &--expanded {transform: rotate(180deg);}
153
155
 
154
156
  .w-icon:before {font-size: 1.1em;}
155
157
  }
@@ -1,5 +1,5 @@
1
1
  <template lang="pug">
2
- .w-app(:class="{ 'theme--dark': dark, 'd-block': block }")
2
+ .w-app(:class="classes")
3
3
  slot
4
4
  notification-manager
5
5
  </template>
@@ -16,7 +16,17 @@ export default {
16
16
  name: 'w-app',
17
17
  props: {
18
18
  dark: { type: Boolean },
19
- block: { type: Boolean }
19
+ block: { type: Boolean },
20
+ row: { type: Boolean },
21
+ alignCenter: { type: Boolean },
22
+ alignEnd: { type: Boolean },
23
+ justifyCenter: { type: Boolean },
24
+ justifyEnd: { type: Boolean },
25
+ justifySpaceBetween: { type: Boolean },
26
+ justifySpaceAround: { type: Boolean },
27
+ justifySpaceEvenly: { type: Boolean },
28
+ textCenter: { type: Boolean },
29
+ textRight: { type: Boolean }
20
30
  },
21
31
 
22
32
  components: { NotificationManager },
@@ -26,6 +36,25 @@ export default {
26
36
  notifManager: null
27
37
  }),
28
38
 
39
+ computed: {
40
+ classes () {
41
+ return {
42
+ 'd-block': this.block,
43
+ row: this.row,
44
+ 'align-center': this.alignCenter,
45
+ 'align-end': this.alignEnd,
46
+ 'justify-center': this.justifyCenter,
47
+ 'justify-end': this.justifyEnd,
48
+ 'justify-space-between': this.justifySpaceBetween,
49
+ 'justify-space-around': this.justifySpaceAround,
50
+ 'justify-space-evenly': this.justifySpaceEvenly,
51
+ 'text-center': this.textCenter,
52
+ 'text-right': this.textRight,
53
+ 'theme--dark': this.dark
54
+ }
55
+ }
56
+ },
57
+
29
58
  methods: {
30
59
  getBreakpoint () {
31
60
  const width = window.innerWidth
@@ -85,6 +114,17 @@ export default {
85
114
  flex-direction: column;
86
115
  min-height: 100vh;
87
116
 
117
+ &.row {flex-direction: row;}
88
118
  &.d-block {display: block;}
119
+ &.align-center {align-items: center;}
120
+ &.align-end {align-items: flex-end;}
121
+ &.justify-center {justify-content: center;}
122
+ &.justify-end {justify-content: flex-end;}
123
+ &.justify-space-between {justify-content: space-between;}
124
+ &.justify-space-around {justify-content: space-around;}
125
+ &.justify-space-evenly {justify-content: space-evenly;}
126
+ &.text-center {text-align: center;}
127
+ &.text-right {text-align: right;}
128
+
89
129
  }
90
130
  </style>
@@ -2,12 +2,12 @@
2
2
  .w-card(:class="classes" :style="styles")
3
3
  .w-card__title(
4
4
  v-if="$slots.title"
5
- :class="{ 'w-card__title--has-toolbar': titleHasToolbar, [titleClass]: titleClass || false }")
5
+ :class="{ 'w-card__title--has-toolbar': titleHasToolbar, ...titleClasses }")
6
6
  slot(name="title")
7
- .w-card__title(v-else-if="title" :class="titleClass || false" v-html="title")
7
+ .w-card__title(v-else-if="title" :class="titleClasses" v-html="title")
8
8
  w-image.w-card__image(v-if="image" :src="image" v-bind="imgProps")
9
9
  slot(name="image-content")
10
- .w-card__content(:class="contentClass || false")
10
+ .w-card__content(:class="contentClasses")
11
11
  slot
12
12
  .w-card__actions(
13
13
  v-if="$slots.actions"
@@ -16,6 +16,8 @@
16
16
  </template>
17
17
 
18
18
  <script>
19
+ import { objectifyClasses } from '../utils/index'
20
+
19
21
  export default {
20
22
  name: 'w-card',
21
23
 
@@ -28,21 +30,31 @@ export default {
28
30
  title: { type: String },
29
31
  image: { type: String },
30
32
  imageProps: { type: Object },
31
- titleClass: { type: String },
32
- contentClass: { type: String }
33
+ titleClass: { type: [String, Object, Array] },
34
+ contentClass: { type: [String, Object, Array] }
33
35
  },
34
36
 
35
37
  emits: [],
36
38
 
37
39
  computed: {
40
+ titleClasses () {
41
+ return objectifyClasses(this.titleClass)
42
+ },
43
+
44
+ contentClasses () {
45
+ return objectifyClasses(this.contentClass)
46
+ },
47
+
38
48
  titleHasToolbar () {
39
49
  const { title } = this.$slots
40
50
  return title && title().map(vnode => vnode.type.name).join('').includes('w-toolbar')
41
51
  },
52
+
42
53
  actionsHasToolbar () {
43
54
  const { actions } = this.$slots
44
55
  return actions && actions().map(vnode => vnode.type.name).join('').includes('w-toolbar')
45
56
  },
57
+
46
58
  imgProps () {
47
59
  return {
48
60
  tag: 'div',
@@ -50,6 +62,7 @@ export default {
50
62
  ...this.imageProps
51
63
  }
52
64
  },
65
+
53
66
  classes () {
54
67
  return {
55
68
  [this.color]: this.color,
@@ -59,6 +72,7 @@ export default {
59
72
  'w-card--shadow': this.shadow
60
73
  }
61
74
  },
75
+
62
76
  styles () {
63
77
  return false
64
78
  }
@@ -0,0 +1,103 @@
1
+ <template lang="pug">
2
+ .w-confirm
3
+ w-menu(v-model="showPopup" v-bind="wMenuProps")
4
+ template(#activator="{ on }")
5
+ w-button.w-confirm__button(v-on="on" v-bind="buttonProps")
6
+ slot
7
+ w-flex(:column="!inline" align-center)
8
+ div
9
+ slot(name="question") Are you sure?
10
+ .w-flex.justify-end(:class="inline ? 'ml2' : 'mt2'")
11
+ w-button.mr2(
12
+ v-if="!noCancel"
13
+ v-bind="cancelButton"
14
+ :bg-color="(cancelButton || {}).bgColor || 'error'"
15
+ @click="onCancel")
16
+ slot(name="cancel") Cancel
17
+ w-button(
18
+ v-bind="confirmButton"
19
+ :bg-color="(confirmButton || {}).bgColor || 'success'"
20
+ @click="onConfirm")
21
+ slot(name="confirm") Confirm
22
+ </template>
23
+
24
+ <script>
25
+ export default {
26
+ name: 'w-confirm',
27
+ props: {
28
+ // Main button props.
29
+ bgColor: { type: String },
30
+ color: { type: String },
31
+ icon: { type: String },
32
+ mainButton: { type: Object }, // Allow passing down an object of props to the w-button component.
33
+
34
+ // Cancel & confirm buttons props.
35
+ noCancel: { type: Boolean }, // Removes the cancel button.
36
+ cancelButton: { type: [Boolean, Object] }, // Allow passing down an object of props to the w-button component.
37
+ confirmButton: { type: Object }, // Allow passing down an object of props to the w-button component.
38
+
39
+ // global menu props.
40
+ inline: { type: Boolean }, // The layout inside the menu.
41
+
42
+ // W-menu props.
43
+ menu: { type: Object }, // Allow passing down an object of props to the w-menu component.
44
+ // All the menu props shorthands, as long as they don't conflict with the button props.
45
+ noArrow: { type: Boolean }, // Adds a directional triangle to the edge of the menu, like a tooltip.
46
+ top: { type: Boolean },
47
+ bottom: { type: Boolean },
48
+ left: { type: Boolean },
49
+ right: { type: Boolean },
50
+ alignTop: { type: Boolean },
51
+ alignBottom: { type: Boolean },
52
+ alignLeft: { type: Boolean },
53
+ alignRight: { type: Boolean },
54
+ persistent: { type: Boolean },
55
+ transition: { type: String }
56
+ },
57
+
58
+ emits: ['cancel', 'confirm'],
59
+
60
+ data: () => ({
61
+ showPopup: false,
62
+ props: []
63
+ }),
64
+
65
+ computed: {
66
+ wMenuProps () {
67
+ return {
68
+ top: this.top,
69
+ bottom: this.bottom,
70
+ left: this.left,
71
+ right: this.right,
72
+ arrow: !this.noArrow,
73
+ alignTop: this.alignTop,
74
+ alignBottom: this.alignBottom,
75
+ alignLeft: this.alignLeft,
76
+ alignRight: this.alignRight,
77
+ persistent: this.persistent,
78
+ transition: this.transition,
79
+ ...this.menu
80
+ }
81
+ },
82
+ buttonProps () {
83
+ return {
84
+ bgColor: this.bgColor,
85
+ color: this.color,
86
+ icon: this.icon,
87
+ ...this.mainButton
88
+ }
89
+ }
90
+ },
91
+
92
+ methods: {
93
+ onCancel () {
94
+ this.$emit('cancel')
95
+ this.showPopup = false
96
+ },
97
+ onConfirm () {
98
+ this.$emit('confirm')
99
+ this.showPopup = false
100
+ }
101
+ }
102
+ }
103
+ </script>
@@ -26,6 +26,7 @@ export default {
26
26
  justifyEnd: { type: Boolean },
27
27
  justifySpaceBetween: { type: Boolean },
28
28
  justifySpaceAround: { type: Boolean },
29
+ justifySpaceEvenly: { type: Boolean },
29
30
  basisZero: { type: Boolean },
30
31
  gap: { type: Number, default: 0 }
31
32
  },
@@ -48,6 +49,7 @@ export default {
48
49
  'justify-end': this.justifyEnd,
49
50
  'justify-space-between': this.justifySpaceBetween,
50
51
  'justify-space-around': this.justifySpaceAround,
52
+ 'justify-space-evenly': this.justifySpaceEvenly,
51
53
  'basis-zero': this.basisZero,
52
54
  [`w-flex--gap${this.gap}`]: this.gap
53
55
  }
@@ -111,9 +111,7 @@ export default {
111
111
  &.size--lg {font-size: round(1.7 * $base-font-size);}
112
112
  &.size--xl {font-size: 2 * $base-font-size;}
113
113
 
114
- // Icon's vertical alignment in button.
115
- .w-button &, .w-button &:before {line-height: inherit;}
116
- // Always an even number to vertical align well in button.
114
+ // Always an even number to align well vertically in a button.
117
115
  .w-button.size--xs & {font-size: round(0.95 * divide($base-font-size, 2)) * 2;}
118
116
  .w-alert.size--xs & {font-size: $base-font-size;}
119
117
  .w-button.size--sm &, .w-alert.size--sm & {font-size: round(1.15 * $base-font-size);}
@@ -23,8 +23,10 @@ component(
23
23
  tag="label"
24
24
  :for="`w-input--${_.uid}`"
25
25
  @click="$emit('click:inner-icon-left', $event)") {{ innerIconLeft }}
26
+ //- All types of input except file.
26
27
  input.w-input__input(
27
28
  v-if="type !== 'file'"
29
+ ref="input"
28
30
  v-model="inputValue"
29
31
  v-on="listeners"
30
32
  @input="onInput"
@@ -45,8 +47,10 @@ component(
45
47
  :required="required || null"
46
48
  :tabindex="tabindex || null"
47
49
  v-bind="attrs")
48
- template(v-if="type === 'file'")
50
+ //- Input type file.
51
+ template(v-else)
49
52
  input(
53
+ ref="input"
50
54
  :id="`w-input--${_.uid}`"
51
55
  type="file"
52
56
  :name="name || null"
@@ -160,7 +164,8 @@ export default {
160
164
  inputNumberError: false,
161
165
  isFocused: false,
162
166
  inputFiles: [], // For input type file.
163
- fileReader: null // For input type file.
167
+ fileReader: null, // For input type file.
168
+ isAutofilled: false
164
169
  }
165
170
  },
166
171
 
@@ -186,6 +191,7 @@ export default {
186
191
  hasValue () {
187
192
  return (
188
193
  this.inputValue ||
194
+ this.inputValue === 0 ||
189
195
  ['date', 'time'].includes(this.type) ||
190
196
  (this.type === 'number' && this.inputNumberError) ||
191
197
  (this.type === 'file' && this.inputFiles.length)
@@ -206,7 +212,7 @@ export default {
206
212
  'w-input--file': this.type === 'file',
207
213
  'w-input--disabled': this.isDisabled,
208
214
  'w-input--readonly': this.isReadonly,
209
- [`w-input--${this.hasValue ? 'filled' : 'empty'}`]: true,
215
+ [`w-input--${this.hasValue || this.isAutofilled ? 'filled' : 'empty'}`]: true,
210
216
  'w-input--focused': this.isFocused && !this.isReadonly,
211
217
  'w-input--dark': this.dark,
212
218
  'w-input--floating-label': this.hasLabel && this.labelPosition === 'inside' && !this.staticLabel,
@@ -293,9 +299,19 @@ export default {
293
299
  }
294
300
  },
295
301
 
302
+ mounted () {
303
+ // On page load, check if the field is autofilled by the browser.
304
+ // 20211229. Only a problem on Chrome. Firefox ok, Safari always prompts before filling up.
305
+ setTimeout(() => {
306
+ if (this.$refs.input.matches(':-webkit-autofill')) this.isAutofilled = true
307
+ }, 400) // Can't be less than 350: time for the browser to autofill.
308
+ },
309
+
296
310
  watch: {
297
311
  modelValue (value) {
298
312
  this.inputValue = value
313
+ // When clearing the field value, also reset the isAutofilled var for the CSS class.
314
+ if (!value && value !== 0) this.isAutofilled = false
299
315
  }
300
316
  }
301
317
  }