upsiflu / less-ui / Less.Ui

Separate State and Layout of interface elements from the main model and build accessible patterns orthogonal to the Dom tree.


type alias Ui region html wrapper =
List (Item region html wrapper)



none : Ui region html wrapper
none =
    []


type Item region html wrapper

🐚

Create

singleton : html -> Ui region_ html wrapper_

🐌

wrap : wrapper -> Ui region_ html_ wrapper

Check out the default wrappers in Less.Ui.Html.

Modify

inRegion : region -> Ui region html wrapper -> Ui region html wrapper

Designate a region for each descendant.

Note that the last designation "wins".

#26: Once designated, Uis can't be redesignated

Append

a ++ b

Apply state

view : CurrentLayout region narrowHtml_ html narrowWrapper_ wrapper -> Ui region html wrapper -> html

⚠️ If you can, prefer one of the functions in Less such as application.


type alias Layout region narrowHtml html narrowWrapper customWrapper =
{ wrap : { current : Less.Link.State
, previous : Maybe Less.Link.State } -> customWrapper -> Wrapper region narrowHtml html narrowWrapper customWrapper
, concat : List html -> html
, arrange : { header : html
, region : region -> html } -> html 
}

The layout is a rule for mapping a Ui to an html tree.


type alias CurrentLayout region narrowHtml html narrowWrapper customWrapper =
{ wrap : customWrapper -> Wrapper region narrowHtml html narrowWrapper customWrapper
, concat : List html -> html
, concatDicts : List (AssocList.Dict (OrHeader region) html) -> AssocList.Dict (OrHeader region) html
, arrange : { header : html
, region : region -> html } -> html 
}

This type of Layout has its current and previous state already applied through applyStates.


type Wrapper region narrowHtml html narrowWrapper wrapper
    = Wrapped ({ howToWrapCurrentRegion : html -> html, howToWrapOtherRegions : html -> html }) (Ui region html wrapper)
    | Keyed ({ howToWrap : List ( String, html ) -> html }) (List ( String, Ui region html wrapper ))
    | Nested ({ regions : List region, narrowLayout : CurrentLayout region narrowHtml narrowHtml narrowWrapper narrowWrapper, combine : { makeInnerHtml : Ui region narrowHtml narrowWrapper -> Maybe narrowHtml } -> html })
    | Labeled ({ label : html, inHeader : Basics.Bool }) (Ui region html wrapper)

Create a custom wrapper to sneak functions into a functionless Ui. At the layout phase, you decide what your wrapper does:

You can either use the provided Wrapper or roll your own. Advantage of rolling your own wrapper type: You don't need to store functions in the Ui, which makes it comparable and serializable.

See Ui.Html for an example of a mostly defunctionalized wrapper.

Convenience

repeat : Basics.Int -> Ui region html wrapper -> Ui region html wrapper

repeat n =
    List.repeat n >> List.concat

Decompose

uncons : Ui region html wrapper -> Maybe ( Ui region html wrapper, Ui region html wrapper )

Attempt to separate the first descendant in the Ui.

Working with Regions


type OrHeader region
    = Header
    | Region region

Extend a sum type by a Header constructor. Every app in Less has a Header.

Advanced Usage

map : (html -> html2) -> Ui region html wrapper -> Ui region html2 wrapper

Modify the type of html in the Ui.

⚠️ If you can, build up your Ui with the final html type.

-- Todo: Tail Call Optimize.

indexedMapList : (Basics.Int -> Ui region html wrapper -> Ui region html wrapper) -> Ui region html wrapper -> Ui region html wrapper

Modify items Uis according to their order. For example, zip their indices between the elements:

singleton [1008] ++ singleton [2004] ++ singleton [1007]
    |> indexedMapList (\i -> (++) (singleton [i]))
    |> List.length
        --> 6

mapEach : (Ui region html wrapper -> Ui region2 html2 wrapper2) -> Ui region html wrapper -> Ui region2 html2 wrapper2

Modify each descendent as a separate Ui and then recombine them.

region html attribute wrapper   "A" ++ region html attribute wrapper   "B" ++ region html attribute wrapper   "C"
    |> mapEach ((++) (html ", "))
    ---> something like A, B, C

mutateWrappers : { leafToWrapper : html -> wrapper } -> (wrapper -> wrapper2) -> Ui region html wrapper -> Ui region html wrapper2

Modify the type of wrapper in the Ui and make sure every direct descendant is a wrapper so it can be modified

⚠️ If you can, build up your Ui with the final wrapper type.

Slated for removal

The following exports have no application and may be removed in the next release.

(currently nothing)