sprintify-ui 0.2.12 → 0.2.13
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/dist/sprintify-ui.es.js +7943 -8182
- package/dist/types/src/components/BaseAutocompleteFetch.vue.d.ts +1 -1
- package/dist/types/src/components/BaseFileUploader.vue.d.ts +9 -9
- package/dist/types/src/components/BaseHasMany.vue.d.ts +1 -1
- package/dist/types/src/components/BaseInput.vue.d.ts +3 -3
- package/dist/types/src/components/BaseInputPercent.vue.d.ts +2 -2
- package/dist/types/src/components/BaseMediaLibrary.vue.d.ts +2 -2
- package/dist/types/src/components/BaseMediaListItem.vue.d.ts +1 -1
- package/dist/types/src/components/BaseMenuItem.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbarItemContent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseNavbarSideItemContent.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTagAutocomplete.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTagAutocompleteFetch.vue.d.ts +1 -1
- package/dist/types/src/components/BaseTextarea.vue.d.ts +1 -1
- package/dist/types/src/components/index.d.ts +1 -2
- package/package.json +1 -1
- package/src/components/BaseForm.stories.js +1 -3
- package/src/components/BaseInput.vue +1 -21
- package/src/components/index.ts +0 -2
- package/dist/types/src/components/BaseNumber.vue.d.ts +0 -125
- package/src/components/BaseNumber.stories.js +0 -66
- package/src/components/BaseNumber.vue +0 -383
|
@@ -1,383 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="base-number relative">
|
|
3
|
-
<Transition
|
|
4
|
-
enter-active-class="transition duration-200 ease-out"
|
|
5
|
-
enter-from-class="transform scale-90 opacity-0"
|
|
6
|
-
enter-to-class="transform scale-100 opacity-100"
|
|
7
|
-
leave-active-class="transition duration-75 ease-in"
|
|
8
|
-
leave-from-class="transform scale-100 opacity-100"
|
|
9
|
-
leave-to-class="transform scale-90 opacity-0"
|
|
10
|
-
>
|
|
11
|
-
<div
|
|
12
|
-
v-if="showInvalidInput && invalidInput"
|
|
13
|
-
class="absolute left-0 top-full z-[1]"
|
|
14
|
-
>
|
|
15
|
-
<div
|
|
16
|
-
class="mt-1 ml-1 rounded bg-red-500 px-2 py-1 text-xs font-medium text-white"
|
|
17
|
-
>
|
|
18
|
-
<span v-if="tooBig"> Maximum {{ max }} </span>
|
|
19
|
-
<span v-else-if="tooSmall"> Minimum {{ min }} </span>
|
|
20
|
-
<span v-else-if="tooPrecise">
|
|
21
|
-
{{ t('sui.maximum_x_decimal_places', { count: precision }) }}
|
|
22
|
-
</span>
|
|
23
|
-
<span v-else>
|
|
24
|
-
{{ t('sui.invalid_value') }}
|
|
25
|
-
</span>
|
|
26
|
-
</div>
|
|
27
|
-
</div>
|
|
28
|
-
</Transition>
|
|
29
|
-
|
|
30
|
-
<div
|
|
31
|
-
class="relative flex"
|
|
32
|
-
:class="[borderColor, borderless ? '' : 'rounded border']"
|
|
33
|
-
>
|
|
34
|
-
<input
|
|
35
|
-
v-model="valueInternal"
|
|
36
|
-
:required="required"
|
|
37
|
-
:name="name"
|
|
38
|
-
:step="stepNormalized"
|
|
39
|
-
:placeholder="placeholder"
|
|
40
|
-
:disabled="disabled"
|
|
41
|
-
:min="min"
|
|
42
|
-
:max="max"
|
|
43
|
-
:class="[
|
|
44
|
-
['full', 'left'].includes(rounded) ? 'rounded-l' : '',
|
|
45
|
-
showInvalidInput ? 'focus:ring-red-400' : 'focus:ring-primary-500',
|
|
46
|
-
]"
|
|
47
|
-
class="w-full border-none focus:z-[1] focus:border-none focus:border-transparent focus:shadow-none focus:outline-none focus:ring-2 focus:ring-offset-1 disabled:cursor-not-allowed disabled:text-slate-300"
|
|
48
|
-
type="text"
|
|
49
|
-
@input="onInput"
|
|
50
|
-
@blur="onBlur"
|
|
51
|
-
@focus="onFocus"
|
|
52
|
-
@keydown="onKeydown"
|
|
53
|
-
>
|
|
54
|
-
<div class="border-l border-slate-300">
|
|
55
|
-
<button
|
|
56
|
-
type="button"
|
|
57
|
-
:class="[['full', 'right'].includes(rounded) ? 'rounded-tr' : '']"
|
|
58
|
-
class="block h-1/2 border-b border-slate-300 bg-white enabled:hover:bg-slate-100 disabled:cursor-not-allowed disabled:text-slate-400"
|
|
59
|
-
:disabled="disabled"
|
|
60
|
-
@click="increment"
|
|
61
|
-
>
|
|
62
|
-
<BaseIcon icon="mdi:chevron-up" />
|
|
63
|
-
</button>
|
|
64
|
-
<button
|
|
65
|
-
type="button"
|
|
66
|
-
:class="[['full', 'right'].includes(rounded) ? 'rounded-br' : '']"
|
|
67
|
-
class="block h-1/2 bg-white enabled:hover:bg-slate-100 disabled:cursor-not-allowed disabled:text-slate-400"
|
|
68
|
-
:disabled="disabled"
|
|
69
|
-
@click="decrement"
|
|
70
|
-
>
|
|
71
|
-
<BaseIcon icon="mdi:chevron-down" />
|
|
72
|
-
</button>
|
|
73
|
-
</div>
|
|
74
|
-
</div>
|
|
75
|
-
</div>
|
|
76
|
-
</template>
|
|
77
|
-
|
|
78
|
-
<script lang="ts" setup>
|
|
79
|
-
import { useField } from '@/composables/field';
|
|
80
|
-
import { isNumber, round } from 'lodash';
|
|
81
|
-
import { PropType } from 'vue';
|
|
82
|
-
import { BaseIcon } from '.';
|
|
83
|
-
import { t } from '@/i18n';
|
|
84
|
-
|
|
85
|
-
const AUTO_CORRECT_TIMEOUT = 2000;
|
|
86
|
-
const SHOW_INVALID_INPUT_TIMEOUT = 500;
|
|
87
|
-
|
|
88
|
-
const props = defineProps({
|
|
89
|
-
modelValue: {
|
|
90
|
-
default: undefined,
|
|
91
|
-
type: [Number, null] as PropType<number | null>,
|
|
92
|
-
},
|
|
93
|
-
/**
|
|
94
|
-
* The step of the input. Can be a number or null.
|
|
95
|
-
*/
|
|
96
|
-
step: {
|
|
97
|
-
default: 1,
|
|
98
|
-
type: Number,
|
|
99
|
-
},
|
|
100
|
-
name: {
|
|
101
|
-
default: undefined,
|
|
102
|
-
type: String,
|
|
103
|
-
},
|
|
104
|
-
placeholder: {
|
|
105
|
-
default: '',
|
|
106
|
-
type: String,
|
|
107
|
-
},
|
|
108
|
-
disabled: {
|
|
109
|
-
default: false,
|
|
110
|
-
type: Boolean,
|
|
111
|
-
},
|
|
112
|
-
required: {
|
|
113
|
-
default: false,
|
|
114
|
-
type: Boolean,
|
|
115
|
-
},
|
|
116
|
-
min: {
|
|
117
|
-
default: undefined,
|
|
118
|
-
type: Number,
|
|
119
|
-
},
|
|
120
|
-
max: {
|
|
121
|
-
default: undefined,
|
|
122
|
-
type: Number,
|
|
123
|
-
},
|
|
124
|
-
hasError: {
|
|
125
|
-
default: false,
|
|
126
|
-
type: Boolean,
|
|
127
|
-
},
|
|
128
|
-
borderless: {
|
|
129
|
-
default: false,
|
|
130
|
-
type: Boolean,
|
|
131
|
-
},
|
|
132
|
-
rounded: {
|
|
133
|
-
default: 'full',
|
|
134
|
-
type: String as PropType<'full' | 'left' | 'right' | 'none'>,
|
|
135
|
-
},
|
|
136
|
-
autoFix: {
|
|
137
|
-
default: false,
|
|
138
|
-
type: Boolean,
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
const emit = defineEmits(['update:modelValue', 'focus', 'blur', 'keydown']);
|
|
143
|
-
|
|
144
|
-
const { hasErrorInternal, emitUpdate, enableForm, disableForm } = useField({
|
|
145
|
-
name: computed(() => props.name),
|
|
146
|
-
required: computed(() => props.required),
|
|
147
|
-
hasError: computed(() => props.hasError),
|
|
148
|
-
emit: emit,
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
const showInvalidInput = ref(false);
|
|
152
|
-
|
|
153
|
-
const stepNormalized = computed<number>(() => {
|
|
154
|
-
if (props.step === undefined) return 1;
|
|
155
|
-
if (props.step === 0) return 1;
|
|
156
|
-
if (props.step === null) return 1;
|
|
157
|
-
if (!isNumber(props.step)) return 1;
|
|
158
|
-
return props.step;
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
const precision = computed(() => {
|
|
162
|
-
const parts = stepNormalized.value.toString().split('.');
|
|
163
|
-
if (parts.length === 1) return 0;
|
|
164
|
-
return parts[1].length;
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
const hasMax = computed(() => props.max !== undefined && props.max !== null);
|
|
168
|
-
const hasMin = computed(() => props.min !== undefined && props.min !== null);
|
|
169
|
-
|
|
170
|
-
function convertToNumber(
|
|
171
|
-
value: string | number | null | undefined
|
|
172
|
-
): number | null {
|
|
173
|
-
if (value === null) return null;
|
|
174
|
-
const number = parseFloat(value + '');
|
|
175
|
-
if (Number.isNaN(number)) {
|
|
176
|
-
return null;
|
|
177
|
-
}
|
|
178
|
-
return number;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
function convertToValidNumber(
|
|
182
|
-
value: string | number | null | undefined
|
|
183
|
-
): number | null {
|
|
184
|
-
let number = convertToNumber(value);
|
|
185
|
-
|
|
186
|
-
if (number === null) return null;
|
|
187
|
-
|
|
188
|
-
if (hasMax.value) {
|
|
189
|
-
number = Math.min(number, props.max as number);
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
if (hasMin.value) {
|
|
193
|
-
number = Math.max(number, props.min as number);
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
return round(number, precision.value);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const valueInternal = ref<null | string | number>(null);
|
|
200
|
-
|
|
201
|
-
const valueInternalNumber = computed<number | null>(() => {
|
|
202
|
-
return convertToNumber(valueInternal.value);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
const valueInternalValidNumber = computed<number | null>(() => {
|
|
206
|
-
return convertToValidNumber(valueInternal.value);
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
const realValueInternalAsString = computed<string>(() => {
|
|
210
|
-
if (valueInternalValidNumber.value === null) return '';
|
|
211
|
-
return valueInternalValidNumber.value.toLocaleString('fullwide', {
|
|
212
|
-
useGrouping: false,
|
|
213
|
-
});
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
const invalidInput = computed(() => {
|
|
217
|
-
if (valueInternalValidNumber.value == null && valueInternal.value == '') {
|
|
218
|
-
return false;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return realValueInternalAsString.value != (valueInternal.value ?? '');
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
const tooBig = computed(() => {
|
|
225
|
-
if (valueInternalNumber.value === null) return false;
|
|
226
|
-
return hasMax.value && valueInternalNumber.value > (props.max as number);
|
|
227
|
-
});
|
|
228
|
-
|
|
229
|
-
const tooSmall = computed(() => {
|
|
230
|
-
if (valueInternalNumber.value === null) return false;
|
|
231
|
-
return hasMin.value && valueInternalNumber.value < (props.min as number);
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
const tooPrecise = computed(() => {
|
|
235
|
-
if (valueInternal.value === null) return false;
|
|
236
|
-
const parts = (valueInternal.value + '').split('.');
|
|
237
|
-
|
|
238
|
-
if (parts.length === 1) return false;
|
|
239
|
-
|
|
240
|
-
return parts[1].length > precision.value;
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
if (convertToValidNumber(props.modelValue) != props.modelValue) {
|
|
244
|
-
emitUpdate(valueInternalValidNumber.value);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
let timeoutId = undefined as undefined | number;
|
|
248
|
-
|
|
249
|
-
function onInput(event: any) {
|
|
250
|
-
clearTimeout(timeoutId);
|
|
251
|
-
|
|
252
|
-
let value = (event.target.value + '' ?? '').replace(/[^\d.-]/g, '');
|
|
253
|
-
|
|
254
|
-
// remove all n + 1 dots
|
|
255
|
-
const parts = value.split('.');
|
|
256
|
-
value = parts.shift() + '';
|
|
257
|
-
|
|
258
|
-
if (parts.length > 0) {
|
|
259
|
-
value += '.' + parts.join('');
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
valueInternal.value = value;
|
|
263
|
-
|
|
264
|
-
emitUpdate(valueInternalValidNumber.value);
|
|
265
|
-
|
|
266
|
-
nextTick(() => {
|
|
267
|
-
showHideInvalidOnInput();
|
|
268
|
-
});
|
|
269
|
-
|
|
270
|
-
timeoutId = setTimeout(() => {
|
|
271
|
-
updateInternalValueToRealValue();
|
|
272
|
-
}, AUTO_CORRECT_TIMEOUT);
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
let showInvalidInputTimeoutId = undefined as undefined | number;
|
|
276
|
-
|
|
277
|
-
function showHideInvalidOnInput() {
|
|
278
|
-
clearTimeout(showInvalidInputTimeoutId);
|
|
279
|
-
|
|
280
|
-
if (!invalidInput.value) {
|
|
281
|
-
showInvalidInput.value = false;
|
|
282
|
-
return;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
showInvalidInputTimeoutId = setTimeout(() => {
|
|
286
|
-
showInvalidInput.value = true;
|
|
287
|
-
}, SHOW_INVALID_INPUT_TIMEOUT);
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function onBlur(e: Event) {
|
|
291
|
-
emit('blur', e);
|
|
292
|
-
|
|
293
|
-
if (invalidInput.value) {
|
|
294
|
-
showInvalidInput.value = true;
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
updateInternalValueToRealValue();
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function onFocus(e: Event) {
|
|
301
|
-
emit('focus', e);
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
function onKeydown(e: KeyboardEvent) {
|
|
305
|
-
if (e.key === 'ArrowUp') {
|
|
306
|
-
increment();
|
|
307
|
-
e.preventDefault();
|
|
308
|
-
} else if (e.key === 'ArrowDown') {
|
|
309
|
-
decrement();
|
|
310
|
-
e.preventDefault();
|
|
311
|
-
}
|
|
312
|
-
emit('keydown', e);
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
const defaultValue = computed<number>(() => {
|
|
316
|
-
return Math.max(0, props.min ?? 0);
|
|
317
|
-
});
|
|
318
|
-
|
|
319
|
-
function updateInternalValueToRealValue() {
|
|
320
|
-
if (!props.autoFix) {
|
|
321
|
-
return;
|
|
322
|
-
}
|
|
323
|
-
if (valueInternalValidNumber.value === null) {
|
|
324
|
-
valueInternal.value = '';
|
|
325
|
-
return;
|
|
326
|
-
}
|
|
327
|
-
valueInternal.value = round(
|
|
328
|
-
valueInternalValidNumber.value ?? defaultValue.value,
|
|
329
|
-
precision.value
|
|
330
|
-
);
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
function increment() {
|
|
334
|
-
if (props.disabled) return;
|
|
335
|
-
if (valueInternalValidNumber.value === null) {
|
|
336
|
-
valueInternal.value = defaultValue.value;
|
|
337
|
-
} else {
|
|
338
|
-
const newValue = round(
|
|
339
|
-
valueInternalValidNumber.value + stepNormalized.value,
|
|
340
|
-
precision.value
|
|
341
|
-
);
|
|
342
|
-
if (!hasMax.value || newValue <= (props.max as number)) {
|
|
343
|
-
valueInternal.value = newValue;
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
emitUpdate(valueInternalValidNumber.value);
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
function decrement() {
|
|
350
|
-
if (props.disabled) return;
|
|
351
|
-
if (valueInternalValidNumber.value === null) {
|
|
352
|
-
valueInternal.value = defaultValue.value;
|
|
353
|
-
} else {
|
|
354
|
-
const newValue = round(
|
|
355
|
-
valueInternalValidNumber.value - stepNormalized.value,
|
|
356
|
-
precision.value
|
|
357
|
-
);
|
|
358
|
-
if (!hasMin.value || newValue >= (props.min as number)) {
|
|
359
|
-
valueInternal.value = newValue;
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
emitUpdate(valueInternalValidNumber.value);
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
const borderColor = computed(() => {
|
|
366
|
-
if (hasErrorInternal.value || invalidInput.value) return 'border-red-500';
|
|
367
|
-
return 'border-slate-300';
|
|
368
|
-
});
|
|
369
|
-
|
|
370
|
-
/** Disable form */
|
|
371
|
-
|
|
372
|
-
watch(
|
|
373
|
-
() => invalidInput.value,
|
|
374
|
-
() => {
|
|
375
|
-
if (invalidInput.value) {
|
|
376
|
-
disableForm();
|
|
377
|
-
} else {
|
|
378
|
-
enableForm();
|
|
379
|
-
}
|
|
380
|
-
},
|
|
381
|
-
{ immediate: true }
|
|
382
|
-
);
|
|
383
|
-
</script>
|