@rypen-dev/shared-components 7.0.19 → 7.1.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,7 +1,7 @@
1
1
  {
2
2
  "name": "@rypen-dev/shared-components",
3
3
  "description": "Shared styles and Vuejs ui components for Rypen projects. Starting with version 6, this package is built with Webpack 5 and Vue 3.",
4
- "version": "7.0.19",
4
+ "version": "7.1.0",
5
5
  "main": "./dist/index.js",
6
6
  "scripts": {
7
7
  "build": "webpack --config ./webpack.config.js",
@@ -5,124 +5,128 @@
5
5
  <a v-if="showRemove" class="color-callout remove" title="Remove image" @click="removeImage"><i class="fa-solid fa-xmark"></i></a>
6
6
  </div>
7
7
  <div class="file-upload-drop">
8
- <div class="drop-target" :class="{over: isOver}" ref="droptarget">
8
+ <div class="drop-target" :class="{over: isOver}" ref="droptargetref">
9
9
  <div><i class="fa-solid fa-download"></i></div>
10
- <input type="file" :id="id" class="show-for-sr" :disabled="disabled || updating" @change="uploadImage" accept="image/*" ref="fileupload" />
10
+ <input type="file" :id="id" class="show-for-sr" :disabled="disabled || updating" @change="uploadImage" accept="image/*" ref="fileuploadref" />
11
11
  <label :for="id" class="main-label"><strong>Choose a banner image</strong> or drag it here</label>
12
12
  </div>
13
13
  </div>
14
14
  </div>
15
15
  </template>
16
- <script>
17
- export default {
18
- name: 'FileDropzone',
19
- props: {
20
- imageBasePath: {
21
- type: String,
22
- default: '', //IMAGE_BASE_PATH
23
- },
24
-
25
- image: [Object, File],
26
- id: String,
27
- showRemove: {
28
- type: Boolean,
29
- default: true,
30
- },
31
- updating: {
32
- type: Boolean,
33
- default: false,
34
- },
35
- disabled: {
36
- type: Boolean,
37
- default: false,
38
- },
16
+ <script setup>
17
+ import { ref, onBeforeMount, onMounted } from 'vue';
18
+
19
+ const props = defineProps({
20
+ imageBasePath: {
21
+ type: String,
22
+ default: '', //IMAGE_BASE_PATH
39
23
  },
40
- data () {
41
- return {
42
- dragDropCapable: false,
43
24
 
44
- reader: null,
25
+ image: [Object, File],
26
+ id: String,
27
+ showRemove: {
28
+ type: Boolean,
29
+ default: true,
30
+ },
31
+ updating: {
32
+ type: Boolean,
33
+ default: false,
34
+ },
35
+ disabled: {
36
+ type: Boolean,
37
+ default: false,
38
+ },
39
+ });
40
+ const emit = defineEmits(['change', 'remove']);
45
41
 
46
- internalImage: '',
42
+ const dragDropCapable = ref(false);
43
+ const reader = ref(null);
44
+ const internalImage = ref('');
45
+ const isOver = ref(false);
47
46
 
48
- isOver: false,
49
- };
50
- },
51
- created: function () {
52
- if (this.image && this.image.ImageUrl) {
53
- // already have an image
54
- this.internalImage = this.imageBasePath + this.image.ImageUrl;
55
- }
47
+ const droptargetref = ref(null);
48
+ const fileuploadref = ref(null);
56
49
 
57
- this.reader = new FileReader();
58
- this.reader.addEventListener('load', this.setImage);
59
- },
60
- mounted: function () {
61
- this.dragDropCapable = this.determineDragDropCapable();
50
+ onBeforeMount(() => {
51
+ if (props.image && props.image.ImageUrl) {
52
+ // already have an image
53
+ internalImage.value = props.imageBasePath + props.image.ImageUrl;
54
+ }
55
+
56
+ reader.value = new FileReader();
57
+ reader.value.addEventListener('load', setImage);
58
+ });
62
59
 
63
- if (this.dragDropCapable) {
60
+ onMounted(() => {
61
+ dragDropCapable.value = determineDragDropCapable();
62
+
63
+ if (dragDropCapable.value) {
64
+ if (droptargetref.value) {
64
65
  // add prevent/stop to all necessary events
65
66
  ['drag', 'drop'].forEach(evt => {
66
- this.$refs.droptarget.addEventListener(evt, (e) => {
67
+ droptargetref.value.addEventListener(evt, (e) => {
67
68
  e.preventDefault();
68
69
  e.stopPropagation();
69
70
  });
70
71
  });
71
72
  ['dragstart', 'dragenter', 'dragover'].forEach(evt => {
72
- this.$refs.droptarget.addEventListener(evt, (e) => {
73
+ droptargetref.value.addEventListener(evt, (e) => {
73
74
  e.preventDefault();
74
75
  e.stopPropagation();
75
76
 
76
- this.isOver = true;
77
+ isOver.value = true;
77
78
  });
78
79
  });
79
80
  ['dragend', 'dragleave'].forEach(evt => {
80
- this.$refs.droptarget.addEventListener(evt, (e) => {
81
+ droptargetref.value.addEventListener(evt, (e) => {
81
82
  e.preventDefault();
82
83
  e.stopPropagation();
83
84
 
84
- this.isOver = false;
85
+ isOver.value = false;
85
86
  });
86
87
  });
87
88
 
88
89
  // add listeners for drop
89
- this.$refs.droptarget.addEventListener('drop', this.fileDrop);
90
+ droptargetref.value.addEventListener('drop', fileDrop);
90
91
  }
91
- },
92
- methods: {
93
- determineDragDropCapable() {
94
- const div = document.createElement('div');
95
- return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div))
96
- && 'FormData' in window
97
- && 'FileReader' in window;
98
- },
99
-
100
- fileDrop(e) {
101
- this.isOver = false;
102
- let files = e.dataTransfer.files;
103
- this.readImage(files[0]);
104
-
105
- this.$emit('change', files[0]);
106
- },
107
- uploadImage(e) {
108
- const { value, files } = e.target;
109
- this.readImage(files[0]);
110
-
111
- this.$emit('change', files[0]);
112
- },
113
- removeImage() {
114
- this.internalImage = '';
115
- this.$emit('remove');
116
- },
117
- readImage(file) {
118
- this.reader.readAsDataURL(file);
119
- },
120
- setImage() {
121
- this.internalImage = this.reader.result;
122
- },
123
- },
124
- computed: {
125
-
126
- },
127
- };
92
+ }
93
+ });
94
+
95
+ function determineDragDropCapable() {
96
+ const div = document.createElement('div');
97
+ return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div))
98
+ && 'FormData' in window
99
+ && 'FileReader' in window;
100
+ }
101
+
102
+ function fileDrop(e) {
103
+ isOver.value = false;
104
+ let files = e.dataTransfer.files;
105
+ readImage(files[0]);
106
+
107
+ emit('change', files[0]);
108
+ }
109
+
110
+ function uploadImage(e) {
111
+ const { value, files } = e.target;
112
+ readImage(files[0]);
113
+
114
+ emit('change', files[0]);
115
+ }
116
+
117
+ function removeImage() {
118
+ internalImage.value = '';
119
+ emit('remove');
120
+ }
121
+
122
+ function readImage(file) {
123
+ // only read if it's an image
124
+ if (file && file.type.startsWith('image/')) {
125
+ reader.value.readAsDataURL(file);
126
+ }
127
+ }
128
+
129
+ function setImage() {
130
+ internalImage.value = reader.value.result;
131
+ }
128
132
  </script>
@@ -8,74 +8,72 @@
8
8
  </span>
9
9
  </span>
10
10
  </template>
11
- <script>
12
- export default {
13
- name: 'FileUpload',
14
- props: {
15
- assetBasePath: {
16
- type: String,
17
- d0efault: '', //MERCH_ASSET_BASE_PATH
18
- },
11
+ <script setup>
12
+ import { ref, computed, onMounted } from 'vue';
19
13
 
20
- file: [Object, File],
21
- id: String,
22
- updating: {
23
- type: Boolean,
24
- default: false,
25
- },
26
- disabled: {
27
- type: Boolean,
28
- default: false,
29
- },
30
- text: {
31
- type: String,
32
- default: 'Choose a File',
33
- },
34
- showFilePath: {
35
- type: Boolean,
36
- default: false,
37
- },
38
- accept: {
39
- type: String,
40
- default: 'image/*',
41
- },
42
- cssClass: String,
14
+ const props = defineProps({
15
+ assetBasePath: {
16
+ type: String,
17
+ default: '', //MERCH_ASSET_BASE_PATH
43
18
  },
44
- data () {
45
- return {
46
- reader: null,
47
19
 
48
- internalFile: '',
49
- };
20
+ file: [Object, File],
21
+ id: String,
22
+ updating: {
23
+ type: Boolean,
24
+ default: false,
50
25
  },
51
- created: function () {
52
- if (this.file) {
53
- this.internalFile = this.assetBasePath + this.file;
54
- }
55
-
56
- this.reader = new FileReader();
57
- this.reader.addEventListener('load', this.setFile);
26
+ disabled: {
27
+ type: Boolean,
28
+ default: false,
58
29
  },
59
- methods: {
60
- uploadFile(e) {
61
- const { value, files } = e.target;
62
- if (files[0]) {
63
- this.readFile(files[0]);
64
-
65
- this.$emit('change', files[0]);
66
- }
67
- },
68
- readFile(file) {
69
- this.reader.readAsDataURL(file);
70
- },
71
- setFile() {
72
- this.internalFile = this.reader.result;
73
- },
30
+ text: {
31
+ type: String,
32
+ default: 'Choose a File',
33
+ },
34
+ showFilePath: {
35
+ type: Boolean,
36
+ default: false,
74
37
  },
75
- computed: {
76
- fullCssClass() {
77
- return (this.disabled || this.updating ? 'disabled' : '') + ' ' + (this.cssClass || '');
78
- },
38
+ accept: {
39
+ type: String,
40
+ default: 'image/*',
79
41
  },
80
- };
42
+ cssClass: String,
43
+ });
44
+ const emit = defineEmits(['change']);
45
+
46
+ const reader = ref(null);
47
+ const fileupload = ref(null);
48
+
49
+ onMounted(() => {
50
+ if (props.file) {
51
+ internalFile.value = props.assetBasePath + props.file;
52
+ }
53
+
54
+ reader.value = new FileReader();
55
+ reader.value.addEventListener('load', setFile);
56
+ });
57
+
58
+ function uploadFile(e) {
59
+ const { value, files } = e.target;
60
+ if (files[0]) {
61
+ readFile(files[0]);
62
+
63
+ // emit the file change
64
+ emit('change', files[0]);
65
+ }
66
+ }
67
+
68
+ function readFile(file) {
69
+ reader.value.readAsDataURL(file);
70
+ }
71
+
72
+ function setFile() {
73
+ internalFile.value = reader.value.result;
74
+ }
75
+
76
+ const fullCssClass = computed(() => {
77
+ return (props.disabled || props.updating ? 'disabled' : '') + ' ' + (props.cssClass || '');
78
+ });
81
79
  </script>
@@ -4,11 +4,8 @@
4
4
  </div>
5
5
  </template>
6
6
 
7
- <script>
8
- export default {
9
- name: 'GenericLoader',
10
- props: {
11
- cssClass: String,
12
- },
13
- }
7
+ <script setup>
8
+ const props = defineProps({
9
+ cssClass: String,
10
+ });
14
11
  </script>
@@ -4,15 +4,6 @@
4
4
  </div>
5
5
  </template>
6
6
 
7
- <script>
7
+ <script setup>
8
8
  import loadingImage from "../assets/rypen_logomarkreveal_100px.gif";
9
-
10
- export default {
11
- name: 'Loader',
12
- data: () => {
13
- return {
14
- loadingImage: loadingImage,
15
- }
16
- },
17
- }
18
9
  </script>
@@ -2,7 +2,7 @@
2
2
  <div class="lookup-container" :class="{ small: small }">
3
3
  <div class="input-container" :class="{ loading: loading, suggestions: suggestionsOpen, small: small, error: invalid }">
4
4
  <input v-if="useExternalValue" ref="inputforexternal" type="text" autocomplete="off" :value="externalValue" :maxlength="maxLength" @input="updateExternalValue" @focus="focusOn" @blur="focusOff" @keyup.enter="enterMethod" :disabled="disabled" />
5
- <input v-else ref="input" type="text" autocomplete="off" v-model="value" :maxlength="maxLength" @focus="focusOn" @blur="focusOff" @keyup.enter="enterMethod" :disabled="disabled" />
5
+ <input v-else ref="inputref" type="text" autocomplete="off" v-model="value" :maxlength="maxLength" @focus="focusOn" @blur="focusOff" @keyup.enter="enterMethod" :disabled="disabled" />
6
6
  <span v-if="loading" class="mini-loader"></span>
7
7
  </div>
8
8
  <div v-if="suggestionsOpen" class="lookup-suggestions">
@@ -13,121 +13,129 @@
13
13
  </div>
14
14
  </div>
15
15
  </template>
16
- <script>
16
+ <script setup>
17
+ import { ref, computed, watch } from "vue";
18
+
17
19
  import { debounce } from "@rypen-dev/helpers";
18
20
 
19
- export default {
20
- name: 'LookupTextBox',
21
- props: {
22
- loading: {
23
- type: Boolean,
24
- default: false,
25
- },
26
- suggestions: {
27
- type: Array,
28
- default: () => [],
29
- },
30
- invalid: {
31
- type: Boolean,
32
- default: false,
33
- },
34
- minimumLength: {
35
- type: Number,
36
- default: 3,
37
- },
38
- maxLength: {
39
- type: Number,
40
- default: 200,
41
- },
42
- small: {
43
- type: Boolean,
44
- default: false,
45
- },
46
- disabled: {
47
- type: Boolean,
48
- default: false,
49
- },
50
- useExternalValue: {
51
- type: Boolean,
52
- default: false,
53
- },
54
- externalValue: String,
55
- nameOnly: {
56
- type: Boolean,
57
- default: false,
58
- },
59
- searchType: {
60
- type: String,
61
- default: 'products'
62
- },
21
+ const props = defineProps({
22
+ loading: {
23
+ type: Boolean,
24
+ default: false,
25
+ },
26
+ suggestions: {
27
+ type: Array,
28
+ default: () => [],
29
+ },
30
+ invalid: {
31
+ type: Boolean,
32
+ default: false,
33
+ },
34
+ minimumLength: {
35
+ type: Number,
36
+ default: 3,
63
37
  },
64
- data: () => {
65
- return {
66
- value: '',
67
- debouncedValue: '',
68
-
69
- focused: false,
70
- };
38
+ maxLength: {
39
+ type: Number,
40
+ default: 200,
71
41
  },
72
- created: function () {
73
- this.debouncedGetSuggestions = debounce(value => {
74
- this.debouncedValue = value;
75
- this.getSuggestions();
76
- });
42
+ small: {
43
+ type: Boolean,
44
+ default: false,
77
45
  },
78
- methods: {
79
- getSuggestions() {
80
- const usedValue = this.useExternalValue ? this.externalValue : this.value;
81
- if (usedValue.length === 0 || usedValue.length >= this.minimumLength) {
82
- this.$emit('search', usedValue);
83
- }
84
- },
85
- selectSuggestion(suggestion) {
86
- let data = suggestion;
87
- if (this.nameOnly) {
88
- data = suggestion.Name;
89
- }
90
-
91
- this.$emit('select', data);
92
- },
93
-
94
- updateExternalValue(e) {
95
- this.$emit('select', e.target.value);
96
- },
97
-
98
- focusInput() {
99
- if (this.$refs.inputforexternal) {
100
- this.$refs.inputforexternal.focus();
101
- } else if (this.$refs.input) {
102
- this.$refs.input.focus();
103
- }
104
- },
105
- focusOn() {
106
- this.focused = true;
107
- },
108
- focusOff() {
109
- setTimeout(() => {
110
- this.focused = false;
111
- this.value = '';
112
- }, 200);
113
- },
114
-
115
- enterMethod() {
116
- this.$emit('enter');
117
- },
46
+ disabled: {
47
+ type: Boolean,
48
+ default: false,
118
49
  },
119
- computed: {
120
- suggestionsOpen() {
121
- return this.debouncedValue && this.debouncedValue.length >= this.minimumLength && this.focused && (!this.loading || this.suggestions.length > 0);
122
- }
50
+ useExternalValue: {
51
+ type: Boolean,
52
+ default: false,
123
53
  },
124
- watch: {
125
- value(newValue) {
126
- this.debouncedGetSuggestions(newValue);
127
- },
128
- externalValue(newValue) {
129
- this.debouncedGetSuggestions(newValue);
130
- },
54
+ externalValue: String,
55
+ nameOnly: {
56
+ type: Boolean,
57
+ default: false,
131
58
  },
59
+ searchType: {
60
+ type: String,
61
+ default: 'products'
62
+ },
63
+ });
64
+
65
+ const emit = defineEmits(['search', 'select', 'enter']);
66
+
67
+ const value = ref('');
68
+ const debouncedValue = ref('');
69
+ const focused = ref(false);
70
+
71
+ const inputref = ref(null);
72
+ const inputforexternal = ref(null);
73
+
74
+ const suggestionsOpen = computed(() => {
75
+ return debouncedValue.value && debouncedValue.value.length >= props.minimumLength && focused.value && (!props.loading || props.suggestions.length > 0);
76
+ });
77
+
78
+ const debouncedGetSuggestions = debounce((newValue) => {
79
+ debouncedValue.value = newValue;
80
+ getSuggestions();
81
+ });
82
+
83
+ function getSuggestions() {
84
+ const usedValue = props.useExternalValue ? props.externalValue : value.value;
85
+ if (usedValue.length === 0 || usedValue.length >= props.minimumLength) {
86
+ emit('search', usedValue);
87
+ }
88
+ }
89
+
90
+ function selectSuggestion(suggestion) {
91
+ let data = suggestion;
92
+ if (props.nameOnly) {
93
+ data = suggestion.Name;
94
+ }
95
+
96
+ emit('select', data);
132
97
  }
98
+
99
+ function updateExternalValue(e) {
100
+ emit('select', e.target.value);
101
+ }
102
+
103
+ function focusInput() {
104
+ if (props.useExternalValue && inputforexternal.value) {
105
+ inputforexternal.value.focus();
106
+ } else if (inputref.value) {
107
+ inputref.value.focus();
108
+ }
109
+ }
110
+
111
+ function focusOn() {
112
+ focused.value = true;
113
+ }
114
+
115
+ function focusOff() {
116
+ setTimeout(() => {
117
+ focused.value = false;
118
+ value.value = '';
119
+ }, 200);
120
+ }
121
+
122
+ function enterMethod() {
123
+ emit('enter');
124
+ }
125
+
126
+ watch(() => props.externalValue, (newValue) => {
127
+ if (props.useExternalValue) {
128
+ debouncedGetSuggestions(newValue);
129
+ }
130
+ }, { immediate: true });
131
+
132
+ watch(value, (newValue) => {
133
+ if (!props.useExternalValue) {
134
+ debouncedGetSuggestions(newValue);
135
+ }
136
+ }, { immediate: true });
137
+
138
+ defineExpose({
139
+ focusInput,
140
+ });
133
141
  </script>