Skip to content

Instantly share code, notes, and snippets.

@lukaszkrzywizna
Last active May 17, 2024 15:12
Show Gist options
  • Save lukaszkrzywizna/917d8f994082bab595d949bbd4dd3dc5 to your computer and use it in GitHub Desktop.
Save lukaszkrzywizna/917d8f994082bab595d949bbd4dd3dc5 to your computer and use it in GitHub Desktop.
[<Erase>]
type IProp<'comp when 'comp : not struct> = | Prop of string * obj
with
static member inline Create (value: string * obj) = Prop value
static member inline Build(props: IProp<'comp> seq) = props |> unbox<(string * obj) seq> |> createObj |> unbox<'comp>
let inline (!<) x = IProp.Build x
module Interop =
let inline mkProperty<'Component when 'Component : not struct> (key:string) (value:obj) : IProp<'Component> =
IProp.Create (key, value)
// Interfaces with attributes has two sections:
// 1) abstract member used for prop access withing the component
// 2) static member inline functions - used for prop creation (later transformed into an object with IProp.Build)
[<Interface>]
type AriaAttributes =
abstract member ``aria-activedescendant`` : string option with get
static member inline AriaActiveDescendant (id: string) =
Interop.mkProperty<#AriaAttributes> (nameof(Unchecked.defaultof<AriaAttributes>.``aria-activedescendant``)) id
abstract member ``aria-atomic`` : bool option with get
static member inline AriaAtomic (value: bool) =
Interop.mkProperty<#AriaAttributes> (nameof(Unchecked.defaultof<AriaAttributes>.``aria-atomic``)) value
// and more...
[<Interface>]
type DOMAttributes<'element & #Element & #EventTarget> =
abstract member onCopy : ClipboardEventHandler<'element> option with get
static member inline OnCopy (value: ClipboardEventHandler<'element>) =
Interop.mkProperty<#DOMAttributes<'element>> (nameof(Unchecked.defaultof<DOMAttributes<'element>>.onCopy)) value
// and more...
[<Interface>]
type HTMLAttributes<'element & #Element & #EventTarget> =
inherit AriaAttributes
inherit DOMAttributes<'element>
// React-specific Attributes
abstract member defaultChecked: bool option with get
static member inline DefaultChecked (value: bool) =
Interop.mkProperty<#HTMLAttributes<'element>> (nameof(Unchecked.defaultof<HTMLAttributes<'element>>.defaultChecked)) value
// and more...
[<Interface>]
type InputHTMLAttributes<'element & #Element & #EventTarget> =
inherit HTMLAttributes<'element>
abstract member disabled: bool option with get
static member inline Disabled (value: bool) =
Interop.mkProperty<#InputHTMLAttributes<'element>> (nameof(Unchecked.defaultof<InputHTMLAttributes<'element>>.disabled)) value
[<Interface>]
type input =
inherit InputHTMLAttributes<HTMLInputElement>
[<Erase>]
type Html =
static member inline input (props: input) = Interop.reactElement "input" props
static member inline input (xs: IProp<input> list) = Html.input !< xs
/// We can build the input element using props from all inherited interfaces.
Html.input [
input.DefaultChecked true
input.Disabled false // only available for input type
input.OnCopy(fun (e: ClipboardEventHandler<HTMLInputElement>) -> ignore e) // note the event type
]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment