Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Virtual EmberConf 2021: Platform State of the Union

Virtual EmberConf 2021: Platform State of the Union

22bb3e56828870ee9a0dd93aeadbe04a?s=128

Godfrey Chan

March 30, 2021
Tweet

Transcript

  1. PLATFORM STATE OF THE UNION

  2. Isaac Lee Jared Galanis Kenigbolo Meya Stephen Matthew Beale Melanie

    Sumner Tom Dale Jen Weber Krati Ahuja Alex Navasardyan Sivakumar Kailasam Framework Learning Steering Framework Steering Framework Framework Learning Learning CLI CLI Scott Newcomer Core Team Changes Learning Learning Data Steering Steering
  3. Improvements Modernized Built-In Components Production Build Templates Auto-Tracking Bug Fixes

    Better Error Messages Prettier New Lint Rules and Fixers <LinkTo> Now Works In Integration Tests Route Transition Debug Utilities ember-cli-update Inspector Collapsible Sidebar Better Component Inspector Test Harness QOL Improvements Template Lint TODOs Template Recast Whitespace Preservation New Polyfills and Codemods Website and Blog Redesign ember new !"lang {{page-title}} @ember!# ES Modules Unbundled ember-source RouterService#refresh()
  4. Improvements Modernized Built-In Components Production Build Templates Auto-Tracking Bug Fixes

    Better Error Messages Prettier New Lint Rules and Fixers <LinkTo> Now Works In Integration Tests Route Transition Debug Utilities ember-cli-update Inspector Collapsible Sidebar Better Component Inspector Test Harness QOL Improvements Template Lint TODOs Template Recast Whitespace Preservation New Polyfills and Codemods Website and Blog Redesign ember new !"lang {{page-title}} @ember!# ES Modules Unbundled ember-source RouterService#refresh()
  5. Improvements Modernized Built-In Components Production Build Templates Auto-Tracking Bug Fixes

    Better Error Messages Prettier New Lint Rules and Fixers <LinkTo> Now Works In Integration Tests Route Transition Debug Utilities ember-cli-update Inspector Collapsible Sidebar Better Component Inspector Test Harness QOL Improvements Template Lint TODOs Template Recast Whitespace Preservation New Polyfills and Codemods Website and Blog Redesign ember new !"lang {{page-title}} @ember!# ES Modules Unbundled ember-source RouterService#refresh()
  6. Improvements Modernized Built-In Components Production Build Templates Auto-Tracking Bug Fixes

    Better Error Messages Prettier New Lint Rules and Fixers <LinkTo> Now Works In Integration Tests Route Transition Debug Utilities ember-cli-update Inspector Collapsible Sidebar Better Component Inspector Test Harness QOL Improvements Template Lint TODOs Template Recast Whitespace Preservation New Polyfills and Codemods Website and Blog Redesign ember new !"lang {{page-title}} @ember!# ES Modules Unbundled ember-source RouterService#refresh()
  7. Improvements Modernized Built-In Components Production Build Templates Auto-Tracking Bug Fixes

    Better Error Messages Prettier New Lint Rules and Fixers <LinkTo> Now Works In Integration Tests Route Transition Debug Utilities ember-cli-update Inspector Collapsible Sidebar Better Component Inspector Test Harness QOL Improvements Template Lint TODOs Template Recast Whitespace Preservation New Polyfills and Codemods Website and Blog Redesign ember new !"lang {{page-title}} @ember!# ES Modules Unbundled ember-source RouterService#refresh()
  8. Improvements Modernized Built-In Components Production Build Templates Auto-Tracking Bug Fixes

    Better Error Messages Prettier New Lint Rules and Fixers <LinkTo> Now Works In Integration Tests Route Transition Debug Utilities ember-cli-update Inspector Collapsible Sidebar Better Component Inspector Test Harness QOL Improvements Template Lint TODOs Template Recast Whitespace Preservation New Polyfills and Codemods Website and Blog Redesign ember new !"lang {{page-title}} @ember!# ES Modules Unbundled ember-source RouterService#refresh()
  9. Deprecations getWithDefault tryInvoke String.prototype Extensions Ember.String Utilities {{#with}} <LinkTo> Positional

    Arguments Implicit Injections Old Browser Support Policy Implicit this Property Lookup {{attrs.*}} Packager Experiment Legacy classNameBindings Template Syntax Classic Edition Optional Features Old Manager Capabilities hasBlock and hasBlockParams Magic Variables Array Observers Ember.Component Features On Built-In Components Transition Methods On Routes and Controllers {{loc}} Ember Global
  10. t of Incoherence Pit of Incoherence Where We Are Where

    We Want to Be Incremental Change
  11. Pit of Incoherence Pit of Incoherence Where We Are Where

    We Want to Be Incremental Change Octane Polaris
  12. Pit of Incoherence Pit of Incoherence Where We Are Where

    We Want to Be Incremental Change Octane Polaris
  13. Embroider HIGHLIGHT #1 Building A Bridge To Tomorrow

  14. Ember addons addons Addons You app You app You App

    app.js vendor.js index.html
  15. Ember addons addons Addons You app You app You App

    app.js vendor.js index.html You app You app De-Facto Standard
  16. z

  17. Named Blocks HIGHLIGHT #2 Content. Content Everywhere.

  18. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <!-- TODO: implement drop down component --> app/templates/index.hbs Choose a destination... Destination Where would be the perfect destination for your
 virtual vacation? Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  19. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <!-- TODO: implement drop down component --> app/templates/index.hbs <div class="drop-down" ...attributes> <button type="button" id="{{this.id}}-button" aria-haspopup="listbox" aria-expanded={{if this.expanded "true" "false"}} {{on "click" this.toggle}}> {{@label}} </button> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Choose a destination... Destination Where would be the perfect destination for your
 virtual vacation? Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island <DropDown @label="Choose a destination..." @items={{this.places}} />
  20. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} /> app/templates/index.hbs <div class="drop-down" ...attributes> <button type="button" id="{{this.id}}-button" aria-haspopup="listbox" aria-expanded={{if this.expanded "true" "false"}} {{on "click" this.toggle}}> {{@label}} </button> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Choose a destination... Destination Where would be the perfect destination for your
 virtual vacation? Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  21. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} /> app/templates/index.hbs <div class="drop-down" ...attributes> <button type="button" id="{{this.id}}-button" aria-haspopup="listbox" aria-expanded={{if this.expanded "true" "false"}} {{on "click" this.toggle}}> {{@label}} </button> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Choose a destination... Destination Where would be the perfect destination for your
 virtual vacation? Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  22. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} /> app/templates/index.hbs <div class="drop-down" ...attributes> <button type="button" id="{{this.id}}-button" aria-haspopup="listbox" aria-expanded={{if this.expanded "true" "false"}} {{on "click" this.toggle}}> {{@label}} </button> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Choose a destination... Destination Where would be the perfect destination for your
 virtual vacation? Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  23. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <button type="button" id="{{this.id}}-button" aria-haspopup="listbox" aria-expanded={{if this.expanded "true" "false"}} {{on "click" this.toggle}}> {{@label}} </button> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> app/components/drop-down.hbs Choose a destination... Destination Where would be the perfect destination for your
 virtual vacation? Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island </li> {{/each}} </ul> {{/if}} </div> {{yield item}}
  24. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <button type="button" id="{{this.id}}-button" aria-haspopup="listbox" aria-expanded={{if this.expanded "true" "false"}} {{on "click" this.toggle}}> {{@label}} </button> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item}} </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Choose a destination... Destination Where would be the perfect destination for your
 virtual vacation? Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  25. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item}} </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Choose a destination... Sorry, we are sold out. Join our mailing list to be notified of new tours! Destination Where would be the perfect destination for your
 virtual vacation?
  26. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item}} </li> {{else}} <li> <h3>Sorry, we are sold out.</h3> <a href="...">Join our mailing list</a> to be notified of new tours! </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Choose a destination... Sorry, we are sold out. Join our mailing list to be notified of new tours! Destination Where would be the perfect destination for your
 virtual vacation?
  27. <h2>Destination</h2> <p>Where would be the perfect destination for your virtual

    vacation?</p> <DropDown @label="Choose a destination..." @items={{this.places}} as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item}} </li> {{else}} <li> <h3>Sorry, we are sold out.</h3> <a href="...">Join our mailing list</a> to be notified of new tours! </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Destination Where would be the perfect destination for your
 virtual vacation? Choose a destination... Too much free time? Become a virtual tour guide and share your passion with the world! Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  28. <!-- Omitted: same markup for header as before --> <DropDown

    @label="Choose a destination..." @items={{this.places}} as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item}} </li> {{/each}} </ul> {{/if}} </div> app/components/drop-down.hbs Destination Where would be the perfect destination for your
 virtual vacation? Choose a destination... Too much free time? Become a virtual tour guide and share your passion with the world! Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  29. <!-- Omitted: same markup for header as before --> <DropDown

    @label="Choose a destination..." @items={{this.places}}> <:banner> <h3>Too much free time?</h3> Become a virtual tour guide and share your passion with the world! </:banner> <:item as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </:item> <:empty> <h3>Sorry, we are sold out.</h3> <a href="...">Join our mailing list</a> to be notified of new tours! </:empty> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <div class="banner">{{yield to="banner"}}</div> <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item to="item"}} </li> {{else}} <li>{{yield to="empty"}}</li> {{/each}} </ul> {{/if}} app/components/drop-down.hbs Destination Where would be the perfect destination for your
 virtual vacation? Choose a destination... Too much free time? Become a virtual tour guide and share your passion with the world! Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  30. <!-- Omitted: same markup for header as before --> <DropDown

    @label="Choose a destination..." @items={{this.places}}> <:banner> <h3>Too much free time?</h3> Become a virtual tour guide and share your passion with the world! </:banner> <:item as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </:item> <:empty> <h3>Sorry, we are sold out.</h3> <a href="...">Join our mailing list</a> to be notified of new tours! </:empty> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <div class="banner">{{yield to="banner"}}</div> <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item to="item"}} </li> {{else}} <li>{{yield to="empty"}}</li> {{/each}} </ul> {{/if}} app/components/drop-down.hbs Destination Where would be the perfect destination for your
 virtual vacation? Choose a destination... Too much free time? Become a virtual tour guide and share your passion with the world! Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  31. <!-- Omitted: same markup for header as before --> <DropDown

    @label="Choose a destination..." @items={{this.places}}> <:banner> <h3>Too much free time?</h3> Become a virtual tour guide and share your passion with the world! </:banner> <:item as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </:item> <:empty> <h3>Sorry, we are sold out.</h3> <a href="...">Join our mailing list</a> to be notified of new tours! </:empty> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <div class="banner">{{yield to="banner"}}</div> <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item to="item"}} </li> {{else}} <li>{{yield to="empty"}}</li> {{/each}} </ul> {{/if}} app/components/drop-down.hbs Destination Where would be the perfect destination for your
 virtual vacation? Choose a destination... Too much free time? Become a virtual tour guide and share your passion with the world! Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  32. <!-- Omitted: same markup for header as before --> <DropDown

    @label="Choose a destination..." @items={{this.places}}> <:banner> <h3>Too much free time?</h3> Become a virtual tour guide and share your passion with the world! </:banner> <:item as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </:item> <:empty> <h3>Sorry, we are sold out.</h3> <a href="...">Join our mailing list</a> to be notified of new tours! </:empty> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <div class="banner">{{yield to="banner"}}</div> <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item to="item"}} </li> {{else}} <li>{{yield to="empty"}}</li> {{/each}} </ul> {{/if}} app/components/drop-down.hbs Destination Where would be the perfect destination for your
 virtual vacation? Choose a destination... Too much free time? Become a virtual tour guide and share your passion with the world! Sorry, we are sold out. Join our mailing list to be notified of new tours!
  33. <!-- Omitted: same markup for header as before --> <DropDown

    @label="Choose a destination..." @items={{this.places}}> <:banner> <h3>Too much free time?</h3> Become a virtual tour guide and share your passion with the world! </:banner> <:item as |item|> <img src={{item.image}} alt="" width="80" height="80"> <h3>{{item.name}}</h3> <p>{{item.description}}</p> </:item> <:empty> <h3>Sorry, we are sold out.</h3> <a href="...">Join our mailing list</a> to be notified of new tours! </:empty> </DropDown> app/templates/index.hbs <div class="drop-down" ...attributes> <!-- Omitted: same markup for button as before --> {{#if this.expanded}} <div class="banner">{{yield to="banner"}}</div> <ul role="listbox" aria-labelledby="{{this.id}}-button" tabindex="-1"> {{#each @items as |item|}} <li role="option" {{on "click" (fn this.select item)}}> {{yield item to="item"}} </li> {{else}} <li>{{yield to="empty"}}</li> {{/each}} </ul> {{/if}} app/components/drop-down.hbs Destination Where would be the perfect destination for your
 virtual vacation? Choose a destination... Too much free time? Become a virtual tour guide and share your passion with the world! Yufuin Scenic Japanese Onsen Town Paris Capital of France O‘ahu Third Largest Hawaiian Island
  34. <MyComponent> <:block>...</:block> </MyComponent> {{#my-component}} <:block>...</:block> {{/my-component}}

  35. <MyComponent> <:block>...</:block> </MyComponent> <MyComponent> <:block>...</:block> <:block>...</:block> <:block>...</:block> </MyComponent>

  36. <MyComponent> <:block>...</:block> </MyComponent> <MyComponent /> <:block>...</:block>

  37. <MyComponent> <:block>...</:block> </MyComponent> <MyComponent> Hello! <:block>...</:block> </MyComponent>

  38. <MyComponent> <:block> {{#if this.condition}} ... {{/if}} </:block> </MyComponent> <MyComponent> {{#if

    this.condition}} <:block>...</:block> {{/if}} </MyComponent>
  39. {{#if (has-block "foo")}} {{yield to="foo"}} {{else}} Some default content {{/if}}

  40. {{yield "one" "two" "three" to="thing"}} <:thing as |first second third|>

    First: {{first}} Second: {{second}} Third: {{third}} </:thing>
  41. <MyComponent> Hello! </MyComponent> <MyComponent> <:default>Hello!</:default> </MyComponent>

  42. {{#my-component}} Hello! {{else}} Bye! {{/my-component}} <MyComponent> <:default>Hello!</:default> <:else>Bye!</:else> </MyComponent>

  43. {{yield}} {{yield to="default"}}

  44. Value Semantics HIGHLIGHT #3 Contextual Components, Helpers, Modifiers and More

  45. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea @label="Bio" @field="bio" /> <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit
  46. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea @label="Bio" @field="bio" /> <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit
  47. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea @label="Bio" @field="bio" /> <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit
  48. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea @label="Bio" @field="bio" /> <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit
  49. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea @label="Bio" @field="bio" /> <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit
  50. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea @label="Bio" @field="bio" /> <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit
  51. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea @label="Bio" @field="bio" /> <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit
  52. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit @label="Bio" @field="bio" /> @form={{...}}
  53. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> <f.TextArea <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> <f.Submit /> </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield (hash Input=(component "my-form/input" form=this) TextArea=(component "my-form/text-area" form=this) Combo=(component "my-form/combo" form=this) Submit=(component "my-form/submit" form=this) ) }} </form> app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit @label="Bio" @field="bio" />
  54. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as | < < < < </MyForm> app/templates/index.hbs <form {{on "submit" this.onSubmit}}> {{yield app/components/my-form.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit Input TextArea Combo Submit|> Input @label="Your Name" @field="name" /> TextArea @label="Bio" @field="bio" /> Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> Submit /> (component "my-form/input" form=this) (component "my-form/text-area" form=this) (component "my-form/combo" form=this) (component "my-form/submit" form=this) }} </form>
  55. NAMED BLOCKS are called by the component author and can

    receive data from the component via block params. CONTEXTUAL COMPONENTS are called by the component consumer and can pass data to the component via arguments and blocks.
  56. {{component "some-component"}} {{modifier "some-modifier"}} {{helper "some-helper"}} new! new!

  57. {{yield (component "some-component")}} {{yield (modifier "some-modifier")}} {{yield (helper "some-helper")}} new!

    new!
  58. <MyComponen @component={{component "some-component"}} /> <MyComponen @modifier={{modifier "some-modifier"}} /> <MyComponen @helper={{helper

    "some-helper"}} /> new! new!
  59. {{component "some-component" foo="bar"}} {{modifier "some-modifier" foo="bar"}} {{helper "some-helper" foo="bar"}} new!

    new!
  60. <f.Component @foo="bar" /> <div {{f.modifier foo="bar"}}>...</div> {{#if (f.helper foo="bar")}}...{{/if}} new!

    new!
  61. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> {{#if (f.isEmpty "name")}} <f.Error @field="name">Please provide your name.</f.Error> {{/if}} <f.TextArea @label="Bio" @field="bio" {{f.autoResize}} /> {{#if (f.hasMinLength "bio" 100)}} <f.Error @field="bio">Your bio is too short.</f.Error> {{else if (f.hasMaxLength "bio" 500)}} <f.Error @field="bio">Your bio is too long.</f.Error> {{/if}} <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> {{#if (f.hasMinLength "visited" 3)}} Wow, you visited a lot of countries! You will be a great tour guide! {{/if}} <f.Submit /> </MyForm> app/templates/index.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit Your bio is too short. Wow, you visited a lot of countries! You will be a great tour guide!
  62. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> {{#if (f.isEmpty "name")}} <f.Error @field="name">Please provide your name.</f.Error> {{/if}} <f.TextArea @label="Bio" @field="bio" {{f.autoResize}} /> {{#if (f.hasMinLength "bio" 100)}} <f.Error @field="bio">Your bio is too short.</f.Error> {{else if (f.hasMaxLength "bio" 500)}} <f.Error @field="bio">Your bio is too long.</f.Error> {{/if}} <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> {{#if (f.hasMinLength "visited" 3)}} Wow, you visited a lot of countries! You will be a great tour guide! {{/if}} <f.Submit /> </MyForm> app/templates/index.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit Your bio is too short. Wow, you visited a lot of countries! You will be a great tour guide!
  63. <h2>Application Form</h2> <p>Become a virtual tour guide and share your

    passion with the world!</p> <MyForm @onSubmit={{this.onSubmit}} as |f|> <f.Input @label="Your Name" @field="name" /> {{#if (f.isEmpty "name")}} <f.Error @field="name">Please provide your name.</f.Error> {{/if}} <f.TextArea @label="Bio" @field="bio" {{f.autoResize}} /> {{#if (f.hasMinLength "bio" 100)}} <f.Error @field="bio">Your bio is too short.</f.Error> {{else if (f.hasMaxLength "bio" 500)}} <f.Error @field="bio">Your bio is too long.</f.Error> {{/if}} <f.Combo @label="Countries Visited" @field="visited" @options={{this.countries}} /> {{#if (f.hasMinLength "visited" 3)}} Wow, you visited a lot of countries! You will be a great tour guide! {{/if}} <f.Submit /> </MyForm> app/templates/index.hbs Application Form Become a virtual tour guide and share your passion with the world! Tomster Your Name Bio Countries Visited France Japan United States Submit Your bio is too short. Wow, you visited a lot of countries! You will be a great tour guide!
  64. import Component from '@glimmer/component'; import { SomeComponent, someModifier, someHelper }

    from 'some-addon'; export default class MyComponent extends Component { SomeComponent = SomeComponent; someModifier = someModifier; someHelper = someHelper; } app/components/my-component.js <this.SomeComponent @foo="bar" /> <div {{this.someModifier foo="bar"}}>...</div> {{#if (this.someHelper foo="bar")}}...{{/if}} app/components/my-component.hbs new!
  65. import Component from '@glimmer/component'; import { SomeComponent, someModifier, someHelper }

    from 'some-addon'; export default class MyComponent extends Component { SomeComponent = SomeComponent; someModifier = someModifier; someHelper = someHelper; } app/components/my-component.js {{yield (hash SomeComponent=(component this.SomeComponent foo="bar") someModifier=(modifier this.someModifier foo="bar") someHelper=(helper this.someHelper foo="bar") ) }} app/components/my-component.hbs new!
  66. import Component from '@glimmer/component'; import { helper } from '@ember/component/helper';

    function sum(numbers) { if (numbers.length === 0) { return 0; } else { return numbers.pop() + sum(numbers); } } export default class MyComponent extends Component { sumHelper = helper(sum); } app/components/my-component.js Sum of 1 to 5: {{this.sumHelper 1 2 3 4 5}} app/components/my-component.hbs new!
  67. import Component from '@glimmer/component'; import { tracked } from '@glimmer/tracking';

    import Modifier from 'ember-modifier'; export default class MyComponent extends Component { @tracked width = 100; @tracked height = 100; get keepInViewport() { let { width, height } = this; return class extends Modifier { didInstall() { // ... } willRemove() { // ... } }; } } app/components/my-component.js <img src={{@src}} width={{this.width}} height={{this.height}} ...attributes {{this.keepInViewport}}> app/components/my-component.hbs new!
  68. import Component from '@glimmer/component'; export default class MyComponent extends Component

    { SomeComponent = SomeComponent; someModifier = someModifier; someHelper = someHelper; } app/components/my-component.js app/components/my-component.hbs new! import { SomeComponent, someModifier, someHelper } from 'some-addon'; this. this. this. SomeComponent @foo="bar" /> someModifier foo="bar"}}>...</div> someHelper foo="bar")}}...{{/if}} < <div {{ {{#if (
  69. app/components/my-component.hbs not yet! import { SomeComponent, someModifier, someHelper } from

    'some-addon'; --- --- SomeComponent @foo="bar" /> someModifier foo="bar"}}>...</div> someHelper foo="bar")}}...{{/if}} < <div {{ {{#if (
  70. app/components/my-component.hbs not yet! import { SomeComponent, someModifier, someHelper } from

    'some-addon'; <SomeComponent @foo="bar" /> <div {{someModifier foo="bar"}}>...</div> {{#if (someHelper foo="bar")}}...{{/if}} app/components/my-component.js import { SomeComponent, someModifier, someHelper } from 'some-addon'; --- --- <SomeComponent @foo="bar" /> <div {{someModifier foo="bar"}}>...</div> {{#if (someHelper foo="bar")}}...{{/if}} import Component from '@glimmer/component'; import { helper } from '@ember/component/helper'; const sum = helper(function sum(numbers) { if (numbers.length === 0) { return 0; } else { return numbers.pop() + sum(numbers); } }); export default class MyComponent extends Component { <template> Sum of 1 to 5: {{sum 1 2 3 4 5}} </template> // other JS things... }
  71. #287 {{#in-element}} New Primitives #615 Auto-Tracking Memoization #669 Tracked Storage

    #625 Helper Manager #626 invokeHelper #496 Strict Mode Templates #581 New Test Waiters #580 Destroyables
  72. #617 RFC Stages Process Updates Accessibility Working Group TypeScript Strike

    Team Tooling #649 Deprecation Staging Polyfills Codemods #685 New Browser Support Policy
  73. None
  74. PLATFORM STATE OF THE UNION