Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

RFC: Shorthand polymorphism using kind property #512

Open
miroslavstastny opened this issue Nov 22, 2018 · 2 comments
Open

RFC: Shorthand polymorphism using kind property #512

miroslavstastny opened this issue Nov 22, 2018 · 2 comments
Labels
⚙️ enhancement New feature or request vsts Paired with ticket in vsts

Comments

@miroslavstastny
Copy link
Member

Feature Request

Problem description

Shorthand is a powerful way how you can define component slots:

<Button icon={{name: "user", size: "micro"}} content="Click me!" />

In the example above, both icon and content are shorthands. It allows you to define as few properties as possible while still giving you full control over the slot props. And in all cases shorthand still manages state, styling and accessibility for you.

Shorthand becomes extremely useful when defining collection of children, for example in ButtonGroup:

<Button.Group
  buttons={[
    { key: 'book', icon: 'book', iconOnly: true },
    { key: 'coffee', icon: 'coffee', iconOnly: true },
    { key: 'play', icon: 'play', iconOnly: true },
  ]}
/>

But what if you would like to add different component to the collection of buttons? What if you want to add a divider?

kind

For that reason we plan to add kind property to the shorthand definition. With that, you can choose which component will be created using the shorthand:

<Button.Group
  buttons={[
    { key: 'book', icon: 'book', iconOnly: true },
    { key: 'coffee', icon: 'coffee', iconOnly: true },
    { kind: 'divider' },
    { key: 'play', icon: 'play', iconOnly: true },
  ]}
/>

Difference between as and kind

All Startdust components already support as property which allows you to override element type in the rendered result. So what is the reason for introducing kind? What is the difference between the two?

Stardust component defines resulting DOM structure, state, styles and accessibility. With as, you are overriding ElementType - that is usually the root element in the resulting DOM structure.
But the original component is still created - with the structure, state, styles and accessibility of the original component.

On the other hand when kind is used, different component is created - with its own structure, state, styles and accessibility.

To summarize - kind defines what component is created. as defines ElementType of the created component.

It is technically possible to combine the two:

<Button.Group
  buttons={[
    ...
    { kind: 'divider', as: MyCustomDivider },
    ...
  ]}
/>

Component implementation

There is no magic happening in factory, it is component's responsibility to handle kind attribute.

Component should allow the kind to be only one of predefined options (ButtonGroup should allow only 'button' or 'divider' and default to 'button' if no kind is specified and nothing else).

Possible use cases considered:

  • ButtonGroup - (button), divider
  • Form - field
  • FormGroup - field
  • Menu - (item), divider, header, menu
  • Chat - (message), control, divider
  • Breadcrumb - divider, content
  • List - (item), header, divider

Other syntaxes considered

Dropdown.Divider.create(),
<Dropdown.Divider />,

() => <Dropdown.Divider />,

resolve => resolve(null, () => <Dropdown.Divider />),

[Dropdown.Header, { as: '?', icon: "trash", text: "Move to trash" }],
[Dropdown.Header, 'Move to trash'],
['header', 'Move to trash'],

{ use: Dropdown.Header, as: 'hr', icon: "trash", text: "Move to trash" },

Dropdown.Header.create(
  ...computedItemProps
  { create: Dropdown.Header, as: 'hr', icon: "trash", text: "Move to trash" },
)

{ is: 'header', as: 'hr', icon: "trash", text: "Move to trash" },
{ use: 'header', as: 'hr', icon: "trash", text: "Move to trash" },
{ kind: 'header', as: 'hr', icon: "trash", text: "Move to trash" },
{ ofType: 'header', as: 'hr', icon: "trash", text: "Move to trash" },
{ create: 'header', as: 'hr', icon: "trash", text: "Move to trash" },
{ component: 'header', as: 'h1' },

{ kind: 'header', as: 'hr', icon: "trash", text: "Move to trash" }, // WINNER

{ kind: 'Header', as: 'hr', icon: "trash", text: "Move to trash" },
{ kind: 'HEADER', as: 'hr', icon: "trash", text: "Move to trash" },
{ kind: Dropdown.Header, as: 'hr', icon: "trash", text: "Move to trash" },
{ kind: Dropdown.KindHeader, as: 'hr', icon: "trash", text: "Move to trash" },
{ kind: KindHeader, as: 'hr', icon: "trash", text: "Move to trash" },
{ kind: 'Dropdown.Header', as: 'hr', icon: "trash", text: "Move to trash" },
@layershifter
Copy link
Member

I was on this meeting, so you got my vote for this. Let's do it 👍

@pkumarie2011 pkumarie2011 added the vsts Paired with ticket in vsts label Nov 22, 2018
@mnajdova
Copy link
Contributor

I really like this idea, total support on it. However, I have couple of question, just my curiosity I guess :)

  • Are we going to allow the user to pass to the kind property custom component? If not, are we going to allow them to use the kind property with some restrictive values (I saw that you mention that the ButtonGroup for example can contain just few available options, but just to be sure that I understood that correctly)?
  • How do we see change in means of complicating the logic for the components that will use it? If we support multiple components in one slot, maybe the parent will need to send different default/override props to all of those components. (I know that the component should support limited amount of these kind options, but still I think there will be lots of logic about which properties should be applied to which Component).

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
⚙️ enhancement New feature or request vsts Paired with ticket in vsts
Projects
None yet
Development

No branches or pull requests

5 participants