Module

Play

Package
purescript-play
Repository
shamansir/purescript-play

The Play API provides a way to define declarative layout for creating flexible, responsive user interfaces in PureScript.

It is inspired by Clay UI layouting system for C++ by Nic Baker. It inherits its simple yet powerful design.

The API supports:

  • Flexbox-like layout with direction control (horizontal/vertical)
  • Size constraints (fixed, fit-to-content, grow-to-fill, ...)
  • Padding and gaps between elements
  • Automatic size calculation and positioning

#Play Source

newtype Play a

A layout tree containing elements of type a with layout definitions. This is the primary type for building layouts before they are computed.

Each element contains:

  • User data of type a
  • Layout definition (sizing, padding, direction, etc.)
  • Zero or more child elements

The only required properties for an element to be visible are the way its width / height calculated.

Example:

myLayout
  = P.i "content"
  ~* P.widthGrow
  ~* P.height 100.0
  ~* P.padding (P.all 5.0)
  ~* P.with [ P.i "child1", P.i "child2" ]
  :: Play String

See more examples in the README and Test/Demo/Examples in the source.

Instances

#Layout Source

newtype Layout a

A computed layout tree with final positioning and sizes. This is the result of running layout computation on a Play definition using Play.layout function.

Each element contains:

  • User data of type a
  • Layout definition (preserved for potential rollback)
  • Computed rectangular bounds (position and size)

Instances

#direction Source

direction :: forall a. Direction -> Play a -> Play a

Set the layout direction for arranging child elements.

  • TopToBottom: Stack children vertically
  • LeftToRight: Arrange children horizontally (default)

Example:

verticalLayout = P.i "container" ~* P.direction P.TopToBottom

#padding Source

padding :: forall a. Padding -> Play a -> Play a

Set padding (inner spacing) on all four sides of an element. Padding creates space between the element's border and its children.

Example:

paddedContainer = P.i "content" ~* P.padding (P.all 10.0)

#childGap Source

childGap :: forall a. Number -> Play a -> Play a

Set the spacing between child elements. This creates gaps between adjacent children in the layout direction.

Example:

spacedContainer = P.p "menu" buttons ~* P.childGap 5.0
spacedContainer2 = P.i "menu" ~* P.childGap 5.0 ~* P.with buttons

#w Source

w :: forall a. Sizing -> Play a -> Play a

Set the width sizing constraint for an element. See Sizing type for available options (None, Fixed, Fit, Grow, FitGrow).

#h Source

h :: forall a. Sizing -> Play a -> Play a

Set the height sizing constraint for an element. See Sizing type for available options (None, Fixed, Fit, Grow, FitGrow).

#with Source

with :: forall a. Array (Play a) -> Play a -> Play a

Add additional children to an existing element. The new children are appended to the existing children list.

Example:

container = P.i "base"
  ~* P.with [child1, child2]
container2 = P.p "base" [child1, child2]
  ~* P.with [child3, child4]  -- Now has 4 children total

#paddingTop Source

paddingTop :: forall a. Number -> Play a -> Play a

Set padding for the top side only. Other padding values remain unchanged.

#paddingLeft Source

paddingLeft :: forall a. Number -> Play a -> Play a

Set padding for the left side only. Other padding values remain unchanged.

#paddingBottom Source

paddingBottom :: forall a. Number -> Play a -> Play a

Set padding for the bottom side only. Other padding values remain unchanged.

#paddingRight Source

paddingRight :: forall a. Number -> Play a -> Play a

Set padding for the right side only. Other padding values remain unchanged.

#default Source

default :: Def

Default layout definition with sensible defaults.

  • Direction: LeftToRight
  • Padding: All sides set to 0
  • Child gap: 0
  • Sizing: Both width and height set to None

This is the starting point for all layout definitions and can be modified using the various property functions.

#all Source

all :: Number -> Padding

Create padding with the same value on all four sides. This is a convenience function for uniform padding.

#tb Source

tb :: Number -> Padding

Create padding for top and bottom sides only (vertical padding). Left and right padding are set to 0.

#lr Source

lr :: Number -> Padding

Create padding for left and right sides only (horizontal padding). Top and bottom padding are set to 0.

#p Source

p :: forall a. a -> Array (Play a) -> Play a

Create a layout element that has children (parent).

Parameters:

  • a: The user data/content for this element
  • Array (Play a): Array of child elements

The created element uses the default layout definition, which can be modified using property functions and the ~* operator.

Example:

container = P.p "header"
  [ P.i "logo"
  , P.i "navigation"
  ]

#i Source

i :: forall a. a -> Play a

Create a leaf layout element with no children (item).

This is the primary constructor for creating layout hierarchies and a convenience function equivalent to P.p a [], the children could be added later using ~* P.with [ child1, child2, ... ] .

Example:

element = P.i "Hello World"

#toTree Source

toTree :: forall a. Play a -> Tree (WithDef a)

Extract the underlying tree structure from a Play layout. This is useful for low-level tree operations.

#fromTree Source

fromTree :: forall a. Tree (WithDef a) -> Play a

Wrap a tree structure as a Play layout. This is the inverse of toTree and is useful when constructing Play layouts from external tree structures.

Takes the compiled elements definitions and wraps them in a Play definition (internal representation is the very same Tree).

#layout Source

layout :: forall a. Play a -> Layout a

Compute the final layout from a Play tree specification. This performs a three-phase layout computation:

  1. Fit Sizing: Calculate minimum required sizes based on content and constraints
  2. Grow Sizing: Distribute remaining space to elements with grow constraints
  3. Positioning: Calculate final positions for all elements

The result is a Layout containing all the elements with their computed bounds (positions and rectangles).

Example:

myPlay = Play.i "root" ~* Play.with [ Play.i "child1", Play.i "child2" ] :: Play String
computedLayout = Play.layout myPlay :: Layout String

#layoutToTree Source

layoutToTree :: forall a. Layout a -> Tree (WithRect a)

Extract the tree structure from a Layout, removing layout definitions. The result contains only the values and computed rectangular bounds. This is useful for rendering with keeping hierarchy or hit-testing operations.

#flattenLayout Source

flattenLayout :: forall a. Layout a -> Array (WithRect a)

Flatten a Layout into an array of all elements with their computed bounds. This provides a simple list of all elements for rendering or processing. The tree hierarchy is flattened but positioning information is preserved, so it is completely safe to iterate the resulting array and place the elements in the corresponding bounds. The parents are followed by their children, so z-index is also preserved.

#rollback Source

rollback :: forall a. Layout a -> Play a

Convert a computed Layout back to a Play specification. This removes the computed positioning information but preserves the layout definitions, allowing for re-computation with modifications.

Example:

myPlay = P.i "root" ~* P.with [ P.i "child1", P.i "child2" ] :: Play String
computedLayout = P.layout myPlay :: P.Layout String
originalPlay = P.rollback computedLayout :: Play String
modifiedPlay = originalPlay ~* P.padding (P.all 5.0) :: Play String
newLayout = P.layout modifiedPlay :: P.Layout String

#layoutSize Source

layoutSize :: forall a. Layout a -> Size

Get the total size of the root element in a computed Layout. This represents the minimum bounding box containing all elements.

#widthFit Source

widthFit :: forall (a :: Type). Play a -> Play a

Set width to fit content (minimum required space).

#widthGrow Source

widthGrow :: forall (a :: Type). Play a -> Play a

Set width to grow and fill available horizontal space.

#widthFitGrow Source

widthFitGrow :: forall (a :: Type). Play a -> Play a

Set width to fit content but grow if extra space is available.

#width Source

width :: forall a. Number -> PropF a

Set width to a fixed pixel value.

#heightFit Source

heightFit :: forall (a :: Type). Play a -> Play a

Set height to fit content (minimum required space).

#heightGrow Source

heightGrow :: forall (a :: Type). Play a -> Play a

Set height to grow and fill available vertical space.

#heightFitGrow Source

heightFitGrow :: forall (a :: Type). Play a -> Play a

Set height to fit content but grow if extra space is available.

#height Source

height :: forall a. Number -> PropF a

Set height to a fixed pixel value.

#topToBottom Source

topToBottom :: forall (a :: Type). Play a -> Play a

Set layout direction to arrange children vertically (top to bottom).

#leftToRight Source

leftToRight :: forall (a :: Type). Play a -> Play a

Set layout direction to arrange children horizontally (left to right). This is the default direction.

#(~*) Source

Operator alias for Play.playProp (left-associative / precedence 1)

Property application operator for chaining layout modifications. This is an alias for flipped function application just to distinguish layout-related calls from other ones. So it could be replaces with (#) operator at any place.

See the example of usage at Play a type above.

#playProp Source

playProp :: forall x a. x -> (x -> Play a) -> Play a

function

Re-exports from Play.Types

#WithRect Source

type WithRect a = { rect :: Rect, v :: a }

An element with its final computed rectangular bounds. The final result of layout computation, so holds Def data no more.

#WithDefSize Source

type WithDefSize a = { def :: Def, size :: Size, v :: a }

An element with layout definition and computed size. Intermediate state during layout computation.

#WithDefRect Source

type WithDefRect a = { def :: Def, rect :: Rect, v :: a }

An element with both layout definition and computed rectangular bounds. Contains complete layout information for potential rollback operations.

#WithDef Source

type WithDef a = { def :: Def, v :: a }

An element with its layout definition. Used during the initial layout specification phase.

#Sizing Source

data Sizing

Defines how an element should size itself along a particular axis.

  • None: No specific sizing constraint
  • Fixed Number: Fixed size in pixels
  • Fit: Size to fit the content (minimum required space)
  • Grow: Expand to fill available space
  • FitGrow: If fitting the content requires more space than growing, then fit anyway, else grow to fill the available space

Constructors

Instances

  • Eq Sizing

    FixedPct Percentage FitMin { min :: Number } FitMax { max :: Number } FitMinMax { min :: Number, max :: Number }

#Size Source

type Size = { height :: Number, width :: Number }

Dimensions of a rectangular area the item occupies. All values are in pixels.

#Rect Source

type Rect = { pos :: Pos, size :: Size }

A rectangular area defined by position and size. Represents the final computed layout bounds of an element.

#Pos Source

type Pos = { x :: Number, y :: Number }

A 2D position of the element's top-left corner.

#Padding Source

type Padding = { bottom :: Number, left :: Number, right :: Number, top :: Number }

Defines padding (inner spacing) for all four sides of an item. Means the space between the border of the item and its children on the corresponding sides. All values are in pixels.

#Offset Source

type Offset = Pos

An alias for Pos, used to represent relative offsets or displacements.

#Direction Source

data Direction

Defines the layout direction for arranging child elements.

  • TopToBottom: Children are arranged vertically from top to bottom
  • LeftToRight: Children are arranged horizontally from left to right

Constructors

Instances

#Def Source

type Def = { childGap :: Number, direction :: Direction, padding :: Padding, sizing :: { height :: Sizing, width :: Sizing } }

The compiled definition from user-specified with API layout properties. Not intented to be constructed manually.