Re: [elm-discuss] Re: Basic behavioral composition

2016-09-05 Thread Rex van der Spuy


Hadn't noticed this section in the guide before. Great explanation
>

... It's just been added :) 

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-09-05 Thread Wouter In t Velt
Hadn't noticed this section in the guide before. Great explanation!
Thanks for sharing.

Op vrijdag 2 september 2016 18:00:31 UTC+2 schreef suttlecommakevin:
>
> This new doc helps a ton. Thanks for this!
>
> http://guide.elm-lang.org/reuse/
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-09-02 Thread suttlecommakevin
This new doc helps a ton. Thanks for this!

http://guide.elm-lang.org/reuse/

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-08-23 Thread suttlecommakevin
Yes, a wonderful and much appreciated breakdown, @debois. Couldn't have 
said it better @Wouter. 

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-08-23 Thread Wouter In t Velt
Thank you for this very clear and concise description @debois!

Coming from React+Flux, I've followed much of the discussions on 
child-parent communication, components etcetera, but I found it really hard 
to scale in elm.
The "everything is a component" from react is a hard habit to break, and 
although I understood (+ learned the hard way) that components are not the 
way to go in elm, it wasn't really clear to me what the right (or better) 
way is.

Your post is a very helpful guideline, thanks!

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-08-22 Thread OvermindDL1
Fantastic description.

On the Snackbar part though, have you thought about making it an 'effect' 
so you can send messages to it and subscribe to it (this pattern might make 
other things easier as well in elm-mdl)?

On Saturday, August 20, 2016 at 1:28:09 PM UTC-6, debois wrote:
>
> This is a great question! 
>
> Without internal state
>
> I think the most productive way of working with Elm is to avoid trying to 
> generalise and stick with expressing yourself directly in elm-lang/html 
> whenever possible. If you find yourself doing something a lot, use helper 
> functions to construct high-frequency pieces of `Html m`. Richards' answer 
> above is compatible with this philosophy. 
>
> You'll see elm-mdl take this route in a number of places, i.e., the Card, 
> Elevation, Footer, Grid, Lists and Typography modules contain just 
> functions constructing `Html a` values for you. You add behaviour as you 
> would anything in elm-lang/html by supplying your own attributes, typically 
> Html.Events.on*. 
>
> With internal state
>
> However, all the answers above make sense only if the Button you're 
> building doesn't have internal state. Let's say yours is a a fancy button 
> with animations; someone needs to track the current animation state of the 
> button, and update that state in response to DOM events. You now have just 
> two options for who that someone might be: (1) That someone is you: Stick 
> with working directly in elm-lang/html and manually integrate animation 
> logic for each button in your app's `Msg/update`. (2) That someone is a 
> component: Built a TEA component for your button. (If you think about it a 
> bit, you'll realise that if you don't like (1), whatever else you do, you 
> *must 
> *do the things TEA components do anyway.)
>
> Composing behaviours
>
> This choice brings us back to the original question: "How do I compose 
> behaviours in Elm"? If you go for (1),  "composing behaviours" is trivial, 
> because you didn't put up a wall in the shape of an API between your fancy 
> button and its surroundings; you just adjust the code from case to case as 
> you need. This emphatically *does not* mean that you now code by 
> cut-and-paste: As usual, when you find yourself doing the same thing in 
> different places, you factor out that thing into a helper function. As you 
> get more helper functions, perhaps a good API for a button component will 
> emerge.
>
> If you go for (2), full TEA component, "composing behaviours" is much, 
> much harder. You have to chose an API your button, and that API will 
> dictate exactly how it can and cannot interact with the rest of your app. 
> For a button, figuring out this API is maybe not that hard (maybe you can 
> set CSS on it, set its label, set its icon, and give it a Msg to fire when 
> clicked), but for even slightly more complex behaviours, I find producing 
> proper APIs surprisingly hard. A very large portion of the time spent on 
> elm-mdl went to devising APIs for seemingly simple components, like Cards, 
> Lists, and Badges. 
>
> The approach we took in elm-mdl was to mimic elm-lang/html as much as 
> possible: The only way to interact with a component is to customise it 
> through parameters to `view` (think `Attribute m`).  You "compose 
> behaviours" specifically by supplying `Msg`es you'd like to be sent in 
> response to internal events of the component. This approach is compatible 
> with the guidelines in Evan's sortableTable 
> . 
>
> In elm-mdl, we customise components only through parameters to `view` 
> because that's what elm-lang/html looks like. You could view it as a 
> ruthless, take-no-prisoners realisation of that guideline, though: When we 
> customise only in `view`, the component *cannot* store any of your data 
> in its model(*). 
>
> So, altogether, this is *my* preferred approach to "composing behaviour" 
> in elm:
>
> 1. Avoid components and work directly with `Html m` if possible. Avoid 
> repeating yourself by ample use of helper functions. "Composing behaviour" 
> is just producing `Html m` values. 
> 2. When you must make a component, let the Model of the component contain 
> *only* internal state of that component.
> 3. When you must make a component, "compose behaviour" with that component 
> by (a) telling it what to look like in `view` and (b) reacting to messages 
> it sends (back) to you. Never touch its Model. Never send it messages.
>
> This approach is not all-encompassing; I had to give up on (3) for the 
> Snackbar  component(**). For 
> UI components in general, though, I do think this approach is something to 
> strive for, and I do think it makes sense outside of elm-mdl. 
>
> Cheers,
>
> Søren
>
> (*) Almost can't. 
>
> (**) Snackbar holds a queue of messages to display. That queue has to live 
> in the model. The user can only add messages to the queue by messing with 
> the model or (actual choi

Re: [elm-discuss] Re: Basic behavioral composition

2016-08-20 Thread debois
This is a great question! 

Without internal state

I think the most productive way of working with Elm is to avoid trying to 
generalise and stick with expressing yourself directly in elm-lang/html 
whenever possible. If you find yourself doing something a lot, use helper 
functions to construct high-frequency pieces of `Html m`. Richards' answer 
above is compatible with this philosophy. 

You'll see elm-mdl take this route in a number of places, i.e., the Card, 
Elevation, Footer, Grid, Lists and Typography modules contain just 
functions constructing `Html a` values for you. You add behaviour as you 
would anything in elm-lang/html by supplying your own attributes, typically 
Html.Events.on*. 

With internal state

However, all the answers above make sense only if the Button you're 
building doesn't have internal state. Let's say yours is a a fancy button 
with animations; someone needs to track the current animation state of the 
button, and update that state in response to DOM events. You now have just 
two options for who that someone might be: (1) That someone is you: Stick 
with working directly in elm-lang/html and manually integrate animation 
logic for each button in your app's `Msg/update`. (2) That someone is a 
component: Built a TEA component for your button. (If you think about it a 
bit, you'll realise that if you don't like (1), whatever else you do, you *must 
*do the things TEA components do anyway.)

Composing behaviours

This choice brings us back to the original question: "How do I compose 
behaviours in Elm"? If you go for (1),  "composing behaviours" is trivial, 
because you didn't put up a wall in the shape of an API between your fancy 
button and its surroundings; you just adjust the code from case to case as 
you need. This emphatically *does not* mean that you now code by 
cut-and-paste: As usual, when you find yourself doing the same thing in 
different places, you factor out that thing into a helper function. As you 
get more helper functions, perhaps a good API for a button component will 
emerge.

If you go for (2), full TEA component, "composing behaviours" is much, much 
harder. You have to chose an API your button, and that API will dictate 
exactly how it can and cannot interact with the rest of your app. For a 
button, figuring out this API is maybe not that hard (maybe you can set CSS 
on it, set its label, set its icon, and give it a Msg to fire when 
clicked), but for even slightly more complex behaviours, I find producing 
proper APIs surprisingly hard. A very large portion of the time spent on 
elm-mdl went to devising APIs for seemingly simple components, like Cards, 
Lists, and Badges. 

The approach we took in elm-mdl was to mimic elm-lang/html as much as 
possible: The only way to interact with a component is to customise it 
through parameters to `view` (think `Attribute m`).  You "compose 
behaviours" specifically by supplying `Msg`es you'd like to be sent in 
response to internal events of the component. This approach is compatible 
with the guidelines in Evan's sortableTable 
. 

In elm-mdl, we customise components only through parameters to `view` 
because that's what elm-lang/html looks like. You could view it as a 
ruthless, take-no-prisoners realisation of that guideline, though: When we 
customise only in `view`, the component *cannot* store any of your data in 
its model(*). 

So, altogether, this is *my* preferred approach to "composing behaviour" in 
elm:

1. Avoid components and work directly with `Html m` if possible. Avoid 
repeating yourself by ample use of helper functions. "Composing behaviour" 
is just producing `Html m` values. 
2. When you must make a component, let the Model of the component contain 
*only* internal state of that component.
3. When you must make a component, "compose behaviour" with that component 
by (a) telling it what to look like in `view` and (b) reacting to messages 
it sends (back) to you. Never touch its Model. Never send it messages.

This approach is not all-encompassing; I had to give up on (3) for the 
Snackbar  component(**). For UI 
components in general, though, I do think this approach is something to 
strive for, and I do think it makes sense outside of elm-mdl. 

Cheers,

Søren

(*) Almost can't. 

(**) Snackbar holds a queue of messages to display. That queue has to live 
in the model. The user can only add messages to the queue by messing with 
the model or (actual choice) send messages to Snackbar. 

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread suttlecommakevin
Thanks for the detailed responses so far! 

I hope I can shed a bit more light here. 

The following concepts are all currently frowned upon in React (not that it 
matters here, just illustrating a point)
- extending classes
- mixins
- traits (ahem - https://github.com/facebook/flow/issues/2135)
- decorators 

In favor of 
- "higher-order components" (aka over complicated function factories)
- "functions as children", which seems like a useful concept until you try it
- "container components" - AKA view renderers

Given this breadth of approaches, what does Elm and FP suggest as a best 
practice for composing shared behaviors, children, interfaces (in OOP-speak), 
mixins, etc? 

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread Max Goldstein
As much as I love "don't overengineer it" as a principle, I'm not sure 
Richard's suggestion solves OP's problem. We want the possibility of NO label 
or NO icon, not just custom values. So that implies Maybe values in the record. 
Except, that opens the possibility of having neither an icon nor a string. So 
that leads me back to the union type I suggested above. (A function that takes 
a list will similarly have to contend with the empty list.)

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread OvermindDL1
Precisely, the thing like `MyButton.label` would return an appropriate 
instanced union holding whatever data you need.

On Friday, August 19, 2016 at 12:58:10 PM UTC-6, Nick H wrote:
>
> I don't think Overmind's and Richard's inputs are at odds. Richard has 
> suggested an API. Overmind's code is what might fit into "-- Implementation 
> goes here".
>
> On Fri, Aug 19, 2016 at 11:52 AM, Richard Feldman  > wrote:
>
>> `elm-mdl` is doing it that way because it is trying to follow how 
>>> Google's material library works, and since there is no way to introspect 
>>> into the virtualnode's to change how they act then it has to wrap things up 
>>> in that pattern, I.E., VirtualNode limitations and Html.Attributes 
>>> limitations require it to be this noisy.  :-)
>>>
>>
>> Yeah, elm-mdl has very specific and unusual design goals (in part 
>> because of ways MDL differs from other UI frameworks, and in part because 
>> of the author's goal for how to present MDL in a DSL) that make it 
>> substantially different from every other project in the Elm world...I would 
>> not look at its design and think "ah, this is probably what I want to do 
>> for my project!" because the opposite is far more likely. :)
>>
>> -- 
>> You received this message because you are subscribed to the Google Groups 
>> "Elm Discuss" group.
>> To unsubscribe from this group and stop receiving emails from it, send an 
>> email to elm-discuss...@googlegroups.com .
>> For more options, visit https://groups.google.com/d/optout.
>>
>
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread Nick H
I don't think Overmind's and Richard's inputs are at odds. Richard has
suggested an API. Overmind's code is what might fit into "-- Implementation
goes here".

On Fri, Aug 19, 2016 at 11:52 AM, Richard Feldman <
richard.t.feld...@gmail.com> wrote:

> `elm-mdl` is doing it that way because it is trying to follow how Google's
>> material library works, and since there is no way to introspect into the
>> virtualnode's to change how they act then it has to wrap things up in that
>> pattern, I.E., VirtualNode limitations and Html.Attributes limitations
>> require it to be this noisy.  :-)
>>
>
> Yeah, elm-mdl has very specific and unusual design goals (in part because
> of ways MDL differs from other UI frameworks, and in part because of the
> author's goal for how to present MDL in a DSL) that make it substantially
> different from every other project in the Elm world...I would not look at
> its design and think "ah, this is probably what I want to do for my
> project!" because the opposite is far more likely. :)
>
> --
> You received this message because you are subscribed to the Google Groups
> "Elm Discuss" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to elm-discuss+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread Richard Feldman

>
> `elm-mdl` is doing it that way because it is trying to follow how Google's 
> material library works, and since there is no way to introspect into the 
> virtualnode's to change how they act then it has to wrap things up in that 
> pattern, I.E., VirtualNode limitations and Html.Attributes limitations 
> require it to be this noisy.  :-)
>

Yeah, elm-mdl has very specific and unusual design goals (in part because 
of ways MDL differs from other UI frameworks, and in part because of the 
author's goal for how to present MDL in a DSL) that make it substantially 
different from every other project in the Elm world...I would not look at 
its design and think "ah, this is probably what I want to do for my 
project!" because the opposite is far more likely. :)

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread OvermindDL1
`elm-mdl` is doing it that way because it is trying to follow how Google's 
material library works, and since there is no way to introspect into the 
virtualnode's to change how they act then it has to wrap things up in that 
pattern, I.E., VirtualNode limitations and Html.Attributes limitations 
require it to be this noisy.  :-)

On Friday, August 19, 2016 at 12:08:14 PM UTC-6, suttlecommakevin wrote:
>
> Very interesting, thank you. Can you explain a bit more on the motives of 
> that architecture and API, please? 
>
> https://debois.github.io/elm-mdl/#buttons
> https://github.com/debois/elm-mdl/blob/master/demo/Demo/Buttons.elm
>
>
>
> On Friday, August 19, 2016 at 2:00:20 PM UTC-4, OvermindDL1 wrote:
>>
>> You could invert it to compose instead of extend, so something like this:
>>
>> ```elm
>> -- Button with a Label
>> MyButton.view [ MyButton.label "blah" ]
>>
>> -- Button with an Icon
>> MyButton.view [ MyButton.icon "iconId" ]
>>
>> -- Button with both
>> MyButton.view [ MyButton.label "blah", MyButton.icon "iconId" ]
>> ```
>>
>> You can easily enforce the icon to always render before the label is that 
>> is a requirement, regardless of position in the list, etc... etc...
>>
>> This is how the `elm-mdl` package works for example.
>>
>>
>> On Friday, August 19, 2016 at 11:46:30 AM UTC-6, suttlecommakevin wrote:
>>>
>>> Apologies if this has been posted elsewhere, but I keep coming back to 
>>> it. 
>>>
>>> Let's get basic. Like *super *basic.
>>>
>>> I get a spec from a designer for a button with 3 types of children. 
>>>
>>>1. A button with a label only
>>>2. A button with an icon only
>>>3. A button with an icon *and* a label
>>>
>>>
>>> In a object-oriented programming environment, you could make a 
>>> ButtonBase class and extend it. 
>>> In React's bizarro world, they try to promote this Higher-order 
>>> Components technique, which is really just a function factory.
>>> In Flow, you can at least start making types, and then, share and 
>>> intersect  them. 
>>>
>>>
>>> *ButtonProps.js*
>>>
>>> // @flow
>>> /* eslint-disable import/prefer-default-export */
>>>
>>> export type ButtonProps = {
>>>   type?: 'button' | 'reset' | 'submit',
>>>   design: 'primary' | 'secondary',
>>>   className?: string,
>>>   children?: Array,
>>>   onClick?: () => void,
>>>   onFocus?: () => void,
>>>   onmouseover?: () => void,
>>>   onmouseout?: () => void,
>>> }
>>>
>>>
>>> *Button.jsx*
>>>
>>> // @flow
>>>
>>> import React from 'react';
>>> import type { ButtonProps } from './ButtonProps';
>>> import './Button.css';
>>>
>>> /* eslint-disable flowtype/space-after-type-colon */
>>> const Button = ({
>>>   design = 'primary',
>>>   className = 'btn',
>>>   type = 'button',
>>>   children } :ButtonProps) =>
>>>
>>>   
>>> {children}
>>>   ;
>>>
>>> export default Button;
>>>
>>>
>>> *Icon.jsx*
>>>
>>> // @flow
>>>
>>> import React from 'react';
>>> import Button from './Button.jsx';
>>> import type { ButtonProps } from './ButtonProps';
>>> import Icon from '../Icons/Icon.jsx';
>>> import type { IconProps } from '../Icons/IconProps';
>>>
>>> type IconButtonProps = ButtonProps & IconProps;
>>>
>>> const IconButton = (props: IconButtonProps) =>
>>>   >> design={props.design}
>>> onClick={props.onClick}
>>> className={`iconBtn ${props.className}`}
>>>   >
>>> 
>>>   ;
>>>
>>> export default IconButton;
>>>
>>>
>>> Notice this line: type IconButtonProps = ButtonProps & IconProps; which 
>>> is just a fancy Object.assign() really. 
>>> It's easy to read, easy to understand, but many would claim it doesn't 
>>> follow "best practices".
>>>
>>>
>>> My question is, how would Elm/FP handle this? 
>>>
>>>
>>>
>>> Thanks, folks. 
>>>
>>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread Richard Feldman
This is a great question! I think there's a very clear answer here:

*Don't overengineer it.*

As you noted, this is basic - *super* basic - so by default, the best 
solution is also super basic.

There's a button with 2 configurable options? Cool, let's write a function 
that accepts that configuration and returns the button we need:

fancyButton : { label : String, icon : String } -> Html msg
fancyButton { label, icon } =
-- Implementation goes here

Done!

In a language where refactoring is nice, you can and should reach for 
simple solutions when the problem is simple.

If the problem gets more complex later, you can then revise from a position 
of knowledge: you'll know *precisely how *it's more complicated, and that 
gives you the information you need to end up with the nicest API possible.

Conversely, trying to design an API to fit nebulous theoretical future use 
cases essentially means going in blind, and it's a recipe for unnecessary 
suffering in Elm. :)

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread Max Goldstein
It sounds like you want a union type to represent the three possible buttons. 
You can have a view function that does case analysis and renders each 
possibility. Any shared code can be moved to a "let" definition, or another 
function. 

I mean, unless in missing something...

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread suttlecommakevin
Very interesting, thank you. Can you explain a bit more on the motives of 
that architecture and API, please? 

https://debois.github.io/elm-mdl/#buttons
https://github.com/debois/elm-mdl/blob/master/demo/Demo/Buttons.elm



On Friday, August 19, 2016 at 2:00:20 PM UTC-4, OvermindDL1 wrote:
>
> You could invert it to compose instead of extend, so something like this:
>
> ```elm
> -- Button with a Label
> MyButton.view [ MyButton.label "blah" ]
>
> -- Button with an Icon
> MyButton.view [ MyButton.icon "iconId" ]
>
> -- Button with both
> MyButton.view [ MyButton.label "blah", MyButton.icon "iconId" ]
> ```
>
> You can easily enforce the icon to always render before the label is that 
> is a requirement, regardless of position in the list, etc... etc...
>
> This is how the `elm-mdl` package works for example.
>
>
> On Friday, August 19, 2016 at 11:46:30 AM UTC-6, suttlecommakevin wrote:
>>
>> Apologies if this has been posted elsewhere, but I keep coming back to 
>> it. 
>>
>> Let's get basic. Like *super *basic.
>>
>> I get a spec from a designer for a button with 3 types of children. 
>>
>>1. A button with a label only
>>2. A button with an icon only
>>3. A button with an icon *and* a label
>>
>>
>> In a object-oriented programming environment, you could make a ButtonBase 
>> class and extend it. 
>> In React's bizarro world, they try to promote this Higher-order 
>> Components technique, which is really just a function factory.
>> In Flow, you can at least start making types, and then, share and 
>> intersect  them. 
>>
>>
>> *ButtonProps.js*
>>
>> // @flow
>> /* eslint-disable import/prefer-default-export */
>>
>> export type ButtonProps = {
>>   type?: 'button' | 'reset' | 'submit',
>>   design: 'primary' | 'secondary',
>>   className?: string,
>>   children?: Array,
>>   onClick?: () => void,
>>   onFocus?: () => void,
>>   onmouseover?: () => void,
>>   onmouseout?: () => void,
>> }
>>
>>
>> *Button.jsx*
>>
>> // @flow
>>
>> import React from 'react';
>> import type { ButtonProps } from './ButtonProps';
>> import './Button.css';
>>
>> /* eslint-disable flowtype/space-after-type-colon */
>> const Button = ({
>>   design = 'primary',
>>   className = 'btn',
>>   type = 'button',
>>   children } :ButtonProps) =>
>>
>>   
>> {children}
>>   ;
>>
>> export default Button;
>>
>>
>> *Icon.jsx*
>>
>> // @flow
>>
>> import React from 'react';
>> import Button from './Button.jsx';
>> import type { ButtonProps } from './ButtonProps';
>> import Icon from '../Icons/Icon.jsx';
>> import type { IconProps } from '../Icons/IconProps';
>>
>> type IconButtonProps = ButtonProps & IconProps;
>>
>> const IconButton = (props: IconButtonProps) =>
>>   > design={props.design}
>> onClick={props.onClick}
>> className={`iconBtn ${props.className}`}
>>   >
>> 
>>   ;
>>
>> export default IconButton;
>>
>>
>> Notice this line: type IconButtonProps = ButtonProps & IconProps; which 
>> is just a fancy Object.assign() really. 
>> It's easy to read, easy to understand, but many would claim it doesn't 
>> follow "best practices".
>>
>>
>> My question is, how would Elm/FP handle this? 
>>
>>
>>
>> Thanks, folks. 
>>
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


[elm-discuss] Re: Basic behavioral composition

2016-08-19 Thread OvermindDL1
You could invert it to compose instead of extend, so something like this:

```elm
-- Button with a Label
MyButton.view [ MyButton.label "blah" ]

-- Button with an Icon
MyButton.view [ MyButton.icon "iconId" ]

-- Button with both
MyButton.view [ MyButton.label "blah", MyButton.icon "iconId" ]
```

You can easily enforce the icon to always render before the label is that 
is a requirement, regardless of position in the list, etc... etc...

This is how the `elm-mdl` package works for example.


On Friday, August 19, 2016 at 11:46:30 AM UTC-6, suttlecommakevin wrote:
>
> Apologies if this has been posted elsewhere, but I keep coming back to it. 
>
> Let's get basic. Like *super *basic.
>
> I get a spec from a designer for a button with 3 types of children. 
>
>1. A button with a label only
>2. A button with an icon only
>3. A button with an icon *and* a label
>
>
> In a object-oriented programming environment, you could make a ButtonBase 
> class and extend it. 
> In React's bizarro world, they try to promote this Higher-order Components 
> technique, which is really just a function factory.
> In Flow, you can at least start making types, and then, share and 
> intersect  them. 
>
>
> *ButtonProps.js*
>
> // @flow
> /* eslint-disable import/prefer-default-export */
>
> export type ButtonProps = {
>   type?: 'button' | 'reset' | 'submit',
>   design: 'primary' | 'secondary',
>   className?: string,
>   children?: Array,
>   onClick?: () => void,
>   onFocus?: () => void,
>   onmouseover?: () => void,
>   onmouseout?: () => void,
> }
>
>
> *Button.jsx*
>
> // @flow
>
> import React from 'react';
> import type { ButtonProps } from './ButtonProps';
> import './Button.css';
>
> /* eslint-disable flowtype/space-after-type-colon */
> const Button = ({
>   design = 'primary',
>   className = 'btn',
>   type = 'button',
>   children } :ButtonProps) =>
>
>   
> {children}
>   ;
>
> export default Button;
>
>
> *Icon.jsx*
>
> // @flow
>
> import React from 'react';
> import Button from './Button.jsx';
> import type { ButtonProps } from './ButtonProps';
> import Icon from '../Icons/Icon.jsx';
> import type { IconProps } from '../Icons/IconProps';
>
> type IconButtonProps = ButtonProps & IconProps;
>
> const IconButton = (props: IconButtonProps) =>
>design={props.design}
> onClick={props.onClick}
> className={`iconBtn ${props.className}`}
>   >
> 
>   ;
>
> export default IconButton;
>
>
> Notice this line: type IconButtonProps = ButtonProps & IconProps; which 
> is just a fancy Object.assign() really. 
> It's easy to read, easy to understand, but many would claim it doesn't 
> follow "best practices".
>
>
> My question is, how would Elm/FP handle this? 
>
>
>
> Thanks, folks. 
>

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.