Skip to content

Commit 83107f6

Browse files
committed
feat(TextInput): component is generic and accepts/returns a number if type is "number", string otherwise
1 parent e634f80 commit 83107f6

File tree

3 files changed

+42
-34
lines changed

3 files changed

+42
-34
lines changed

apps/docs/src/stories/Components/TextInput.story.vue

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010
<pf-text-input v-model="text1" aria-label="text input example" />
1111
</story-canvas>
1212

13+
<story-canvas title="Numeric">
14+
<pf-text-input v-model="number1" type="number" aria-label="text input example" />
15+
</story-canvas>
16+
1317
<story-canvas title="Disabled">
1418
<pf-text-input
1519
disabled
@@ -106,4 +110,5 @@ import ClockIcon from '@vue-patternfly/icons/clock-icon';
106110
107111
const text1: Ref<string | null> = ref(null);
108112
const text2 = ref('');
113+
const number1 = ref(0);
109114
</script>

packages/core/src/components/TextInput.vue

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
v-bind="$attrs"
1919
ref="inputRef"
2020
:value="value"
21-
:type="type"
21+
:type="type ?? 'text'"
2222
:aria-invalid="effectiveValidated === 'error'"
2323
:disabled="disabled || undefined"
2424
:readonly="!!readOnlyVariant || readonly"
@@ -37,21 +37,10 @@
3737
</span>
3838
</template>
3939

40-
<script lang="ts" setup>
41-
import { computed, toRefs, type InputHTMLAttributes, getCurrentInstance, useTemplateRef } from 'vue';
42-
import { useChildrenTracker } from '../use';
43-
import styles from '@patternfly/react-styles/css/components/FormControl/form-control';
44-
import { useInputValidation, type InputValidateState } from '../input';
45-
import { FormGroupInputsKey, FormInputsKey } from './Form/common';
46-
import { useOUIAProps, type OUIAProps } from '../helpers/ouia';
47-
import PfFormControlIcon from './FormControlIcon.vue';
40+
<script lang="ts">
41+
export type InputType = 'text' | 'date' | 'datetime-local' | 'email' | 'month' | 'number' | 'password' | 'search' | 'tel' | 'time' | 'url' | 'week';
4842
49-
defineOptions({
50-
name: 'PfTextInput',
51-
inheritAttrs: false,
52-
});
53-
54-
export interface Props extends OUIAProps, /* @vue-ignore */ Omit<InputHTMLAttributes, 'value' | 'type' | 'aria-invalid'> {
43+
export interface Props<T extends InputType = 'text'> extends OUIAProps, /* @vue-ignore */ Omit<InputHTMLAttributes, 'value' | 'type' | 'aria-invalid'> {
5544
/** Flag to show if the text input is disabled. */
5645
disabled?: boolean;
5746
/** Flag to apply expanded styling */
@@ -65,19 +54,7 @@ export interface Props extends OUIAProps, /* @vue-ignore */ Omit<InputHTMLAttrib
6554
*/
6655
validated?: InputValidateState;
6756
/** Type that the text input accepts. */
68-
type?:
69-
| 'text'
70-
| 'date'
71-
| 'datetime-local'
72-
| 'email'
73-
| 'month'
74-
| 'number'
75-
| 'password'
76-
| 'search'
77-
| 'tel'
78-
| 'time'
79-
| 'url'
80-
| 'week';
57+
type?: T;
8158
/** Value of the text input. */
8259
modelValue?: string | number | null;
8360
/** Aria-label. The text input requires an associated id or aria-label. */
@@ -88,9 +65,23 @@ export interface Props extends OUIAProps, /* @vue-ignore */ Omit<InputHTMLAttrib
8865
/** Disables validation status icon */
8966
noStatusIcon?: boolean;
9067
}
68+
</script>
69+
70+
<script lang="ts" setup generic="T extends InputType = 'text'">
71+
import { computed, toRefs, type InputHTMLAttributes, getCurrentInstance, useTemplateRef } from 'vue';
72+
import { useChildrenTracker } from '../use';
73+
import styles from '@patternfly/react-styles/css/components/FormControl/form-control';
74+
import { useInputValidation, type InputValidateState } from '../input';
75+
import { FormGroupInputsKey, FormInputsKey } from './Form/common';
76+
import { useOUIAProps, type OUIAProps } from '../helpers/ouia';
77+
import PfFormControlIcon from './FormControlIcon.vue';
9178
92-
const props = withDefaults(defineProps<Props>(), {
93-
type: 'text',
79+
defineOptions({
80+
name: 'PfTextInput',
81+
inheritAttrs: false,
82+
});
83+
84+
const props = withDefaults(defineProps<Props<T>>(), {
9485
autoValidate: true,
9586
modelValue: undefined,
9687
});
@@ -103,7 +94,7 @@ defineEmits<{
10394
(name: 'input', event: Event): void;
10495
(name: 'invalid', event: Event): void;
10596
(name: 'keyup', event: KeyboardEvent): void;
106-
(name: 'update:modelValue', value: string): void;
97+
(name: 'update:modelValue', value: T extends 'number' ? number : string): void;
10798
(name: 'update:validated', value: InputValidateState): void;
10899
}>();
109100
@@ -122,7 +113,7 @@ const {
122113
effectiveValidated,
123114
onBlur,
124115
onChange,
125-
onInput,
116+
onInput: commonOnInput,
126117
onInvalid,
127118
onKeyUp,
128119
...inputValidationData
@@ -139,6 +130,18 @@ function focus() {
139130
input.value?.focus();
140131
}
141132
133+
function onInput(event: InputEvent) {
134+
if (!input.value) {
135+
return;
136+
}
137+
const value = input.value.value;
138+
if (props.type === 'number') {
139+
commonOnInput(event, value ? parseFloat(value) : null);
140+
} else {
141+
commonOnInput(event, value);
142+
}
143+
}
144+
142145
defineExpose({
143146
...inputValidationData,
144147
input,

packages/core/src/input.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,9 @@ export function useInputValidation({
9696
reportValidity,
9797
setCustomValidity,
9898

99-
onInput(event: InputEvent) {
99+
onInput(event: InputEvent, value?: any) {
100100
instance?.$emit('input', event);
101-
value.value = (event.target as InputElement).value;
101+
value.value = value ?? (event.target as InputElement).value;
102102
if (autoValidate === 'input') {
103103
reportValidity();
104104
} else {

0 commit comments

Comments
 (0)