vueless 0.0.569 → 0.0.571
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 +1 -1
- package/types.ts +24 -3
- package/ui.button/types.ts +2 -2
- package/ui.container-accordion/UAccordion.vue +2 -2
- package/ui.container-accordion/types.ts +1 -0
- package/ui.container-modal/UModal.vue +15 -8
- package/ui.container-page/UPage.vue +10 -6
- package/ui.form-checkbox/types.ts +7 -0
- package/ui.form-checkbox-group/UCheckboxGroup.vue +1 -1
- package/ui.form-checkbox-multi-state/UCheckboxMultiState.vue +4 -1
- package/ui.form-color-picker/UColorPicker.vue +67 -147
- package/ui.form-color-picker/storybook/Docs.mdx +2 -2
- package/ui.form-color-picker/storybook/{stories.js → stories.ts} +13 -5
- package/ui.form-color-picker/types.ts +64 -0
- package/ui.form-color-picker/useAttrs.ts +15 -0
- package/ui.form-input/UInput.vue +162 -321
- package/ui.form-input/{config.js → config.ts} +3 -0
- package/ui.form-input/storybook/Docs.mdx +2 -2
- package/ui.form-input/storybook/{stories.js → stories.ts} +14 -6
- package/ui.form-input/types.ts +103 -0
- package/ui.form-input/useAttrs.ts +31 -0
- package/ui.form-input-file/UInputFile.vue +188 -245
- package/ui.form-input-file/storybook/Docs.mdx +2 -2
- package/ui.form-input-file/storybook/{stories.js → stories.ts} +13 -5
- package/ui.form-input-file/types.ts +72 -0
- package/ui.form-input-file/useAttrs.ts +21 -0
- package/ui.form-input-file/{utilFileForm.js → utilFileForm.ts} +1 -1
- package/ui.form-input-money/UInputMoney.vue +76 -223
- package/ui.form-input-money/storybook/Docs.mdx +2 -2
- package/ui.form-input-money/storybook/{stories.js → stories.ts} +14 -6
- package/ui.form-input-money/types.ts +118 -0
- package/ui.form-input-money/useAttrs.ts +15 -0
- package/ui.form-input-money/{useFormatCurrency.js → useFormatCurrency.ts} +28 -17
- package/ui.form-input-money/utilFormat.ts +83 -0
- package/ui.form-input-number/UInputNumber.vue +69 -156
- package/ui.form-input-number/storybook/Docs.mdx +2 -2
- package/ui.form-input-number/storybook/{stories.js → stories.ts} +17 -9
- package/ui.form-input-number/types.ts +65 -0
- package/ui.form-input-number/useAttrs.ts +15 -0
- package/ui.form-input-rating/UInputRating.vue +70 -158
- package/ui.form-input-rating/storybook/Docs.mdx +2 -2
- package/ui.form-input-rating/storybook/{stories.js → stories.ts} +14 -6
- package/ui.form-input-rating/types.ts +67 -0
- package/ui.form-input-rating/useAttrs.ts +14 -0
- package/ui.form-input-search/UInputSearch.vue +97 -224
- package/ui.form-input-search/storybook/Docs.mdx +2 -2
- package/ui.form-input-search/storybook/{stories.js → stories.ts} +13 -5
- package/ui.form-input-search/types.ts +93 -0
- package/ui.form-input-search/useAttrs.ts +15 -0
- package/ui.form-radio/URadio.vue +1 -1
- package/ui.form-radio-group/URadioGroup.vue +1 -1
- package/ui.navigation-pagination/UPagination.vue +15 -15
- package/ui.navigation-pagination/types.ts +3 -0
- package/ui.navigation-progress/UProgress.vue +16 -2
- package/ui.navigation-progress/types.ts +2 -0
- package/ui.text-files/UFiles.vue +20 -16
- package/ui.text-files/types.ts +1 -1
- package/ui.text-notify/UNotify.vue +38 -48
- package/ui.text-notify/types.ts +24 -0
- package/web-types.json +227 -138
- package/ui.form-color-picker/useAttrs.js +0 -9
- package/ui.form-input/useAttrs.js +0 -15
- package/ui.form-input-file/useAttrs.js +0 -15
- package/ui.form-input-money/useAttrs.js +0 -9
- package/ui.form-input-money/utilFormat.js +0 -75
- package/ui.form-input-number/useAttrs.js +0 -9
- package/ui.form-input-rating/useAttrs.js +0 -8
- package/ui.form-input-search/useAttrs.js +0 -9
- /package/ui.form-color-picker/{config.js → config.ts} +0 -0
- /package/ui.form-color-picker/{constants.js → constants.ts} +0 -0
- /package/ui.form-input/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-file/{config.js → config.ts} +0 -0
- /package/ui.form-input-file/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-money/{config.js → config.ts} +0 -0
- /package/ui.form-input-money/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-number/{config.js → config.ts} +0 -0
- /package/ui.form-input-number/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-rating/{config.js → config.ts} +0 -0
- /package/ui.form-input-rating/{constants.js → constants.ts} +0 -0
- /package/ui.form-input-search/{config.js → config.ts} +0 -0
- /package/ui.form-input-search/{constants.js → constants.ts} +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { onMounted, nextTick, ref, onBeforeUnmount, toValue, watch } from "vue";
|
|
2
2
|
|
|
3
|
-
import
|
|
3
|
+
import { getRawValue, getFormattedValue } from "./utilFormat.ts";
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import type { FormatOptions } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
export default function useFormatCurrency(elementId: string = "", options: () => FormatOptions) {
|
|
6
8
|
let prevValue = "";
|
|
7
|
-
let inputElement = null;
|
|
9
|
+
let inputElement: HTMLInputElement | null = null;
|
|
8
10
|
|
|
9
11
|
const formattedValue = ref("");
|
|
10
12
|
const rawValue = ref("");
|
|
@@ -17,41 +19,48 @@ export default function useFormatCurrency(elementId, options) {
|
|
|
17
19
|
);
|
|
18
20
|
|
|
19
21
|
onMounted(() => {
|
|
20
|
-
inputElement = document.getElementById(elementId);
|
|
21
|
-
inputElement.addEventListener("input", onInput);
|
|
22
|
+
inputElement = document.getElementById(elementId) as HTMLInputElement;
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
if (inputElement) {
|
|
25
|
+
inputElement.addEventListener("input", onInput);
|
|
26
|
+
onInput(formattedValue.value as unknown as InputEvent);
|
|
27
|
+
}
|
|
24
28
|
});
|
|
25
29
|
|
|
26
30
|
onBeforeUnmount(() => {
|
|
27
|
-
inputElement
|
|
31
|
+
if (inputElement) {
|
|
32
|
+
inputElement.removeEventListener("input", onInput);
|
|
33
|
+
}
|
|
28
34
|
});
|
|
29
35
|
|
|
30
36
|
// Use to set input value manually
|
|
31
|
-
function setValue(value) {
|
|
32
|
-
const localFormattedValue =
|
|
37
|
+
function setValue(value: string | number) {
|
|
38
|
+
const localFormattedValue = getFormattedValue(value, toValue(options));
|
|
33
39
|
|
|
34
40
|
formattedValue.value = localFormattedValue;
|
|
35
|
-
rawValue.value =
|
|
41
|
+
rawValue.value = getRawValue(localFormattedValue, toValue(options));
|
|
36
42
|
|
|
37
43
|
prevValue = formattedValue.value;
|
|
38
44
|
}
|
|
39
45
|
|
|
40
|
-
async function onInput(event) {
|
|
46
|
+
async function onInput(event: Event) {
|
|
41
47
|
if (!event.target) return;
|
|
42
48
|
|
|
43
49
|
await nextTick(async () => {
|
|
50
|
+
if (!inputElement) return;
|
|
51
|
+
|
|
44
52
|
let cursorStart = inputElement.selectionStart;
|
|
45
53
|
let cursorEnd = inputElement.selectionEnd;
|
|
46
54
|
|
|
47
55
|
const hasValueInputValue = cursorEnd === 1 && cursorStart === 1;
|
|
48
|
-
const
|
|
56
|
+
const input = event.target as HTMLInputElement;
|
|
57
|
+
const value = input.value || "";
|
|
49
58
|
|
|
50
|
-
const localFormattedValue =
|
|
59
|
+
const localFormattedValue = getFormattedValue(value, toValue(options));
|
|
51
60
|
|
|
52
61
|
const currentValueOffsetLength = localFormattedValue
|
|
53
62
|
.split("")
|
|
54
|
-
.filter((value) => value === toValue(options).thousandsSeparator).length;
|
|
63
|
+
.filter((value: string) => value === toValue(options).thousandsSeparator).length;
|
|
55
64
|
|
|
56
65
|
const prevValueOffsetLength = prevValue
|
|
57
66
|
.split("")
|
|
@@ -61,17 +70,19 @@ export default function useFormatCurrency(elementId, options) {
|
|
|
61
70
|
const offset = currentValueOffsetLength - prevValueOffsetLength;
|
|
62
71
|
|
|
63
72
|
formattedValue.value = localFormattedValue || toValue(options).prefix;
|
|
64
|
-
rawValue.value =
|
|
73
|
+
rawValue.value = getRawValue(localFormattedValue, toValue(options));
|
|
65
74
|
|
|
66
75
|
await nextTick(() => {
|
|
67
|
-
if (localFormattedValue.length === cursorEnd) return;
|
|
76
|
+
if (localFormattedValue.length === cursorEnd || !cursorStart || !cursorEnd) return;
|
|
68
77
|
|
|
69
78
|
if (hasValueInputValue && prefixLength) {
|
|
70
79
|
cursorStart += prefixLength;
|
|
71
80
|
cursorEnd += prefixLength;
|
|
72
81
|
}
|
|
73
82
|
|
|
74
|
-
inputElement
|
|
83
|
+
if (inputElement) {
|
|
84
|
+
inputElement.setSelectionRange(cursorStart + offset, cursorEnd + offset);
|
|
85
|
+
}
|
|
75
86
|
});
|
|
76
87
|
|
|
77
88
|
prevValue = formattedValue.value;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { FormatOptions } from "./types.ts";
|
|
2
|
+
|
|
3
|
+
const isNumberValueRegExp = /^[\d,.\s-]+$/;
|
|
4
|
+
const rawDecimalMark = ".";
|
|
5
|
+
const comma = ",";
|
|
6
|
+
|
|
7
|
+
export function getRawValue(value: string | number, options: FormatOptions): string {
|
|
8
|
+
const { thousandsSeparator, decimalSeparator, prefix } = options;
|
|
9
|
+
|
|
10
|
+
value = String(value).endsWith(decimalSeparator)
|
|
11
|
+
? String(value).replace(decimalSeparator, "")
|
|
12
|
+
: String(value);
|
|
13
|
+
|
|
14
|
+
const rawValueWithPrefix = value
|
|
15
|
+
.replaceAll(thousandsSeparator, "")
|
|
16
|
+
.replace(decimalSeparator, ".");
|
|
17
|
+
|
|
18
|
+
return rawValueWithPrefix.replace(prefix, "");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function getFormattedValue(value: string | number, options: FormatOptions): string {
|
|
22
|
+
const {
|
|
23
|
+
thousandsSeparator,
|
|
24
|
+
decimalSeparator,
|
|
25
|
+
minFractionDigits,
|
|
26
|
+
maxFractionDigits,
|
|
27
|
+
prefix,
|
|
28
|
+
positiveOnly,
|
|
29
|
+
} = options;
|
|
30
|
+
|
|
31
|
+
const invalidValuesRegExp = new RegExp("[^\\d,\\d.\\s-" + decimalSeparator + "]", "g");
|
|
32
|
+
const doubleValueRegExp = new RegExp("([,\\.\\s-" + decimalSeparator + "])+", "g");
|
|
33
|
+
|
|
34
|
+
// slice to first decimal mark
|
|
35
|
+
value = String(value)
|
|
36
|
+
.replaceAll(comma, decimalSeparator)
|
|
37
|
+
.split(decimalSeparator)
|
|
38
|
+
.slice(0, 2)
|
|
39
|
+
.map((value: string, index: number) =>
|
|
40
|
+
index ? value.replaceAll(thousandsSeparator, "") : value,
|
|
41
|
+
)
|
|
42
|
+
.join(decimalSeparator);
|
|
43
|
+
|
|
44
|
+
value = String(value)
|
|
45
|
+
.replace(invalidValuesRegExp, "")
|
|
46
|
+
.replace(doubleValueRegExp, "$1")
|
|
47
|
+
.replaceAll(decimalSeparator, rawDecimalMark);
|
|
48
|
+
|
|
49
|
+
const isNumber = isNumberValueRegExp.test(value);
|
|
50
|
+
const isFloat = value.endsWith(rawDecimalMark) || value.endsWith(".0");
|
|
51
|
+
|
|
52
|
+
if (!value || !isNumber || isFloat) {
|
|
53
|
+
return `${prefix}${value.replaceAll(rawDecimalMark, decimalSeparator)}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const intlNumberOptions: Intl.NumberFormatOptions = {
|
|
57
|
+
minimumFractionDigits:
|
|
58
|
+
minFractionDigits <= maxFractionDigits ? minFractionDigits : maxFractionDigits,
|
|
59
|
+
maximumFractionDigits: maxFractionDigits,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
if (positiveOnly) {
|
|
63
|
+
intlNumberOptions.signDisplay = "never";
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const intlNumber = new Intl.NumberFormat("en-US", intlNumberOptions);
|
|
67
|
+
|
|
68
|
+
const rawValue = getRawValue(value, {
|
|
69
|
+
decimalSeparator,
|
|
70
|
+
thousandsSeparator,
|
|
71
|
+
prefix,
|
|
72
|
+
minFractionDigits: 0,
|
|
73
|
+
maxFractionDigits: 2,
|
|
74
|
+
positiveOnly: false,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const formattedValue = intlNumber
|
|
78
|
+
.format(parseFloat(rawValue))
|
|
79
|
+
.replaceAll(comma, thousandsSeparator)
|
|
80
|
+
.replaceAll(rawDecimalMark, decimalSeparator);
|
|
81
|
+
|
|
82
|
+
return prefix + formattedValue;
|
|
83
|
+
}
|
|
@@ -1,3 +1,70 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
|
|
4
|
+
import UIcon from "../ui.image-icon/UIcon.vue";
|
|
5
|
+
import UButton from "../ui.button/UButton.vue";
|
|
6
|
+
import ULabel from "../ui.form-label/ULabel.vue";
|
|
7
|
+
import { getDefault } from "../utils/ui.ts";
|
|
8
|
+
|
|
9
|
+
import defaultConfig from "./config.ts";
|
|
10
|
+
import { UInputNumber } from "./constants.ts";
|
|
11
|
+
import useAttrs from "./useAttrs.ts";
|
|
12
|
+
|
|
13
|
+
import type { UInputNumberProps } from "./types.ts";
|
|
14
|
+
|
|
15
|
+
defineOptions({ inheritAttrs: false });
|
|
16
|
+
|
|
17
|
+
const props = withDefaults(defineProps<UInputNumberProps>(), {
|
|
18
|
+
step: getDefault<UInputNumberProps>(defaultConfig, UInputNumber).step,
|
|
19
|
+
min: getDefault<UInputNumberProps>(defaultConfig, UInputNumber).min,
|
|
20
|
+
max: getDefault<UInputNumberProps>(defaultConfig, UInputNumber).max,
|
|
21
|
+
labelAlign: getDefault<UInputNumberProps>(defaultConfig, UInputNumber).labelAlign,
|
|
22
|
+
size: getDefault<UInputNumberProps>(defaultConfig, UInputNumber).size,
|
|
23
|
+
disabled: getDefault<UInputNumberProps>(defaultConfig, UInputNumber).disabled,
|
|
24
|
+
dataTest: "",
|
|
25
|
+
config: () => ({}),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
const emit = defineEmits([
|
|
29
|
+
/**
|
|
30
|
+
* Triggers when the input value changes.
|
|
31
|
+
* @property {number} modelValue
|
|
32
|
+
*/
|
|
33
|
+
"update:modelValue",
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
const {
|
|
37
|
+
config,
|
|
38
|
+
valueAttrs,
|
|
39
|
+
labelAttrs,
|
|
40
|
+
removeButtonAttrs,
|
|
41
|
+
removeIconAttrs,
|
|
42
|
+
addButtonAttrs,
|
|
43
|
+
addIconAttrs,
|
|
44
|
+
numberAttrs,
|
|
45
|
+
} = useAttrs(props);
|
|
46
|
+
|
|
47
|
+
const count = computed({
|
|
48
|
+
get: () => props.modelValue,
|
|
49
|
+
set: (value) => emit("update:modelValue", value),
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const isAddButtonDisabled = computed(() => count.value >= props.max);
|
|
53
|
+
const isRemoveButtonDisabled = computed(() => count.value <= props.min);
|
|
54
|
+
|
|
55
|
+
function onClickRemove() {
|
|
56
|
+
const newCount = count.value - props.step;
|
|
57
|
+
|
|
58
|
+
count.value = newCount >= props.min ? newCount : count.value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function onClickAdd() {
|
|
62
|
+
const newCount = count.value + props.step;
|
|
63
|
+
|
|
64
|
+
count.value = newCount <= props.max ? newCount : count.value;
|
|
65
|
+
}
|
|
66
|
+
</script>
|
|
67
|
+
|
|
1
68
|
<template>
|
|
2
69
|
<ULabel
|
|
3
70
|
:label="label"
|
|
@@ -24,7 +91,7 @@
|
|
|
24
91
|
<UIcon
|
|
25
92
|
internal
|
|
26
93
|
:size="size"
|
|
27
|
-
:name="config.defaults
|
|
94
|
+
:name="config.defaults?.removeIcon"
|
|
28
95
|
:color="isRemoveButtonDisabled ? 'gray' : 'grayscale'"
|
|
29
96
|
v-bind="removeIconAttrs"
|
|
30
97
|
/>
|
|
@@ -48,164 +115,10 @@
|
|
|
48
115
|
<UIcon
|
|
49
116
|
internal
|
|
50
117
|
:size="size"
|
|
51
|
-
:name="config.defaults
|
|
118
|
+
:name="config.defaults?.addIcon"
|
|
52
119
|
:color="isAddButtonDisabled ? 'gray' : 'grayscale'"
|
|
53
120
|
v-bind="addIconAttrs"
|
|
54
121
|
/>
|
|
55
122
|
</UButton>
|
|
56
123
|
</ULabel>
|
|
57
124
|
</template>
|
|
58
|
-
|
|
59
|
-
<script setup>
|
|
60
|
-
import { computed } from "vue";
|
|
61
|
-
|
|
62
|
-
import UIcon from "../ui.image-icon/UIcon.vue";
|
|
63
|
-
import UButton from "../ui.button/UButton.vue";
|
|
64
|
-
import ULabel from "../ui.form-label/ULabel.vue";
|
|
65
|
-
import { getDefault } from "../utils/ui.ts";
|
|
66
|
-
|
|
67
|
-
import defaultConfig from "./config.js";
|
|
68
|
-
import { UInputNumber } from "./constants.js";
|
|
69
|
-
import useAttrs from "./useAttrs.js";
|
|
70
|
-
|
|
71
|
-
defineOptions({ inheritAttrs: false });
|
|
72
|
-
|
|
73
|
-
const props = defineProps({
|
|
74
|
-
/**
|
|
75
|
-
* Input value.
|
|
76
|
-
*/
|
|
77
|
-
modelValue: {
|
|
78
|
-
type: Number,
|
|
79
|
-
required: true,
|
|
80
|
-
},
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Input step.
|
|
84
|
-
*/
|
|
85
|
-
step: {
|
|
86
|
-
type: Number,
|
|
87
|
-
default: getDefault(defaultConfig, UInputNumber).step,
|
|
88
|
-
},
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Input min value.
|
|
92
|
-
*/
|
|
93
|
-
min: {
|
|
94
|
-
type: Number,
|
|
95
|
-
default: getDefault(defaultConfig, UInputNumber).min,
|
|
96
|
-
},
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* Input max value.
|
|
100
|
-
*/
|
|
101
|
-
max: {
|
|
102
|
-
type: Number,
|
|
103
|
-
default: getDefault(defaultConfig, UInputNumber).max,
|
|
104
|
-
},
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* Input label below number.
|
|
108
|
-
*/
|
|
109
|
-
label: {
|
|
110
|
-
type: String,
|
|
111
|
-
default: "",
|
|
112
|
-
},
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Label placement.
|
|
116
|
-
* @values top, topWithDesc, left, right
|
|
117
|
-
*/
|
|
118
|
-
labelAlign: {
|
|
119
|
-
type: String,
|
|
120
|
-
default: getDefault(defaultConfig, UInputNumber).labelAlign,
|
|
121
|
-
},
|
|
122
|
-
|
|
123
|
-
/**
|
|
124
|
-
* Input description.
|
|
125
|
-
*/
|
|
126
|
-
description: {
|
|
127
|
-
type: String,
|
|
128
|
-
default: "",
|
|
129
|
-
},
|
|
130
|
-
|
|
131
|
-
/**
|
|
132
|
-
* Error message.
|
|
133
|
-
*/
|
|
134
|
-
error: {
|
|
135
|
-
type: String,
|
|
136
|
-
default: "",
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* Input size.
|
|
141
|
-
* @values sm, md, lg
|
|
142
|
-
*/
|
|
143
|
-
size: {
|
|
144
|
-
type: String,
|
|
145
|
-
default: getDefault(defaultConfig, UInputNumber).size,
|
|
146
|
-
},
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Disable the input.
|
|
150
|
-
*/
|
|
151
|
-
disabled: {
|
|
152
|
-
type: Boolean,
|
|
153
|
-
default: getDefault(defaultConfig, UInputNumber).disabled,
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* Component config object.
|
|
158
|
-
*/
|
|
159
|
-
config: {
|
|
160
|
-
type: Object,
|
|
161
|
-
default: () => ({}),
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
/**
|
|
165
|
-
* Data-test attribute for automated testing.
|
|
166
|
-
*/
|
|
167
|
-
dataTest: {
|
|
168
|
-
type: String,
|
|
169
|
-
default: "",
|
|
170
|
-
},
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
const emit = defineEmits([
|
|
174
|
-
/**
|
|
175
|
-
* Triggers when the input value changes.
|
|
176
|
-
* @property {number} modelValue
|
|
177
|
-
*/
|
|
178
|
-
"update:modelValue",
|
|
179
|
-
]);
|
|
180
|
-
|
|
181
|
-
const {
|
|
182
|
-
config,
|
|
183
|
-
valueAttrs,
|
|
184
|
-
labelAttrs,
|
|
185
|
-
removeButtonAttrs,
|
|
186
|
-
removeIconAttrs,
|
|
187
|
-
addButtonAttrs,
|
|
188
|
-
addIconAttrs,
|
|
189
|
-
numberAttrs,
|
|
190
|
-
} = useAttrs(props);
|
|
191
|
-
|
|
192
|
-
const count = computed({
|
|
193
|
-
get: () => props.modelValue,
|
|
194
|
-
set: (value) => emit("update:modelValue", value),
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
const isAddButtonDisabled = computed(() => count.value >= props.max);
|
|
198
|
-
const isRemoveButtonDisabled = computed(() => count.value <= props.min);
|
|
199
|
-
|
|
200
|
-
function onClickRemove() {
|
|
201
|
-
const newCount = count.value - props.step;
|
|
202
|
-
|
|
203
|
-
count.value = newCount >= props.min ? newCount : count.value;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
function onClickAdd() {
|
|
207
|
-
const newCount = count.value + props.step;
|
|
208
|
-
|
|
209
|
-
count.value = newCount <= props.max ? newCount : count.value;
|
|
210
|
-
}
|
|
211
|
-
</script>
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Meta, Title, Subtitle, Description, Primary, Controls, Stories, Source } from "@storybook/blocks";
|
|
2
2
|
import { getSource } from "../../utils/storybook.ts";
|
|
3
3
|
|
|
4
|
-
import * as stories from "./stories.
|
|
5
|
-
import defaultConfig from "../config.
|
|
4
|
+
import * as stories from "./stories.ts";
|
|
5
|
+
import defaultConfig from "../config.ts?raw"
|
|
6
6
|
|
|
7
7
|
<Meta of={stories} />
|
|
8
8
|
<Title of={stories} />
|
|
@@ -8,6 +8,14 @@ import {
|
|
|
8
8
|
import UInputNumber from "../../ui.form-input-number/UInputNumber.vue";
|
|
9
9
|
import UCol from "../../ui.container-col/UCol.vue";
|
|
10
10
|
|
|
11
|
+
import type { Meta, StoryFn } from "@storybook/vue3";
|
|
12
|
+
import type { UInputNumberProps } from "../types.ts";
|
|
13
|
+
|
|
14
|
+
interface UInputNumberArgs extends UInputNumberProps {
|
|
15
|
+
slotTemplate?: string;
|
|
16
|
+
enum: "size";
|
|
17
|
+
}
|
|
18
|
+
|
|
11
19
|
export default {
|
|
12
20
|
id: "3050",
|
|
13
21
|
title: "Form Inputs & Controls / Input Number",
|
|
@@ -22,9 +30,9 @@ export default {
|
|
|
22
30
|
parameters: {
|
|
23
31
|
...getDocsDescription(UInputNumber.__name),
|
|
24
32
|
},
|
|
25
|
-
};
|
|
33
|
+
} as Meta;
|
|
26
34
|
|
|
27
|
-
const DefaultTemplate = (args) => ({
|
|
35
|
+
const DefaultTemplate: StoryFn<UInputNumberArgs> = (args: UInputNumberArgs) => ({
|
|
28
36
|
components: { UInputNumber },
|
|
29
37
|
setup() {
|
|
30
38
|
const slots = getSlotNames(UInputNumber.__name);
|
|
@@ -33,17 +41,17 @@ const DefaultTemplate = (args) => ({
|
|
|
33
41
|
},
|
|
34
42
|
template: `
|
|
35
43
|
<UInputNumber v-bind="args" v-model="args.modelValue">
|
|
36
|
-
${args.slotTemplate || getSlotsFragment()}
|
|
44
|
+
${args.slotTemplate || getSlotsFragment("")}
|
|
37
45
|
</UInputNumber>
|
|
38
46
|
`,
|
|
39
47
|
});
|
|
40
48
|
|
|
41
|
-
const EnumVariantTemplate = (args, { argTypes }) => ({
|
|
49
|
+
const EnumVariantTemplate: StoryFn<UInputNumberArgs> = (args: UInputNumberArgs, { argTypes }) => ({
|
|
42
50
|
components: { UInputNumber, UCol },
|
|
43
51
|
setup() {
|
|
44
52
|
return {
|
|
45
53
|
args,
|
|
46
|
-
options: argTypes[args.enum]
|
|
54
|
+
options: argTypes?.[args.enum]?.options,
|
|
47
55
|
};
|
|
48
56
|
},
|
|
49
57
|
data() {
|
|
@@ -74,7 +82,7 @@ Default.args = { step: 1, min: 1, max: 100 };
|
|
|
74
82
|
|
|
75
83
|
export const Label = DefaultTemplate.bind({});
|
|
76
84
|
Label.args = {
|
|
77
|
-
|
|
85
|
+
modelValue: 1,
|
|
78
86
|
step: 1,
|
|
79
87
|
min: 1,
|
|
80
88
|
max: 100,
|
|
@@ -84,7 +92,7 @@ Label.args = {
|
|
|
84
92
|
export const Sizes = EnumVariantTemplate.bind({});
|
|
85
93
|
Sizes.args = {
|
|
86
94
|
enum: "size",
|
|
87
|
-
|
|
95
|
+
modelValue: 1,
|
|
88
96
|
step: 1,
|
|
89
97
|
min: 1,
|
|
90
98
|
max: 100,
|
|
@@ -92,7 +100,7 @@ Sizes.args = {
|
|
|
92
100
|
|
|
93
101
|
export const ValueLimit = DefaultTemplate.bind({});
|
|
94
102
|
ValueLimit.args = {
|
|
95
|
-
|
|
103
|
+
modelValue: 1,
|
|
96
104
|
step: 1,
|
|
97
105
|
min: 5,
|
|
98
106
|
max: 10,
|
|
@@ -101,7 +109,7 @@ ValueLimit.args = {
|
|
|
101
109
|
|
|
102
110
|
export const Step = DefaultTemplate.bind({});
|
|
103
111
|
Step.args = {
|
|
104
|
-
|
|
112
|
+
modelValue: 1,
|
|
105
113
|
step: 5,
|
|
106
114
|
min: 1,
|
|
107
115
|
max: 100,
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import defaultConfig from "./config.ts";
|
|
2
|
+
|
|
3
|
+
export type Config = Partial<typeof defaultConfig>;
|
|
4
|
+
|
|
5
|
+
export interface UInputNumberProps {
|
|
6
|
+
/**
|
|
7
|
+
* Input value.
|
|
8
|
+
*/
|
|
9
|
+
modelValue: number;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Input step.
|
|
13
|
+
*/
|
|
14
|
+
step?: number;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Input min value.
|
|
18
|
+
*/
|
|
19
|
+
min?: number;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Input max value.
|
|
23
|
+
*/
|
|
24
|
+
max?: number;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Input label below number.
|
|
28
|
+
*/
|
|
29
|
+
label?: string;
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Label placement.
|
|
33
|
+
*/
|
|
34
|
+
labelAlign?: "top" | "topWithDesc" | "left" | "right";
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Input description.
|
|
38
|
+
*/
|
|
39
|
+
description?: string;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Error message.
|
|
43
|
+
*/
|
|
44
|
+
error?: string;
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Input size.
|
|
48
|
+
*/
|
|
49
|
+
size?: "sm" | "md" | "lg";
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Disable the input.
|
|
53
|
+
*/
|
|
54
|
+
disabled?: boolean;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Component config object.
|
|
58
|
+
*/
|
|
59
|
+
config?: Config;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Data-test attribute for automated testing.
|
|
63
|
+
*/
|
|
64
|
+
dataTest?: string;
|
|
65
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import useUI from "../composables/useUI.ts";
|
|
2
|
+
|
|
3
|
+
import defaultConfig from "./config.ts";
|
|
4
|
+
|
|
5
|
+
import type { UseAttrs } from "../types.ts";
|
|
6
|
+
import type { UInputNumberProps, Config } from "./types.ts";
|
|
7
|
+
|
|
8
|
+
export default function useAttrs(props: UInputNumberProps): UseAttrs<Config> {
|
|
9
|
+
const { config, getKeysAttrs } = useUI<Config>(defaultConfig, () => props.config);
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
config,
|
|
13
|
+
...getKeysAttrs(),
|
|
14
|
+
};
|
|
15
|
+
}
|