Comments (16)
Oh, all the trickery! 😵 Thanks a lot! You're a Fable wizard! 🧙♂️
from feliz.
Not very short and used in a number of places => do not inline. if it used once or twice in your app to call a couple of functions inline, no problem at all.
from feliz.
Are there better ways to accomplish this?
Not that I know of, I am glad you already found a workaround
Since this is completely general and might be needed in many situations, would you consider adding support for this in Feliz?
Actually I think this usage of getLabelProps()
is too low-level for a Fable binding, the idea of a spread is a Javascript thing and when building Fable bindings, I believe that one should keep F#-y things only, so if you are building a binding for downshift, I would expect the binding to give me:
getLabelProps : unit -> IReactProperty list
which wraps the internal getLabelProps
with objectEntries
in the binding implementation (i.e. getLabelProps >> objectEntries
) then I could yield!
with the other properties:
Html.div [
yield! (getLabelProps())
yield prop.className "foo"
]
I guess the same applies for spreading a style
from feliz.
I see your point, I agree in the context of getLabelProps
(I have written bindings for downshift and know it's not hard to do there).
But what about MUI's mixin? It's defined some levels down (theme.mixins.toolbar
) in interfaces that are only used for directly accessing native JS code, as is commonly seen in bindings. Changing this to return something else would mean that everything up the hierarchy would also need to be modified to not be interfaces but instead classes with custom logic. It seems like this can, in general, cause a potentially big maintenance step up from (slightly tweaked) ts2fable bindings, just to change this one thing. And this would be necessary for all projects where this is relevant.
In short, having this possibility in Feliz would make things a lot easier for maintainers of bindings where this is necessary.
I agree that it's low-level and that ideally, bindings returning something to be spread would return IReactProperty []
, but it can cause notably higher maintenance.
Just sharing thoughts here; ideally I'd like F#-idiomatic bindings everywhere, of course.
from feliz.
But what about MUI's mixin? It's defined some levels down (theme.mixins.toolbar) in interfaces that are only used for directly accessing native JS code, as is commonly seen in bindings. Changing this to return something else would mean that everything up the hierarchy would also need to be modified to not be interfaces but instead classes with custom logic. It seems like this can, in general, cause a potentially big maintenance step up from (slightly tweaked) ts2fable bindings, just to change this one thing. And this would be necessary for all projects where this is relevant.
Can you show me an example?
In short, having this possibility in Feliz would make things a lot easier for maintainers of bindings where this is necessary.
I still think these primitives shouldn't be exposed through Feliz, nor the binding that depends on it.
I agree that it's low-level and that ideally, bindings returning something to be spread would return IReactProperty [], but it can cause notably higher maintenance.
IMO, correctness and API ergonomics > maintenance because if you build an adhoc binding, the maintaince costs are transferred to the application code instead of the library code (which is what the library is trying to achieve: hiding the weird javascripty parts from the application code)
from feliz.
Hm, let's see.
Say I have the following binding type for some JS-native object:
type Mixins =
abstract toolbar: obj with get, set
type Theme =
abstract mixins: Mixins with get, set
// lots of other members
I'd like to use theme.mixins.toolbar
as IStyleAttribute []
. Since toolbar: obj
must exist in the bindings in one form or another (since that's how the JS API is), this leaves me two options:
1. Use them as abstract classes instead of interfaces, and add members with other names
I think I like this best, though it's certainly not perfect.
[<AbstractClass>]
type Mixins =
abstract toolbar: obj with get, set
member this.toolbarStyles =
this.toolbar |> objectEntries |> unbox<IStyleAttribute []>
- Pros: Simple change, low maintenance, no quasi-duplicated types (which can also be confusing for users - for example, the above object may be created directly by the user, for example using
jsOptions
, when creating a custom theme) - Cons:
Bigger size since it now compiles as a class, the native API is always there in addition to whatever else you add, and you therefore have to find your own names if you can't add overloads.Also unsure ifEdit: See next comment.jsOptions
etc. will create a POJO. Fable REPL indicates it will, but that may be an implementation detail for all I know.
2. Have customized bindings in addition to "native" bindings
This is what I indicated in my previous comment. In addition to Mixins
and Theme
, we define:
type FelizMixins =
abstract toolbar: IStyleAttribute list
type FelizTheme =
abstract mixins: FelizMixins with get, set
// lots of other members
Then we use this instead.
- Pros: We can stick to interfaces
- Cons: Every function in the JS API that accepts or returns a normal
Theme
must be wrapped in order to convert betweenFelizTheme
andTheme
. For object graphs running several level deep, this conversion may not be particularly fun to maintain, nor very efficient (everything is converted all the time, as opposed to option 1, where the conversion happens when you use a particular member).
Please ask if I'm not being clear enough.
from feliz.
Oh wait, it seems I can use extension members for option 1, meaning that some of the cons no longer apply: Fable REPL
from feliz.
@cmeeren no extension methods needed, try this for option 1
[<AbstractClass; Erase>]
type Mixins =
[<Emit("Object.entries($0.toolbar)")>]
member this.toolbar : IStyleAttribute [] = jsNative
EDIT: this is of course only if you want to read the properties
SEE Fable REPL
from feliz.
Thanks! That's even better. I'll try to use that when I can. Do you have to use jsNative
? I.e., no F# code for those members? I get errors if I try (which I guess makes sense, since it's erased?)
from feliz.
When you use [<Emit(...)>]
, the expression on the left hand side is ignored altogether (actually if jsNative
was to run, it throws an exception "js only" or something like that)
from feliz.
Sorry I was unclear; I was wondering if I had to use [<Emit(...)>]
or if it was possible to use your suggestion also with F# code for the member. But that doesn't seem to work (ReferenceError: Foo$$get_B is not defined
).
from feliz.
Works if the member is inline
[<AbstractClass; Erase>]
type Foo =
abstract A: int with get, set
member inline this.B = this?A + 5
from feliz.
Thanks! happy to help 😄
from feliz.
...Though that has the same considerations as other inline
stuff, right? That if the body is not very short, it might be better to make it non-inline? I.e. use the Emit
trick or extension members?
from feliz.
Can we close this issue @cmeeren?
from feliz.
Sure!
from feliz.
Related Issues (20)
- ReactComponentAttribute for props list HOT 2
- Q: Documentation on breaking changes in 2.6? [WAS Updating Feliz.UseListener to Feliz 2.6.0] HOT 4
- CSS overflow-anchor property HOT 1
- Error with Feliz 2.7 HOT 2
- Making UseElmish's dispatch function stable
- Feliz.Markdown escapeHtml doesn't seem to work HOT 1
- UseElmish: Failed to resolve import "use-sync-external-store/shim" HOT 3
- `react-markdown` removes the `escapeHtml` property HOT 1
- Clarification and Potential Improvement on PR #480 useEffectOnce behavior HOT 5
- Expanding Feliz.Rechart HOT 3
- Component created with a forwardRef that has generic type parameters loses state HOT 2
- "Directory import use-sync-external-store\shim is not supported" in UseElmish.fs.js HOT 2
- Use with Elmish documentation is lacking integration HOT 2
- Enhance Handling of F# Record Types as Props in ReactComponent Attribute HOT 4
- Explore if Feliz.CompilerPlugin can support POJO made using `[<ParamObject>]`
- prop.pattern produces invalid html HOT 4
- React 19 HOT 4
- Svg attribute `fill-rule` missing
- Update tests and move to github actions [Contributions Welcome]
- Doc changes havent been pushed to site HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from feliz.