Skip to content

octoberswimmer/thunder

Repository files navigation

Thunder

Masc (Go WASM Apps) + SLDS on Salesforce

This repository provides libraries for building applications for Salesforce's Lightning Experience in Go using SLDS-styled masc components, which follow the Elm Architecture.

Thunder is made up of these masc components, a thunder LWC for running the compiled wasm applications, a lightweight API designed to mirror the REST API, and a CLI to make development a joy.

Repository Structure:

. (repo root)
├ cmd/thunder/           CLI source (Cobra commands: serve, deploy)
│  ├ main.go             CLI implementation
│  ├ main_test.go        CLI command tests
├ salesforce/            embedded metadata templates
│  ├ classes/            Apex classes
│  └ lwc/                LWC wrappers (`go`, `thunder`)
├ components/            MASC components for Thunder apps
├ api/                   REST proxy for WASM apps, UI API metadata (GetObjectInfo, GetPicklistValuesByRecordType), Record API for convenient field access (StringValue, Value), Places API for address autocomplete, Settings API for Thunder configuration, and Exit API for application lifecycle management
└ examples/              example Thunder applications
   ├ thunderDemo/        main demo app showcasing all components
   └ validation/         comprehensive form validation example

Key parts:

  • thunder LWC (c:thunder):
    • Loads a Go WASM app as static resource, injects global API functions, and runs the app.
    • Exposes the recordId from Lightning record pages to Go WASM code via globalThis.recordId.
  • Thunder SLDS Components (components/):
    • Go library offering SLDS-styled Masc components like Button, DataTable, Grid, Textarea, and Stencil.
  • Apex GoBridge (salesforce/classes/GoBridge.cls):
    • @AuraEnabled callRest(...) to map REST API calls to Apex.
  • thunder CLI (cmd/thunder):
    • Command-line tool to serve a Thunder app while in development and, and to build and deploy it to a Salesforce org. Example Applications (examples/):
    • thunderDemo: Demonstrates all Thunder components in a Go WASM app, organized into Actions, Data, ObjectInfo, and Layout tabs. Showcases component-only development without direct SLDS classes or elem usage.
    • validation: Comprehensive form validation example with real-time error handling, demonstrating ValidationState and validated components.

Getting Started:

  1. Install dependencies:
  2. Run the thunderDemo app locally:
    $ force login
    $ thunder serve ./examples/thunderDemo
    This compiles examples/thunderDemo/main.go and starts a web server to serve the app.
  3. Deploy to Salesforce using thunder deploy ./examples/thunderDemo --tab
  4. Click Fetch Accounts to see a data table rendered from your Thunder app.

Thunder Components

Thunder provides a comprehensive set of SLDS-styled components for building Lightning Experience applications:

Form Components

  • TextInput: Single-line text input with label and validation styling
  • Textarea: Multi-line text input for longer content (e.g., addresses, descriptions)
  • Select: Dropdown selection with picklist options
  • Datepicker: Date input with SLDS calendar styling (uses time.Time values)
  • Timepicker: Time input with 24-hour format (HH:MM)
  • Checkbox: Boolean input with proper labeling
  • RadioGroup: Multiple choice selection with radio buttons in form layout
  • RadioButtonGroup: Multiple choice selection with button-style radio controls
  • ValidatedTextInput, ValidatedTextarea, etc.: Form components with built-in validation state management

Layout Components

  • Grid & GridColumn: Responsive grid system for flexible layouts
    components.Grid(
        components.GridColumn("1-of-2", /* first column content */),
        components.GridColumn("1-of-2", /* second column content */),
        components.GridColumn("1-of-1", /* full-width content */),
    )
  • CenteredGrid: Grid with center alignment for loading states and centered content
  • Card: Content containers with headers and proper spacing
  • Page & PageHeader: Page-level layout with consistent styling
  • Modal: Dialog overlays for secondary workflows
  • ModalWithClose: Modal with built-in close button and enhanced functionality
  • Form: Semantic form wrapper with proper SLDS styling
  • Container: Basic layout wrapper to avoid direct element usage
  • Spacer: Flexible spacing container with margin/padding options
  • MarginTop, MarginBottom, PaddingHorizontal, etc.: Semantic spacing components

Data Components

  • DataTable: Feature-rich data tables with sorting and actions
  • DataTableWithMenu: Enhanced data table with dropdown menu actions and loading states
  • Lookup: Search and selection for related records
  • AddressAutocomplete: Google Maps Places API integration for address input with autocomplete suggestions

UI Components

  • Button: Action buttons with variant styling (Neutral, Brand, Destructive)
  • LoadingButton: Button with built-in spinner and disabled state
  • Badge: Status indicators and labels
  • Breadcrumb: Navigation hierarchy display
  • Icon: SLDS icon integration
  • ProgressBar: Progress indication for long-running operations
  • Spinner: Loading indicators in multiple sizes
  • LoadingSpinner: Centered loading spinner for containers
  • Stencil: Skeleton placeholders for loading states
  • Tabs: Tabbed content organization
  • Toast: Notification messages

Text Components

  • Text: Styled text with size variants (Small, Regular, Large)
  • Paragraph: Paragraph elements with text styling
  • Heading: Heading elements (H1/H2/H3) with semantic sizing (Small, Medium, Large)

Component Features

  • Complete Abstraction: No direct SLDS classes or masc elements required in application code
  • Semantic APIs: Type-safe spacing, sizing, and styling options
  • Consistent Spacing: Semantic spacing components (Spacer, MarginTop, etc.)
  • Responsive Design: Grid system adapts to different screen sizes
  • Accessibility: Full SLDS accessibility compliance
  • Event Handling: Clean event binding with Go functions
  • Type Safety: Strongly typed APIs for reliable development
  • Loading States: Built-in support for loading spinners and disabled states

Example: Component-Only Development

Thunder components provide complete abstraction from SLDS classes and DOM elements:

// Instead of using elem.Div with SLDS classes
elem.Div(
    masc.Markup(masc.Class("slds-m-top_medium", "slds-align_absolute-center")),
    components.Spinner("medium"),
)

// Use semantic layout components
components.MarginTop(components.SpaceMedium,
    components.LoadingSpinner("medium"),
)

// Complex layouts with semantic spacing
func (m *AppModel) renderPatientForm(send func(masc.Msg)) masc.ComponentOrHTML {
    return components.Page(
        components.PageHeader("Patient Information", "Enter patient details"),
        components.Card("Patient Details",
            components.Grid(
                components.GridColumn("1-of-2",
                    components.ValidatedTextInput("First Name", m.firstName,
                        components.ValidationState{
                            Required:     true,
                            HasError:     m.hasError("firstName"),
                            ErrorMessage: m.errors["firstName"],
                            Placeholder:  "Enter first name",
                            Tooltip:      "Legal first name as shown on ID",
                        },
                        func(e *masc.Event) {
                            send(firstNameMsg(e.Target.Get("value").String()))
                        },
                    ),
                ),
                components.GridColumn("1-of-2",
                    components.ValidatedTextInput("Last Name", m.lastName,
                        components.ValidationState{
                            Required:    true,
                            Placeholder: "Enter last name",
                            Tooltip:     "Legal last name as shown on ID",
                        },
                        func(e *masc.Event) {
                            send(lastNameMsg(e.Target.Get("value").String()))
                        },
                    ),
                ),
            ),
            // Loading button with built-in spinner - conditional rendering with masc.If
            masc.If(m.isSubmitting,
                components.LoadingButton("Saving...", components.VariantBrand),
            ),
            masc.If(!m.isSubmitting,
                components.Button("Save", components.VariantBrand, func(e *masc.Event) {
                    send(saveMsg{})
                }),
            ),
        ),
    )
}

Form Validation

Thunder provides validated form components that handle error states, required field validation, and help text. Each validated component includes:

  • Error State Management: Red styling for validation errors
  • Required Field Indicators: Asterisk (*) for required fields
  • Help Text: Descriptive text below form fields
  • Real-time Validation: Immediate feedback on user input

Validated Components

  • ValidatedTextInput: Text input with validation state
  • ValidatedTextarea: Multi-line text with validation
  • ValidatedSelect: Dropdown selection with validation
  • ValidatedRadioButtonGroup: Radio button group with validation state
  • ValidatedDatepicker: Date input with validation (uses time.Time values)
  • ValidatedTimepicker: Time input with validation (24-hour format)
  • ValidatedLookup: Search and selection component with validation state

ValidationState

All validated components use the ValidationState struct:

type ValidationState struct {
    HasError     bool   // Show error styling
    Required     bool   // Show asterisk indicator
    ErrorMessage string // Error text to display
    HelpText     string // Help text below field
    Tooltip      string // Tooltip text (shows as help icon next to label)
    Placeholder  string // Input placeholder text
}

Tooltip Support

Validated components support tooltips that appear as help icons (ⓘ) next to field labels:

  • Help Icon: Unicode info symbol appears next to labels when tooltip is provided
  • Native Tooltip: Uses HTML title attribute for cross-browser compatibility
  • SLDS Styling: Proper spacing and color for SLDS compliance
// Field with tooltip and placeholder
components.ValidatedTextInput("Phone Number", m.phone, components.ValidationState{
    Required:    false,
    Tooltip:     "Include area code. Start international numbers with +",
    Placeholder: "(555) 123-4567",
    HelpText:    "Contact phone number (optional)",
}, func(e *masc.Event) {
    send(phoneChangedMsg(e.Target.Get("value").String()))
})

Convenience Constructors

Thunder provides convenience functions for common ValidationState configurations:

// Simple tooltip
validation := components.WithTooltip("This field requires special formatting")

// Placeholder only
validation := components.WithPlaceholder("Enter value here")

// Both tooltip and placeholder
validation := components.WithTooltipAndPlaceholder("Help text", "placeholder")

// Required field
validation := components.Required()

// Required field with tooltip
validation := components.RequiredWithTooltip("This required field needs special attention")

Example: Comprehensive Validated Form

validationState := components.ValidationState{
    HasError:     len(m.email) > 0 && !isValidEmail(m.email),
    Required:     true,
    ErrorMessage: "Please enter a valid email address",
    HelpText:     "We'll use this to send important updates",
    Tooltip:      "Email format: [email protected]",
    Placeholder:  "[email protected]",
}

components.ValidatedTextInput("Email", m.email, validationState, func(e *masc.Event) {
    send(emailChangedMsg(e.Target.Get("value").String()))
})

Example: Radio Button Group with Validation

// Gender selection with validation
genderOptions := []components.RadioButtonOption{
    {Label: "Female", Value: "Female"},
    {Label: "Male", Value: "Male"},
    {Label: "Other", Value: "Other"},
    {Label: "Unknown", Value: "Unknown"},
}

validationState := components.ValidationState{
    Required:     true,
    HasError:     m.genderValidationError,
    ErrorMessage: "Please select a gender",
    HelpText:     "Gender as it appears on legal documents",
}

components.ValidatedRadioButtonGroup("Gender", "patient-gender", genderOptions, m.selectedGender, validationState, func(value string) {
    send(genderChangedMsg(value))
})

Examples

The examples/ directory contains complete Thunder applications demonstrating different patterns:

thunderDemo

The main demonstration app showcasing all Thunder components across four tabs:

  • Actions: Buttons, badges, icons, and date pickers
  • Data: Interactive data table with filtering, pagination, and controls
  • ObjectInfo: Salesforce metadata display using the UI API
  • Layout: Grid system demonstration

Features component-only development with no direct SLDS classes or masc elements.

thunder serve ./examples/thunderDemo

validation

Comprehensive form validation example demonstrating:

  • Real-time field validation with ValidationState
  • Required field indicators and error messages
  • Loading states with LoadingButton
  • Semantic spacing with MarginTop and Spacer
  • Address autocomplete integration with Google Maps Places API
  • Thunder Settings configuration for API keys

Shows how to build robust forms using only Thunder components.

thunder serve ./examples/validation

Both examples are complete Go modules that can be run independently with thunder serve or deployed with thunder deploy.

Thunder CLI

Thunder provides a CLI with two subcommands, serve and deploy, for local development and deployment of Go WASM apps on Salesforce.

Installation

go install github.com/octoberswimmer/thunder/cmd/thunder@latest

Usage

thunder serve [dir] --port PORT   # build & serve locally (defaults to current dir)
thunder deploy [dir] [--tab]      # deploy app to Salesforce org (defaults to current dir)

serve

  • --port, -p: Port to serve on (default 8000)

thunder serve:

  • Builds the app in dev mode (GOOS=js GOARCH=wasm -tags dev).
  • Serves on http://localhost:PORT, auto-rebuilds on file changes.
  • Proxies /services/... REST calls to your Salesforce org via CLI auth.
  • Opens your default browser to the served app URL.

The CLI watches Go source files (.go, go.mod, go.sum) and automatically rebuilds the WASM bundle on changes. Refresh the browser to load the latest build. API REST requests (via /services/) are automatically proxied through your active Salesforce CLI session. Be sure to run force login beforehand.

deploy

  • --tab, -t: Also include a CustomTab in the deployment and open it for the app
  • --watch, -w: Watch for file changes and automatically redeploy

thunder deploy:

  • Builds a production WebAssembly bundle.
  • Packages metadata (static resource, Apex classes, LWC wrappers, app LWC, and optional CustomTab) in-memory.
  • Generates package.xml (includes CustomTab if requested) and deploys all metadata via your CLI session.
  • With --tab, adds a CustomTab to the package, deploys it, and opens /lightning/n/<app> in your browser.
  • With --watch, monitors Go source files and automatically redeploys on changes for rapid development cycles.

About

Masc (Go WASM Apps) + SLDS on Salesforce

Resources

Stars

Watchers

Forks

Releases

No releases published