Skip to content

Commit 51b2659

Browse files
authored
Merge pull request #115 from Jenesius/issue_114
feat: update input-number, add suffix
2 parents c686db7 + b37e123 commit 51b2659

File tree

9 files changed

+129
-59
lines changed

9 files changed

+129
-59
lines changed

examples/all-inputs/App.vue

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@
6060
<input-field name = "number" type = "number" label = "With label" />
6161
<input-field name = "number" type = "number" label = "Disabled" disabled />
6262
<input-field name = "number" type = "number" label = "With Error" :errors = "['Some mistake']" />
63+
<input-field name = "number" type = "number" label = "With Unit" :pretty="prettyUnit('meters')" />
64+
<input-field name = "number" type = "number" label = "With Suffix" suffix = "MHz" />
6365

6466
<h2>Input Radio</h2>
6567

@@ -103,15 +105,34 @@ import {Form} from "../../plugin";
103105
104106
const form = new Form();
105107
function modifyOnlyChar(a: string) {
106-
return a.replace(/\D/g, '');
108+
return a.replace(/\d/g, '');
107109
}
110+
let k = new Intl.NumberFormat("en-US", { style: "decimal" });
111+
112+
// Formatting Number
113+
114+
108115
function addPrettySymbol(symbol: string) {
109116
return (value: unknown) => {
110117
if (typeof value !== 'string') return '';
111118
112119
return `${value} ${symbol}`;
113120
}
114121
}
122+
function prettyUnit(unit: string) {
123+
return (v: unknown) => {
124+
if (typeof v !== "string" && typeof v !== "number") {
125+
return v;
126+
}
127+
v = String(v);
128+
v = v.replace(/[^0-9.]/g, '')
129+
130+
v = k.format(Number(v));
131+
132+
return `${v} ${unit}`
133+
}
134+
}
135+
115136
116137
const optionsCheckbox = [
117138
{

plugin/index.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,12 @@ import ComputedValue from "./methods/ComputedValue";
1616

1717
import utils from "./utils/utils";
1818

19+
import Widgets from "./widgets";
20+
1921
export {
2022
Form,
2123
FormProxy,
22-
24+
Widgets,
2325
useProxyState,
2426
useInputState,
2527
useFormState,

plugin/local-hooks/only-number.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export default function onlyNumber(a: unknown) {
2+
if (typeof a !== "string") return '';
3+
return a.replace(/[^\d,.+-]/,'')
4+
}

plugin/local-hooks/use-modify.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import {StringModify} from "../types";
2+
import warn from "../debug/warn";
3+
4+
type ModifyParam = undefined | StringModify | Array<StringModify | undefined>
5+
export default function useModify(callbackModifyProps: () => ModifyParam) {
6+
function parse(param: ModifyParam) {
7+
if (!param) return [];
8+
if (!Array.isArray(param)) return [param];
9+
return param.filter(a => a !== undefined) as StringModify[]
10+
}
11+
12+
return function execute(v: unknown): string {
13+
const arr = parse(callbackModifyProps()); // Getting array of handlers
14+
15+
arr.forEach(callback => v = callback(v));
16+
try {
17+
arr.forEach(callback => v = callback(v));
18+
} catch (e) {
19+
warn('[modify]', `Error in modify callback with value ${v}`, e);
20+
}
21+
22+
return !!v ? String(v) : '';
23+
}
24+
}

plugin/types/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,3 +50,7 @@ export type IPropsInput = {
5050
autofocus: boolean
5151
}
5252

53+
54+
export type StringModify = (v: unknown) => string
55+
56+

plugin/widgets/index.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import InputCheckbox from "./inputs/input-checkbox/widget-input-checkbox.vue";
2+
import InputNumber from "./inputs/input-number/widget-input-number.vue";
3+
import InputPassword from "./inputs/input-password/widget-input-password.vue";
4+
import InputRadio from "./inputs/input-radio/widget-input-radio.vue";
5+
import InputSelect from "./inputs/input-select/widget-input-select.vue";
6+
import InputSingleCheckbox from './inputs/input-single-checkbox/widget-input-single-checkbox.vue';
7+
import InputSingleRadio from "./inputs/input-single-radio/widget-input-single-radio.vue";
8+
import InputSwitch from "./inputs/input-switch/widget-input-switch.vue";
9+
import InputTel from "./inputs/input-tel/widget-input-tel.vue";
10+
import InputText from "./inputs/input-text/widget-input-text.vue";
11+
import InputTextarea from "./inputs/input-textarea/widget-input-textarea.vue";
12+
13+
export default {
14+
InputCheckbox,
15+
InputNumber,
16+
InputPassword,
17+
InputRadio,
18+
InputSelect,
19+
InputSingleCheckbox,
20+
InputSingleRadio,
21+
InputSwitch,
22+
InputTel,
23+
InputText,
24+
InputTextarea
25+
}

plugin/widgets/inputs/input-number/widget-input-number.vue

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,24 @@
66
'container-input-number_error': errors.length !== 0
77
}"
88
>
9-
109
<widget-number-step
1110
@step = "onStep"
1211
/>
1312
<input
1413
ref = "refInput"
1514
class = "input-number"
1615
type = "text"
17-
:value = "modelValue"
16+
:value = "isFocused ? modelValue : executePretty(modelValue)"
1817
@input = "onInput($event.target.value)"
1918
:disabled = "disabled"
2019
:autofocus="autofocus"
2120

2221
@keyup.up = "onStep(true)"
2322
@keyup.down.prevent = "onStep(false)"
23+
@focusin = "isFocused = true"
24+
@focusout = "isFocused = false"
2425
>
26+
<span v-if = "suffix" class = "input-number-suffix">{{suffix}}</span>
2527
</div>
2628
</input-wrap>
2729
</template>
@@ -30,29 +32,36 @@
3032
import InputWrap from "../input-wrap.vue";
3133
import WidgetNumberStep from "./widget-number-step.vue";
3234
import {ref, withDefaults} from "vue";
35+
import {StringModify} from "../../../types";
36+
import useModify from "../../../local-hooks/use-modify";
3337
3438
interface Props{
3539
step?: number,
3640
label?: string,
3741
errors: string[],
3842
modelValue: any,
3943
disabled: boolean,
40-
autofocus: boolean
44+
autofocus: boolean,
45+
name: string,
46+
pretty?: StringModify | StringModify[] | Function,
47+
suffix?: string,
48+
decimal?: boolean
4149
}
4250
const props = withDefaults(defineProps<Props>(), {
4351
step: 1
4452
})
53+
const isFocused = ref(false);
54+
55+
const executePretty = useModify(() => props.pretty);
56+
4557
4658
const emits = defineEmits<{
4759
(e: 'update:modelValue', value: any): void
4860
}>()
4961
const refInput = ref<HTMLInputElement>()
50-
function onInput(v: string | number) {
51-
52-
if (typeof v === "string") {
53-
v = v.replace(/\D/g, '');
54-
}
55-
emits("update:modelValue", Number(v));
62+
function onInput(v: string) {
63+
v = v.replace(/[^0-9.]/g, '');
64+
emits("update:modelValue", Number.parseFloat(v));
5665
if (refInput.value)
5766
refInput.value.value = String(v);
5867
}
@@ -67,7 +76,7 @@ function onStep(v: boolean) {
6776
6877
.container-input-number{
6978
display: grid;
70-
grid-template-columns: 30px 1fr;
79+
grid-template-columns: 30px 1fr min-content;
7180
border: 1px solid var(--vf-input-border-color);
7281
height: var(--vf-input-height);
7382
border-radius: var(--vf-input-border-radius);
@@ -105,4 +114,10 @@ function onStep(v: boolean) {
105114
top: 0;
106115
z-index: 0;
107116
}
117+
.input-number-suffix {
118+
color: var(--vf-input-black-light);
119+
line-height: var(--vf-input-height);
120+
font-size: var(--vf-input-font-size);
121+
padding: 0 5px 0 0;
122+
}
108123
</style>

plugin/widgets/inputs/input-text/widget-input-text.vue

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
ref="refInput"
1313
class="vf-input_clean input-text"
1414
type="text"
15-
:value="isFocused ? modelValue : pretty ? pretty(modelValue) : modelValue"
15+
:value="isFocused ? modelValue : executePretty(modelValue)"
1616
:disabled="disabled"
1717
:autofocus="autofocus"
1818
:placeholder="placeholder"
@@ -27,60 +27,39 @@
2727
<script setup lang="ts">
2828
import InputWrap from "../input-wrap.vue";
2929
import {ref, watch} from "vue";
30-
import warn from "../../../debug/warn";
30+
import useModify from "../../../local-hooks/use-modify";
31+
import {StringModify} from "../../../types";
32+
import onlyNumber from "../../../local-hooks/only-number";
3133
32-
type ModifyFunction = (a: string) => string
33-
34-
const props = withDefaults(defineProps<{
34+
const props = defineProps<{
3535
label?: string,
3636
errors: string[],
3737
modelValue: any,
3838
disabled: boolean,
3939
autofocus: boolean,
40-
pretty?: (a: string) => string,
41-
modify?: ModifyFunction | ModifyFunction[]
40+
pretty?: StringModify | StringModify[] | Function,
41+
modify?: StringModify | StringModify[]| Function
4242
placeholder?: string,
4343
maxLength?: string | number,
4444
maxlength?: string | number,
4545
prefix?: string,
4646
name?: string
47-
numeric?: boolean
48-
}>(), {
49-
pretty: (a: string) => a,
50-
})
47+
numeric?: boolean,
48+
}>()
5149
5250
const isFocused = ref(false);
5351
const refInput = ref<HTMLInputElement>(props.modelValue);
5452
const emit = defineEmits<{
5553
(e: 'update:modelValue', value: any): void
5654
}>()
5755
58-
function onlyNumber(a: string) {
59-
return a.replace(/[^\d,.+-]/,'')
60-
}
61-
62-
/**
63-
* @description Function for wrapping all modify callbacks.
64-
* */
65-
function executeModify(v: string): string {
66-
const arrayModifyCallback: ModifyFunction[] = [];
67-
68-
arrayModifyCallback.push(
69-
...(!props.modify ? [] : Array.isArray(props.modify) ? props.modify : [props.modify])
70-
);
71-
72-
if (props.numeric) arrayModifyCallback.unshift(onlyNumber)
73-
74-
try {
75-
arrayModifyCallback.forEach(modify => {
76-
v = modify(v)
77-
})
78-
} catch (e) {
79-
warn(`input-text${props.name ? ` (${props.name})` : ''}`, `Modify handler throw the error`, e)
80-
}
81-
82-
return v;
83-
}
56+
const executePretty = useModify(() => props.pretty);
57+
const executeModify = useModify(
58+
() => [
59+
props.numeric ? onlyNumber : undefined,
60+
...(Array.isArray(props.modify) ? props.modify : [props.modify])
61+
]
62+
)
8463
8564
function onInput(v: string) {
8665
if (
@@ -115,7 +94,7 @@ watch(() => props.maxLength, () => onInput(props.modelValue));
11594
border: var(--vf-input-border-error);
11695
}
11796
.input-text-prefix {
118-
color: #646363;
97+
color: var(--vf-input-black-light);
11998
line-height: var(--vf-input-height);
12099
font-size: var(--vf-input-font-size);
121100
padding: 0 0 0 4px;

src/pages/test/App.vue

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,24 @@
11
<template>
22
<div class="container-examples">
33

4-
<input-field type = "text" name = "sun" required label = "Username" disabled/>
54

6-
<input-field type = "text" name = "sun" required label = "Username"/>
7-
8-
<input-field type = "text" name = "sun" label = "Username"/>
9-
10-
<input-field type = "text" name = "sun" label = "Username" prefix = "MMM" :pretty = "splitPoint"/>
11-
<input-field type = "text" name = "sun" label = "numeric" prefix = "MMM" :modify = "[]" numeric />
5+
<input-field type = "text" name = "sun" label = "Username" prefix = "MMM" :modify = "splitPoint"/>
126

137
<widget-child/>
148
</div>
159
</template>
1610

1711
<script setup lang='ts'>
1812
import InputField from "../../../plugin/widgets/input-field.vue";
19-
import {Form, useInputState} from "../../../plugin";
13+
import {config, Form, useInputState} from "../../../plugin";
2014
import {onMounted, ref} from "vue";
2115
import WidgetChild from "@/pages/test/widget-child.vue";
2216
2317
const form = new Form();
2418
25-
19+
config({
20+
debug: false
21+
})
2622
onMounted(() => setTimeout(() => form.validate(), 1000))
2723
2824

0 commit comments

Comments
 (0)