Skip to content

Instantly share code, notes, and snippets.

@OnurGumus
Created July 19, 2023 16:59
Show Gist options
  • Save OnurGumus/bbee215eca9c5a6995dd241bfb0b0f4a to your computer and use it in GitHub Desktop.
Save OnurGumus/bbee215eca9c5a6995dd241bfb0b0f4a to your computer and use it in GitHub Desktop.
import { useRef, useState } from "react";
import ReactDOM from "react-dom";
import { createRoot } from 'react-dom/client'
import { Canvas, MeshProps, useFrame } from '@react-three/fiber'
import { Mesh } from "three";
import React from "react";
function Box(props) {
// This reference will give us direct access to the mesh
const mesh = useRef<Mesh>(null!)
// Set up state for the hovered and active state
const [hovered, setHover] = useState(false)
const [active, setActive] = useState(false)
const f = mesh?.current?.rotation!
// Subscribe this component to the render-loop, rotate the mesh every frame
useFrame((state, delta) =>(mesh.current.rotation.x += delta))
// Return view, these are regular three.js elements expressed in JSX
return (
<mesh
{...props}
ref={mesh}
scale={active ? 1.5 : 1}
onClick={(event) => setActive(!active)}
onPointerOver={(event) => setHover(true)}
onPointerOut={(event) => setHover(false)}>
<boxGeometry args={[1, 1, 1]} />
<meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
</mesh>
)
}
interface IAboutProps { title : string ; }
export const About = (props:IAboutProps ) => {
return (
<Canvas>
<ambientLight />
<pointLight position={[10, 10, 10]} />
<Box position={[-1.2, 0, 0]} />
<Box position={[1.2, 0, 0]} />
</Canvas>)
}
module Sample.Components
open Browser.Types
open Lit
open LitStore
let private hmr = HMR.createToken ()
open Types
[<HookComponent>]
let LocalNameInput () =
Hook.useHmr (hmr)
let ctx = Hook.useStore (AppContext.store)
let value, setValue = Hook.useState "Local"
let inputRef = Hook.useRef<HTMLInputElement> ()
let className =
Hook.use_scoped_css
"""
input {
border-radius: 7.5px;
}
"""
html
$"""
<div class="{className} content">
<p>Local state: <i>{ctx.Username} {value}!</i></p>
<label>
"Name:"
<input class="name-input"
{Lit.refValue inputRef}
value={value}
@keyup={EvVal (fun s-> setValue s; AppContext.dispatch (AppContext.SetUsername s))}
@focus={Ev(fun _ ->
inputRef.Value
|> Option.iter (fun el -> el.select ())
)}>
</label>
</div>
"""
module ReactLib =
open Feliz
[<ReactComponent(import="About", from="./About.tsx")>]
let About (title: string) = React.imported()
[<ReactComponent>]
let MyComponent showClock =
let m = React.ofLit (LocalNameInput())
let state, setState = React.useState 0
React.useEffectOnce (
(fun () ->
printfn "Initializing React component..."
React.createDisposable (fun () -> printfn "Disposing React component...")
)
)
Html.div [
prop.className "card"
prop.children [
Html.div [
prop.className "card-content"
prop.children [
m
Html.div [
prop.className "content"
prop.children [
Html.p
$"""I'm a React component. Clock is {if showClock then
"visible"
else
"hidden"}"""
Html.button [
prop.className "button"
prop.onClick (fun _ -> setState (state + 1))
prop.text $"""Clicked {state} time{if state = 1 then "" else "s"}!"""
]
]
]
]
]
]
]
let ReactLitComponent = React.toLit ReactLib.MyComponent true
let ReactLitComponent2 = React.toLit ReactLib.About
// This render function integrates with Elmish and doesn't keep local state
let elmishNameInput value dispatch =
html
$"""
<div class="content">
<p>Elmish state: <i>Hello {value}!</i></p>
<label>
Name:
<input class="name-input"
value={value}
@keyup={EvVal dispatch}>
</label>
</div>
"""
// This function keeps local state and can use hooks
[<HookComponent>]
let ClockDisplay model dispatch =
Hook.useHmr (hmr)
let ctx = Hook.useStore (AppContext.store)
let transitionMs = 800
let clasName =
Hook.use_scoped_css
$"""
.clock-container {{
transition-duration: {transitionMs}ms;
}}
.clock-container.transition-enter {{
opacity: 0;
transform: scale(2) rotate(1turn);
}}
.clock-container.transition-leave {{
opacity: 0;
transform: scale(0.1) rotate(-1.5turn);
}}
@keyframes move-side-by-side {{
from {{ margin-left: -50%%; }}
to {{ margin-left: 50%%; }}
}}
button {{
animation: 1.5s linear 1s infinite alternate move-side-by-side;
}}
"""
let transition =
Hook.useTransition (
transitionMs,
onEntered = (fun () -> ToggleClock true |> dispatch),
onLeft = (fun () -> ToggleClock false |> dispatch)
)
let clockContainer () =
html
$"""
<div class="clock-container {transition.className}">
<my-clock
minute-colors="white, red, yellow, purple"
hour-color="yellow"></my-clock>
</div>
"""
html
$"""
<div class="{clasName} vertical-container">
<button class="button"
style="margin: 1rem 0"
?disabled={transition.isRunning}
@click={Ev(fun _ ->
AppContext.dispatch (AppContext.SetUsername "onur")
if model.ShowClock then
transition.triggerLeave ()
else
transition.triggerEnter ()
)}>
{ctx.Username} clock
</button>
{if transition.hasLeft then
Lit.nothing
else
clockContainer ()}
</div>
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment