statezero 0.1.0b61__tar.gz → 0.1.0b62__tar.gz

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.
Files changed (63) hide show
  1. {statezero-0.1.0b61 → statezero-0.1.0b62}/PKG-INFO +1 -1
  2. {statezero-0.1.0b61 → statezero-0.1.0b62}/pyproject.toml +1 -1
  3. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/classes.py +216 -3
  4. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero.egg-info/PKG-INFO +1 -1
  5. {statezero-0.1.0b61 → statezero-0.1.0b62}/README.md +0 -0
  6. {statezero-0.1.0b61 → statezero-0.1.0b62}/requirements.txt +0 -0
  7. {statezero-0.1.0b61 → statezero-0.1.0b62}/setup.cfg +0 -0
  8. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/__init__.py +0 -0
  9. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/__init__.py +0 -0
  10. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/__init__.py +0 -0
  11. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/action_serializers.py +0 -0
  12. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/actions.py +0 -0
  13. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/apps.py +0 -0
  14. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/config.py +0 -0
  15. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/context_manager.py +0 -0
  16. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/db_telemetry.py +0 -0
  17. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/event_emitters.py +0 -0
  18. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/exception_handler.py +0 -0
  19. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/extensions/__init__.py +0 -0
  20. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/extensions/custom_field_serializers/__init__.py +0 -0
  21. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/extensions/custom_field_serializers/file_fields.py +0 -0
  22. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/extensions/custom_field_serializers/money_field.py +0 -0
  23. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/extensions/custom_field_serializers/pydantic_field.py +0 -0
  24. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/extensions/simple_history.py +0 -0
  25. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/f_handler.py +0 -0
  26. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/helpers.py +0 -0
  27. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/management/commands/statezero_testserver.py +0 -0
  28. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/middleware.py +0 -0
  29. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/migrations/0001_initial.py +0 -0
  30. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/migrations/0002_delete_modelviewsubscription.py +0 -0
  31. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/migrations/__init__.py +0 -0
  32. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/orm.py +0 -0
  33. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/permissions.py +0 -0
  34. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/query_optimizer.py +0 -0
  35. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/schemas.py +0 -0
  36. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/search_providers/__init__.py +0 -0
  37. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/search_providers/basic_search.py +0 -0
  38. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/search_providers/postgres_search.py +0 -0
  39. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/serializers.py +0 -0
  40. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/signals.py +0 -0
  41. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/testing.py +0 -0
  42. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/urls.py +0 -0
  43. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/utils.py +0 -0
  44. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/adaptors/django/views.py +0 -0
  45. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/__init__.py +0 -0
  46. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/actions.py +0 -0
  47. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/ast_parser.py +0 -0
  48. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/ast_validator.py +0 -0
  49. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/config.py +0 -0
  50. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/context_storage.py +0 -0
  51. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/event_bus.py +0 -0
  52. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/event_emitters.py +0 -0
  53. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/exceptions.py +0 -0
  54. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/hook_checks.py +0 -0
  55. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/interfaces.py +0 -0
  56. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/process_request.py +0 -0
  57. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/query_cache.py +0 -0
  58. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/telemetry.py +0 -0
  59. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero/core/types.py +0 -0
  60. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero.egg-info/SOURCES.txt +0 -0
  61. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero.egg-info/dependency_links.txt +0 -0
  62. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero.egg-info/requires.txt +0 -0
  63. {statezero-0.1.0b61 → statezero-0.1.0b62}/statezero.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: statezero
3
- Version: 0.1.0b61
3
+ Version: 0.1.0b62
4
4
  Summary: Connect your Python backend to a modern JavaScript SPA frontend with 90% less complexity.
5
5
  Author-email: Robert <robert.herring@statezero.dev>
6
6
  Project-URL: homepage, https://www.statezero.dev
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "statezero"
7
- version = "0.1.0b61"
7
+ version = "0.1.0b62"
8
8
  description = "Connect your Python backend to a modern JavaScript SPA frontend with 90% less complexity."
9
9
  readme = "README.md"
10
10
  license = { file = "LICENSE" }
@@ -1,10 +1,11 @@
1
- from dataclasses import dataclass, field
1
+ from dataclasses import field
2
2
  from enum import Enum
3
- from typing import Any, Dict, List, Optional, Set, Type, Union
3
+ from typing import Any, Dict, List, Literal, Optional, Set, Type, Union, Annotated
4
4
 
5
5
  import jsonschema
6
6
  from fastapi.encoders import jsonable_encoder
7
- from pydantic import BaseModel, Field
7
+ from pydantic import BaseModel, Field, field_validator
8
+ from pydantic.dataclasses import dataclass
8
9
 
9
10
  from statezero.core.types import ORMField
10
11
 
@@ -205,6 +206,213 @@ class FieldGroup:
205
206
  field_names: Optional[List[str]] = None
206
207
 
207
208
 
209
+ # =============================================================================
210
+ # Layout Elements - JSON Forms inspired layout system
211
+ # =============================================================================
212
+
213
+ class LayoutType(str, Enum):
214
+ """Types of layout elements"""
215
+ VERTICAL = "VerticalLayout"
216
+ HORIZONTAL = "HorizontalLayout"
217
+ GROUP = "Group"
218
+ CONTROL = "Control"
219
+ DISPLAY = "Display"
220
+ ALERT = "Alert"
221
+ LABEL = "Label"
222
+ DIVIDER = "Divider"
223
+
224
+
225
+ @dataclass
226
+ class Control:
227
+ """
228
+ A form control bound to a serializer field.
229
+ Uses same attribute names as FieldDisplayConfig for consistency.
230
+
231
+ Attributes:
232
+ field_name: The serializer field this control is bound to
233
+ display_component: Custom UI component name
234
+ filter_queryset: Filter options for FK/M2M fields
235
+ display_help_text: Additional help text
236
+ extra: Additional custom metadata passed to the component
237
+ label: Override the field's title
238
+ full_width: Whether this control should span full width
239
+ """
240
+ field_name: str
241
+ display_component: Optional[str] = None
242
+ filter_queryset: Optional[Dict[str, Any]] = None
243
+ display_help_text: Optional[str] = None
244
+ extra: Optional[Dict[str, Any]] = None
245
+ label: Optional[str] = None
246
+ full_width: bool = False
247
+ type: Literal["Control"] = field(default="Control", init=False)
248
+
249
+
250
+ @dataclass
251
+ class Display:
252
+ """
253
+ A display-only element that renders data from context.
254
+ Does not collect input - purely for showing information.
255
+
256
+ Attributes:
257
+ context_path: Dot-notation path to value in workflow context (e.g., "unit.access_code")
258
+ display_component: UI component to render with (e.g., "code-display", "copy-url")
259
+ label: Label to show above the display
260
+ extra: Additional custom metadata passed to the component
261
+ """
262
+ context_path: str
263
+ display_component: str = "text"
264
+ label: Optional[str] = None
265
+ extra: Optional[Dict[str, Any]] = None
266
+ type: Literal["Display"] = field(default="Display", init=False)
267
+
268
+
269
+ @dataclass
270
+ class Alert:
271
+ """
272
+ An alert/info banner element.
273
+
274
+ Attributes:
275
+ severity: Alert type - "info", "warning", "error", "success"
276
+ text: Static text to display
277
+ context_path: Or pull text from context
278
+ """
279
+ severity: Literal["info", "warning", "error", "success"] = "info"
280
+ text: Optional[str] = None
281
+ context_path: Optional[str] = None
282
+ type: Literal["Alert"] = field(default="Alert", init=False)
283
+
284
+
285
+ @dataclass
286
+ class Label:
287
+ """
288
+ A static text label element.
289
+
290
+ Attributes:
291
+ text: The text to display
292
+ variant: Text style - "heading", "subheading", "body", "caption"
293
+ """
294
+ text: str
295
+ variant: Literal["heading", "subheading", "body", "caption"] = "body"
296
+ type: Literal["Label"] = field(default="Label", init=False)
297
+
298
+
299
+ @dataclass
300
+ class Divider:
301
+ """A visual separator/divider element."""
302
+ type: Literal["Divider"] = field(default="Divider", init=False)
303
+
304
+
305
+ @dataclass
306
+ class Conditional:
307
+ """
308
+ Conditionally render a layout based on form data or context.
309
+
310
+ The `when` expression is evaluated as JavaScript with access to:
311
+ - formData: Current form field values
312
+ - context: Workflow context data
313
+
314
+ Examples:
315
+ when="formData.payment_method === 'card'"
316
+ when="context.has_wifi === true"
317
+ when="formData.amount > 100"
318
+
319
+ Attributes:
320
+ when: JavaScript expression that returns a boolean
321
+ layout: Layout to render when condition is true
322
+ """
323
+ when: str
324
+ layout: "LayoutElement"
325
+ type: Literal["Conditional"] = field(default="Conditional", init=False)
326
+
327
+
328
+ @dataclass
329
+ class Tab:
330
+ """
331
+ A single tab within a Tabs container.
332
+
333
+ Attributes:
334
+ label: Tab button label
335
+ layout: Content to render when tab is active
336
+ """
337
+ label: str
338
+ layout: "LayoutElement"
339
+
340
+
341
+ @dataclass
342
+ class Tabs:
343
+ """
344
+ A tabbed container for organizing content into switchable panels.
345
+
346
+ Attributes:
347
+ tabs: List of Tab elements
348
+ default_tab: Index of initially active tab (0-based)
349
+ """
350
+ tabs: List[Tab] = field(default_factory=list)
351
+ default_tab: int = 0
352
+ type: Literal["Tabs"] = field(default="Tabs", init=False)
353
+
354
+
355
+ # Layout element union type for type hints
356
+ LayoutElement = Union[
357
+ Control, Display, Alert, Label, Divider, Conditional, Tabs,
358
+ "VerticalLayout", "HorizontalLayout", "Group"
359
+ ]
360
+
361
+
362
+ @dataclass
363
+ class VerticalLayout:
364
+ """
365
+ Stack elements vertically.
366
+
367
+ Attributes:
368
+ elements: Child layout elements
369
+ gap: Spacing between elements - "sm", "md", "lg"
370
+ """
371
+ elements: List["LayoutElement"] = field(default_factory=list)
372
+ gap: Literal["sm", "md", "lg"] = "md"
373
+ type: Literal["VerticalLayout"] = field(default="VerticalLayout", init=False)
374
+
375
+
376
+ @dataclass
377
+ class HorizontalLayout:
378
+ """
379
+ Stack elements horizontally.
380
+
381
+ Attributes:
382
+ elements: Child layout elements
383
+ gap: Spacing between elements - "sm", "md", "lg"
384
+ align: Vertical alignment - "start", "center", "end", "stretch"
385
+ """
386
+ elements: List["LayoutElement"] = field(default_factory=list)
387
+ gap: Literal["sm", "md", "lg"] = "md"
388
+ align: Literal["start", "center", "end", "stretch"] = "start"
389
+ type: Literal["HorizontalLayout"] = field(default="HorizontalLayout", init=False)
390
+
391
+
392
+ @dataclass
393
+ class Group:
394
+ """
395
+ A labeled container/section with nested layout.
396
+
397
+ Attributes:
398
+ label: Section heading
399
+ description: Section description
400
+ layout: Nested layout (defaults to VerticalLayout)
401
+ collapsible: Whether the group can be collapsed
402
+ collapsed: Initial collapsed state
403
+ """
404
+ label: str
405
+ description: Optional[str] = None
406
+ layout: Optional["LayoutElement"] = None
407
+ collapsible: bool = False
408
+ collapsed: bool = False
409
+ type: Literal["Group"] = field(default="Group", init=False)
410
+
411
+
412
+ # Convenience type for the root layout
413
+ Layout = Union[VerticalLayout, HorizontalLayout]
414
+
415
+
208
416
  @dataclass
209
417
  class DisplayMetadata:
210
418
  """
@@ -214,11 +422,16 @@ class DisplayMetadata:
214
422
  display_title: Main heading/title override
215
423
  display_description: Explanatory text about the model/action
216
424
  field_groups: Logical grouping of fields (e.g., "Contact Info", "Address Details")
425
+ - Legacy: use `layout` for more control
217
426
  field_display_configs: Per-field customization (custom components, filters, help text)
427
+ - Legacy: use Control elements in `layout` for more control
428
+ layout: Rich layout tree for complex form/display rendering. Takes precedence over
429
+ field_groups when present. Supports nesting, display-only elements, conditionals, etc.
218
430
  extra: Additional custom metadata for framework-specific or UI-specific extensions
219
431
  """
220
432
  display_title: Optional[str] = None
221
433
  display_description: Optional[str] = None
222
434
  field_groups: Optional[List[FieldGroup]] = None
223
435
  field_display_configs: Optional[List[FieldDisplayConfig]] = None
436
+ layout: Optional[Layout] = None
224
437
  extra: Optional[Dict[str, Any]] = None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: statezero
3
- Version: 0.1.0b61
3
+ Version: 0.1.0b62
4
4
  Summary: Connect your Python backend to a modern JavaScript SPA frontend with 90% less complexity.
5
5
  Author-email: Robert <robert.herring@statezero.dev>
6
6
  Project-URL: homepage, https://www.statezero.dev
File without changes
File without changes