@redseed/redseed-ui-vue3 2.7.0 → 2.8.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": "@redseed/redseed-ui-vue3",
3
- "version": "2.7.0",
3
+ "version": "2.8.0",
4
4
  "description": "RedSeed UI Vue 3 components",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -9,11 +9,11 @@
9
9
  "keywords": [],
10
10
  "author": "",
11
11
  "license": "ISC",
12
- "devDependencies": {
12
+ "dependencies": {
13
13
  "@heroicons/vue": "^2.1.5",
14
14
  "@vueuse/components": "^10.11.0",
15
15
  "@vueuse/core": "^10.11.0",
16
16
  "lottie-web": "^5.12.2",
17
- "vue": "^3.4.34"
17
+ "vue": "^3.4.36"
18
18
  }
19
19
  }
@@ -1,9 +1,8 @@
1
1
  <script setup>
2
2
  import { ref, computed } from 'vue'
3
- import { useElementSize } from '@vueuse/core'
4
3
  import Empty from '../Empty/Empty.vue'
5
4
  import Pagination from '../Pagination/Pagination.vue'
6
-
5
+ import { useResponsiveWidth } from '../../helpers/responsiveWidth'
7
6
 
8
7
  const props = defineProps({
9
8
  controlApplied: {
@@ -24,21 +23,21 @@ const props = defineProps({
24
23
  },
25
24
  })
26
25
 
27
- const cardGroupElement = ref(null);
26
+ const cardGroupElement = ref(null)
28
27
 
29
- const { width } = useElementSize(cardGroupElement);
28
+ const { responsiveWidth } = useResponsiveWidth(cardGroupElement)
30
29
 
31
30
  const cardGroupClasses = computed(() => [
32
31
  'rsui-card-group',
33
32
  {
34
- 'rsui-card-group--2xs': width.value < 375,
35
- 'rsui-card-group--xs': width.value >= 375 && width.value < 480,
36
- 'rsui-card-group--sm': width.value >= 480 && width.value < 640,
37
- 'rsui-card-group--md': width.value >= 640 && width.value < 768,
38
- 'rsui-card-group--lg': width.value >= 768 && width.value < 1024,
39
- 'rsui-card-group--xl': width.value >= 1024 && width.value < 1280,
40
- 'rsui-card-group--2xl': width.value >= 1280 && width.value < 1536,
41
- 'rsui-card-group--3xl': width.value >= 1536
33
+ 'rsui-card-group--2xs': responsiveWidth.value['2xs'],
34
+ 'rsui-card-group--xs': responsiveWidth.value['xs'],
35
+ 'rsui-card-group--sm': responsiveWidth.value['sm'],
36
+ 'rsui-card-group--md': responsiveWidth.value['md'],
37
+ 'rsui-card-group--lg': responsiveWidth.value['lg'],
38
+ 'rsui-card-group--xl': responsiveWidth.value['xl'],
39
+ 'rsui-card-group--2xl': responsiveWidth.value['2xl'],
40
+ 'rsui-card-group--3xl': responsiveWidth.value['3xl'],
42
41
  }
43
42
  ])
44
43
 
@@ -46,60 +45,48 @@ const pageUpdated = (event) => {
46
45
  emit('pageUpdated', event)
47
46
  }
48
47
 
49
- const emit = defineEmits(['pageUpdated']);
48
+ const emit = defineEmits(['pageUpdated'])
50
49
 
51
50
  const showEmptyMessage = computed(() => !props.totalItems && !props.controlApplied)
52
51
 
53
52
  const showNotFoundMessage = computed(() => !props.totalItems && props.controlApplied)
54
-
55
53
  </script>
56
54
  <template>
57
- <div ref="cardGroupElement" :class="cardGroupClasses">
58
- <div class="rsui-card-group__pagination">
59
- <Pagination v-if="totalItems > perPage" :totalItems="totalItems" :perPage="perPage" :currentPage="currentPage"
60
- @change="pageUpdated"></Pagination>
61
- </div>
62
-
63
- <div v-if="totalItems" class="rsui-card-group__cards">
64
-
65
-
66
- <slot></slot>
67
-
68
- </div>
69
-
70
- <div v-if="showEmptyMessage" class="rsui-card-group__empty">
71
- <Empty @clickPrimaryAction="$emit('clickEmptyAction')">
72
- <template #image>
73
- <slot name="empty-image"></slot>
74
- </template>
75
- <template #title v-if="$slots['empty-title']">
76
- <slot name="empty-title"></slot>
77
- </template>
78
- <template #primary-action-label v-if="$slots['empty-action-label']">
79
- <slot name="empty-action-label"></slot>
80
- </template>
81
-
82
- <slot name="empty-description">It looks like there's nothing here yet.</slot>
83
- </Empty>
84
- </div>
85
- <div v-if="showNotFoundMessage" class="rsui-card-group">
86
- <Empty>
87
- <slot name="filter-empty-description">No items meet your filter criteria.</slot>
88
- </Empty>
89
- </div>
55
+ <div ref="cardGroupElement" :class="cardGroupClasses">
56
+ <div class="rsui-card-group__pagination">
57
+ <Pagination v-if="totalItems > perPage" :totalItems="totalItems" :perPage="perPage" :currentPage="currentPage"
58
+ @change="pageUpdated"></Pagination>
90
59
  </div>
60
+ <div v-if="totalItems" class="rsui-card-group__cards">
61
+ <slot></slot>
62
+ </div>
63
+ <div v-if="showEmptyMessage" class="rsui-card-group__empty">
64
+ <Empty @clickPrimaryAction="$emit('clickEmptyAction')">
65
+ <template #image>
66
+ <slot name="empty-image"></slot>
67
+ </template>
68
+ <template #title v-if="$slots['empty-title']">
69
+ <slot name="empty-title"></slot>
70
+ </template>
71
+ <template #primary-action-label v-if="$slots['empty-action-label']">
72
+ <slot name="empty-action-label"></slot>
73
+ </template>
74
+
75
+ <slot name="empty-description">It looks like there's nothing here yet.</slot>
76
+ </Empty>
77
+ </div>
78
+ <div v-if="showNotFoundMessage" class="rsui-card-group">
79
+ <Empty>
80
+ <slot name="filter-empty-description">No items meet your filter criteria.</slot>
81
+ </Empty>
82
+ </div>
83
+ </div>
91
84
  </template>
92
85
  <style scoped lang="scss">
93
86
  .rsui-card-group {
94
87
  &__cards {
95
88
  @apply grid;
96
- }
97
-
98
- &--2xs,
99
- &--xs {
100
- .rsui-card-group__cards {
101
- @apply gap-4 grid-cols-1;
102
- }
89
+ @apply gap-4 grid-cols-1;
103
90
  }
104
91
 
105
92
  &--sm,
@@ -124,7 +111,6 @@ const showNotFoundMessage = computed(() => !props.totalItems && props.controlApp
124
111
  }
125
112
  &__pagination {
126
113
  @apply w-full flex items-center justify-center mb-4;
127
-
128
114
  }
129
115
  }
130
116
  </style>
@@ -1,40 +1,26 @@
1
1
  <script setup>
2
- import { ref, computed, onMounted, onUnmounted } from 'vue'
2
+ import { ref, computed } from 'vue'
3
3
  import ButtonPrimary from '../Button/ButtonPrimary.vue'
4
4
  import ButtonSecondary from '../Button/ButtonSecondary.vue'
5
5
  import ButtonTertiary from '../Button/ButtonTertiary.vue'
6
6
  import BodyText from '../BodyText/BodyText.vue'
7
7
  import { ExclamationCircleIcon } from '@heroicons/vue/24/outline'
8
+ import { useResponsiveWidth } from '../../helpers/responsiveWidth'
8
9
 
9
10
  const emit = defineEmits(['clickPrimaryAction', 'clickSecondaryAction', 'clickTertiaryAction'])
10
11
 
11
- const emptyClass = computed(() => [
12
- 'rsui-empty',
13
- ])
14
-
15
12
  const emptyElement = ref(null)
16
13
 
17
- const isWide = ref(false)
18
-
19
- function calculateWidth() {
20
- if (!emptyElement.value) return
14
+ const { responsiveWidth } = useResponsiveWidth(emptyElement, 480)
21
15
 
22
- const width = emptyElement.value.offsetWidth
16
+ const isWide = computed(() => !!responsiveWidth.value.specific)
23
17
 
24
- isWide.value = width >= 480
25
- if (isWide.value) {
26
- emptyElement.value.classList.add('rsui-empty--wide')
27
- } else {
28
- emptyElement.value.classList.remove('rsui-empty--wide')
18
+ const emptyClass = computed(() => [
19
+ 'rsui-empty',
20
+ {
21
+ 'rsui-empty--wide': isWide.value,
29
22
  }
30
- }
31
-
32
- onMounted(() => {
33
- calculateWidth()
34
- window.addEventListener('resize', calculateWidth)
35
- })
36
-
37
- onUnmounted(() => window.addEventListener('resize', calculateWidth))
23
+ ])
38
24
  </script>
39
25
  <template>
40
26
  <div v-if="$slots.title || $slots.default"
@@ -1,9 +1,10 @@
1
1
  <script setup>
2
- import { ref, computed, onMounted, onUnmounted, watch } from 'vue'
2
+ import { ref, computed, watch } from 'vue'
3
3
  import FormFieldSearch from '../FormField/FormFieldSearch.vue'
4
4
  import FormFieldSelect from '../FormField/FormFieldSelect.vue'
5
5
  import Sorting from '../Sorting/Sorting.vue'
6
6
  import Pagination from '../Pagination/Pagination.vue'
7
+ import { useResponsiveWidth } from '../../helpers/responsiveWidth'
7
8
 
8
9
  const props = defineProps({
9
10
  searchable: {
@@ -43,6 +44,20 @@ const emit = defineEmits(['change'])
43
44
 
44
45
  const listControlElement = ref(null)
45
46
 
47
+ const { responsiveWidth } = useResponsiveWidth(listControlElement)
48
+
49
+ const listControlClass = computed(() => [
50
+ 'rsui-list-control',
51
+ {
52
+ 'rsui-list-control--sm': responsiveWidth.value.sm,
53
+ 'rsui-list-control--md': responsiveWidth.value.md,
54
+ 'rsui-list-control--lg': responsiveWidth.value.lg,
55
+ 'rsui-list-control--xl': responsiveWidth.value.xl,
56
+ 'rsui-list-control--2xl': responsiveWidth.value['2xl'],
57
+ 'rsui-list-control--3xl': responsiveWidth.value['3xl'],
58
+ }
59
+ ])
60
+
46
61
  const filterLimit = ref(4)
47
62
 
48
63
  const searchText = ref('')
@@ -63,50 +78,10 @@ function fireChangeEvent() {
63
78
  pagination: pagination.value
64
79
  })
65
80
  }
66
-
67
- function calculateWidth() {
68
- if (!listControlElement.value) return
69
-
70
- const sizeClasses = [
71
- 'rsui-list-control--sm',
72
- 'rsui-list-control--md',
73
- 'rsui-list-control--lg',
74
- 'rsui-list-control--xl',
75
- ]
76
-
77
- listControlElement.value.classList.remove(...sizeClasses)
78
-
79
- const width = listControlElement.value.offsetWidth
80
-
81
- if (width >= 1280) {
82
- listControlElement.value.classList.add(sizeClasses[3])
83
- return
84
- }
85
-
86
- if (width >= 1024) {
87
- listControlElement.value.classList.add(sizeClasses[2])
88
- return
89
- }
90
-
91
- if (width >= 640) {
92
- listControlElement.value.classList.add(sizeClasses[1])
93
- return
94
- }
95
-
96
- listControlElement.value.classList.add(sizeClasses[0])
97
- return
98
- }
99
-
100
- onMounted(() => {
101
- calculateWidth()
102
- window.addEventListener('resize', calculateWidth)
103
- })
104
-
105
- onUnmounted(() => window.addEventListener('resize', calculateWidth))
106
81
  </script>
107
82
  <template>
108
83
  <div ref="listControlElement"
109
- class="rsui-list-control"
84
+ :class="listControlClass"
110
85
  >
111
86
  <div v-if="searchable"
112
87
  class="rsui-list-control__search"
@@ -168,14 +143,14 @@ onUnmounted(() => window.addEventListener('resize', calculateWidth))
168
143
  .rsui-list-control {
169
144
  @apply flex flex-wrap justify-between gap-x-2 gap-y-3;
170
145
  &--sm {
171
- .rsui-list-control__search {
172
- @apply w-full;
173
- }
174
146
  .rsui-list-control__filters {
175
147
  @apply w-full grid-cols-2;
176
148
  }
177
149
  }
178
150
  &--md {
151
+ .rsui-list-control__search {
152
+ @apply w-auto;
153
+ }
179
154
  .rsui-list-control__filters {
180
155
  @apply flex;
181
156
  }
@@ -184,11 +159,17 @@ onUnmounted(() => window.addEventListener('resize', calculateWidth))
184
159
  }
185
160
  }
186
161
  &--lg {
162
+ .rsui-list-control__search {
163
+ @apply w-auto;
164
+ }
187
165
  .rsui-list-control__filters {
188
166
  @apply flex-1 grid-cols-4;
189
167
  }
190
168
  }
191
- &--xl {
169
+ &--xl, &--2xl, &--3xl {
170
+ .rsui-list-control__search {
171
+ @apply w-auto;
172
+ }
192
173
  .rsui-list-control__filters {
193
174
  @apply grid-cols-4;
194
175
  }
@@ -198,7 +179,7 @@ onUnmounted(() => window.addEventListener('resize', calculateWidth))
198
179
  }
199
180
 
200
181
  &__search {
201
- @apply w-auto;
182
+ @apply w-full;
202
183
  }
203
184
  &__filters {
204
185
  @apply grid gap-2;
@@ -1,7 +1,8 @@
1
1
  <script setup>
2
- import { ref, computed, useSlots, onMounted, onUnmounted, watch } from 'vue'
2
+ import { ref, computed, useSlots } from 'vue'
3
3
  import { UserIcon } from '@heroicons/vue/24/solid'
4
4
  import ButtonTertiary from '../Button/ButtonTertiary.vue'
5
+ import { useResponsiveWidth } from '../../helpers/responsiveWidth'
5
6
 
6
7
  const props = defineProps({
7
8
  avatar: {
@@ -20,27 +21,9 @@ const props = defineProps({
20
21
 
21
22
  const listItemElement = ref(null)
22
23
 
23
- const isWide = ref(false)
24
+ const { responsiveWidth } = useResponsiveWidth(listItemElement, 480)
24
25
 
25
- function calculateWidth() {
26
- if (!listItemElement.value) return
27
-
28
- const width = listItemElement.value.offsetWidth
29
-
30
- isWide.value = width >= 480
31
- if (isWide.value) {
32
- listItemElement.value.classList.add('rsui-list-item--wide')
33
- } else {
34
- listItemElement.value.classList.remove('rsui-list-item--wide')
35
- }
36
- }
37
-
38
- onMounted(() => {
39
- calculateWidth()
40
- window.addEventListener('resize', calculateWidth)
41
- })
42
-
43
- onUnmounted(() => window.addEventListener('resize', calculateWidth))
26
+ const isWide = computed(() => !!responsiveWidth.value.specific)
44
27
 
45
28
  const slots = useSlots()
46
29
 
@@ -53,6 +36,7 @@ const listItemClass = computed(() => [
53
36
  {
54
37
  'rsui-list-item--clickable': props.clickable,
55
38
  'rsui-list-item--avatar': props.avatar,
39
+ 'rsui-list-item--wide': isWide.value,
56
40
  }
57
41
  ])
58
42
 
@@ -0,0 +1,55 @@
1
+ import { ref, watch } from 'vue'
2
+ import { useElementBounding } from '@vueuse/core'
3
+
4
+ export function useResponsiveWidth(elementRef, specific = null) {
5
+
6
+ const breakpoints = {
7
+ '2xs': 375,
8
+ 'xs': 480,
9
+ 'sm': 640,
10
+ 'md': 768,
11
+ 'lg': 1024,
12
+ 'xl': 1280,
13
+ '2xl': 1536,
14
+ '3xl': 1920,
15
+ }
16
+
17
+ const responsiveWidth = ref({
18
+ '2xs': false,
19
+ 'xs': false,
20
+ 'sm': false,
21
+ 'md': false,
22
+ 'lg': false,
23
+ 'xl': false,
24
+ '2xl': false,
25
+ '3xl': false,
26
+ 'specific': false,
27
+ })
28
+
29
+ const { width } = useElementBounding(elementRef)
30
+
31
+ watch(width, calculateResponsiveWidth)
32
+
33
+ function calculateResponsiveWidth() {
34
+ if (specific && Number.isInteger(specific)) {
35
+ if (width.value >= specific) responsiveWidth.value.specific = true
36
+ if (width.value < specific) responsiveWidth.value.specific = false
37
+ }
38
+
39
+ // reset all responsiveWidth values
40
+ for (const key in breakpoints) { responsiveWidth.value[key] = false }
41
+
42
+ if (width.value >= breakpoints['3xl']) return responsiveWidth.value['3xl'] = true
43
+ if (width.value >= breakpoints['2xl']) return responsiveWidth.value['2xl'] = true
44
+ if (width.value >= breakpoints['xl']) return responsiveWidth.value['xl'] = true
45
+ if (width.value >= breakpoints['lg']) return responsiveWidth.value['lg'] = true
46
+ if (width.value >= breakpoints['md']) return responsiveWidth.value['md'] = true
47
+ if (width.value >= breakpoints['sm']) return responsiveWidth.value['sm'] = true
48
+ if (width.value >= breakpoints['xs']) return responsiveWidth.value['xs'] = true
49
+ if (width.value >= breakpoints['2xs']) return responsiveWidth.value['2xs'] = true
50
+ }
51
+
52
+ return {
53
+ responsiveWidth,
54
+ }
55
+ }