@prefecthq/prefab-ui-playground 0.19.0 → 0.19.1
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/playground.html +58 -9
package/package.json
CHANGED
package/playground.html
CHANGED
|
@@ -15283,6 +15283,7 @@ class Form(ContainerComponent):
|
|
|
15283
15283
|
fields_only: Literal[True],
|
|
15284
15284
|
submit_label: str = "Submit",
|
|
15285
15285
|
on_submit: Action | list[Action] | None = None,
|
|
15286
|
+
defaults: dict[str, Any] | None = None,
|
|
15286
15287
|
css_class: str | None = None,
|
|
15287
15288
|
) -> list[Any]: ...
|
|
15288
15289
|
|
|
@@ -15295,6 +15296,7 @@ class Form(ContainerComponent):
|
|
|
15295
15296
|
fields_only: Literal[False] = ...,
|
|
15296
15297
|
submit_label: str = "Submit",
|
|
15297
15298
|
on_submit: Action | list[Action] | None = None,
|
|
15299
|
+
defaults: dict[str, Any] | None = None,
|
|
15298
15300
|
css_class: str | None = None,
|
|
15299
15301
|
) -> Form: ...
|
|
15300
15302
|
|
|
@@ -15306,6 +15308,7 @@ class Form(ContainerComponent):
|
|
|
15306
15308
|
fields_only: bool = False,
|
|
15307
15309
|
submit_label: str = "Submit",
|
|
15308
15310
|
on_submit: Action | list[Action] | None = None,
|
|
15311
|
+
defaults: dict[str, Any] | None = None,
|
|
15309
15312
|
css_class: str | None = None,
|
|
15310
15313
|
) -> Form | list[Any]:
|
|
15311
15314
|
"""Generate a form from a Pydantic model.
|
|
@@ -15364,11 +15367,23 @@ class Form(ContainerComponent):
|
|
|
15364
15367
|
submit_label: Text for the submit button.
|
|
15365
15368
|
on_submit: Action(s) fired on submit. A \`CallTool\` with no
|
|
15366
15369
|
arguments gets auto-filled from model fields.
|
|
15370
|
+
defaults: Runtime values keyed by field name. These override the
|
|
15371
|
+
model's class-level \`Field(default=...)\` for this render only,
|
|
15372
|
+
letting callers (e.g. LLM agents) pre-populate the form with
|
|
15373
|
+
context-specific values. Unknown keys raise \`ValueError\`.
|
|
15367
15374
|
css_class: Additional CSS classes on the form container.
|
|
15368
15375
|
"""
|
|
15369
15376
|
from prefab_ui.components.base import _component_stack
|
|
15370
15377
|
from prefab_ui.components.button import Button
|
|
15371
15378
|
|
|
15379
|
+
if defaults:
|
|
15380
|
+
unknown = set(defaults) - set(model.model_fields)
|
|
15381
|
+
if unknown:
|
|
15382
|
+
raise ValueError(
|
|
15383
|
+
f"defaults contains unknown field(s) for "
|
|
15384
|
+
f"{model.__name__}: {sorted(unknown)}"
|
|
15385
|
+
)
|
|
15386
|
+
|
|
15372
15387
|
if fields_only:
|
|
15373
15388
|
# Suppress auto-parenting during creation to avoid duplicates
|
|
15374
15389
|
# (Labels/Inputs would otherwise auto-parent to both the
|
|
@@ -15378,7 +15393,7 @@ class Form(ContainerComponent):
|
|
|
15378
15393
|
with defer():
|
|
15379
15394
|
children: list[Any] = []
|
|
15380
15395
|
for name, field_info in model.model_fields.items():
|
|
15381
|
-
component = _field_to_component(name, field_info)
|
|
15396
|
+
component = _field_to_component(name, field_info, defaults)
|
|
15382
15397
|
if component is not None:
|
|
15383
15398
|
children.append(component)
|
|
15384
15399
|
|
|
@@ -15400,7 +15415,7 @@ class Form(ContainerComponent):
|
|
|
15400
15415
|
children = []
|
|
15401
15416
|
|
|
15402
15417
|
for name, field_info in model.model_fields.items():
|
|
15403
|
-
component = _field_to_component(name, field_info)
|
|
15418
|
+
component = _field_to_component(name, field_info, defaults)
|
|
15404
15419
|
if component is not None:
|
|
15405
15420
|
children.append(component)
|
|
15406
15421
|
|
|
@@ -15446,6 +15461,25 @@ def _maybe_enrich_tool_call(
|
|
|
15446
15461
|
return CallTool(**kwargs)
|
|
15447
15462
|
|
|
15448
15463
|
|
|
15464
|
+
def _format_date_default(value: Any, kind: type) -> str | None:
|
|
15465
|
+
"""Serialize a date/time/datetime default to the HTML input format."""
|
|
15466
|
+
if value is None:
|
|
15467
|
+
return None
|
|
15468
|
+
if isinstance(value, str):
|
|
15469
|
+
return value
|
|
15470
|
+
if kind is datetime.datetime and isinstance(value, datetime.datetime):
|
|
15471
|
+
return value.strftime("%Y-%m-%dT%H:%M")
|
|
15472
|
+
if (
|
|
15473
|
+
kind is datetime.date
|
|
15474
|
+
and isinstance(value, datetime.date)
|
|
15475
|
+
and not isinstance(value, datetime.datetime)
|
|
15476
|
+
):
|
|
15477
|
+
return value.isoformat()
|
|
15478
|
+
if kind is datetime.time and isinstance(value, datetime.time):
|
|
15479
|
+
return value.isoformat(timespec="minutes")
|
|
15480
|
+
return None
|
|
15481
|
+
|
|
15482
|
+
|
|
15449
15483
|
def _humanize(name: str) -> str:
|
|
15450
15484
|
"""Convert snake_case field name to Title Case label."""
|
|
15451
15485
|
return name.replace("_", " ").title()
|
|
@@ -15498,7 +15532,11 @@ def _get_ui_hints(field_info: FieldInfo) -> dict[str, Any]:
|
|
|
15498
15532
|
return {}
|
|
15499
15533
|
|
|
15500
15534
|
|
|
15501
|
-
def _field_to_component(
|
|
15535
|
+
def _field_to_component(
|
|
15536
|
+
name: str,
|
|
15537
|
+
field_info: FieldInfo,
|
|
15538
|
+
defaults: dict[str, Any] | None = None,
|
|
15539
|
+
) -> Any:
|
|
15502
15540
|
"""Map a single Pydantic field to the appropriate form component(s)."""
|
|
15503
15541
|
from prefab_ui.components.checkbox import Checkbox
|
|
15504
15542
|
from prefab_ui.components.column import Column
|
|
@@ -15519,9 +15557,12 @@ def _field_to_component(name: str, field_info: FieldInfo) -> Any:
|
|
|
15519
15557
|
|
|
15520
15558
|
label_text = field_info.title or _humanize(name)
|
|
15521
15559
|
placeholder = field_info.description or label_text
|
|
15522
|
-
|
|
15523
|
-
|
|
15524
|
-
|
|
15560
|
+
if defaults is not None and name in defaults:
|
|
15561
|
+
default = defaults[name]
|
|
15562
|
+
elif field_info.default is not PydanticUndefined:
|
|
15563
|
+
default = field_info.default
|
|
15564
|
+
else:
|
|
15565
|
+
default = None
|
|
15525
15566
|
constraints = _extract_constraints(field_info)
|
|
15526
15567
|
ui_hints = _get_ui_hints(field_info)
|
|
15527
15568
|
|
|
@@ -15584,26 +15625,34 @@ def _field_to_component(name: str, field_info: FieldInfo) -> Any:
|
|
|
15584
15625
|
|
|
15585
15626
|
# date/time types → specialized input
|
|
15586
15627
|
if inner is datetime.date:
|
|
15628
|
+
value = _format_date_default(default, datetime.date)
|
|
15587
15629
|
col = Column(gap=2)
|
|
15588
15630
|
col.children = [
|
|
15589
15631
|
Label(label_text, optional=not required),
|
|
15590
|
-
Input(input_type="date", name=name, required=required),
|
|
15632
|
+
Input(input_type="date", name=name, value=value, required=required),
|
|
15591
15633
|
]
|
|
15592
15634
|
return col
|
|
15593
15635
|
|
|
15594
15636
|
if inner is datetime.time:
|
|
15637
|
+
value = _format_date_default(default, datetime.time)
|
|
15595
15638
|
col = Column(gap=2)
|
|
15596
15639
|
col.children = [
|
|
15597
15640
|
Label(label_text, optional=not required),
|
|
15598
|
-
Input(input_type="time", name=name, required=required),
|
|
15641
|
+
Input(input_type="time", name=name, value=value, required=required),
|
|
15599
15642
|
]
|
|
15600
15643
|
return col
|
|
15601
15644
|
|
|
15602
15645
|
if inner is datetime.datetime:
|
|
15646
|
+
value = _format_date_default(default, datetime.datetime)
|
|
15603
15647
|
col = Column(gap=2)
|
|
15604
15648
|
col.children = [
|
|
15605
15649
|
Label(label_text, optional=not required),
|
|
15606
|
-
Input(
|
|
15650
|
+
Input(
|
|
15651
|
+
input_type="datetime-local",
|
|
15652
|
+
name=name,
|
|
15653
|
+
value=value,
|
|
15654
|
+
required=required,
|
|
15655
|
+
),
|
|
15607
15656
|
]
|
|
15608
15657
|
return col
|
|
15609
15658
|
|