chrislopresto/ember-freestyle

Proposed New API

lukemelia opened this issue ยท 7 comments

We have some new ideas for the public API for Freestyle that we think will make conceptual and ergonomic improvements for developers. Here's the idea:

Example of new API usage

 <Freestyle::Guide
    @title='My App'
    @subtitle='A Living Style Guide'
  as |fg|
>
  <fg.Section @name='Shared' as |section|>
    <section.Subsection @name='Buttons'>

       {{!-- Showing one item, simple usage: --}}
       <Freestyle::Item @title="MyComponent">
         <App::Button @color="red" @action={{log-action 'clicked button'}} />
       </Freestyle::Item>

       {{!-- Showing one item, advanced usage: --}}
       <Freestyle::Item as |i|>
         <i.Note>
           <Remarkable>I am some documentation about red buttons</Remarkable>
         </i.Note>
         <i.Example>
           <App::Button @color="red" @action={{log-action 'clicked button'}} />
         </i.Example>
         <i.ExampleSource />
       </Freestyle::Item>

       {{!-- Showing a collection of variants with easy toggle
             to show all or specific item: --}}
       <Freestyle::ItemCollection @title="Link Buttons" as |c|>
         <c.Item @title="Normal">
           <App::LinkButton @action={{log-action 'clicked button'}} />
         </c.Item>
         <c.Item @title="Disabled" as |i|>
           <i.Note>
             Buttons can be disabled
           </i.Note>
           <i.Example>
             <App::LinkButton @disabled={{true}} @action={{log-action 'clicked button'}} />
           </i.Example>
           <i.ExampleSource />
         </c.Item>
       </Freestyle::ItemCollection>

       {{!-- Showing an item with a control panel to dynamically update values: --}}

       {{!-- Simple --}}
       <Freestyle::DynamicItem
         @dynamicProperties={{hash
           size=(hash value=10 inputType='number')
         }}
         @title="Buttons of Different Sizes"
         as |dynamic|
       >
         <App::Button @size={{dynamic.size}} />
       </Freestyle::DynamicItem>

       {{!-- Advanced --}}
       <Freestyle::DynamicItem
         @dynamicProperties={{hash
           size=(hash value=10 inputType='number')
         }}
         @title="Buttons of Different Sizes"
         as |dynamic i|
       >
         <i.Note>
           Buttons size intelligently
         </i.Note>
         <i.Example>
           <App::Button @size={{dynamic.size}} />
         </i.Example>
         <i.ExampleSource />
       </Freestyle::DynamicItem>

    </section.Subsection>
  </fs.Section>
</Freestyle::Guide>

The old component names would deprecated. Here is a list:

  • <FreestyleUsage> - deprecated, move to Freestyle::Item
  • <FreestyleDynamic> - deprecated, move to Freestyle::DynamicItem
  • <FreestyleNote> - deprecated, move to Freestyle::Item'd yielded Note
  • <FreestyleNotes> - deprecated, was for internal use - open an issue
  • <FreestyleAnnotation> - deprecated, move to Freestyle::Item'd yielded Note
  • <FreestyleCollection> - deprecated, move to Freestyle::ItemCollection
  • <FreestyleVariant> - deprecated, move to Item yielded by ItemCollection
  • <FreestyleGuide> - deprecated, name change only to Freestyle::Guide
  • <FreestyleMenu> - deprecated, was for internal use - open an issue
  • <FreestyleUsageControls> - deprecated, was for internal use - open an issue
  • <FreestylePalette> - deprecated, name change only to Freestyle::ColorPalette
  • <FreestyleTypeface> - deprecated, name change only to Freestyle::Typeface
  • <FreestyleSection> - deprecated, move to Section yielded from Freestyle::Guide
  • <FreestyleSubsection> - deprecated, was used by yielded Section, still is, internal name change to Freestyle::Subsection
  • <FreestyleSnippet> - deprecated, was for internal use - open an issue

Alternate idea for achieving goals of Freestyle::DynamicItem, via @mattmcmanus. Basically, Freestyle::Item would have the ability to include a control panel so you wouldn't need a dedicated component:

       <Freestyle::Item as |Item|>
         <Item.ControlPanel as |Controls|>
           <Controls.Number @value=10 />
         </Item.ControlPanel>
         <Item.Note>
           <Remarkable>I am some documentation about red buttons</Remarkable>
         </Item.Note>
         <Item.Example as |values|>
           <App::Button @size={{values.size}} />
         </Item.Example>
         <Item.ExampleSource />
       </Freestyle::Item>

What @lukemelia mentioned above is a good summary. I have some spikes on this usage pattern that I've been experimenting with in one of our addons. I'm happy to share what I have if that would be helpful.

Here's another riff using Usage instead of Item

<Freestyle::Usage as |Usage|>
  <Usage.ControlPanel as |Controls|>
    <Controls.String @name="label" @value="A Label" />
    <Controls.String @name="value" @value="The Value" />
    <Controls.Array @name="errors" /> # Comma separated list of strings
    <Controls.Array @name="warnings" />
    <Controls.Bool @name="disabled" @value={{false}} />
    <Controls.Bool @name="autofocus" @value={{false}} />
    <Controls.Action @name="onInput" /> # Automatically logs to console, could use a flash message
    <Controls.Action @name="onFocusOut" />
  </Usage.ControlPanel>
 
 <Usage.Note>DOCUMENTATION</Usage.Note>

  <Usage.Example as |values|>
    <YInput
      @label={{values.label}}
      @value={{values.value}}
      @errors={{values.errors}}
      @warnings={{values.warnings}}
      @disabled={{values.disabled}}
      @autofocus={{values.autofocus}}
      @onInput={{values.onInput}}
      @onFocusOut={{values.onFocusOut}}
    />
  </Usage.Example>
  <Usage.Source />
</ComponentUsage>

One detail not specifically called out above... this API would see Freestyle get out of the markdown business -- if you want markdown in your notes, you would be responsible for including your own markdown addon and using it in your notes.

Update: this particular change has been completed by #357

Now that a polyfill is available for the Yieldable Named Blocks feature, I thought it would be worth considering how the proposed API would look using that approach:

<Freestyle::Item>
  <:control-panel as |Controls|>
    <Controls.Number @value=10 />
  </:control-panel>
  <:example as |values|>
    <App::Button @size={{values.size}} />
  </:example>
  <:note>
    <Remarkable>I am some documentation about red buttons</Remarkable>
  </:note>
</Freestyle::Item>

The biggest advantage I see is that the <Freestyle::Item> component has control over the order and rendering of each sub-part. There's no need to include a <:source> like there is in the contextual components version.

Update, the latest releases include <Freestyle::Usage>, which make some of the ideas in this thread a reality.