Skip to content

Commit

Permalink
Feliz v1.17 with new [Hook] attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
Zaid-Ajaj committed Nov 15, 2020
1 parent 811d5ee commit e959306
Show file tree
Hide file tree
Showing 19 changed files with 128 additions and 33 deletions.
2 changes: 1 addition & 1 deletion .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
]
},
"fable": {
"version": "3.0.0-nagareyama-beta-002",
"version": "3.0.0-nagareyama-rc-007",
"commands": [
"fable"
]
Expand Down
4 changes: 4 additions & 0 deletions Feliz.CompilerPlugins/AstUtils.fs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ let isRecord (compiler: PluginHelper) (fableType: Fable.Type) =
| Fable.Type.DeclaredType (entity, genericArgs) -> compiler.GetEntity(entity).IsFSharpRecord
| _ -> false

let isReactElement (fableType: Fable.Type) =
match fableType with
| Fable.Type.DeclaredType (entity, genericArgs) -> entity.QualifiedName.EndsWith "ReactElement"
| _ -> false

let recordHasField name (compiler: PluginHelper) (fableType: Fable.Type) =
match fableType with
Expand Down
5 changes: 3 additions & 2 deletions Feliz.CompilerPlugins/Feliz.CompilerPlugins.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@
<PackageLicenseUrl>https://github.com/Zaid-Ajaj/Feliz/blob/master/LICENSE</PackageLicenseUrl>
<PackageTags>fsharp;fable;react;html</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>0.3.0</Version>
<Version>0.4.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Update AST version</PackageReleaseNotes>
<PackageReleaseNotes>Implement [Hook] Attribute</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<Compile Include="AstUtils.fs" />
<Compile Include="ReactComponent.fs" />
<Compile Include="Hook.fs" />
<Compile Include="PrimitiveElement.fs" />
<Compile Include="PrimitiveElementWithChildren.fs" />
</ItemGroup>
Expand Down
41 changes: 41 additions & 0 deletions Feliz.CompilerPlugins/Hook.fs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
namespace Feliz

open Fable
open Fable.AST

/// <summary>Applies to custom defined React hooks to ensure the generated code starts with "use" in order for fast-refresh to pick it up</summary>
type HookAttribute() =
inherit MemberDeclarationPluginAttribute()
override _.FableMinimumVersion = "3.0"

/// <summary>Transforms call-site into createElement calls</summary>
override _.TransformCall(compiler, memb, expr) =
let membArgs = memb.CurriedParameterGroups |> List.concat
match expr with
| Fable.Call(callee, info, typeInfo, range) ->
let callee =
match callee with
| Fable.Expr.IdentExpr ident ->
// capitalize same-file references
Fable.Expr.IdentExpr { ident with Name = "use" + ident.Name }
| Fable.Expr.Import(importInfo, fableType, sourceLocation) ->
// capitalize component imports from different modules/files
let selector = "use" + importInfo.Selector
let modifiedImportInfo = { importInfo with Selector = selector }
Fable.Expr.Import(modifiedImportInfo, fableType, sourceLocation)
| _ ->
callee

Fable.Call(callee, info, typeInfo, range)

| _ ->
expr

override this.Transform(compiler, decl) =
if decl.Info.IsValue || decl.Info.IsGetter || decl.Info.IsSetter then
// Invalid attribute usage
let errorMessage = sprintf "Expecting a function declation for %s when using [<Hook>]" decl.Name
compiler.LogWarning(errorMessage, ?range=decl.Body.Range)
decl
else
{ decl with Name = "use" + decl.Name }
5 changes: 5 additions & 0 deletions Feliz.CompilerPlugins/ReactComponent.fs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ type ReactComponentAttribute(exportDefault: bool) =
let errorMessage = sprintf "Expecting a function declation for %s when using [<ReactComponent>]" decl.Name
compiler.LogWarning(errorMessage, ?range=decl.Body.Range)
decl
else if not (AstUtils.isReactElement decl.Body.Type) then
// output of a React function component must be a ReactElement
let errorMessage = sprintf "Expected function %s to return a ReactElement when using [<ReactComponent>]" decl.Name
compiler.LogWarning(errorMessage, ?range=decl.Body.Range)
decl
else
// TODO: make sure isRecord works with records
if decl.Args.Length = 1 && AstUtils.isRecord compiler decl.Args.[0].Type then
Expand Down
4 changes: 2 additions & 2 deletions Feliz.Delay/Feliz.Delay.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageVersion>0.2.1</PackageVersion>
<PackageVersion>0.3.0</PackageVersion>
<Authors>Cody Johnson, Zaid Ajaj</Authors>
<Description>Adds easy to use delayed rendering</Description>
<PackageLicenseUrl>https://github.com/Zaid-Ajaj/Feliz/blob/master/LICENSE</PackageLicenseUrl>
Expand All @@ -18,7 +18,7 @@
</ItemGroup>

<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Feliz\Feliz.fsproj" />
Expand Down
4 changes: 2 additions & 2 deletions Feliz.Markdown/Feliz.Markdown.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageIconUrl></PackageIconUrl>
<PackageTags>fsharp;fable;react;html</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>1.2.0</Version>
<Version>1.3.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
Expand All @@ -25,6 +25,6 @@
<Content Include="*.fsproj; *.fs; *.js;" PackagePath="fable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
</Project>
4 changes: 2 additions & 2 deletions Feliz.PigeonMaps/Feliz.PigeonMaps.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageIconUrl></PackageIconUrl>
<PackageTags>fsharp;fable;react;html</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>2.3.0</Version>
<Version>2.4.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Update Feliz dependency</PackageReleaseNotes>
Expand All @@ -29,6 +29,6 @@
<Content Include="*.fsproj; *.fs; *.js;" PackagePath="fable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
</Project>
4 changes: 2 additions & 2 deletions Feliz.Popover/Feliz.Popover.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageIconUrl></PackageIconUrl>
<PackageTags>fsharp;fable;react;html</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>2.2.0</Version>
<Version>2.3.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Update Feliz dependency</PackageReleaseNotes>
Expand All @@ -26,6 +26,6 @@
<Content Include="*.fsproj; *.fs; *.js;" PackagePath="fable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
</Project>
4 changes: 2 additions & 2 deletions Feliz.Recharts/Feliz.Recharts.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageIconUrl></PackageIconUrl>
<PackageTags>fsharp;fable;react;html</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>3.0.0</Version>
<Version>3.1.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Distinguished types for the various charts instead of a generic IReactProperty</PackageReleaseNotes>
Expand Down Expand Up @@ -46,6 +46,6 @@
<Content Include="*.fsproj; *.fs; *.js;" PackagePath="fable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
</Project>
4 changes: 2 additions & 2 deletions Feliz.RoughViz/Feliz.RoughViz.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<PackageIconUrl></PackageIconUrl>
<PackageTags>fsharp;fable;react;html;feliz</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>1.3.0</Version>
<Version>1.4.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Update Feliz dependency</PackageReleaseNotes>
Expand All @@ -27,6 +27,6 @@
<Content Include="*.fsproj; *.fs; *.js;" PackagePath="fable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
</Project>
6 changes: 3 additions & 3 deletions Feliz.UseDeferred/Feliz.UseDeferred.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
<PackageIconUrl></PackageIconUrl>
<PackageTags>fsharp;fable;react;html;feliz</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>1.3.0</Version>
<Version>1.4.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Update Feliz dependency</PackageReleaseNotes>
<PackageReleaseNotes>Update Feliz dependency and use [Hook]</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<Compile Include="UseDeferred.fs" />
Expand All @@ -21,6 +21,6 @@
<Content Include="*.fsproj; *.fs; *.js;" PackagePath="fable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
</Project>
7 changes: 5 additions & 2 deletions Feliz.UseDeferred/UseDeferred.fs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ open Feliz
[<AutoOpen>]
module ReactHookExtensions =
type React with
[<Hook>]
static member useDeferred(operation: Async<'T>, dependencies: obj array) =
let (deferred, setDeferred) = React.useState(Deferred.HasNotStartedYet)
let token = React.useCancellationToken()
Expand All @@ -79,6 +80,7 @@ module ReactHookExtensions =

deferred

[<Hook>]
static member useDeferredCallback(operation: 'TIn -> Async<'TOut>, setDeferred: Deferred<'TOut> -> unit) =
let cancellationToken = React.useRef(new System.Threading.CancellationTokenSource())
let executeOperation arg = async {
Expand All @@ -104,9 +106,10 @@ module ReactHookExtensions =

start

[<Hook>]
static member useDeferredParallel<'T, 'U, 'Key when 'Key : comparison>(deferred: Deferred<'T>, map: 'T -> ('Key * Async<'U>) list) =
let (data, setData) = React.useState(Map.empty)
let addData = React.useCallbackRef(fun (key, value) -> setData(Map.add key value data))
let (data, setData) = React.useStateWithUpdater(Map.empty)
let addData = React.useCallbackRef(fun (key, value) -> setData(fun prev -> Map.add key value prev))
let token = React.useCancellationToken()
let mapKeyedOperatons (operations: ('Key * Async<'U>) list) = [
for (key, operation) in operations do
Expand Down
6 changes: 3 additions & 3 deletions Feliz.UseElmish/Feliz.UseElmish.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@
<PackageIconUrl></PackageIconUrl>
<PackageTags>fsharp;fable;react;html;feliz</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>1.4.1</Version>
<Version>1.5.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Fix IDisposable overloads</PackageReleaseNotes>
<PackageReleaseNotes>Update Feliz dependency, use [Hook]</PackageReleaseNotes>
</PropertyGroup>
<ItemGroup>
<Compile Include="UseElmish.fs" />
Expand All @@ -21,7 +21,7 @@
<Content Include="*.fsproj; *.fs; *.js;" PackagePath="fable\" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
<PackageReference Include="Fable.Promise" Version="2.0.0" />
<PackageReference Include="Fable.Elmish" Version="3.0.6" />
</ItemGroup>
Expand Down
12 changes: 8 additions & 4 deletions Feliz.UseElmish/UseElmish.fs
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,13 @@ module UseElmishExtensions =
| _ -> None

type React with
[<Hook>]
static member useElmish<'State,'Msg> (init: 'State * Cmd<'Msg>, update: 'Msg -> 'State -> 'State * Cmd<'Msg>, dependencies: obj[]) =
let state = React.useRef(fst init)
let ring = React.useRef(RingBuffer(10))
let childState, setChildState = React.useState(fst init)
let token = React.useCancellationToken()
let setChildState () =
let setChildState () =
JS.setTimeout(fun () ->
if not token.current.IsCancellationRequested then
setChildState state.current
Expand All @@ -83,9 +84,9 @@ module UseElmishExtensions =

let dispatch = React.useCallbackRef(dispatch)

React.useEffect((fun () ->
React.createDisposable(fun () ->
getDisposable state.current
React.useEffect((fun () ->
React.createDisposable(fun () ->
getDisposable state.current
|> Option.iter (fun o -> o.Dispose())
)
), dependencies)
Expand All @@ -102,13 +103,16 @@ module UseElmishExtensions =

(childState, dispatch)

[<Hook>]
static member inline useElmish<'State,'Msg> (init: 'State * Cmd<'Msg>, update: 'Msg -> 'State -> 'State * Cmd<'Msg>) =
React.useElmish(init, update, [||])

[<Hook>]
static member useElmish<'State,'Msg> (init: unit -> 'State * Cmd<'Msg>, update: 'Msg -> 'State -> 'State * Cmd<'Msg>, dependencies: obj[]) =
let init = React.useMemo(init, dependencies)

React.useElmish(init, update, dependencies)

[<Hook>]
static member inline useElmish<'State,'Msg> (init: unit -> 'State * Cmd<'Msg>, update: 'Msg -> 'State -> 'State * Cmd<'Msg>) =
React.useElmish(init, update, [||])
4 changes: 2 additions & 2 deletions Feliz.UseMediaQuery/Feliz.UseMediaQuery.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<PackageVersion>1.3.0</PackageVersion>
<PackageVersion>1.4.0</PackageVersion>
<Authors>Jonas Bösch, Zaid Ajaj</Authors>
<Description>useMediaQuery hooks to build responsive websites </Description>
<PackageLicenseUrl>https://github.com/Zaid-Ajaj/Feliz/blob/master/LICENSE</PackageLicenseUrl>
Expand All @@ -20,7 +20,7 @@
<PackageReference Include="Fable.Browser.MediaQueryList" Version="1.1.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Update="FSharp.Core" Version="4.7.0" />
<PackageReference Update="FSharp.Core" Version="4.7.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Feliz\Feliz.fsproj" />
Expand Down
6 changes: 4 additions & 2 deletions Feliz.UseMediaQuery/UseMediaQuery.fs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ module Breakpoints =
WideScreen = 1216
}

let inline private maxWidth (breakpoint: int) =
let inline private maxWidth (breakpoint: int) =
"(max-width: " + (unbox<string> breakpoint) + "px)"

let private makeQueries breakpoints =
Expand All @@ -49,6 +49,7 @@ module UseMediaQueryExtension =
type React with
/// A hook for media queries, this hook will force a component
/// to re-render when the specified media query changes.
[<Hook>]
static member useMediaQuery (mediaQuery: string) =
let mq, setMq = React.useState(fun () -> window.matchMedia(mediaQuery).matches)

Expand All @@ -57,7 +58,7 @@ module UseMediaQueryExtension =
let handler = fun () -> setMq mediaQueryList.matches

handler()

addListener mediaQueryList handler

React.createDisposable(fun () -> removeListener mediaQueryList handler)
Expand All @@ -68,6 +69,7 @@ module UseMediaQueryExtension =
/// A hook for responsive design, this hook will force a component
/// to re-render the components on resize.
/// Returns a discriminated union with the new width.
[<Hook>]
static member useResponsive(?breakpoints: Breakpoints) =
let breakpoints = Option.defaultValue Breakpoints.defaults breakpoints
let m, l, t, d = makeQueries breakpoints
Expand Down
4 changes: 2 additions & 2 deletions Feliz/Feliz.fsproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
<PackageLicenseUrl>https://github.com/Zaid-Ajaj/Feliz/blob/master/LICENSE</PackageLicenseUrl>
<PackageTags>fsharp;fable;react;html</PackageTags>
<Authors>Zaid Ajaj</Authors>
<Version>1.16.2</Version>
<Version>1.17.0</Version>
<TargetFramework>netstandard2.0</TargetFramework>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageReleaseNotes>Only implement [ReactComponent], hide [PrimitiveElement] for now for another release</PackageReleaseNotes>
<PackageReleaseNotes>Implement prop.wrap for textarea elements and introduce [Hook] attribute</PackageReleaseNotes>
</PropertyGroup>
<PropertyGroup>
<NpmDependencies>
Expand Down
Loading

0 comments on commit e959306

Please sign in to comment.