Skip to content

Commit 3ffcf39

Browse files
committed
feat: expose useCustomControl
1 parent 4bf7f24 commit 3ffcf39

File tree

3 files changed

+72
-95
lines changed

3 files changed

+72
-95
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './useCustomField';
2+
export * from './useCustomControl';
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { shallowRef, toValue } from 'vue';
2+
import { FieldTypePrefixes } from '../constants';
3+
import { ControlProps, Reactivify } from '../types';
4+
import { exposeField, resolveControlField } from '../useFormField';
5+
import { normalizeProps, propsToValues, useUniqId, useCaptureProps } from '../utils/common';
6+
import { useInputValidity } from '../validation';
7+
8+
export interface CustomControlProps<TValue = unknown> extends ControlProps<TValue> {
9+
/**
10+
* Whether the field is readonly.
11+
*/
12+
readonly?: boolean;
13+
}
14+
15+
export function useCustomControl<TValue = unknown>(
16+
_props: Reactivify<CustomControlProps<TValue>, 'schema' | '_field'>,
17+
) {
18+
const props = normalizeProps(_props, ['schema', '_field']);
19+
const controlId = useUniqId(FieldTypePrefixes.CustomField);
20+
const controlEl = shallowRef<HTMLInputElement>();
21+
const field = resolveControlField<TValue>(props);
22+
const { labelledByProps, accessibleErrorProps, describedByProps, isDisabled } = field;
23+
const { updateValidity } = useInputValidity({ field });
24+
25+
field.registerControl({
26+
getControlElement: () => controlEl.value,
27+
getControlId: () => controlId,
28+
});
29+
30+
const controlProps = useCaptureProps(() => {
31+
return {
32+
...propsToValues(props, ['name', 'readonly']),
33+
...labelledByProps.value,
34+
...describedByProps.value,
35+
...accessibleErrorProps.value,
36+
'aria-readonly': toValue(props.readonly) ? ('true' as const) : undefined,
37+
'aria-disabled': isDisabled.value ? ('true' as const) : undefined,
38+
id: controlId,
39+
};
40+
}, controlEl);
41+
42+
return exposeField(
43+
{
44+
/**
45+
* The id of the control element.
46+
*/
47+
controlId,
48+
49+
/**
50+
* Props for the control element/group.
51+
*/
52+
controlProps,
53+
/**
54+
* Validates the field.
55+
*/
56+
validate: updateValidity,
57+
},
58+
field,
59+
);
60+
}
Lines changed: 11 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,22 @@
1-
import { shallowRef, toValue } from 'vue';
2-
import { FieldTypePrefixes } from '../constants';
3-
import { Reactivify, StandardSchema } from '../types';
4-
import { exposeField, useFormField } from '../useFormField';
5-
import { normalizeProps, propsToValues, useUniqId, useCaptureProps } from '../utils/common';
6-
import { useInputValidity } from '../validation';
1+
import { Reactivify } from '../types';
2+
import { resolveFieldInit, useFormField, WithFieldProps } from '../useFormField';
3+
import { normalizeProps } from '../utils/common';
74
import { registerField } from '@formwerk/devtools';
5+
import { CustomControlProps, useCustomControl } from './useCustomControl';
86

9-
export interface CustomFieldProps<TValue = unknown> {
10-
/**
11-
* The label of the field.
12-
*/
13-
label: string;
14-
15-
/**
16-
* The v-model value of the field.
17-
*/
18-
modelValue?: TValue | undefined;
19-
20-
/**
21-
* Description text that provides additional context about the field.
22-
*/
23-
description?: string;
24-
25-
/**
26-
* The name attribute of the input element.
27-
*/
28-
name?: string;
29-
30-
/**
31-
* The initial static value of the field.
32-
*/
33-
value?: TValue | undefined;
34-
35-
/**
36-
* Whether the field is readonly.
37-
*/
38-
readonly?: boolean;
39-
40-
/**
41-
* Whether the field is disabled.
42-
*/
43-
disabled?: boolean;
44-
45-
/**
46-
* Schema for field validation.
47-
*/
48-
schema?: StandardSchema<TValue>;
49-
}
7+
export type CustomFieldProps<TValue = unknown> = WithFieldProps<CustomControlProps<TValue>>;
508

519
export function useCustomField<TValue = unknown>(_props: Reactivify<CustomFieldProps<TValue>, 'schema'>) {
5210
const props = normalizeProps(_props, ['schema']);
53-
const controlId = useUniqId(FieldTypePrefixes.CustomField);
54-
const controlEl = shallowRef<HTMLInputElement>();
55-
const field = useFormField<TValue | undefined>({
56-
label: props.label,
57-
description: props.description,
58-
path: props.name,
59-
initialValue: (toValue(props.modelValue) ?? toValue(props.value)) as TValue | undefined,
60-
disabled: props.disabled,
61-
schema: props.schema,
62-
});
63-
64-
const { labelledByProps, accessibleErrorProps, describedByProps, isDisabled } = field;
65-
const { updateValidity } = useInputValidity({ field });
66-
67-
field.registerControl({
68-
getControlElement: () => controlEl.value,
69-
getControlId: () => controlId,
70-
});
71-
72-
const controlProps = useCaptureProps(() => {
73-
return {
74-
...propsToValues(props, ['name', 'readonly']),
75-
...labelledByProps.value,
76-
...describedByProps.value,
77-
...accessibleErrorProps.value,
78-
'aria-readonly': toValue(props.readonly) ? ('true' as const) : undefined,
79-
'aria-disabled': isDisabled.value ? ('true' as const) : undefined,
80-
id: controlId,
81-
};
82-
}, controlEl);
11+
const field = useFormField(resolveFieldInit<TValue>(props));
12+
const control = useCustomControl<TValue>({
13+
...props,
14+
_field: field,
15+
} as any);
8316

8417
if (__DEV__) {
8518
registerField(field, 'Custom');
8619
}
8720

88-
return exposeField(
89-
{
90-
/**
91-
* The id of the control element.
92-
*/
93-
controlId,
94-
95-
/**
96-
* Props for the control element/group.
97-
*/
98-
controlProps,
99-
/**
100-
* Validates the field.
101-
*/
102-
validate: updateValidity,
103-
},
104-
field,
105-
);
21+
return control;
10622
}

0 commit comments

Comments
 (0)