μλ
μΉκ΅¬,
Feliz(λ° μ€μ λ‘ Feliz.Bulma)μ μΌμΌ μ¬μ©μλ‘μ μ λ νμ prop.children
μ€μ²©μΌλ‘ μΈν΄ μ΄λ €μμ κ²ͺκ³ μμ΅λλ€. v2 μ μμ λν κ·νμ μ견μ μκ³ μΆμ΅λλ€.
Html.div [
prop.className "myClass"
Html.div "Nested"
]
μ΄μ©λ©΄ κ·Έλ° μΌμ΄ λΆκ°λ₯ν μλ μμ§λ§ Feliz.Engine μμ @alfonsogarciacaroμ μμ μ 보μκ³ κ°μ μμ€μ μνκ³Ό μ΄λ¦°μ΄λ₯Ό κ°λ κ²μ΄ λ무 μ νΉμ μΈ κ² κ°μ΅λλ€. π
μ΄λ° μ’
λ₯μ μ§μμ μΆκ°νλ©΄ μ ν μΆλ‘ μ΄ ν¨μ¬ λ κ΄λν΄μ§λλ€(λλ μΈλͺ¨μλ€κ³ λ§ν μλ μμ΅λλ€). κ·Έλ¬λ©΄ Attribute = Properties = ReactElement
κ° μκΈ° λλ¬Έμ
λλ€. κΈ°λ³Έμ μΌλ‘ λͺ¨λ κ²μ΄ κ°μ μ νμΌλ‘ λ°μλ€μ¬μ§ κ²μ
λλ€...
λν μ΄λ₯Ό κ°λ₯νκ² νλ €λ©΄ νμ μΆκ° λ¨κ³κ° νμνκΈ° λλ¬Έμ μ±λ₯μ μν₯μ λ―ΈμΉ "μλμΌλ‘" μμμ μμ±μ λΆν νκΈ° μν΄ React μμ μΆκ° λ μ΄μ΄λ₯Ό μΆκ°ν΄μΌ ν©λλ€. μ΄κ²μ λν λΆλ¦¬λ₯Ό λ§λλ λ° νμν μ 보λ₯Ό μ μ₯νκΈ° μν΄ λ²λ€ ν¬κΈ°λ₯Ό μ¦κ°μν΅λλ€.
κ°μΈμ μΌλ‘ λλ μ΄ κΈ°λ₯μ μ’μνμ§ μμ΅λλ€.
λλ μ£Όλ‘ λ λλ§μ μΆκ°λλ λ°νμ μ€λ²ν€λ λλ¬Έμ μ΄ μ κ·Ό λ°©μμ λν΄ μκ°λ¦° κ°μ μ κ°μ§κ³ μμ΅λλ€. λν λλ μκ°μ μ μ§νλ κ²μ μ νΈ κ² ReactElement
μμ λ³λμ ReactAttribute
. κ·Έλμ κ°μΈμ μΌλ‘ νμ¬ APIλ₯Ό ν¨μ¬ λ μ νΈν©λλ€.
λ΄ κ²½νμ λ°λ₯΄λ©΄ μ¬μ©μλ‘λΆν° μ΄ λ¬Έμ μ λν΄ λ§μ΄ λ€μμ§λ§ ν΄λμ€ μ΄λ¦κ³Ό μμμ΄ μλ div
컨ν
μ€νΈμμλ§ _λ§_μ
λλ€. λ΄ μΌλ°μ μΈ μλ΅μ μ΄μ μ μ¬ν κ²μ μμ±ν μ μλ μμ λμ°λ―Έ κΈ°λ₯μ μμ±νλ κ²μ
λλ€.
div [ "myClass" ] [
Html.div "nested"
]
μ¬κΈ°μμ Material UIμμ νλ κ²μ²λΌ ν΄λμ€ λλ κΈ°ν μμ£Ό μ¬μ©νλ μμ±μ μ μ©νλ ν¨κ³Όμ λ μ ν©νλ€λ©΄ κ³ μ ν νμ₯ λ©μλλ₯Ό μμ±νμ§ μμ μ΄μ κ° μλ κ² κ°μ΅λλ€. μ»΄νμΌλ¬λ₯Ό λ νΌλμ€λ½κ² νκ±°λ νμ μμ μ±μ κ°μμν€μ§ μμΌλ©΄μ F#μ μ¬μ©νλ©΄ κ΅¬μ± κ°λ₯μ±μ΄ μμ ν μ¬λΌμ§λλ€.
[<AutoOpen>]
module MuiExtensions
open Feliz
open Feliz.MaterialUI
type Mui
with
static member gridItem (children:seq<ReactElement>):ReactElement =
Mui.grid [
grid.item true
grid.children children
]
static member gridItem (props:seq<IReactProperty>):ReactElement =
Mui.grid [
grid.item true
yield! props
]
λͺ¨λ μ견μ κ°μ¬λ립λλ€. μ λ ν λ‘ νλ¦μ μνμ΅λλ€. π μ μκ²λ divClassed "myClass" [ children ]
μ λμ μ λ§μ λμ°λ―Έκ° μμ§λ§ λ€λ₯Έ μ¬λμ κ΄μ μ μκ³ μΆμμ΅λλ€.
μ΄κ²μ React μμλ₯Ό λͺ©λ‘μμ κ³μ° ννμμΌλ‘ λ³κ²½ν κ²½μ° μ ν μ νμ μ μ§νλ©΄μ μ€μ λ‘ κ°λ₯ν΄μΌ ν©λλ€.
div {
className "myClass"
div { ... }
}
CE ꡬνμ μ½λλ² μ΄μ€μ ν¬κΈ°λ₯Ό λλ¦¬κ³ μ μ§ κ΄λ¦¬λ₯Ό λ μ΄λ ΅κ² λ§λ€λ©° propsκ° μ μλ ββλ κΈ°λ³Έ μμμ κ°μ μΌλΆλ₯Ό μ²λ¦¬νλ κ²μ μ½κ° κΉλ€λ‘μ΅λλ€/μ§κΈμ²λΌ κ°λ° μ€μ΄ μλλΌ μ»΄νμΌ μ μ€ν¨ν΄μΌ ν©λλ€.
// Would probably need to make the base builder generic so we can use a type restriction and define this DU for
// each element so we can properly restrict what types are valid as primatives
type ReactBuilderChild =
| Child of ReactElement
| Children of ReactElement list
| Float of float
| Int of int
| String of string
| None
member this.GetChildren () =
match this with
| ReactBuilderChild.Children children -> children
| _ -> failwith "Cannot combine children with primitive values."
type ReactBuilderState =
{ Children: ReactElement list
Props: IReactProperty list }
[<AbstractClass;NoEquality;NoComparison>]
type ReactBuilder () =
[<EditorBrowsable(EditorBrowsableState.Never)>]
member _.Yield (x: ReactElement) = { Children = ReactBuilderChild.Child x; Props = [] }
[<EditorBrowsable(EditorBrowsableState.Never)>]
member _.Yield (x: ReactElement list) = { Children = ReactBuilderChild.Children x; Props = [] }
[<EditorBrowsable(EditorBrowsableState.Never)>]
member _.Yield (x: float) = { Children = ReactBuilderChild.Float x; Props = [] }
...
[<EditorBrowsable(EditorBrowsableState.Never)>]
member _.Yield (x: unit) = { Children = ReactBuilderChild.None; Props = [] }
[<EditorBrowsable(EditorBrowsableState.Never)>]
member _.Combine (state: ReactBuilderState, x: ReactBuilderState) =
{ Children = (state.Children.GetChildren()) @ (x.Children.GetChildren()); Props = state.Props @ x.Props }
[<EditorBrowsable(EditorBrowsableState.Never)>]
member _.Zero () = { Children = ReactBuilderChild.None; Props = [] }
[<EditorBrowsable(EditorBrowsableState.Never)>]
member this.For (state: ReactBuilderState, f: unit -> ReactBuilderState) = this.Combine(state, f())
[<CustomOperation("className")>]
member _.className (state: ReactBuilderState, value: string) =
{ state with Props = (Interop.mkAttr "className" value)::state.Props }
[<CustomOperation("children")>]
member _.children (state: ReactBuilderState, value: ReactElement list) =
{ state with Children = state.Children @ value }
abstract Run : ReactBuilderState -> ReactElement
[<NoEquality;NoComparison>]
type DivBuilder () =
inherit ReactBuilder()
[<EditorBrowsable(EditorBrowsableState.Never)>]
member _.Run (state: ReactBuilderState) =
match state with
| { Children = ReactBuilderChild.None; Props = props } -> Interop.createElement "div" props
| { Children = ReactBuilderChild.Children children } -> Interop.reactElementWithChildren "div" children
| { Children = ReactBuilderChild.Float f } -> Interop.reactElementWithChild "div" f
| _ -> ...
let div = DivBuilder()
λ΄κ° νμ ν μ μλ κ²μ Fableμ΄ CE λ°°κ΄μ μΌλΆ/μ 체λ₯Ό μ¬λ°λ₯΄κ² μ»΄νμΌνκ³ μμ
μ κ²μ κ°λ₯νκ² λ§λλ λ°©λ²μ
λλ€(νμ¬ prop
μ νμΈ κ²μ²λΌ).
ν λ‘ μ£Όμ λ₯Ό λνλ΄κΈ° μν΄ μ λͺ©μ λ³κ²½ν΄ λ¬λΌλ μ²μμ? π
@Dzoukr μ΄μ λν μ΄μ ν λ‘ μ΄ μμμ΅λλ€. μ λ νμ€ν λΉμ νΈμ λλ€.
λμ°λ―Έ ν¨μλ μ΄μν μ΄μ€ λͺ©λ‘ ꡬ문μ λ€μ κ°μ Έμ κΈ°λ³Έμ μΌλ‘ μ΄ libμ μ£Όμ μ΄μ μ€ νλλ₯Ό μ κ±°νκ³ div+class μ΄μμ μ€μ prop μ¬μ©μ λμμ΄ λμ§ μκΈ° λλ¬Έμ μ΄μμ μ΄μ§ μμ΅λλ€.
@Zaid-Ajaj μ΄ μμμ νμνκΈ° μν΄ λ체 λ€μμ€νμ΄μ€λ₯Ό μ΄μ΄ μ£Όμκ² μ΅λκΉ? Feliz.Experimental κ°μκ±°μ? λ°λΌμ κΈ°λ³Έ Feliz λ€μμ€νμ΄μ€λ Reactλ³΄λ€ μμ λ μ΄μ΄μ λͺ©νλ₯Ό μ μ§νλ λ°λ©΄ λ체λ λ λ λ¨μ μΈ μ κ·Όμ μλν μ μμ΅λλ€.
μ΄μ¨λ , λλ μν κ·Έλ£Ήνλ₯Ό μ μ§νκΈ° μν΄ λ€μκ³Ό κ°μ κ²μ μ’μν©λλ€.
Html.div [
props [
prop.className "myClass"
]
Html.div "Nested"
]
props μ€μ²©μ μμκ° μλ λ°©μμΌλ‘ 무ν μ€μ²©μ΄ μ μ©λμ§ μκΈ° λλ¬Έμ prop μ€μ²©μ΄ μμ μ€μ²©λ³΄λ€ λ κΉλν΄ λ³΄μ
λλ€. props
컨ν
μ΄λλ Html.*
μμμ μΈν°νμ΄μ€λ₯Ό 곡μ νμ¬ λ λ€ ν¬ν¨νλ μμμ μ ν¨ν μμμΌλ‘ λͺ¨λΈλ§ν©λλ€.
μ±λ₯μ μ§μΌλ΄μΌ ν λΆλΆμ΄μ§λ§ μλνμ§ μκ³ λ κ·Έ μν₯μ μ μ μλ€κ³ μκ°ν©λλ€. λκ° μκ² μ΄μ. μΆκ° μμ μ΄ λ¬΄μκ² λ€λ¦΄μ§ λͺ¨λ₯΄μ§λ§ μ€μ λ‘λ λ λλ§μμ λ°μνλ λ€λ₯Έ λͺ¨λ μμ μ λΉν΄ μ€μνμ§ μμ΅λλ€.
@zanaptak λ§μνμ λλ‘ μνλ€μ΄ μμ΄λ€μ²λΌ κΉκ² μμ΄μ μ λ κ·Έ μμ΄λμ΄κ° μμ£Ό μ’μ΅λλ€.
λμ°λ―Έ λ° μ΄μ€ λͺ©λ‘ ꡬ문 μ£Όμ
div+classλ³΄λ€ ν¨μ¬ λ λ§μ μ€μ μν μ¬μ©μ λμμ΄ λμ§ μμ΅λλ€.
let inline withProps elementFunction props (children: #seq<ReactElement>) =
(prop.children (children :> ReactElement seq))
:: props
|> elementFunction
let myDiv = withProps Html.div
myDiv [ prop.className "myClass" ] [
Html.div "Nested"
]
μνλ κ²½μ° λͺ¨λ μμμ "μ΄μ€ λͺ©λ‘"κ³Ό κ°μ ꡬ문μ μ¬μ©νλλ‘ μ°μ°μλ₯Ό μ μν μλ μμ΅λλ€.
let inline (@+) elementFunction props =
fun children -> withProps elementFunction props children
let inline (@++) elementFunction prop =
fun children -> withProps elementFunction [ prop ] children
Html.div @+ [ prop.className "myClass" ]
<| [ Html.div "nested" ]
Html.div @++ prop.className "myClass"
<| [ Html.div "nested" ]
"λ μ’μ 보μ΄λ" κ²μ΄ μ£Όκ΄μ μΌ μ μκΈ° λλ¬Έμ μ΄κ²μ κΉλ€λ‘μ΄ μ£Όμ μ λλ€. μλ§λ κ°μ₯ μ€μν κ²μ μ£Όμ λ³κ²½ μ¬νμ νΌνλ κ²μ΄μ§λ§, μ€νμ νκ³ μΆλ€λ©΄ Feliz.Engine μ μ¬μ©νλ©΄ λ©λλ€.
// Dependencies:
// - Fable.React
// - Feliz.Engine.Event dependencies
open Fable.Core
open Fable.Core.JsInterop
open Feliz
open Fable.React
type Node =
| El of ReactElement
| Style of string * string
| Prop of string * obj
member this.AsReactEl =
match this with
| El el -> el
| _ -> failwith "not an element"
let private makeNode tag nodes =
let props = obj()
let style = obj()
let children = ResizeArray()
nodes |> Seq.iter (function
| El el -> children.Add(el)
| Style(k, v) -> style?(k) <- v
| Prop(k, v) -> props?(k) <- v
)
if JS.Constructors.Object.keys(style).Count > 0 then
props?style <- style
ReactBindings.React.createElement(tag, props, children) |> El
let Html = HtmlEngine(makeNode, str >> El, fun () -> El nothing)
let Svg = SvgEngine(makeNode, str >> El, fun () -> El nothing)
let prop = AttrEngine((fun k v -> Prop(k, v)), (fun k v -> Prop(k, v)))
let style = CssEngine(fun k v -> Style(k, v))
let ev = EventEngine(fun k f -> Prop("on" + k.[0].ToString().ToUpper() + k.[1..], f))
ν μ€νΈ:
let myEl = // Node
Html.div [
prop.className "myClass"
Html.div "Nested"
]
let myElAsReactEl = myEl.AsReactEl // ReactElement
λμ°λ―Έ ν¨μλ μ΄μν μ΄μ€ λͺ©λ‘ ꡬ문μ λ€μ κ°μ Έμ€κΈ° λλ¬Έμ μ΄μμ μ΄μ§ μμ΅λλ€.
@zanaptak λμ°λ―Έ ν¨μλ λ κ°μ λͺ©λ‘μ μ
λ ₯μΌλ‘ μ¬μ©ν νμκ° μμ΅λλ€. div [ "class" ] [ ]
λ λ κ°μ λͺ©λ‘μ κ°μ Έμ€λ μΌλ°μ μΈ μλ리μ€μ ν μμΌ λΏμ
λλ€. μ΄λ¬ν κΈ°λ₯μ 보기λ₯Ό λ λ¨μνκ² λ§λλ κ΅¬μ± μμμΌ μλ μμ΅λλ€.
Todo.List [ for item in items -> Todo.Item item ]
κΈ°μ μ μΌλ‘ λͺ©λ‘μ 무νλλ‘ μ€μ²©ν μ μμ§λ§ κ·Έκ²μ μμ΄λμ΄κ° μλλλ€. λ ν° UI μ½λμμ λ μμ κΈ°λ₯μ΄λ κ΅¬μ± μμλ₯Ό μ¬μ©νλ©΄ κ· νμ΄ μ μ§λ©λλ€.
κ·Έλ¬λ μ΄μμ μΌλ‘λ μ½λλ₯Ό μμ£Ό λΆν΄ν νμκ° μμΌλ©° νλμ κΈ°λ₯μ κ°λ₯ν ν μ½κΈ° μ¬μμΌ ν©λλ€. μ 리νλ μκ°μ΄ λλλ‘ _flow_λ₯Ό μμ κΈ° λλ¬Έμ
λλ€. μ΄κ²μ Fable.Reactμ DSLμ λ¬Έμ μμ΅λλ€. μ¬κΈ°μ λ§€λ² νμμ μ§μ νλ λ°©λ²μ λν΄ _μκ°_ν΄μΌ νμ΅λλ€. Felizλ children
μ λ μμ€ μ€μ²©μ ν¬μνμ¬ μ΄ λ¬Έμ λ₯Ό μμ ν©λλ€.
μμ§ν μμ΄μμ΄ λμ§ μ λͺ¨λ₯΄κ² μ΅λλ€. @alfonsogarciacaroκ° λ§νλ―μ΄
"λ μ’μ 보μ΄λ" κ²μ΄ μ£Όκ΄μ μΌ μ μκΈ° λλ¬Έμ μ΄κ²μ κΉλ€λ‘μ΄ μ£Όμ μ λλ€.
μ€ν μ£Όμ :
μ΄ μμμ νμνκΈ° μν΄ λ체 λ€μμ€νμ΄μ€λ₯Ό μ΄μ΄ μ£Όμκ² μ΅λκΉ? Feliz.Experimental κ°μκ±°μ? λ°λΌμ κΈ°λ³Έ Feliz λ€μμ€νμ΄μ€λ Reactλ³΄λ€ μμ λ μ΄μ΄μ λͺ©νλ₯Ό μ μ§νλ λ°λ©΄ λ체λ λ λ λ¨μ μΈ μ κ·Όμ μλν μ μμ΅λλ€.
νμ¬λ‘μλ Feliz νλ‘μ νΈμμ λ€λ₯Έ DSLμ μ μ§ν κ³νμ΄ μμ΅λλ€. μ λ OSS μκ°/μ©λμ΄ λ§€μ° μ νλμ΄ μμΌλ©° λ¬Έμ, μν λ° λ μ ν μ€νΈλ μνκ³ λΌμ΄λΈλ¬λ¦¬μ κ°μ νμ¬ μ κ·Ό λ°©μμ κ°μ νκΈ° μν λ Έλ ₯μ κΈ°μΈμ΄κ³ μΆμ΅λλ€.
μ¦, @alfonsogarciacaroμ Feliz.Engineμ μμ λ‘κ² μ€ννκ³ μμ μκ² λ μ ν©ν DSLμ μ¬μ©νμμμ€.
κ°μ₯ μ μ©ν λκΈ
ν λ‘ μ£Όμ λ₯Ό λνλ΄κΈ° μν΄ μ λͺ©μ λ³κ²½ν΄ λ¬λΌλ μ²μμ? π
@Dzoukr μ΄μ λν μ΄μ ν λ‘ μ΄ μμμ΅λλ€. μ λ νμ€ν λΉμ νΈμ λλ€.
λμ°λ―Έ ν¨μλ μ΄μν μ΄μ€ λͺ©λ‘ ꡬ문μ λ€μ κ°μ Έμ κΈ°λ³Έμ μΌλ‘ μ΄ libμ μ£Όμ μ΄μ μ€ νλλ₯Ό μ κ±°νκ³ div+class μ΄μμ μ€μ prop μ¬μ©μ λμμ΄ λμ§ μκΈ° λλ¬Έμ μ΄μμ μ΄μ§ μμ΅λλ€.
@Zaid-Ajaj μ΄ μμμ νμνκΈ° μν΄ λ체 λ€μμ€νμ΄μ€λ₯Ό μ΄μ΄ μ£Όμκ² μ΅λκΉ? Feliz.Experimental κ°μκ±°μ? λ°λΌμ κΈ°λ³Έ Feliz λ€μμ€νμ΄μ€λ Reactλ³΄λ€ μμ λ μ΄μ΄μ λͺ©νλ₯Ό μ μ§νλ λ°λ©΄ λ체λ λ λ λ¨μ μΈ μ κ·Όμ μλν μ μμ΅λλ€.
μ΄μ¨λ , λλ μν κ·Έλ£Ήνλ₯Ό μ μ§νκΈ° μν΄ λ€μκ³Ό κ°μ κ²μ μ’μν©λλ€.
props μ€μ²©μ μμκ° μλ λ°©μμΌλ‘ 무ν μ€μ²©μ΄ μ μ©λμ§ μκΈ° λλ¬Έμ prop μ€μ²©μ΄ μμ μ€μ²©λ³΄λ€ λ κΉλν΄ λ³΄μ λλ€.
props
컨ν μ΄λλHtml.*
μμμ μΈν°νμ΄μ€λ₯Ό 곡μ νμ¬ λ λ€ ν¬ν¨νλ μμμ μ ν¨ν μμμΌλ‘ λͺ¨λΈλ§ν©λλ€.μ±λ₯μ μ§μΌλ΄μΌ ν λΆλΆμ΄μ§λ§ μλνμ§ μκ³ λ κ·Έ μν₯μ μ μ μλ€κ³ μκ°ν©λλ€. λκ° μκ² μ΄μ. μΆκ° μμ μ΄ λ¬΄μκ² λ€λ¦΄μ§ λͺ¨λ₯΄μ§λ§ μ€μ λ‘λ λ λλ§μμ λ°μνλ λ€λ₯Έ λͺ¨λ μμ μ λΉν΄ μ€μνμ§ μμ΅λλ€.