@policystudio/policy-studio-ui-vue 1.0.16 → 1.0.20

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.
Files changed (51) hide show
  1. package/.eslintrc.js +67 -0
  2. package/.storybook/main.js +2 -1
  3. package/.storybook/preview.js +1 -1
  4. package/README.md +8 -0
  5. package/babel.config.js +3 -0
  6. package/backup-package-lock.json +37194 -0
  7. package/{src/assets/scss/tailwind.css → dist/css/psui_styles.css} +2213 -2735
  8. package/package.json +29 -19
  9. package/src/assets/images/check-checkbox-button.svg +1 -0
  10. package/src/assets/images/radio-checked-button.svg +1 -0
  11. package/src/assets/scss/base.scss +1 -1
  12. package/src/components/accordion/PsAccordion.vue +44 -0
  13. package/src/components/accordion/PsAccordionItem.vue +102 -0
  14. package/src/components/buttons/PsButton.vue +36 -13
  15. package/src/components/chips/PsChips.vue +164 -0
  16. package/src/components/controls/PsCheckbox.vue +3 -3
  17. package/src/components/controls/PsDraggable.vue +27 -2
  18. package/src/components/controls/PsRadioButton.vue +58 -57
  19. package/src/components/controls/PsSlider.vue +13 -12
  20. package/src/components/controls/PsSwitch.vue +76 -76
  21. package/src/components/datatable/PsDataTable.vue +89 -0
  22. package/src/components/datatable/PsDataTableItem.vue +57 -0
  23. package/src/components/forms/PsDropdown.vue +196 -0
  24. package/src/components/forms/PsInput.vue +9 -6
  25. package/src/components/tabs/PsTabHeader.vue +20 -21
  26. package/src/components/tooltip/PsDialogTooltip.vue +79 -0
  27. package/src/components/tooltip/PsRichTooltip.vue +38 -0
  28. package/src/components/tooltip/PsTooltip.vue +120 -0
  29. package/src/components/ui/PsIcon.vue +128 -0
  30. package/src/index.js +51 -22
  31. package/src/stories/Accordion.stories.js +35 -0
  32. package/src/stories/Button.stories.js +11 -11
  33. package/src/stories/Checkbox.stories.js +21 -14
  34. package/src/stories/Chips.stories.js +49 -0
  35. package/src/stories/Colors.stories.mdx +36 -35
  36. package/src/stories/Datatable.stories.js +50 -0
  37. package/src/stories/Dialog.stories.js +9 -9
  38. package/src/stories/Draggable.stories.js +24 -0
  39. package/src/stories/Dropdown.stories.js +34 -0
  40. package/src/stories/Input.stories.js +10 -10
  41. package/src/stories/RadioButton.stories.js +24 -8
  42. package/src/stories/Slider.stories.js +9 -9
  43. package/src/stories/Swith.stories.js +10 -10
  44. package/src/stories/TabHeader.stories.js +9 -9
  45. package/src/stories/Toast.stories.js +13 -13
  46. package/src/stories/Toggle.stories.js +29 -5
  47. package/src/stories/Tooltip.stories.js +113 -0
  48. package/src/util/GeneralFunctions.js +23 -0
  49. package/src/util/imageLoader.js +50 -0
  50. package/tailwind.config.js +19 -4
  51. package/src/assets/scss/tailwind.scss +0 -61088
@@ -0,0 +1,196 @@
1
+ <template>
2
+ <div
3
+ class="psui-relative psui-inline-block psui-text-left"
4
+ ref="PSDropdown"
5
+ >
6
+
7
+ <div class="psui-bg-red" ref="PSDropdownTrigger" v-if="$slots.dropdownTrigger" @click="show && !toggleWhenActive ? '' : toggle()" >
8
+ <slot name="dropdownTrigger" ></slot>
9
+ </div>
10
+
11
+ <button
12
+ v-else
13
+ @click="show && !toggleWhenActive ? '' : toggle()"
14
+ type="button"
15
+ class="psui-inline-flex psui-justify-center psui-items-center psui-w-full psui-font-medium psui-focus:shadow-outline-blue psui-dropdown-button psui-text-sm psui-leading-none"
16
+ :class="[buttonClasses]"
17
+ :id="id"
18
+ aria-haspopup="true"
19
+ aria-expanded="true"
20
+ ref="PSDropdownTrigger"
21
+ >
22
+ <slot v-if="show && $slots.buttonLabelOnShow" name="buttonLabelOnShow"></slot>
23
+ <slot v-else name="buttonLabel"></slot>
24
+ </button>
25
+
26
+ <div
27
+ ref="PSDropdownDialog"
28
+ role="menu"
29
+ class="psui-dropdown-dialog psui-hidden psui-origin-top-right psui-fixed psui-mt-2 psui-w-auto psui-rounded psui-shadow-lg psui-border psui-border-blue05 psui-z-50 psui-opacity-0"
30
+ aria-orientation="vertical"
31
+ :aria-labelledby="id"
32
+ :class="[dialogClasses]"
33
+ :style="{ minWidth: minWidthDropdown, marginLeft: marginLeft }"
34
+ >
35
+ <div class="w-full">
36
+ <h2 class="psui-text-gray02 psui-font-bold psui-whitespace-no-wrap psui-mb-4 ts--accent--1" v-if="title">{{ title }}</h2>
37
+ <slot name="items"></slot>
38
+ </div>
39
+
40
+ </div>
41
+ </div>
42
+ </template>
43
+
44
+ <script>
45
+ import { randomString, getParentScrollableEl } from '../../util/GeneralFunctions'
46
+
47
+ export default {
48
+ name: 'PsDropdown',
49
+ props: {
50
+ buttonClasses: {
51
+ type: String,
52
+ default: 'psui-bg-white psui-border psui-border-blue'
53
+ },
54
+ title: {
55
+ type: String,
56
+ },
57
+ dialogClasses: {
58
+ type: String,
59
+ default: 'psui-p-6 psui-left-0 psui-bg-white'
60
+ },
61
+ minWidthDropdown: {
62
+ type: [String, Number],
63
+ },
64
+ maxWidthDropDown: {
65
+ type: String,
66
+ default: '340px'
67
+ },
68
+ buttonLabelOnShow: {
69
+ type: Boolean,
70
+ default: false
71
+ },
72
+ toggleWhenActive: {
73
+ type: Boolean,
74
+ default: true
75
+ },
76
+ },
77
+ data() {
78
+ return {
79
+ show: false,
80
+ id: randomString(8),
81
+ marginLeft: '-0px',
82
+ scrollableParentEl : null
83
+ }
84
+ },
85
+ computed: {
86
+ getMaxWidth() {
87
+ let bounds = this.$refs.PSDropdown.getBoundingClientRect()
88
+ return (document.documentElement.clientWidth - bounds['left']) -30
89
+ }
90
+ },
91
+ beforeDestroy() {
92
+ this.unwatchParentScrolling()
93
+ },
94
+ methods: {
95
+ toggle() {
96
+ if (!this.show) {
97
+ this.open()
98
+ } else {
99
+ this.close()
100
+ }
101
+ },
102
+ watchParentScrolling() {
103
+ this.scrollableParentEl = getParentScrollableEl(this.$refs.PSDropdown)
104
+ if (this.scrollableParentEl) {
105
+ this.scrollableParentEl.addEventListener('scroll', this.updatePosition)
106
+ }
107
+ },
108
+ unwatchParentScrolling() {
109
+ if (this.scrollableParentEl) {
110
+ this.scrollableParentEl.removeEventListener('scroll', this.updatePosition)
111
+ }
112
+ },
113
+ updatePosition() {
114
+
115
+ const PSDropdownDialog = this.$refs.PSDropdownDialog
116
+ const PSDropdownTrigger = this.$refs.PSDropdownTrigger
117
+ if (!PSDropdownDialog || !PSDropdownTrigger) return
118
+
119
+ const rectTrigger = PSDropdownTrigger.getBoundingClientRect()
120
+ const rectDialog = PSDropdownDialog.getBoundingClientRect()
121
+ const windowWidth = document.documentElement.clientWidth
122
+
123
+ PSDropdownDialog.style.position = 'fixed'
124
+ PSDropdownDialog.style.top = `${rectTrigger.y + rectTrigger.height }px`
125
+
126
+ if (( rectTrigger.x + rectDialog.width + 20 ) > windowWidth ) {
127
+ PSDropdownDialog.style.left = `${windowWidth - rectDialog.width - 30}px`
128
+ } else {
129
+ PSDropdownDialog.style.left = `${rectTrigger.x}px`
130
+ }
131
+
132
+ if(rectTrigger.top < 10) {
133
+ this.close()
134
+ console.warn('The dropdown are too close from the top of the page')
135
+ return
136
+ }
137
+
138
+ setTimeout(() => { PSDropdownDialog.style.opacity = 1 }, 10)
139
+
140
+ },
141
+ open() {
142
+ this.$emit('open')
143
+ this.show = true
144
+ this.$refs.PSDropdownDialog.style.opacity = 0
145
+ this.$refs.PSDropdownDialog.style.display = 'block'
146
+ setTimeout(() => {
147
+ this.updatePosition()
148
+ this.watchParentScrolling()
149
+ document.addEventListener("keyup", this.handleEsc)
150
+ window.addEventListener("resize", this.updatePosition)
151
+ window.addEventListener("click", this.clickOutside)
152
+ }, 10)
153
+ },
154
+ close() {
155
+ if (this.show) {
156
+ this.$emit('close')
157
+ this.$refs.PSDropdownDialog.style.display = 'none'
158
+ this.$refs.PSDropdownDialog.style.opacity = 0
159
+ this.show = false
160
+ this.unwatchParentScrolling()
161
+ }
162
+ document.removeEventListener("keyup", this.handleEsc)
163
+ document.removeEventListener("resize", this.updatePosition)
164
+ document.removeEventListener("click", this.clickOutside)
165
+ },
166
+ handleEsc(evt) {
167
+ if (this.show && evt.keyCode === 27) this.close()
168
+ },
169
+ clickOutside(event) {
170
+ if(!this.show) return
171
+ if (!(this.$refs.PSDropdown == event.target || this.$refs.PSDropdown.contains(event.target))) {
172
+ this.close()
173
+ }
174
+ }
175
+ }
176
+ }
177
+ </script>
178
+
179
+ <style>
180
+
181
+ .dropdown-button {
182
+ background-color: transparent;
183
+ padding-top: 2.5px;
184
+ padding-bottom: 2.5px;
185
+ min-height: 27px;
186
+ }
187
+
188
+ .dropdown-button:focus {
189
+ outline: none;
190
+ }
191
+
192
+ .psui-dropdown-dialog {
193
+ transition: opacity 150ms ease-in-out;
194
+ }
195
+
196
+ </style>
@@ -14,11 +14,11 @@
14
14
  :class="[getInputClasses, { 'psui-border-red' : validation.hasError }]"
15
15
  :required="required"
16
16
  :value="value"
17
- @focus="$emit('focus')"
18
- @blur="$emit('blur')"
19
- @input="$emit('input', $event.target.value)"
20
- @keydown.enter="$emit('keydown', $event.target.value)"
21
- @change="$emit('change')"
17
+ @focus="$emit('focus', $event)"
18
+ @blur="$emit('blur', $event)"
19
+ @input="$emit('input', $event)"
20
+ @keydown.enter="$emit('keydown', $event)"
21
+ @change="$emit('change', $event)"
22
22
  v-bind="getAttrs"
23
23
  />
24
24
  <div class="psui-absolute psui-inset-y-0 psui-right-0 psui-pr-2 psui-flex psui-items-center" v-if="this.$slots.append">
@@ -70,7 +70,7 @@ export default {
70
70
  },
71
71
  computed: {
72
72
  getInputClasses() {
73
- return `${this.getPadding} ${this.getText} psui-text-gray-60 psui-bg-white psui-w-full psui-border psui-border-gray-30 psui-rounded-md psui-block hover:psui-border-blue-50 focus:psui-border-blue-50`
73
+ return `${this.getPadding} ${this.getText} psui-text-gray-60 psui-w-full psui-border psui-border-gray-30 psui-rounded-md psui-block hover:psui-border-blue-50 focus:psui-border-blue-50 ${this.getState}`
74
74
  },
75
75
  getText() {
76
76
  return this.mini ? 'psui-text-small' : ''
@@ -78,6 +78,9 @@ export default {
78
78
  getPadding() {
79
79
  return this.mini ? 'psui-px-2 mini-p' : 'psui-py-2 psui-px-4'
80
80
  },
81
+ getState() {
82
+ return this.disabled ? 'disabled:psui-bg-gray-20' : 'psui-bg-white'
83
+ },
81
84
  getAttrs() {
82
85
  const defaultAttrs = {
83
86
  autocapitalize: 'sentences',
@@ -21,6 +21,26 @@
21
21
  export const themeOptions = ['standard', 'underline', 'folder']
22
22
  export default {
23
23
  name: 'PsTabHeader',
24
+ props: {
25
+ theme: {
26
+ type: String,
27
+ default: 'standard',
28
+ validator: (value) => themeOptions.indexOf(value) !== -1
29
+ },
30
+ items: {
31
+ type: Array,
32
+ required: true
33
+ },
34
+ selected: {},
35
+ keyLabel: {
36
+ type: String,
37
+ default: 'label'
38
+ },
39
+ keyValue: {
40
+ type: String,
41
+ default: 'value'
42
+ }
43
+ },
24
44
  computed: {
25
45
  wrapperClasses() {
26
46
  if (this.theme === 'underline') {
@@ -67,27 +87,6 @@ export default {
67
87
  }
68
88
  }
69
89
  },
70
-
71
- props: {
72
- theme: {
73
- type: String,
74
- default: 'standard',
75
- validator: (value) => themeOptions.indexOf(value) !== -1
76
- },
77
- items: {
78
- type: Array,
79
- required: true
80
- },
81
- selected: {},
82
- keyLabel: {
83
- type: String,
84
- default: 'label'
85
- },
86
- keyValue: {
87
- type: String,
88
- default: 'value'
89
- }
90
- },
91
90
  methods: {
92
91
  selectTab(item) {
93
92
  this.$emit('update:selected', this.getIsObject ? item : item[this.keyValue] )
@@ -0,0 +1,79 @@
1
+ <template>
2
+ <PsTooltip :cssClass="getCssClass.content" :title="title">
3
+ <template v-slot:trigger>
4
+ <slot></slot>
5
+ </template>
6
+ <template
7
+ v-slot:dialog
8
+ class="psui-flex psui-fkex-col psui-gap-3 psui-items-start"
9
+ >
10
+ <p :class="type === 'white' ? 'psui-text-gray-50' : ''">{{ text }}</p>
11
+ <button
12
+ v-if="buttonText"
13
+ class="psui-py-2 psui-px-4 psui-rounded-md"
14
+ :class="getCssClass.button"
15
+ @click="onClick"
16
+ >
17
+ {{ buttonText }}
18
+ </button>
19
+ </template>
20
+ </PsTooltip>
21
+ </template>
22
+
23
+ <script>
24
+ import PsTooltip from "./PsTooltip.vue"
25
+
26
+ export default {
27
+ name: "PsDialogTooltip",
28
+ components: { PsTooltip },
29
+ props: {
30
+ text: {
31
+ type: String,
32
+ },
33
+ title: {
34
+ type: String,
35
+ },
36
+ buttonText: {
37
+ type: String,
38
+ },
39
+ type: {
40
+ type: String,
41
+ default: "white",
42
+ validator: (value) => ["white", "dark", "color"].includes(value),
43
+ },
44
+ cssClass: {
45
+ type: String,
46
+ required: false,
47
+ },
48
+ },
49
+ emits: ["click"],
50
+ computed: {
51
+ getCssClass() {
52
+
53
+ if (this.type === "dark")
54
+ return {
55
+ content: `psui-bg-blue-70 psui-text-white ${this.cssClass}`,
56
+ button: `psui-bg-blue-60 psui-text-white`,
57
+ }
58
+ if (this.type === "color")
59
+ return {
60
+ content: `psui-bg-blue-50 psui-text-white ${this.cssClass}`,
61
+ button: `psui-bg-blue-60 psui-text-white`,
62
+ }
63
+
64
+ return { content: `psui-bg-white psui-text-gray-80 ${this.cssClass}`, button: `psui-bg-blue-20 psui-text-blue-60`,}
65
+ },
66
+ },
67
+ methods: {
68
+ onClick() {
69
+ this.$emit("click")
70
+ },
71
+ },
72
+ }
73
+ </script>
74
+
75
+ <style scoped>
76
+ button {
77
+ width: fit-content;
78
+ }
79
+ </style>>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <PsTooltip :cssClass="`${textColorClass} ${cssClass}`" :title="title">
3
+ <template v-slot:trigger>
4
+ <slot></slot>
5
+ </template>
6
+ </PsTooltip>
7
+ </template>
8
+
9
+ <script>
10
+ import PsTooltip from "../tooltip/PsTooltip.vue"
11
+
12
+ export default {
13
+ name: "PsRichTooltip",
14
+ components: { PsTooltip },
15
+ props: {
16
+ title: {
17
+ type: String,
18
+ default: "",
19
+ },
20
+ type: {
21
+ type: String,
22
+ default: "gray",
23
+ validator: (type) => ["gray", "red", "blue"].includes(type),
24
+ },
25
+ cssClass: {
26
+ type: String,
27
+ default: "",
28
+ },
29
+ },
30
+ computed: {
31
+ textColorClass() {
32
+ if (this.type === "red") return `psui-text-red-70 psui-bg-red-10 `
33
+ if (this.type === "blue") return `psui-bg-blue-70 psui-text-white`
34
+ return `psui-text-gray-80 psui-bg-gray-30 `
35
+ },
36
+ },
37
+ }
38
+ </script>
@@ -0,0 +1,120 @@
1
+ <template>
2
+ <div @mouseover="open" @mouseleave="close" ref="tooltip">
3
+ <div ref="tooltiptrigger">
4
+ <slot name="trigger"></slot>
5
+ </div>
6
+
7
+ <div class="psui-relative">
8
+ <div
9
+ role="menu"
10
+ ref="dialog"
11
+ class="
12
+ psui-fixed
13
+ psui-hidden
14
+ psui-opacity-0
15
+ psui-transition-opacity
16
+ psui-duration-500
17
+ psui-ease-in-out
18
+ "
19
+ >
20
+ <div
21
+ class="
22
+ psui-flex
23
+ psui-flex-col
24
+ psui-py-1
25
+ psui-px-2
26
+ psui-rounded-md
27
+ psui-shadow-md
28
+ psui-z-20
29
+ "
30
+ aria-orientation="vertical"
31
+ :class="cssClass"
32
+ >
33
+ <h2 v-if="title" class="psui-font-bold">{{ title}}</h2>
34
+ <slot name="dialog" class="psui-font-normal"
35
+ >
36
+ </slot
37
+ >
38
+ </div>
39
+ </div>
40
+ </div>
41
+ </div>
42
+ </template>
43
+
44
+ <script>
45
+ export default {
46
+ name: "PsTooltip",
47
+ props: {
48
+ title: {
49
+ type: String,
50
+ },
51
+ ignoreDialog: {
52
+ type: Boolean,
53
+ default: false,
54
+ },
55
+ keepOpen: {
56
+ default: false,
57
+ },
58
+ cssClass:{
59
+ type: String,
60
+ default: 'psui-bg-gray-50 psui-text-white'
61
+ }
62
+ },
63
+ inheritAttrs: true,
64
+ emits: ["show"],
65
+ data() {
66
+ return {
67
+ show: false,
68
+ closingTimeout: null,
69
+ }
70
+ },
71
+ mounted() {
72
+ console.log(this.$attrs)
73
+ document.addEventListener("resize", this.updatePosition)
74
+ },
75
+ beforeDestroy() {
76
+ document.removeEventListener("resize", this.updatePosition)
77
+ },
78
+ methods: {
79
+ open() {
80
+ if (this.show || this.ignoreDialog) return
81
+ this.$emit("show")
82
+ this.show = true
83
+
84
+ this.$refs.dialog.style.display = "block"
85
+ this.$refs.dialog.style.opacity = 0
86
+
87
+ setTimeout(() => {
88
+ this.updatePosition()
89
+ }, 10)
90
+ },
91
+ close() {
92
+ if (this.show && this.$refs.dialog) {
93
+ this.$emit("close")
94
+ this.show = false
95
+
96
+ this.$refs.dialog.style.display = "none"
97
+ }
98
+ },
99
+ updatePosition() {
100
+ const dialog = this.$refs.dialog
101
+ const trigger = this.$refs.tooltiptrigger
102
+
103
+ const rectDialog = dialog.getBoundingClientRect()
104
+ const rectTrigger = trigger.getBoundingClientRect()
105
+ const windowWidth = document.documentElement.clientWidth
106
+ dialog.style.top = `${rectTrigger.y + rectTrigger.height}px`
107
+
108
+ if (rectTrigger.x + rectDialog.width + 20 > windowWidth) {
109
+ dialog.style.left = `${windowWidth - rectDialog.width - 30}px`
110
+ } else {
111
+ dialog.style.left = `${rectTrigger.x}px`
112
+ }
113
+
114
+ setTimeout(() => {
115
+ dialog.style.opacity = 100
116
+ }, 100)
117
+ },
118
+ },
119
+ }
120
+ </script>
@@ -0,0 +1,128 @@
1
+ <template>
2
+ <div style="display: contents">
3
+ <span
4
+ v-if="getIconType === 'material-icons'"
5
+ class="material-icons-round"
6
+ :class="[getIconClasses]"
7
+ >
8
+ {{ getIcon }}
9
+ </span>
10
+ <img v-else-if="getIconType === 'url'" :src="icon" :class="[iconClasses]" />
11
+ <inline-svg
12
+ v-else
13
+ :src="icon"
14
+ :width="getWidth"
15
+ :height="getHeight"
16
+ :stroke="getColor"
17
+ :fill="getColor"
18
+ ></inline-svg>
19
+ </div>
20
+ </template>
21
+
22
+ <script>
23
+ import tailwindConfig from '../../../tailwind.config'
24
+ import imageLoader from '../../util/imageLoader'
25
+ export default {
26
+ name: 'AppIcon',
27
+ props: {
28
+ icon: {
29
+ type: String,
30
+ required: true
31
+ },
32
+ type: {
33
+ type: String,
34
+ },
35
+ iconClasses: {
36
+ type: String
37
+ },
38
+ size: {
39
+ type: [Number, String],
40
+ },
41
+ width: {
42
+ type: Number,
43
+ default: 24
44
+ },
45
+ height: {
46
+ type: Number,
47
+ default: 24
48
+ },
49
+ stroke: {
50
+ type: String,
51
+ default: null
52
+ },
53
+ color: {
54
+ type: String,
55
+ default: null,
56
+ validator: value => {
57
+ return value.includes('psui-text-') &&
58
+ typeof(tailwindConfig.theme.colors[value.replace('psui-text-', '')]) != 'undefined' ||
59
+ typeof(tailwindConfig.theme.colors[value]) != 'undefined'
60
+ }
61
+ },
62
+ loaderIcon: {
63
+ type: String,
64
+ default: 'hourglass_top'
65
+ },
66
+ loaderErrorIcon: {
67
+ type: String,
68
+ default: 'more_horiz'
69
+ }
70
+ },
71
+ data() {
72
+ return {
73
+ finishedImageLoad: false,
74
+ imageLoadError: false
75
+ }
76
+ },
77
+ computed: {
78
+ getIconType() {
79
+ if(this.imageLoadError || !this.finishedImageLoad) return 'material-icons'
80
+ if(this.type) return this.type
81
+ if(!this.icon.includes('/')) return 'material-icons'
82
+ if(!this.icon.includes('.svg')) return 'url'
83
+ return 'svg'
84
+ },
85
+ getIcon() {
86
+ if(!this.icon.includes('/')) return this.icon
87
+ if(!this.finishedImageLoad && !this.imageLoadError && this.loaderIcon) return this.loaderIcon
88
+ if(this.imageLoadError) return this.loaderErrorIcon
89
+ return this.icon ? this.icon : ''
90
+ },
91
+ getIconClasses() {
92
+ if(this.iconClasses) return this.iconClasses
93
+ return `${this.size} ${this.color}`
94
+ },
95
+ getWidth() {
96
+ if(this.size) return this.size
97
+ return this.width
98
+ },
99
+ getHeight() {
100
+ if(this.size) return this.size
101
+ return this.height
102
+ },
103
+ getColor() {
104
+ if(this.getIconType === 'material-icons') return this.color
105
+ return tailwindConfig.theme.colors[this.color.replace('psui-text-', '')] || tailwindConfig.theme.colors[this.color]
106
+ }
107
+ },
108
+ watch: {
109
+ 'icon': function() {
110
+ this.loadImage()
111
+ }
112
+ },
113
+ mounted() {
114
+ if(this.icon.includes('/')) this.loadImage()
115
+ },
116
+ methods: {
117
+ loadImage() {
118
+ imageLoader({ imageUrl: this.icon, returnsBase64: false })
119
+ .then(() => {
120
+ this.finishedImageLoad = true
121
+ })
122
+ .catch(() => {
123
+ this.imageLoadError = true
124
+ })
125
+ }
126
+ }
127
+ }
128
+ </script>