Skip to content

Latest commit

 

History

History
937 lines (793 loc) · 25.7 KB

File metadata and controls

937 lines (793 loc) · 25.7 KB
title Layout DSL
description Declarative layout description language for pages, sections, and responsive grids

import { Layout, Grid, Columns, Box, Monitor, Smartphone, Tablet, MousePointer } from 'lucide-react';

The Layout DSL (Domain-Specific Language) is ObjectUI's declarative syntax for defining page structure, sections, and responsive grids. It abstracts away CSS Grid, Flexbox, and platform-specific layout engines.

Philosophy: Constraints Enable Creativity

Instead of giving you infinite layout freedom (and infinite ways to break responsive design), ObjectUI provides a constrained, opinionated layout system:

  • 12-Column Grid: All layouts use a 12-column responsive grid
  • Section-Based: Pages are composed of sections, sections contain fields/widgets
  • Auto-Responsive: Breakpoints applied automatically (no media queries)
  • Platform-Agnostic: Same DSL renders as CSS Grid (web), Auto Layout (iOS), ConstraintLayout (Android)

Why Constraints?

  • Consistency: All forms look professionally designed
  • Accessibility: Keyboard navigation and screen readers work automatically
  • Maintainability: Designers can't create 47 different button sizes

Layout Hierarchy

Page
 ├─ Header (Title, Actions, Breadcrumbs)
 ├─ Main Region
 │   ├─ Section 1
 │   │   ├─ Field Group
 │   │   │   ├─ Field A (span: 6)
 │   │   │   └─ Field B (span: 6)
 │   │   └─ Widget
 │   └─ Section 2
 │       └─ Related List
 └─ Sidebar Region
     ├─ Widget: Quick Stats
     └─ Widget: Activity Feed

Page Templates

Top-level layout structures that define macro organization.

Standard Template

context: record
object: account
template: standard
regions:
  - name: header
    components:
      - type: page:header
        properties:
          title: Customer Details
          actions: [edit, delete, share]
  - name: main
    components:
      - type: page:section
        properties:
          label: Contact Information
          fields: [name, email, phone]
  - name: sidebar
    components:
      - type: widget
        properties:
          component: activity_feed

Visual Layout:

┌────────────────────────────────────────────────────┐
│ Header: Customer Details        [Edit] [Delete]    │
├──────────────────────────────┬─────────────────────┤
│                              │                     │
│  Main Region                 │  Sidebar            │
│                              │                     │
│  ┌────────────────────────┐  │  ┌───────────────┐ │
│  │ Contact Information    │  │  │ Activity Feed │ │
│  │ Name: ____________     │  │  │ • Called      │ │
│  │ Email: ___________     │  │  │ • Emailed     │ │
│  │ Phone: ___________     │  │  └───────────────┘ │
│  └────────────────────────┘  │                     │
│                              │                     │
└──────────────────────────────┴─────────────────────┘

Breakpoint Behavior:

  • Desktop (≥1024px): Sidebar on right (25% width)
  • Tablet (768-1023px): Sidebar below main (full width)
  • Mobile (less than 768px): Sidebar below main (full width)

Console Template

High-density layout for power users (like Salesforce Service Console).

context: app
template: console
regions:
  - name: left
    width: small
    components:
      - type: record:list
        properties:
          object: case
          
  - name: right
    width: full
    components:
      - type: record:details
        properties:
          tabs: [details, related, activity]

Visual Layout:

┌──────────────┬─────────────────────────────────────┐
│              │  Case #12345                        │
│ Case List    │  ┌───┬─────────┬──────────┬────────┐│
│              │  │Det│ Related │ Activity │        ││
│ □ Case #123  │  └───┴─────────┴──────────┴────────┘│
│ ■ Case #124  │                                     │
│ □ Case #125  │  Subject: Email not working         │
│ □ Case #126  │  Priority: High                     │
│              │  Status: In Progress                │
│              │                                     │
│              │  [Resolve] [Escalate]               │
└──────────────┴─────────────────────────────────────┘

Use Cases:

  • Customer service (Case management)
  • Sales (Opportunity pipeline + details)
  • Helpdesk (Ticket queue + ticket details)

Wizard Template

Multi-step flow with progress indicator.

# page_template: wizard
steps:
  - name: account_info
    label: Account Information
    fields: [company_name, industry, size]
  - name: contact_details
    label: Contact Details
    fields: [name, email, phone]
  - name: preferences
    label: Preferences
    fields: [newsletter, notifications]
  - name: review
    label: Review & Submit
    type: summary

Visual Layout:

┌────────────────────────────────────────────────────┐
│  New Customer Setup                                │
│  ● Account Info → ○ Contact → ○ Preferences → ○   │
├────────────────────────────────────────────────────┤
│                                                    │
│  Account Information                               │
│                                                    │
│  Company Name: _______________________________     │
│  Industry:     [Select Industry ▼]                 │
│  Company Size: ○ 1-10  ○ 11-50  ○ 51-200          │
│                                                    │
│                          [Cancel]  [Next Step →]   │
└────────────────────────────────────────────────────┘

The 12-Column Grid System

All layouts use a responsive grid that divides space into 12 columns.

Basic Grid Layout

section:
  label: Contact Information
  columns: 2  # Each field takes 6/12 columns (50% width)
  fields:
    - name      # Column 1-6
    - email     # Column 7-12
    - phone     # Column 1-6 (new row)
    - company   # Column 7-12

Rendered Grid:

┌──────────────────────┬──────────────────────┐
│ Name: ______________ │ Email: _____________ │
├──────────────────────┼──────────────────────┤
│ Phone: _____________ │ Company: ___________ │
└──────────────────────┴──────────────────────┘

Custom Span Widths

section:
  label: Product Details
  layout:
    - field: product_name
      span: 12  # Full width
    - field: price
      span: 4   # 33% width
    - field: quantity
      span: 4   # 33% width
    - field: total
      span: 4   # 33% width
    - field: description
      span: 12  # Full width

Rendered Grid:

┌─────────────────────────────────────────────────┐
│ Product Name: _________________________________│
├───────────────┬───────────────┬────────────────┤
│ Price: $_____ │ Qty: ________ │ Total: $______ │
├───────────────┴───────────────┴────────────────┤
│ Description:                                    │
│ ____________________________________________    │
│ ____________________________________________    │
└─────────────────────────────────────────────────┘

Responsive Breakpoints

Grid automatically collapses on smaller screens:

section:
  columns: 3  # Desktop: 3 columns, Tablet: 2 columns, Mobile: 1 column
  fields: [field_a, field_b, field_c, field_d, field_e, field_f]

Desktop (≥1024px): 3 columns

┌──────────┬──────────┬──────────┐
│ Field A  │ Field B  │ Field C  │
├──────────┼──────────┼──────────┤
│ Field D  │ Field E  │ Field F  │
└──────────┴──────────┴──────────┘

Tablet (768-1023px): 2 columns

┌──────────────┬──────────────┐
│ Field A      │ Field B      │
├──────────────┼──────────────┤
│ Field C      │ Field D      │
├──────────────┼──────────────┤
│ Field E      │ Field F      │
└──────────────┴──────────────┘

Mobile (less than 768px): 1 column

┌────────────────────────┐
│ Field A                │
├────────────────────────┤
│ Field B                │
├────────────────────────┤
│ Field C                │
├────────────────────────┤
│ Field D                │
├────────────────────────┤
│ Field E                │
├────────────────────────┤
│ Field F                │
└────────────────────────┘

Sections: Organizing Fields

Sections are collapsible containers for related fields.

Basic Section

sections:
  - label: Contact Information
    collapsible: true
    collapsed: false  # Expanded by default
    fields:
      - name
      - email
      - phone

Rendered:

┌─ Contact Information ──────────────────────────▼─┐
│                                                  │
│  Name:  __________________________________________│
│  Email: __________________________________________│
│  Phone: __________________________________________│
│                                                  │
└──────────────────────────────────────────────────┘

Conditional Sections

Show sections based on field values or permissions:

sections:
  - label: Basic Info
    fields: [name, email]
  
  - label: Billing Information
    visible:
      field: account_type
      value: premium  # Only show for premium accounts
    fields: [payment_method, billing_address]
  
  - label: Admin Settings
    visible:
      permission: admin  # Only show to admins
    fields: [api_key, rate_limit]

Section Variants

sections:
  - label: Quick Summary
    variant: compact  # Reduced padding
    columns: 4
    fields: [status, priority, assignee, due_date]
  
  - label: Description
    variant: spacious  # Extra padding
    fields: [long_description]
  
  - label: Danger Zone
    variant: danger  # Red border, warning icon
    fields: [archive, delete]

Field Groups and Inline Layout

Inline Field Group

Group related fields on the same row:

sections:
  - label: Name
    layout:
      - type: field_group
        inline: true
        fields:
          - field: first_name
            span: 6
            placeholder: First
          - field: last_name
            span: 6
            placeholder: Last

Rendered:

Name
┌──────────────────────┬──────────────────────┐
│ First: _____________ │ Last: ______________ │
└──────────────────────┴──────────────────────┘

Address Field Group

- type: field_group
  label: Address
  fields:
    - field: street
      span: 12
    - field: city
      span: 6
    - field: state
      span: 3
    - field: postal_code
      span: 3

Rendered:

Address
┌─────────────────────────────────────────────────┐
│ Street: _______________________________________│
├──────────────────────┬───────────┬────────────┤
│ City: _______________ │ State: __ │ ZIP: _____ │
└──────────────────────┴───────────┴────────────┘

Tabs: Multi-Page Layouts

Organize large forms into tabbed sections.

Basic Tabs

layout:
  mode: tabbed
  tabs:
    - name: details
      label: Details
      icon: file-text
      sections:
        - label: Basic Info
          fields: [name, email, phone]
    
    - name: address
      label: Address
      icon: map-pin
      sections:
        - label: Primary Address
          fields: [street, city, state, zip]
    
    - name: preferences
      label: Preferences
      icon: settings
      sections:
        - label: Notifications
          fields: [email_notifications, sms_notifications]

Rendered:

┌──────────────────────────────────────────────────┐
│ [Details] [Address] [Preferences]                │
├──────────────────────────────────────────────────┤
│                                                  │
│  Basic Info                                      │
│  Name:  __________________________________________│
│  Email: __________________________________________│
│  Phone: __________________________________________│
│                                                  │
└──────────────────────────────────────────────────┘

Lazy-Loaded Tabs

Load tab content only when clicked (performance optimization):

tabs:
  - name: details
    label: Details
    lazy: false  # Load immediately
  
  - name: history
    label: History (1,234 records)
    lazy: true   # Load when tab clicked
    source: /api/customers/123/history

Tab Badges and Counters

tabs:
  - name: details
    label: Details
  
  - name: tasks
    label: Tasks
    badge: 5  # Show "5" badge
    badgeVariant: danger  # Red badge
  
  - name: notes
    label: Notes
    badge: { count: 12, variant: info }

Responsive Layout Modifiers

Device-Specific Visibility

fields:
  - name: detailed_description
    span: 12
    visible:
      desktop: true   # Show on desktop
      tablet: true    # Show on tablet
      mobile: false   # Hide on mobile
  
  - name: short_summary
    span: 12
    visible:
      desktop: false  # Hide on desktop
      tablet: false   # Hide on tablet
      mobile: true    # Show on mobile

Orientation-Specific Layout

section:
  columns:
    portrait: 1   # 1 column in portrait mode
    landscape: 2  # 2 columns in landscape mode
  fields: [field_a, field_b, field_c]

Related Lists: Embedding Child Records

Display child records within a parent record's page.

Basic Related List

sections:
  - type: related_list
    label: Contacts
    object: contact
    relationField: account_id  # contact.account_id → account.id
    columns:
      - name
      - email
      - phone
    actions:
      - type: standard_new
        label: New Contact

Rendered:

┌─ Contacts ─────────────────────────────── [+ New Contact] ─┐
│                                                             │
│  Name              Email              Phone                │
│  ────────────────  ─────────────────  ─────────────────    │
│  John Doe          john@acme.com      555-1234            │
│  Jane Smith        jane@acme.com      555-5678            │
│                                                             │
│  Showing 2 of 2 contacts                                    │
└─────────────────────────────────────────────────────────────┘

Inline Editing Related List

sections:
  - type: related_list
    label: Invoice Line Items
    object: invoice_line
    relationField: invoice_id
    mode: inline_edit  # Edit cells directly
    columns:
      - field: product
        type: lookup
        object: product
      - field: quantity
        type: number
        editable: true
      - field: unit_price
        type: currency
        editable: true
      - field: total
        type: formula
        formula: quantity * unit_price
        editable: false
    actions:
      - type: add_row
        label: Add Line Item

Widgets: Embedding Rich Components

Widgets are pre-built UI components that display data or provide functionality.

Metric Widget

sections:
  - type: widget
    component: metric
    config:
      title: Open Opportunities
      value: 47
      trend: +12%
      trendDirection: up
      icon: trending-up
      color: success

Rendered:

┌─────────────────────┐
│ Open Opportunities  │
│                     │
│      47      ↑ +12% │
│                     │
└─────────────────────┘

Activity Feed Widget

sections:
  - type: widget
    component: activity_feed
    config:
      object: activity
      filter: { related_to: '{recordId}' }
      limit: 10
      showFilters: true

Custom Widget

sections:
  - type: widget
    component: custom.approval_timeline
    config:
      recordId: '{recordId}'
      showComments: true

Advanced Layouts

Master-Detail Split View

layout:
  type: split_view
  orientation: horizontal  # or 'vertical'
  split: 60  # Left: 60%, Right: 40%
  left:
    type: list_view
    object: opportunity
    view: my_opportunities
  right:
    type: detail_view
    object: opportunity
    recordId: '{selectedRecordId}'

Grid of Cards

layout:
  type: card_grid
  columns:
    desktop: 3
    tablet: 2
    mobile: 1
  cards:
    - type: metric_card
      title: Revenue
      value: $1.2M
    - type: metric_card
      title: Deals
      value: 47
    - type: chart_card
      title: Pipeline
      chartType: funnel

Kanban Board Layout

layout:
  type: kanban
  object: project_task
  groupBy: status
  columns:
    - value: todo
      label: To Do
      color: gray
    - value: in_progress
      label: In Progress
      color: blue
    - value: done
      label: Done
      color: green
  cardFields:
    - title
    - assignee
    - due_date

Layout Schema Reference

Page Definition

interface PageLayout {
  template: 'standard' | 'console' | 'wizard';
  title?: string;
  subtitle?: string;
  icon?: string;
  regions: {
    header?: Component[];
    main: Component[];
    sidebar?: Component[];
    footer?: Component[];
  };
  responsive?: ResponsiveConfig;
}

Section Definition

interface Section {
  type: 'section';
  label: string;
  description?: string;
  icon?: string;
  collapsible?: boolean;
  collapsed?: boolean;
  columns?: number | ResponsiveColumns;
  variant?: 'default' | 'compact' | 'spacious' | 'danger';
  visible?: VisibilityRule;
  fields: FieldReference[];
}

Field Layout

interface FieldLayout {
  field: string;  // Field name from ObjectQL schema
  span?: number;  // Column span (1-12)
  offset?: number;  // Column offset
  label?: string;  // Override label
  placeholder?: string;
  helpText?: string;
  required?: boolean;
  readonly?: boolean;
  visible?: VisibilityRule;
}

Responsive Columns

interface ResponsiveColumns {
  desktop?: number;   // ≥1024px
  tablet?: number;    // 768-1023px
  mobile?: number;    // less than 768px
  portrait?: number;
  landscape?: number;
}

Visibility Rule

type VisibilityRule =
  | { field: string; value: any }  // Show if field equals value
  | { permission: string }         // Show if user has permission
  | { expression: string }         // Show if expression evaluates to true
  | { desktop?: boolean; tablet?: boolean; mobile?: boolean };

Real-World Examples

Customer 360 Page

name: customer_360
object: customer
template: standard
regions:
  header:
    - type: title
      field: name
    - type: actions
      buttons: [edit, delete, share, convert]
  
  main:
    - type: section
      label: Overview
      columns: 2
      fields:
        - name
        - status
        - industry
        - employee_count
        - website
        - phone
    
    - type: section
      label: Key Contacts
      columns: 1
      component:
        - type: related_list
          object: contact
          relationField: account_id
          columns: [name, title, email, phone]
    
    - type: section
      label: Open Opportunities
      component:
        - type: related_list
          object: opportunity
          relationField: account_id
          filter: { stage: { $ne: 'closed_won' } }
          columns: [name, amount, close_date, stage]
  
  sidebar:
    - type: widget
      component: metric
      config:
        title: Total Revenue
        value: $1.2M
    
    - type: widget
      component: activity_feed
      config:
        limit: 10

Multi-Step Onboarding Wizard

name: employee_onboarding
object: employee
template: wizard
steps:
  - name: personal_info
    label: Personal Information
    sections:
      - label: Basic Details
        columns: 2
        fields:
          - first_name
          - last_name
          - email
          - phone
          - date_of_birth
          - ssn
  
  - name: employment
    label: Employment Details
    sections:
      - label: Position
        fields:
          - job_title
          - department
          - manager
          - start_date
          - employment_type
  
  - name: compensation
    label: Compensation
    sections:
      - label: Salary & Benefits
        fields:
          - base_salary
          - bonus_eligible
          - equity_grant
          - benefits_plan
  
  - name: review
    label: Review & Submit
    type: summary
    sections:
      - type: summary_view
        showAllFields: true

Performance Considerations

Lazy Loading

Load sections/tabs only when visible:

sections:
  - label: Details
    lazy: false  # Load immediately
  
  - label: History (10,000 records)
    lazy: true   # Load when section expanded
    source: /api/customers/123/history

Virtual Scrolling

For long lists of fields:

section:
  label: Product Catalog (1,000 items)
  virtualScroll: true
  itemHeight: 60  # px
  fields: [...]  # Large array

Progressive Rendering

Render above-the-fold content first:

layout:
  renderStrategy: progressive
  priority:
    - sections[0]  # Render first section immediately
    - sections[1]  # Render second section after 100ms
    - sections[2]  # Render third section after 200ms

What's Next?

} title="Widget Contract" href="/docs/protocols/objectui/widget-contract" description="Standard props and events for UI components" /> } title="Action Protocol" href="/docs/protocols/objectui/actions" description="Buttons, triggers, and navigation flows" />

Related Resources