wave-ui 1.56.0 → 1.57.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,8 +1,11 @@
1
1
  {
2
2
  "name": "wave-ui",
3
- "version": "1.56.0",
3
+ "version": "1.57.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
+ "license": "MIT",
7
+ "repository": "https://github.com/antoniandre/wave-ui",
8
+ "funding": "https://github.com/sponsors/antoniandre",
6
9
  "main": "./dist/wave-ui.umd.js",
7
10
  "unpkg": "dist/wave-ui.umd.js",
8
11
  "jsdelivr": "dist/wave-ui.umd.js",
@@ -11,6 +14,7 @@
11
14
  "./dist/wave-ui.css": "./dist/wave-ui.css",
12
15
  "./dist/wave-ui.cjs.js": "./dist/wave-ui.cjs.js",
13
16
  "./src/wave-ui": "./src/wave-ui/index.js",
17
+ "./src/wave-ui/scss/_variables.scss": "./src/wave-ui/scss/_variables.scss",
14
18
  ".": {
15
19
  "import": "./dist/wave-ui.es.js",
16
20
  "require": "./dist/wave-ui.umd.js"
@@ -29,13 +33,11 @@
29
33
  "vue framework",
30
34
  "ui"
31
35
  ],
32
- "license": "MIT",
33
- "repository": "https://github.com/antoniandre/wave-ui",
34
36
  "scripts": {
35
37
  "dev": "vite",
36
38
  "build": "vite build --base /wave-ui/",
37
39
  "build-bundle": "BUNDLE=true vite build && mv ./dist/style.css ./dist/wave-ui.css",
38
- "serve": "vite preview --root docs --base /wave-ui/",
40
+ "serve": "vite preview --base /wave-ui/",
39
41
  "lint": "vite lint"
40
42
  },
41
43
  "sideEffects": [
@@ -44,40 +46,40 @@
44
46
  "*.vue"
45
47
  ],
46
48
  "devDependencies": {
47
- "@babel/core": "^7.17.9",
48
- "@babel/eslint-parser": "^7.17.0",
49
- "@babel/plugin-proposal-class-properties": "^7.16.7",
49
+ "@babel/core": "^7.19.0",
50
+ "@babel/eslint-parser": "^7.18.9",
51
+ "@babel/plugin-proposal-class-properties": "^7.18.6",
50
52
  "@vitejs/plugin-vue": "^1.10.2",
51
- "autoprefixer": "^10.4.2",
53
+ "autoprefixer": "^10.4.8",
52
54
  "axios": "^0.21.4",
53
- "core-js": "^3.21.0",
55
+ "core-js": "^3.25.0",
54
56
  "eslint": "^7.32.0",
55
57
  "eslint-config-standard": "^16.0.3",
56
- "eslint-plugin-import": "^2.25.4",
58
+ "eslint-plugin-import": "^2.26.0",
57
59
  "eslint-plugin-node": "^11.1.0",
58
60
  "eslint-plugin-promise": "^5.2.0",
59
61
  "eslint-plugin-vue": "^7.20.0",
60
62
  "font-awesome": "^4.7.0",
61
63
  "ghspa": "^1.0.0",
62
- "gsap": "^3.9.1",
64
+ "gsap": "^3.11.1",
63
65
  "ionicons": "^4.6.3",
64
66
  "material-design-icons": "^3.0.1",
65
- "postcss": "^8.4.12",
67
+ "postcss": "^8.4.16",
66
68
  "rollup-plugin-delete": "^2.0.0",
67
- "sass": "^1.49.7",
68
- "simple-syntax-highlighter": "^1.5.0",
69
- "splitpanes": "^2.3.8",
70
- "vite": "^2.7.13",
71
- "vite-plugin-pug": "^0.3.0",
69
+ "sass": "^1.54.8",
70
+ "simple-syntax-highlighter": "^1.5.1",
71
+ "splitpanes": "^2.4.1",
72
+ "vite": "^2.9.15",
73
+ "vite-plugin-pug": "^0.3.1",
72
74
  "vite-plugin-vue2": "^1.9.3",
73
- "vue": "^2.6.14",
74
- "vue-router": "^3.5.3",
75
+ "vue": "^2.7.10",
76
+ "vue-router": "^3.6.5",
75
77
  "vue-svg-loader": "^0.16.0",
76
- "vue-template-compiler": "^2.6.14",
77
- "vueperslides": "^2.15.2",
78
+ "vue-template-compiler": "^2.7.10",
79
+ "vueperslides": "^2.15.3",
78
80
  "vuex": "^3.6.2"
79
81
  },
80
82
  "dependencies": {
81
- "@mdi/font": "^6.5.95"
83
+ "@mdi/font": "^6.9.96"
82
84
  }
83
85
  }
@@ -5,12 +5,11 @@
5
5
  </template>
6
6
 
7
7
  <script>
8
- import config from '../utils/config'
9
8
  import NotificationManager from './w-notification-manager.vue'
10
- import DynamicCSS from '../utils/dynamic-css'
9
+ import dynamicCSS from '../utils/dynamic-css'
11
10
 
12
- const breakpointsNames = Object.keys(config.breakpoints)
13
- const breakpointsValues = Object.values(config.breakpoints)
11
+ // Global var for faster results in the resize event handler.
12
+ let breakpointsDef = { keys: [], values: [] }
14
13
 
15
14
  export default {
16
15
  name: 'w-app',
@@ -58,11 +57,11 @@ export default {
58
57
  methods: {
59
58
  getBreakpoint () {
60
59
  const width = window.innerWidth
61
- const breakpoints = breakpointsValues.slice(0)
60
+ const breakpoints = breakpointsDef.values.slice(0)
62
61
  // Most performant lookup.
63
62
  breakpoints.push(width)
64
63
  breakpoints.sort((a, b) => a - b)
65
- const breakpoint = breakpointsNames[breakpoints.indexOf(width)] || 'xl'
64
+ const breakpoint = breakpointsDef.keys[breakpoints.indexOf(width)] || 'xl'
66
65
 
67
66
  if (breakpoint !== this.currentBreakpoint) {
68
67
  this.currentBreakpoint = breakpoint
@@ -78,19 +77,18 @@ export default {
78
77
  }
79
78
 
80
79
  this.$waveui.breakpoint.width = width
81
- },
82
-
83
- dynamicStyles () {
84
- return DynamicCSS()
85
80
  }
86
81
  },
87
82
 
88
83
  mounted () {
84
+ const { config } = this.$waveui
85
+ breakpointsDef = { keys: Object.keys(config.breakpoints), values: Object.values(config.breakpoints) }
86
+
89
87
  // Inject global dynamic CSS classes in document head.
90
88
  if (!document.getElementById('wave-ui-styles')) {
91
89
  const css = document.createElement('style')
92
90
  css.id = 'wave-ui-styles'
93
- css.innerHTML = this.dynamicStyles()
91
+ css.innerHTML = dynamicCSS(config)
94
92
 
95
93
  const firstStyle = document.head.querySelectorAll('style,link[rel="stylesheet"]')[0]
96
94
  if (firstStyle) firstStyle.before(css)
@@ -127,6 +125,5 @@ export default {
127
125
  &.justify-space-evenly {justify-content: space-evenly;}
128
126
  &.text-center {text-align: center;}
129
127
  &.text-right {text-align: right;}
130
-
131
128
  }
132
129
  </style>
@@ -103,7 +103,7 @@ export default {
103
103
  ]
104
104
  },
105
105
  externalLink () {
106
- return /^(https?:)?\/\//.test(this.route)
106
+ return /^(https?:)?\/\/|mailto:|tel:/.test(this.route)
107
107
  },
108
108
  classes () {
109
109
  return {
@@ -1,7 +1,7 @@
1
1
  <template lang="pug">
2
2
  .w-divider(
3
3
  :class="classes"
4
- role="presentation"
4
+ :role="$slots.default ? null : 'presentation'"
5
5
  :aria-orientation="vertical ? 'vertical' : 'horizontal'")
6
6
  slot
7
7
  </template>
@@ -144,12 +144,10 @@ export default {
144
144
  el.Validation.message = validationMessage
145
145
  },
146
146
 
147
+ // Reset is called from:
148
+ // - the form `reset` event listener
149
+ // - the modelValue watcher when set to `null`.
147
150
  reset (e) {
148
- // Reset is called from:
149
- // - the form `reset` event listener
150
- // - the value watcher when set to `null`.
151
- // Prevent resetting twice on form reset that sets the value to null.
152
- if (!e) return
153
151
  this.status = null
154
152
 
155
153
  // Since the whole w-form may be disabled or readonly,
@@ -10,8 +10,6 @@ component.w-icon(
10
10
  </template>
11
11
 
12
12
  <script>
13
- import config from '../utils/config'
14
-
15
13
  export default {
16
14
  name: 'w-icon',
17
15
 
@@ -47,7 +45,7 @@ export default {
47
45
 
48
46
  computed: {
49
47
  hasLigature () {
50
- return config.iconsLigature === this.fontName
48
+ return this.$waveui.config.iconsLigature === this.fontName
51
49
  },
52
50
  forcedSize () {
53
51
  return this.size && (!isNaN(this.size) ? `${this.size}px` : this.size)
@@ -16,7 +16,6 @@ transition-group(
16
16
  </template>
17
17
 
18
18
  <script>
19
- import config from '../utils/config'
20
19
  import NotificationManager from '../utils/notification-manager'
21
20
 
22
21
  export default {
@@ -28,7 +27,7 @@ export default {
28
27
 
29
28
  computed: {
30
29
  conf () {
31
- return config.notificationManager
30
+ return this.$waveui.config.notificationManager
32
31
  },
33
32
  notifications () {
34
33
  return this.notifManager?.notifications || []
@@ -1,8 +1,9 @@
1
1
  <template lang="pug">
2
2
  transition(:name="transitionName" appear)
3
3
  .w-notification(v-if="show" :class="classes" :style="styles")
4
- w-alert.white--bg(
4
+ w-alert(
5
5
  v-bind="alertProps"
6
+ :class="alertClasses"
6
7
  @input="$emit('update:modelValue', false);$emit('input', false)")
7
8
  slot
8
9
  </template>
@@ -118,6 +119,11 @@ export default {
118
119
  }
119
120
  },
120
121
 
122
+ alertClasses () {
123
+ if (this.bgColor || ((this.success || this.info || this.warning || this.error) && this.plain)) return null
124
+ return 'white--bg'
125
+ },
126
+
121
127
  styles () {
122
128
  return {
123
129
  zIndex: this.zIndex || this.zIndex === 0 || null
@@ -73,7 +73,7 @@
73
73
  v-if="$scopedSlots[`item-cell.${header.key}`] || $scopedSlots[`item-cell.${j + 1}`] || $scopedSlots['item-cell']"
74
74
  :key="`${j}-a`"
75
75
  :data-label="header.label"
76
- :class="`text-${header.align || 'left'}`")
76
+ :class="{ [`text-${header.align || 'left'}`]: true, 'w-table__cell--sticky': header.sticky }")
77
77
  slot(
78
78
  v-if="$scopedSlots[`item-cell.${header.key}`]"
79
79
  :name="`item-cell.${header.key}`"
@@ -103,7 +103,7 @@
103
103
  v-else
104
104
  :key="`${j}-b`"
105
105
  :data-label="header.label"
106
- :class="`text-${header.align || 'left'}`")
106
+ :class="{ [`text-${header.align || 'left'}`]: true, 'w-table__cell--sticky': header.sticky }")
107
107
  div(v-html="item[header.key] || ''")
108
108
  span.w-table__col-resizer(
109
109
  v-if="j < headers.length - 1 && resizableColumns"
@@ -147,6 +147,7 @@ export default {
147
147
  items: { type: Array, required: true },
148
148
  headers: { type: Array, required: true },
149
149
  noHeaders: { type: Boolean },
150
+ fixedLayout: { type: Boolean },
150
151
  fixedHeaders: { type: Boolean },
151
152
  fixedFooter: { type: Boolean },
152
153
  loading: { type: Boolean },
@@ -264,11 +265,13 @@ export default {
264
265
 
265
266
  classes () {
266
267
  return {
268
+ 'w-table--fixed-layout': this.fixedLayout || this.resizableColumns || this.hasStickyColumn,
267
269
  'w-table--mobile': this.isMobile || null,
268
270
  'w-table--resizable-cols': this.resizableColumns || null,
269
271
  'w-table--resizing': this.colResizing.dragging,
270
272
  'w-table--fixed-header': this.fixedHeaders,
271
- 'w-table--fixed-footer': this.fixedFooter
273
+ 'w-table--fixed-footer': this.fixedFooter,
274
+ 'w-table--sticky-column': this.hasStickyColumn
272
275
  }
273
276
  },
274
277
 
@@ -276,6 +279,10 @@ export default {
276
279
  return ~~this.mobileBreakpoint && this.$waveui.breakpoint.width <= ~~this.mobileBreakpoint
277
280
  },
278
281
 
282
+ hasStickyColumn () {
283
+ return this.headers.find(header => header.sticky)
284
+ },
285
+
279
286
  // Faster lookup than array.includes(uid) and also cached.
280
287
  selectedRowsByUid () {
281
288
  return this.selectedRowsInternal.reduce((obj, uid) => (obj[uid] = true) && obj, {})
@@ -291,6 +298,7 @@ export default {
291
298
  headerClasses (header) {
292
299
  return {
293
300
  'w-table__header--sortable': header.sortable !== false, // Can also be falsy with `0`.
301
+ 'w-table__header--sticky': header.sticky,
294
302
  'w-table__header--resizable': !!this.resizableColumns,
295
303
  [`text-${header.align || 'left'}`]: true
296
304
  }
@@ -529,7 +537,7 @@ $tr-border-top: 1px;
529
537
  border-collapse: collapse;
530
538
  border: none;
531
539
 
532
- &--resizable-cols {
540
+ &--fixed-layout {
533
541
  table-layout: fixed; // Allow resizing beyond the cell minimum text width.
534
542
  }
535
543
 
@@ -552,6 +560,7 @@ $tr-border-top: 1px;
552
560
  position: sticky;
553
561
  top: 0;
554
562
  background-color: #fff;
563
+ z-index: 1; // For sticky columns to go under.
555
564
 
556
565
  &:after {
557
566
  content: '';
@@ -563,6 +572,22 @@ $tr-border-top: 1px;
563
572
  }
564
573
  }
565
574
 
575
+ &__header--sticky {
576
+ position: sticky;
577
+ left: 0;
578
+
579
+ &:before {
580
+ content: '';
581
+ position: absolute;
582
+ top: 0;
583
+ left: 0;
584
+ right: 0;
585
+ bottom: 0;
586
+ z-index: -1;
587
+ background-color: #fff;
588
+ }
589
+ }
590
+
566
591
  // Sorting arrow.
567
592
  &__header--sortable {cursor: pointer;}
568
593
  &__header-sort {
@@ -652,6 +677,24 @@ $tr-border-top: 1px;
652
677
  }
653
678
  }
654
679
 
680
+ &__cell--sticky {
681
+ position: sticky;
682
+ left: 0;
683
+
684
+ &:before, &:after {
685
+ content: '';
686
+ position: absolute;
687
+ top: 0;
688
+ left: 0;
689
+ right: 0;
690
+ bottom: 0;
691
+ z-index: -1;
692
+ }
693
+ &:before {background-color: #fff;}
694
+ }
695
+ tr:nth-child(odd) &__cell--sticky:after {background-color: $table-tr-odd-color;}
696
+ tr:hover &__cell--sticky:after {background-color: $table-tr-hover-color;}
697
+
655
698
  .no-data &__cell {
656
699
  background-color: rgba(255, 255, 255, 0.2);
657
700
  padding: (2 * $base-increment) $base-increment;
@@ -668,6 +711,7 @@ $tr-border-top: 1px;
668
711
  position: sticky;
669
712
  bottom: 0;
670
713
  background-color: #fff;
714
+ z-index: 1; // For sticky columns to go under.
671
715
 
672
716
  &:after {
673
717
  content: '';
@@ -329,6 +329,8 @@ export default {
329
329
  &__bar-extra {
330
330
  margin-left: auto;
331
331
  align-self: center;
332
+ position: sticky;
333
+ right: 0;
332
334
 
333
335
  .w-tabs__bar--right &,
334
336
  .w-tabs__bar--center & {margin-left: 0;}
@@ -356,6 +358,7 @@ export default {
356
358
  // ------------------------------------------------------
357
359
  &__content-wrap {
358
360
  position: relative;
361
+ flex-grow: 1;
359
362
 
360
363
  .w-tabs--card & {
361
364
  border: $border;
@@ -34,6 +34,8 @@ export default class WaveUI {
34
34
  return obj
35
35
  }, { ...config.colors, black: '#000', white: '#fff', transparent: 'transparent', inherit: 'inherit' })
36
36
 
37
+ config = {} // Store and expose the config in the $waveui object.
38
+
37
39
  static install (Vue, options = {}) {
38
40
  // Register directives.
39
41
  // for (const id in directives) {
@@ -103,7 +105,10 @@ export default class WaveUI {
103
105
  }
104
106
  }
105
107
 
108
+ this.config = config
109
+ this.notify = (...args) => notificationManager.notify(...args)
106
110
  WaveUI.instance = this
111
+
107
112
  // Make waveui reactive and expose the single instance in Vue.
108
113
  WaveUI.vueInstance.prototype.$waveui = WaveUI.vueInstance.observable(this)
109
114
 
@@ -116,4 +121,7 @@ export default class WaveUI {
116
121
  }
117
122
  }
118
123
 
119
- WaveUI.version = '__VERSION__'
124
+ /**
125
+ * Returns the WaveUI instance. Equivalent to using `$waveui` inside templates.
126
+ */
127
+ export const useWaveUI = () => inject('$waveui')
@@ -1,14 +1,3 @@
1
- import config from './config'
2
-
3
- const { css: cssConfig } = config
4
- const entries = Object.entries(config.breakpoints)
5
- const breakpoints = entries.map(([label, max], i) => {
6
- // Construct the breakpoint objects.
7
- const [, value = 0] = entries[i - 1] || []
8
- return { label, min: value ? value + 1 : 0, max }
9
- })
10
-
11
- let computedStyles = null
12
1
  // Defaults CSS variables. Will be overridden in the main function of this file (the export default)
13
2
  // which fetches the CSS :root variables generated by _layout.scss.
14
3
  const cssVars = {
@@ -16,7 +5,7 @@ const cssVars = {
16
5
  baseIncrement: 4
17
6
  }
18
7
 
19
- const generateColors = () => {
8
+ const generateColors = config => {
20
9
  let styles = ''
21
10
  const { cssScope } = cssVars
22
11
 
@@ -30,7 +19,7 @@ const generateColors = () => {
30
19
  }
31
20
 
32
21
  // Color shades are generated in core.js, if the option is on.
33
- if (cssConfig.colorShades && config.colorShades) {
22
+ if (config.css.colorShades && config.colorShades) {
34
23
  Object.entries(config.colorShades).forEach(([label, color]) => {
35
24
  styles +=
36
25
  `${cssScope} .${label}--bg{background-color:${color}}` +
@@ -56,7 +45,7 @@ const generateColors = () => {
56
45
  }
57
46
 
58
47
  // Generate the layout grid. E.g. xs1, xs2, ..., xl12.
59
- const generateBreakpoints = () => {
48
+ const generateBreakpoints = (breakpoints, grid) => {
60
49
  let styles = ''
61
50
  const { cssScope } = cssVars
62
51
 
@@ -74,20 +63,20 @@ const generateBreakpoints = () => {
74
63
  // Discard `xs` since the min is 0 (`media query (min-width: 0)`), and leave in _layout.scss.
75
64
  if (label === 'xs') {
76
65
  // For each breakpoint, loop from 1 to 12. E.g. xs1, xs2, ..., xl12.
77
- for (let i = 0; i < cssConfig.grid; i++) {
66
+ for (let i = 0; i < grid; i++) {
78
67
  styles +=
79
- `${cssScope} .${label}${cssConfig.grid - i}{` +
80
- `width:${parseFloat(((cssConfig.grid - i) * 100 / cssConfig.grid).toFixed(4))}%;}`
68
+ `${cssScope} .${label}${grid - i}{` +
69
+ `width:${parseFloat(((grid - i) * 100 / grid).toFixed(4))}%;}`
81
70
  }
82
71
  }
83
72
  else {
84
73
  styles += `@media(min-width:${min}px){`
85
74
 
86
75
  // For each breakpoint, loop from 1 to 12. E.g. xs1, xs2, ..., xl12.
87
- for (let i = 0; i < cssConfig.grid; i++) {
76
+ for (let i = 0; i < grid; i++) {
88
77
  styles +=
89
- `${cssScope} .${label}${cssConfig.grid - i}{` +
90
- `width:${parseFloat(((cssConfig.grid - i) * 100 / cssConfig.grid).toFixed(4))}%;}`
78
+ `${cssScope} .${label}${grid - i}{` +
79
+ `width:${parseFloat(((grid - i) * 100 / grid).toFixed(4))}%;}`
91
80
  }
92
81
 
93
82
  styles += '}'
@@ -104,7 +93,7 @@ const generateBreakpoints = () => {
104
93
  The drawback is that it generates so much CSS that I don't think it is worth it.
105
94
  In this test, for only 2 margin rules, it already generates 35kb of CSS...
106
95
 
107
- const generateBreakpointSpaces = () => {
96
+ const generateBreakpointSpaces = breakpoints => {
108
97
  let styles = ''
109
98
  const { cssScope, baseIncrement } = cssVars
110
99
 
@@ -128,7 +117,7 @@ const generateBreakpointSpaces = () => {
128
117
  styles += `${cssScope} .${label}-mx${i}{margin-right:${i * baseIncrement}px;margin-left:${i * baseIncrement}px}`
129
118
  }
130
119
  styles += '}'
131
- })
120
+ })
132
121
 
133
122
  breakpoints.forEach(({ label, max }) => {
134
123
  // Discard `xs`: xsd is just like xs.
@@ -148,7 +137,7 @@ const generateBreakpointSpaces = () => {
148
137
  return styles
149
138
  } */
150
139
 
151
- const genBreakpointLayoutClasses = () => {
140
+ const genBreakpointLayoutClasses = breakpoints => {
152
141
  let styles = ''
153
142
  const { cssScope, baseIncrement } = cssVars
154
143
  const layoutClasses = [
@@ -188,7 +177,6 @@ const genBreakpointLayoutClasses = () => {
188
177
  const array12 = Array(12).fill()
189
178
 
190
179
  // Define media queries for each breakpoint: xs, sm, md, lg, xl.
191
-
192
180
  breakpoints.forEach(({ label, min }) => {
193
181
  // Discard `xs` since the min is 0 (`media query (min-width: 0)`), and leave in _layout.scss.
194
182
  if (label !== 'xs') {
@@ -230,16 +218,23 @@ const genBreakpointLayoutClasses = () => {
230
218
  return styles
231
219
  }
232
220
 
233
- export default () => {
234
- let styles = ''
235
- computedStyles = getComputedStyle(document.documentElement)
221
+ export default config => {
222
+ const entries = Object.entries(config.breakpoints)
223
+ const breakpointsDef = entries.map(([label, max], i) => {
224
+ // Construct the breakpoint objects.
225
+ const [, value = 0] = entries[i - 1] || []
226
+ return { label, min: value ? value + 1 : 0, max }
227
+ })
228
+
229
+ const computedStyles = getComputedStyle(document.documentElement)
236
230
  cssVars.cssScope = computedStyles.getPropertyValue('--css-scope')
237
231
  cssVars.baseIncrement = parseInt(computedStyles.getPropertyValue('--base-increment'))
238
232
 
239
- styles += generateColors()
240
- styles += generateBreakpoints()
241
- if (cssConfig.breakpointLayoutClasses) styles += genBreakpointLayoutClasses()
242
- // if (cssConfig.breakpointSpaces) styles += generateBreakpointSpaces()
233
+ let styles = ''
234
+ styles += generateColors(config)
235
+ styles += generateBreakpoints(breakpointsDef, config.css.grid)
236
+ if (config.css.breakpointLayoutClasses) styles += genBreakpointLayoutClasses(breakpointsDef)
237
+ // if (config.css.breakpointSpaces) styles += generateBreakpointSpaces(breakpointsDef)
243
238
 
244
239
  return styles
245
240
  }