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 <https://flowtype.org/docs/functions.html#overloading> them. 
>
>
> *ButtonProps.js*
>
> // @flow
> /* eslint-disable import/prefer-default-export */
>
> export type ButtonProps = {
>   type?: 'button' | 'reset' | 'submit',
>   design: 'primary' | 'secondary',
>   className?: string,
>   children?: Array<HTMLElement>,
>   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) =>
>
>   <button className={[`${design} ${className}`]} type={type}>
>     {children}
>   </button>;
>
> 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) =>
>   <Button
>     design={props.design}
>     onClick={props.onClick}
>     className={`iconBtn ${props.className}`}
>   >
>     <Icon glyph={props.glyph} />
>   </Button>;
>
> 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 [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to