Skip to content

Commit 1372ab6

Browse files
authored
feat: add the form_action property to manually trigger form actions (#98)
1 parent 9b9e705 commit 1372ab6

8 files changed

Lines changed: 174 additions & 9 deletions

File tree

.changeset/shiny-cats-crash.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@modelscope-studio/antd': minor
3+
'modelscope_studio': minor
4+
---
5+
6+
feat: add the `form_action` property to manually trigger form actions

backend/modelscope_studio/components/antd/form/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ def __init__(
4545
value: dict | None = None,
4646
props: dict | None = None,
4747
*,
48+
form_action: Literal['reset', 'submit', 'validate'] | None = None,
4849
colon: bool = True,
4950
disabled: bool | None = None,
5051
component: str | False | None = None,
@@ -84,6 +85,7 @@ def __init__(
8485
elem_style=elem_style,
8586
**kwargs)
8687
self.props = props
88+
self.form_action = form_action
8789
self.colon = colon
8890
self.disabled = disabled
8991
self.component = component

docs/components/antd/form/README-zh_CN.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,9 @@ High-performance form component with data domain management. Includes data entry
55
## Examples
66

77
<demo name="basic"></demo>
8-
<demo name="form_rules" title="Form Rules"></demo>
8+
<demo name="form_rules" title="表单规则"></demo>
9+
<demo name="dynamic_form" title="动态表单"></demo>
10+
11+
通过修改`form_action`可以手动触发表单动作,每当`form_action`变化并触发对应表单动作时,都会自动重置`form_action`的值,以便后续多次调用。
12+
13+
<demo name="form_action" title="表单动作"></demo>

docs/components/antd/form/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ High-performance form component with data domain management. Includes data entry
66

77
<demo name="basic"></demo>
88
<demo name="form_rules" title="Form Rules"></demo>
9+
<demo name="dynamic_form" title="Dynamic Form"></demo>
10+
11+
By modifying `form_action`, you can manually trigger a form action. Whenever `form_action` changes and triggers the corresponding form action, the value of `form_action` will be automatically reset for subsequent multiple calls.
12+
13+
<demo name="form_action" title="Form Action"></demo>
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import gradio as gr
2+
import modelscope_studio.components.antd as antd
3+
import modelscope_studio.components.base as ms
4+
5+
6+
def submit(form_value):
7+
print(form_value)
8+
9+
10+
def add(state_value):
11+
count = len(state_value)
12+
return state_value + [{
13+
"form_name": str(count),
14+
"label": "Label " + str(count)
15+
}]
16+
17+
18+
with gr.Blocks() as demo, ms.Application(), antd.ConfigProvider():
19+
state = gr.State([{"form_name": "0", "label": "Label 0"}])
20+
with antd.Form() as form:
21+
with antd.Form.Item():
22+
add_btn = antd.Button("Add List")
23+
24+
@gr.render(inputs=[state])
25+
def render_inputs(state_data):
26+
for item in state_data:
27+
with antd.Form.Item(form_name=item["form_name"],
28+
label=item["label"]):
29+
antd.Input()
30+
31+
with antd.Form.Item():
32+
antd.Button("Submit", type="primary", html_type="submit")
33+
add_btn.click(fn=add, inputs=[state], outputs=[state])
34+
form.finish(fn=submit, inputs=[form])
35+
36+
if __name__ == "__main__":
37+
demo.queue().launch()
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import gradio as gr
2+
import modelscope_studio.components.antd as antd
3+
import modelscope_studio.components.base as ms
4+
5+
6+
def on_submit(_form):
7+
print(_form) # the Form Component will automatically collect the form data
8+
9+
10+
def bind_action_event(action):
11+
12+
def on_action():
13+
return gr.update(form_action=action)
14+
15+
return on_action
16+
17+
18+
with gr.Blocks() as demo:
19+
with ms.Application():
20+
with antd.ConfigProvider():
21+
with antd.Card(title="Out of the Form"):
22+
submit_btn = antd.Button("Submit", type="primary")
23+
reset_btn = antd.Button("Reset")
24+
validate_btn = antd.Button("Validate")
25+
26+
with antd.Form(label_col=dict(span=8),
27+
wrapper_col=dict(span=16)) as form:
28+
with antd.Form.Item(
29+
form_name="username",
30+
label="Username",
31+
rules=[{
32+
"required": True,
33+
"message": 'Please input your username!'
34+
}, {
35+
"pattern":
36+
"^[a-zA-Z0-9]+$",
37+
"message":
38+
"Username can only contain letters and numbers!"
39+
}, {
40+
"min":
41+
6,
42+
"message":
43+
"Username must be at least 6 characters long!"
44+
}, {
45+
"max":
46+
20,
47+
"message":
48+
"Username must be at most 20 characters long!"
49+
}]):
50+
antd.Input()
51+
with antd.Form.Item(
52+
form_name="password",
53+
label="Password",
54+
rules=[
55+
{
56+
"required": True,
57+
"message": 'Please input your password!'
58+
},
59+
{
60+
# custom validator with javascript function
61+
"validator":
62+
"""(rule, value, cb) => {
63+
if (value !== '123') {
64+
cb('Password must be "123"')
65+
}
66+
cb()
67+
}"""
68+
}
69+
]):
70+
antd.Input.Password()
71+
72+
with antd.Form.Item(wrapper_col=dict(offset=8, span=16)):
73+
antd.Button("Submit", type="primary", html_type="submit")
74+
form.finish(on_submit, inputs=[form])
75+
submit_btn.click(bind_action_event("submit"), outputs=[form])
76+
reset_btn.click(bind_action_event("reset"), outputs=[form])
77+
validate_btn.click(bind_action_event("validate"), outputs=[form])
78+
79+
if __name__ == "__main__":
80+
demo.queue().launch()

frontend/antd/form/Index.svelte

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,12 @@
1515
import cls from 'classnames';
1616
import { writable } from 'svelte/store';
1717
18+
import type { FormProps } from './form';
19+
1820
const AwaitedForm = importComponent(() => import('./form'));
1921
export let gradio: Gradio;
2022
export let value: Record<string, any>;
23+
export let form_action: FormProps['formAction'] | null = null;
2124
export let props: Record<string, any> = {};
2225
const updatedProps = writable(props);
2326
$: updatedProps.update((prev) => ({ ...prev, ...props }));
@@ -43,6 +46,7 @@
4346
elem_style,
4447
as_item,
4548
value,
49+
form_action,
4650
restProps: $$restProps,
4751
},
4852
{
@@ -61,6 +65,7 @@
6165
elem_style,
6266
as_item,
6367
value,
68+
form_action,
6469
restProps: $$restProps,
6570
});
6671
</script>
@@ -79,10 +84,14 @@
7984
values_change: 'valuesChange',
8085
})}
8186
slots={$slots}
87+
formAction={$mergedProps.form_action}
8288
value={$mergedProps.value}
8389
onValueChange={(v) => {
8490
value = v;
8591
}}
92+
onResetFormAction={() => {
93+
form_action = null;
94+
}}
8695
{setSlotParams}
8796
>
8897
<slot />

frontend/antd/form/form.tsx

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,51 @@ import { sveltify } from '@svelte-preprocess-react';
22
import type { SetSlotParams } from '@svelte-preprocess-react/slot';
33
import { useEffect } from 'react';
44
import { useFunction } from '@utils/hooks/useFunction';
5+
import { useMemoizedFn } from '@utils/hooks/useMemoizedFn';
56
import { renderParamsSlot } from '@utils/renderParamsSlot';
67
import { Form as AForm, type GetProps } from 'antd';
78

8-
export const Form = sveltify<
9-
GetProps<typeof AForm> & {
10-
value: Record<string, any>;
11-
onValueChange: (value: Record<string, any>) => void;
12-
setSlotParams: SetSlotParams;
13-
},
14-
['requiredMark']
15-
>(
9+
export interface FormProps extends GetProps<typeof AForm> {
10+
value: Record<string, any>;
11+
onValueChange: (value: Record<string, any>) => void;
12+
setSlotParams: SetSlotParams;
13+
formAction?: 'reset' | 'submit' | 'validate' | null;
14+
onResetFormAction: () => void;
15+
}
16+
17+
export const Form = sveltify<FormProps, ['requiredMark']>(
1618
({
1719
value,
20+
formAction,
1821
onValueChange,
1922
requiredMark,
2023
onValuesChange,
2124
feedbackIcons,
2225
setSlotParams,
2326
slots,
27+
onResetFormAction,
2428
...props
2529
}) => {
2630
const [form] = AForm.useForm();
2731
const feedbackIconsFunction = useFunction(feedbackIcons);
2832
const requiredMarkFunction = useFunction(requiredMark);
33+
const onResetFormActionMemoized = useMemoizedFn(onResetFormAction);
34+
35+
useEffect(() => {
36+
switch (formAction) {
37+
case 'reset':
38+
form.resetFields();
39+
break;
40+
case 'submit':
41+
form.submit();
42+
break;
43+
case 'validate':
44+
form.validateFields();
45+
break;
46+
}
47+
onResetFormActionMemoized();
48+
}, [form, formAction, onResetFormActionMemoized]);
49+
2950
useEffect(() => {
3051
if (value) {
3152
form.setFieldsValue(value);

0 commit comments

Comments
 (0)