mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 21:39:07 +00:00
156 lines
4.6 KiB
Text
156 lines
4.6 KiB
Text
interface Html.Internal.Shared
|
|
exposes [
|
|
App,
|
|
Html,
|
|
Attribute,
|
|
CyclicStructureAccessor,
|
|
Handler,
|
|
Size,
|
|
element,
|
|
text,
|
|
none,
|
|
translate,
|
|
translateStatic,
|
|
nodeSize,
|
|
]
|
|
imports [
|
|
Action.{ Action },
|
|
]
|
|
|
|
App state initData : {
|
|
init : DecodingResult initData -> state,
|
|
render : state -> Html state,
|
|
wasmUrl : Str,
|
|
}
|
|
|
|
DecodingResult a : Result a [Leftover (List U8), TooShort]
|
|
|
|
Html state : [
|
|
None,
|
|
Text Str,
|
|
Element Str Size (List (Attribute state)) (List (Html state)),
|
|
]
|
|
|
|
# The pre-calculated byte size of the rendered HTML string
|
|
Size : Nat
|
|
|
|
Attribute state : [
|
|
EventListener Str (List CyclicStructureAccessor) (Handler state),
|
|
HtmlAttr Str Str,
|
|
DomProp Str (List U8),
|
|
Style Str Str,
|
|
]
|
|
|
|
CyclicStructureAccessor : [
|
|
ObjectField Str CyclicStructureAccessor,
|
|
ArrayIndex U32 CyclicStructureAccessor,
|
|
SerializableValue,
|
|
]
|
|
|
|
# If we are only exposing the functions then are we better off just turning everything into a Custom?
|
|
# At some point we need a common format anyway. Wrapper lambda is irrelevant for perf in context of an event.
|
|
Handler state : [
|
|
Normal (state, List (List U8) -> Action state),
|
|
Custom (state, List (List U8) -> { action : Action state, stopPropagation : Bool, preventDefault : Bool }),
|
|
]
|
|
|
|
# -------------------------------
|
|
# VIEW FUNCTIONS
|
|
# -------------------------------
|
|
## Define an HTML Element
|
|
element : Str -> (List (Attribute state), List (Html state) -> Html state)
|
|
element = \tagName ->
|
|
\attrs, children ->
|
|
# While building the node nodes, calculate the size of Str it will render to
|
|
withTag = 2 * (3 + Str.countUtf8Bytes tagName)
|
|
withAttrs = List.walk attrs withTag \acc, attr -> acc + attrSize attr
|
|
totalSize = List.walk children withAttrs \acc, child -> acc + nodeSize child
|
|
|
|
Element tagName totalSize attrs children
|
|
|
|
text : Str -> Html state
|
|
text = \content -> Text content
|
|
|
|
none : Html state
|
|
none = None
|
|
|
|
nodeSize : Html state -> Nat
|
|
nodeSize = \node ->
|
|
when node is
|
|
Text content -> Str.countUtf8Bytes content
|
|
Element _ size _ _ -> size
|
|
None -> 0
|
|
|
|
attrSize : Attribute state -> Nat
|
|
attrSize = \attr ->
|
|
when attr is
|
|
EventListener _ _ _ -> 0
|
|
HtmlAttr key value -> 4 + Str.countUtf8Bytes key + Str.countUtf8Bytes value
|
|
DomProp _ _ -> 0
|
|
Style key value -> 4 + Str.countUtf8Bytes key + Str.countUtf8Bytes value
|
|
|
|
# -------------------------------
|
|
# TRANSLATE STATE TYPE
|
|
# -------------------------------
|
|
translate : Html c, (p -> c), (c -> p) -> Html p
|
|
translate = \node, parentToChild, childToParent ->
|
|
when node is
|
|
Text content ->
|
|
Text content
|
|
|
|
Element name size attrs children ->
|
|
newAttrs = List.map attrs \a -> translateAttr a parentToChild childToParent
|
|
newChildren = List.map children \c -> translate c parentToChild childToParent
|
|
|
|
Element name size newAttrs newChildren
|
|
|
|
None -> None
|
|
|
|
translateAttr : Attribute c, (p -> c), (c -> p) -> Attribute p
|
|
translateAttr = \attr, parentToChild, childToParent ->
|
|
when attr is
|
|
EventListener eventName accessors childHandler ->
|
|
EventListener eventName accessors (translateHandler childHandler parentToChild childToParent)
|
|
|
|
HtmlAttr k v -> HtmlAttr k v
|
|
DomProp k v -> DomProp k v
|
|
Style k v -> Style k v
|
|
|
|
translateHandler : Handler c, (p -> c), (c -> p) -> Handler p
|
|
translateHandler = \childHandler, parentToChild, childToParent ->
|
|
when childHandler is
|
|
Normal childFn ->
|
|
parentFn = \parentState, jsons ->
|
|
parentState |> parentToChild |> childFn jsons |> Action.map childToParent
|
|
|
|
Normal parentFn
|
|
|
|
Custom childFn ->
|
|
parentFn = \parentState, jsons ->
|
|
{ action, stopPropagation, preventDefault } = childFn (parentToChild parentState) jsons
|
|
|
|
{ action: action |> Action.map childToParent, stopPropagation, preventDefault }
|
|
|
|
Custom parentFn
|
|
|
|
translateStatic : Html state -> Html *
|
|
translateStatic = \node ->
|
|
when node is
|
|
Text content ->
|
|
Text content
|
|
|
|
Element name size attrs children ->
|
|
newAttrs = List.keepOks attrs keepStaticAttr
|
|
newChildren = List.map children translateStatic
|
|
|
|
Element name size newAttrs newChildren
|
|
|
|
None -> None
|
|
|
|
keepStaticAttr : Attribute _ -> Result (Attribute *) {}
|
|
keepStaticAttr = \attr ->
|
|
when attr is
|
|
EventListener _ _ _ -> Err {}
|
|
HtmlAttr k v -> Ok (HtmlAttr k v)
|
|
DomProp _ _ -> Err {}
|
|
Style k v -> Ok (Style k v)
|