sprintify-ui 0.0.30 → 0.0.32

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.
@@ -1,60 +1,101 @@
1
1
  <template>
2
2
  <nav
3
- v-if="lastPage > 1 || lastPage < modelValue"
3
+ v-show="lastPage > 1 || lastPage < modelValue"
4
4
  ref="paginationNode"
5
- class="flex items-center justify-between border-t border-slate-200"
5
+ class="flex items-start border-t border-slate-200"
6
6
  >
7
- <div class="flex -mt-px w-0 flex-1">
8
- <button
9
- type="button"
10
- :disabled="modelValue == 1"
11
- class="inline-flex items-center border-t-2 border-transparent px-1 py-4 text-sm font-medium text-slate-500 hover:enabled:border-slate-300 hover:enabled:text-slate-700 disabled:cursor-not-allowed disabled:opacity-60"
12
- @click="previous()"
7
+ <div class="flex grow items-center justify-between">
8
+ <div class="-mt-px flex flex-1">
9
+ <button
10
+ type="button"
11
+ :disabled="modelValue == 1"
12
+ class="inline-flex items-center border-t-2 border-transparent px-1 py-4 text-sm font-medium text-slate-500 hover:enabled:border-slate-300 hover:enabled:text-slate-700 disabled:cursor-not-allowed disabled:opacity-60"
13
+ @click="previous()"
14
+ >
15
+ <BaseIcon
16
+ class="mx-2 h-5 w-5 text-slate-400"
17
+ icon="heroicons-solid:chevron-left"
18
+ />
19
+ </button>
20
+ </div>
21
+ <div :class="[mobileLayout ? 'hidden' : '-mt-px flex']">
22
+ <button
23
+ v-for="(i, index) in items"
24
+ :key="i + (index + '')"
25
+ type="button"
26
+ class="inline-flex items-center border-t-2 px-4 py-4 text-sm font-medium"
27
+ :class="[
28
+ i == modelValue ? 'border-primary-500 text-primary-500' : '',
29
+ i != modelValue ? 'border-transparent text-slate-500' : '',
30
+ i != modelValue && isClickable(i)
31
+ ? 'hover:border-slate-300 hover:text-slate-700'
32
+ : '',
33
+ ]"
34
+ @click="onButtonClick(i)"
35
+ >
36
+ {{ i }}
37
+ </button>
38
+ </div>
39
+ <div
40
+ v-if="mobileLayout"
41
+ class="mx-3 flex shrink-0 items-center justify-end"
13
42
  >
14
- <BaseIcon
15
- class="mr-3 h-5 w-5 text-slate-400"
16
- icon="heroicons-solid:arrow-narrow-left"
43
+ <span class="mr-2 text-sm font-normal text-slate-500">
44
+ {{ $t('sui.page') }}
45
+ </span>
46
+ <input
47
+ v-model="manualPageMobile"
48
+ type="number"
49
+ :min="1"
50
+ :max="lastPage"
51
+ :step="1"
52
+ class="rounded border border-slate-300 py-0 px-0.5 pl-1.5"
53
+ @keydown.enter="onManualPageMobileEnter"
54
+ @input="onManualPageMobileInput"
55
+ @blur="setPageFromManualPageMobile"
17
56
  />
18
- {{ $t('sui.previous') }}
19
- </button>
57
+ <span class="ml-2 text-sm font-normal text-slate-500">
58
+ {{ $t('sui.of') }} {{ lastPage }}
59
+ </span>
60
+ </div>
61
+ <div class="-mt-px flex flex-1 justify-end">
62
+ <button
63
+ :disabled="modelValue >= lastPage"
64
+ class="inline-flex items-center border-t-2 border-transparent px-1 py-4 text-sm font-medium text-slate-500 hover:enabled:border-slate-300 hover:enabled:text-slate-700 disabled:cursor-not-allowed disabled:opacity-60"
65
+ @click="next()"
66
+ >
67
+ <BaseIcon
68
+ class="mx-2 h-5 w-5 text-slate-400"
69
+ icon="heroicons-solid:chevron-right"
70
+ />
71
+ </button>
72
+ </div>
20
73
  </div>
21
- <div :class="[mobileLayout ? 'hidden' : 'flex -mt-px']">
22
- <button
23
- v-for="(i, index) in items"
24
- :key="i + (index + '')"
25
- type="button"
26
- class="inline-flex items-center border-t-2 px-4 py-4 text-sm font-medium"
27
- :class="[
28
- i == modelValue ? 'border-primary-500 text-primary-500' : '',
29
- i != modelValue ? 'border-transparent text-slate-500' : '',
30
- i != modelValue && isClickable(i)
31
- ? 'hover:border-slate-300 hover:text-slate-700'
32
- : '',
33
- ]"
34
- @click="onButtonClick(i)"
35
- >
36
- {{ i }}
37
- </button>
38
- </div>
39
- <div class="flex -mt-px w-0 flex-1 justify-end">
40
- <button
41
- :disabled="modelValue >= lastPage"
42
- class="inline-flex items-center border-t-2 border-transparent px-1 py-4 text-sm font-medium text-slate-500 hover:enabled:border-slate-300 hover:enabled:text-slate-700 disabled:cursor-not-allowed disabled:opacity-60"
43
- @click="next()"
44
- >
45
- {{ $t('sui.next') }}
46
- <BaseIcon
47
- class="ml-3 h-5 w-5 text-slate-400"
48
- icon="heroicons-solid:arrow-narrow-right"
49
- />
50
- </button>
74
+ <div
75
+ v-if="!mobileLayout"
76
+ class="mt-3 ml-4 flex shrink-0 items-center justify-end"
77
+ >
78
+ <span class="mr-3 text-sm font-medium text-slate-500">
79
+ {{ $t('sui.go_to_page') }}
80
+ </span>
81
+ <input
82
+ v-model="manualPage"
83
+ type="number"
84
+ :min="1"
85
+ :max="lastPage"
86
+ :step="1"
87
+ class="rounded border border-slate-300 py-0.5 px-0.5 pl-2"
88
+ @keydown.enter="onManualPageEnter"
89
+ @input="onManualPageInput"
90
+ @blur="setPageFromManualPage"
91
+ />
51
92
  </div>
52
93
  </nav>
53
94
  </template>
54
95
 
55
96
  <script lang="ts" setup>
56
97
  import { useResizeObserver } from '@vueuse/core';
57
- import { range } from 'lodash';
98
+ import { debounce, isNumber, range } from 'lodash';
58
99
  import { Ref } from 'vue';
59
100
 
60
101
  const props = defineProps({
@@ -75,18 +116,28 @@ const props = defineProps({
75
116
 
76
117
  const emit = defineEmits(['update:model-value']);
77
118
 
119
+ const manualPage = ref(null) as Ref<null | string | number>;
120
+ const manualPageMobile = ref(props.modelValue) as Ref<null | string | number>;
121
+
122
+ watch(
123
+ () => props.modelValue,
124
+ (value) => {
125
+ manualPageMobile.value = value;
126
+ }
127
+ );
128
+
78
129
  function next() {
79
130
  if (props.modelValue >= props.lastPage) {
80
131
  return;
81
132
  }
82
- emit('update:model-value', props.modelValue + 1);
133
+ updateModalValue(props.modelValue + 1);
83
134
  }
84
135
 
85
136
  function previous() {
86
137
  if (props.modelValue == 1) {
87
138
  return;
88
139
  }
89
- emit('update:model-value', props.modelValue - 1);
140
+ updateModalValue(props.modelValue - 1);
90
141
  }
91
142
 
92
143
  const paginationNode = ref(null) as Ref<null | HTMLElement>;
@@ -163,6 +214,53 @@ function onButtonClick(i: number | string) {
163
214
  if (!isClickable(i)) {
164
215
  return;
165
216
  }
166
- emit('update:model-value', i);
217
+ updateModalValue(i);
218
+ }
219
+
220
+ const onManualPageInput = debounce(() => {
221
+ setPageFromManualPage();
222
+ }, 1000);
223
+
224
+ function onManualPageEnter(e: any) {
225
+ e.preventDefault();
226
+ setPageFromManualPage();
227
+ }
228
+
229
+ function setPageFromManualPage() {
230
+ updateModalValue(manualPage.value);
231
+ nextTick(() => {
232
+ manualPage.value = null;
233
+ });
234
+ }
235
+
236
+ const onManualPageMobileInput = debounce(() => {
237
+ setPageFromManualPageMobile();
238
+ }, 1000);
239
+
240
+ function onManualPageMobileEnter(e: any) {
241
+ e.preventDefault();
242
+ setPageFromManualPageMobile();
243
+ }
244
+
245
+ function setPageFromManualPageMobile() {
246
+ updateModalValue(manualPageMobile.value);
247
+ if (!isValidPage(manualPageMobile.value)) {
248
+ nextTick(() => {
249
+ manualPageMobile.value = props.modelValue;
250
+ });
251
+ }
252
+ }
253
+
254
+ function updateModalValue(newPage: number | string | null | undefined) {
255
+ if (isValidPage(newPage)) {
256
+ emit('update:model-value', newPage);
257
+ }
258
+ }
259
+
260
+ function isValidPage(newPage: number | string | null | undefined) {
261
+ if (isNumber(newPage) && newPage >= 1 && newPage <= props.lastPage) {
262
+ return true;
263
+ }
264
+ return false;
167
265
  }
168
266
  </script>
package/src/lang/en.json CHANGED
@@ -19,6 +19,7 @@
19
19
  "error": "Error",
20
20
  "file_must_be_of_type": "The file must be of type",
21
21
  "filters": "Filters",
22
+ "go_to_page": "Go to ",
22
23
  "min_x_characters": "{x} characters minimum",
23
24
  "month": "Month",
24
25
  "next": "Next",
@@ -26,7 +27,9 @@
26
27
  "none": "None",
27
28
  "nothing_found": "Nothing found",
28
29
  "notifications_empty": "You have no new notifications",
30
+ "of": "of",
29
31
  "or": "or",
32
+ "page": "Page",
30
33
  "pagination_detail": "{page} records of {total}",
31
34
  "previous": "Previous",
32
35
  "previous_month": "Previous month",
package/src/lang/fr.json CHANGED
@@ -19,6 +19,7 @@
19
19
  "error": "Erreur",
20
20
  "file_must_be_of_type": "Le fichier doit être de type",
21
21
  "filters": "Filtres",
22
+ "go_to_page": "Page",
22
23
  "min_x_characters": "{x} caractères minimum",
23
24
  "month": "Mois",
24
25
  "next": "Suivant",
@@ -26,7 +27,9 @@
26
27
  "none": "Aucun",
27
28
  "nothing_found": "Rien n'a été trouvé",
28
29
  "notifications_empty": "Vous n'avez aucune nouvelle notification",
30
+ "of": "de",
29
31
  "or": "ou",
32
+ "page": "Page",
30
33
  "pagination_detail": "{page} items de {total}",
31
34
  "previous": "Précédent",
32
35
  "previous_month": "Mois précédent",
@@ -21,7 +21,7 @@ export type OptionValue = string | number;
21
21
 
22
22
  export type Option = Record<string, any>;
23
23
 
24
- export type Selection = Record<string, any> | null | undefined;
24
+ export type Selection = Option | null | undefined;
25
25
 
26
26
  export type NormalizedOption = {
27
27
  option: Option;