wave-ui 3.14.3 → 3.15.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": "3.14.3",
3
+ "version": "3.15.0",
4
4
  "description": "A UI framework for Vue.js 3 (and 2) with only the bright side. :sunny:",
5
5
  "author": "Antoni Andre <antoniandre.web@gmail.com>",
6
6
  "homepage": "https://antoniandre.github.io/wave-ui",
@@ -42,53 +42,53 @@
42
42
  "vue framework",
43
43
  "ui"
44
44
  ],
45
+ "scripts": {
46
+ "dev": "vite",
47
+ "build": "vite build --base /wave-ui/",
48
+ "build-types": "tsc -p ./tsconfig.json",
49
+ "build-bundle": "BUNDLE=true vite build && npm run build-types && mv ./dist/style.css ./dist/wave-ui.css",
50
+ "preview": "vite preview --base /wave-ui/",
51
+ "lint": "vite lint",
52
+ "publish-doc": "npm run build && npm run build-bundle && git add . && git commit -m 'Publish documentation on Github.' && git push && git push --tag"
53
+ },
45
54
  "devDependencies": {
46
- "@eslint/js": "^9.8.0",
55
+ "@eslint/js": "^9.9.1",
47
56
  "@faker-js/faker": "^8.4.1",
48
- "@mdi/font": "^6.9.96",
49
- "@tsconfig/recommended": "^1.0.6",
50
- "@typescript-eslint/eslint-plugin": "^6.21.0",
51
- "@typescript-eslint/parser": "^6.21.0",
52
- "@vitejs/plugin-vue": "^5.0.5",
53
- "@vue/compiler-sfc": "3.4.26",
54
- "autoprefixer": "^10.4.19",
55
- "axios": "^1.7.2",
56
- "eslint": "^9.8.0",
57
+ "@mdi/font": "^7.4.47",
58
+ "@tsconfig/recommended": "^1.0.7",
59
+ "@typescript-eslint/eslint-plugin": "^8.4.0",
60
+ "@typescript-eslint/parser": "^8.4.0",
61
+ "@vitejs/plugin-vue": "^5.1.3",
62
+ "@vue/compiler-sfc": "3.4.38",
63
+ "autoprefixer": "^10.4.20",
64
+ "axios": "^1.7.7",
65
+ "eslint": "^9.9.1",
57
66
  "eslint-config-standard": "^17.1.0",
58
- "eslint-plugin-import": "^2.29.1",
59
- "eslint-plugin-n": "^17.10.1",
60
- "eslint-plugin-promise": "^7.0.0",
61
- "eslint-plugin-vue": "^9.27.0",
67
+ "eslint-plugin-import": "^2.30.0",
68
+ "eslint-plugin-n": "^17.10.2",
69
+ "eslint-plugin-promise": "^7.1.0",
70
+ "eslint-plugin-vue": "^9.28.0",
62
71
  "font-awesome": "^4.7.0",
63
72
  "globals": "^15.9.0",
64
73
  "gsap": "^3.12.5",
65
74
  "ionicons": "^4.6.3",
66
75
  "material-design-icons": "^3.0.1",
67
- "postcss": "^8.4.38",
76
+ "postcss": "^8.4.44",
68
77
  "pug": "^3.0.3",
69
78
  "rollup-plugin-delete": "^2.0.0",
70
- "sass": "^1.77.6",
71
- "simple-syntax-highlighter": "^3.0.5",
79
+ "sass": "^1.77.8",
80
+ "simple-syntax-highlighter": "^3.0.8",
72
81
  "splitpanes": "^3.1.5",
73
- "typescript": "^5.5.2",
74
- "typescript-eslint": "^8.0.0",
75
- "vite": "^5.3.1",
82
+ "typescript": "^5.5.4",
83
+ "typescript-eslint": "^8.4.0",
84
+ "vite": "^5.4.2",
76
85
  "vite-svg-loader": "^5.1.0",
77
- "vue": "^3.4.30",
78
- "vue-router": "^4.4.0",
86
+ "vue": "^3.4.38",
87
+ "vue-router": "^4.4.3",
79
88
  "vueperslides": "^3.5.1",
80
89
  "vuex": "^4.1.0"
81
90
  },
82
91
  "peerDependencies": {
83
92
  "vue": "^3.2.0"
84
- },
85
- "scripts": {
86
- "dev": "vite",
87
- "build": "vite build --base /wave-ui/",
88
- "build-types": "tsc -p ./tsconfig.json",
89
- "build-bundle": "BUNDLE=true vite build && npm run build-types && mv ./dist/style.css ./dist/wave-ui.css",
90
- "serve": "vite preview --base /wave-ui/",
91
- "lint": "vite lint",
92
- "publish-doc": "npm run build && npm run build-bundle && git add . && git commit -m 'Publish documentation on Github.' && git push && git push --tag"
93
93
  }
94
- }
94
+ }
@@ -1,17 +1,20 @@
1
1
  <template lang="pug">
2
- component.w-image-wrap(:is="wrapperTag" :class="wrapperClasses" :style="wrapperStyles")
2
+ component.w-image(:is="wrapperTag" :class="wrapperClasses" :style="wrapperStyles")
3
3
  transition(:name="transition" appear)
4
- component.w-image(
4
+ component.w-image__image(
5
5
  v-if="loaded"
6
- :is="tag"
6
+ :is="normalized.tag"
7
7
  :class="imageClasses"
8
8
  :style="imageStyles"
9
- :src="tag === 'img' ? imgSrc : null")
10
- .w-image__loader(v-if="!noSpinner && loading")
9
+ :src="normalized.tag === 'img' ? computedImg.src : null")
10
+ span.w-image__loader(v-if="!noSpinner && loading")
11
11
  slot(v-if="$slots.loading" name="loading")
12
12
  w-progress(v-else circle indeterminate v-bind="spinnerColor ? { color: spinnerColor } : {}")
13
13
  component.w-image__content(v-if="$slots.default" :is="wrapperTag" :class="contentClass")
14
14
  slot
15
+ figcaption.w-image__caption.caption(v-if="$slots.caption" :class="captionClass")
16
+ slot(name="caption")
17
+ figcaption.w-image__caption.caption(v-else-if="caption" :class="captionClass" v-html="caption")
15
18
  </template>
16
19
 
17
20
  <script>
@@ -23,7 +26,7 @@ component.w-image-wrap(:is="wrapperTag" :class="wrapperClasses" :style="wrapperS
23
26
  * - adaptive size: given ratio + height 100% (use bg)
24
27
  * - adaptive & locked size: given width or height and using <img>
25
28
  *
26
- * @todo handle figure, captions, srcset, webp.
29
+ * @todo handle srcset.
27
30
  **/
28
31
 
29
32
  import { consoleWarn } from '../utils/console'
@@ -31,10 +34,12 @@ import { consoleWarn } from '../utils/console'
31
34
  export default {
32
35
  name: 'w-image',
33
36
  props: {
34
- tag: { type: String, default: 'span' },
37
+ tag: { type: String, default: 'span' }, // span, div, figure, img.
35
38
  src: { type: String },
36
39
  width: { type: [Number, String] },
37
40
  height: { type: [Number, String] },
41
+ maxWidth: { type: [Number, String] },
42
+ maxHeight: { type: [Number, String] },
38
43
  ratio: { type: [Number, String] },
39
44
  lazy: { type: Boolean },
40
45
  absolute: { type: Boolean },
@@ -44,7 +49,9 @@ export default {
44
49
  spinnerColor: { type: String },
45
50
  fallback: { type: String },
46
51
  transition: { type: String, default: 'fade' },
47
- contentClass: { type: [String, Array, Object] }
52
+ contentClass: { type: [String, Array, Object] },
53
+ caption: { type: String },
54
+ captionClass: { type: String }
48
55
  },
49
56
 
50
57
  emits: ['loading', 'loaded', 'error'],
@@ -53,49 +60,78 @@ export default {
53
60
  return {
54
61
  loading: false,
55
62
  loaded: false,
56
- imgSrc: '',
57
- imgWidth: this.width || 0,
58
- imgHeight: this.height || 0,
59
- imgComputedRatio: 0
63
+ // The computed image source, and real image dimensions.
64
+ computedImg: {
65
+ src: '',
66
+ width: 0,
67
+ height: 0,
68
+ ratio: 0
69
+ }
60
70
  }
61
71
  },
62
72
 
63
73
  computed: {
64
- imgGivenRatio () {
65
- return parseFloat(this.ratio)
74
+ // Normalized props.
75
+ normalized () {
76
+ return {
77
+ width: (!isNaN(this.width) ? `${this.width}px` : this.width) || null,
78
+ height: (!isNaN(this.height) ? `${this.height}px` : this.height) || null,
79
+ maxWidth: (!isNaN(this.maxWidth) ? `${this.maxWidth}px` : this.maxWidth) || null,
80
+ maxHeight: (!isNaN(this.maxHeight) ? `${this.maxHeight}px` : this.maxHeight) || null,
81
+ ratio: parseFloat(this.ratio) || undefined,
82
+ tag: this.tag === 'img' || this.tag === 'figure' || this.caption ? 'img' : 'span'
83
+ }
66
84
  },
67
85
 
68
86
  wrapperTag () {
87
+ if (this.caption || this.tag === 'figure') return 'figure'
69
88
  return ['span', 'div'].includes(this.tag) ? this.tag : 'span'
70
89
  },
71
90
 
72
91
  wrapperClasses () {
73
92
  return {
74
- 'w-image-wrap--absolute': this.absolute,
75
- 'w-image-wrap--fixed': this.fixed,
76
- 'w-image-wrap--has-ratio': this.imgGivenRatio
93
+ 'w-image--absolute': this.absolute,
94
+ 'w-image--fixed': this.fixed,
95
+ 'w-image--has-ratio': this.normalized.ratio
77
96
  }
78
97
  },
79
98
 
80
99
  wrapperStyles () {
100
+ let width = this.normalized.width
101
+ const height = this.normalized.height
102
+ let maxWidth = this.normalized.maxWidth
103
+ let aspectRatio = this.normalized.ratio
104
+
105
+ if (aspectRatio && !width && !height) width = '100%'
106
+ else if (!width && !height) {
107
+ width = '100%'
108
+ maxWidth = this.normalized.maxWidth || `${this.computedImg.width}px`
109
+ aspectRatio = aspectRatio || (this.computedImg.width / this.computedImg.height)
110
+ }
111
+ else if ((width && !height) || (height && !width)) {
112
+ aspectRatio = aspectRatio || (this.computedImg.width / this.computedImg.height)
113
+ }
114
+
81
115
  return {
82
- width: this.imgGivenRatio ? null : ((!isNaN(this.imgWidth) ? `${this.imgWidth}px` : this.imgWidth) || null),
83
- height: this.imgGivenRatio || this.tag === 'img' ? null : ((!isNaN(this.imgHeight) ? `${this.imgHeight}px` : this.imgHeight) || null),
84
- 'padding-bottom': this.imgGivenRatio && `${this.imgGivenRatio * 100}%`
116
+ width,
117
+ height,
118
+ maxWidth,
119
+ maxHeight: this.normalized.maxHeight,
120
+ aspectRatio
85
121
  }
86
122
  },
87
123
 
88
124
  imageClasses () {
89
125
  return {
90
- 'w-image--loading': this.loading,
91
- 'w-image--loaded': this.loaded,
92
- 'w-image--contain': this.contain
126
+ 'w-image__image--loading': this.loading,
127
+ 'w-image__image--loaded': this.loaded,
128
+ 'w-image__image--contain': this.contain
93
129
  }
94
130
  },
95
131
 
96
132
  imageStyles () {
97
133
  return {
98
- 'background-image': this.tag !== 'img' && this.loaded ? `url('${this.imgSrc}')` : null
134
+ 'background-image': this.normalized.tag !== 'img' && this.loaded ? `url('${this.computedImg.src}')` : null
99
135
  }
100
136
  }
101
137
  },
@@ -112,16 +148,14 @@ export default {
112
148
  return new Promise(resolve => {
113
149
  const img = new Image()
114
150
  img.onload = e => {
115
- if (!this.width && !this.height && !this.imgGivenRatio) {
116
- this.imgWidth = e.target.width
117
- this.imgHeight = e.target.height
118
- }
119
- this.imgComputedRatio = e.target.height / e.target.width
151
+ this.computedImg.width = e.target.width
152
+ this.computedImg.height = e.target.height
153
+ this.computedImg.ratio = e.target.height / e.target.width
120
154
 
121
155
  this.loading = false
122
156
  this.loaded = true
123
- this.imgSrc = loadFallback ? this.fallback : this.src
124
- this.$emit('loaded', this.imgSrc)
157
+ this.computedImg.src = loadFallback ? this.fallback : this.src
158
+ this.$emit('loaded', this.computedImg.src)
125
159
 
126
160
  return resolve(img)
127
161
  }
@@ -162,43 +196,28 @@ export default {
162
196
  watch: {
163
197
  src () {
164
198
  this.loadImage()
165
- },
166
- width (value) {
167
- this.imgWidth = value
168
- },
169
- height (value) {
170
- this.imgHeight = value
171
199
  }
172
200
  }
173
201
  }
174
202
  </script>
175
203
 
176
204
  <style lang="scss">
177
- .w-image-wrap {
205
+ .w-image {
178
206
  position: relative;
179
207
  display: inline-flex;
208
+ flex-direction: column;
180
209
  flex-grow: 0;
181
210
  flex-shrink: 0;
182
- width: 4em;
183
211
 
184
212
  &--has-ratio {width: 100%;}
185
- &[class^="bdrs"], &[class*=" bdrs"] {overflow: hidden;}
213
+ &--has-ratio, &[class^="bdrs"], &[class*=" bdrs"] {overflow: hidden;}
186
214
 
187
215
  img {
188
216
  width: 100%;
189
- height: auto;
217
+ height: 100%; // Allow stretching by design.
218
+ overflow: hidden; // Should be contained in the parent.
190
219
  position: static;
191
220
  }
192
- }
193
-
194
- .w-image {
195
- background-image: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'); // 1x1 blank gif.
196
- background-repeat: no-repeat;
197
- background-size: cover;
198
- position: absolute;
199
- inset: 0;
200
-
201
- &--contain {background-size: contain;}
202
221
 
203
222
  &__loader, &__content {
204
223
  position: absolute;
@@ -208,5 +227,20 @@ export default {
208
227
  align-items: center;
209
228
  z-index: 1;
210
229
  }
230
+
231
+ &__image {
232
+ background-image: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'); // 1x1 blank gif.
233
+ background-repeat: no-repeat;
234
+ background-size: cover;
235
+ position: absolute;
236
+ inset: 0;
237
+
238
+ &--contain {background-size: contain;}
239
+ }
240
+
241
+ &__caption {
242
+ padding-top: $base-increment;
243
+ text-align: right;
244
+ }
211
245
  }
212
246
  </style>