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

3L-Components

 3L-Components

Azizi Yazit

June 28, 2021
Tweet

More Decks by Azizi Yazit

Other Decks in Research

Transcript

  1. Auto biography PLUGIN MvvM MvC Module Component Accordion1 > Content

    Accordion2 > Tab1 Tab2 Tab3 Content Btn Btn Card title Select > Option1 Option2 Option3 Widget Component Library Application Design Tokens StyleGuide UX Design System
  2. Component-Based Architecture Structure Component Library Design System 1 2 3

    Component Library Component Library Component Library
  3. Material Design Consumer Consumer Consumer Consumer Design System <firebase-select [options]=“itemsA”

    ></firebase-select> <firebase-select [options]=“itemsB” ></firebase-select> <firebase-select [options]=“itemsC” ></firebase-select> 1 2 3 Disclaimer: this is not the actual google component structure. This is just an example
  4. Why 3LC, why not 2LC? Design System Abstractions Product with

    multiple apps Product with multiple apps
  5. Why 3LC, why not 2LC? Design System Abstractions Product with

    multiple apps Product with multiple apps Another level of abstraction
  6. Why 3LC, why not 4LC? Component library - Consumers Design

    System - Provider Abstractions Abstractions Abstractions Design System - Consumer Component Libraries Atomic Components - Across teams Base Style-guide Base Standards & Conventions Team Specific Basic Components Team Specific Style-guide Team Specific Standards & Conventions
  7. 3 Level Component Component Library Design System <org-select [options]=“itemsA” ></org-select>

    <org-select [options]=“itemsB” ></org-select> <org-select [options]=“itemsC” ></org-select> Abstractions Abstractions Component Library Component Library Component Library
  8. Material Design Consumer Consumer Consumer Consumer Provider Abstractions Principle of

    least power Abstractions Abstractions is cool but it must be balanced with the principles of least power to avoid wrong abstractions
  9. The Sunk Cost Fallacy Developer hate to see duplications Refactor

    to a new reusable component Simple Web Page Loop until code becomes incomprehensible ABC XYZ DEF QWS …. …. …. This creates a new abstraction. New design requirement, new variant added Universal abstraction now behaves differently for different cases.
  10. The Sunk Cost Fallacy Developer hate to see duplications Refactor

    to a new reusable component Simple Web Page Loop until code becomes incomprehensible ABC XYZ DEF QWS …. …. …. This creates a new abstraction. New design requirement, new variant added Universal abstraction now behaves differently for different cases. Sunk cost fallacy is whereby a person is reluctant to abandon a strategy or course of action even though the abandonment would be more beneficial - as you don’t want to lose out on the effort you have already sunk (can’t be recovered) Simple Web Page ABC XYZ DEF QWS …. …. ….
  11. CC 10:47 / 35:31 Cheng Lau (FB) A lots of

    problems arise from bad understanding where we should be in the levels of abstraction
  12. 3LC’s Compounding Configuring Implementing mindset of “develop once used forever”

    Abstracting away UI Behaviour & UI logics Provide very minimal user interface.
  13. Compounding Compound components is a pattern in which components are

    used together such that they share an implicit state that let’s them communicate with each other in the background. Parent Component Child Component 1 Child Component 2 Implicit state
  14. Compounding Think of compound components like the <select> and <option>

    elements in HTML. Apart they don’t do too much, but together they allow you to create the complete experience. — Kent C. Dodds <select name="cars" id="cars"> <option value="volvo">Volvo</option> <option value="saab">Saab</option> </select>
  15. Compounding > components/select select.component select-top-control.component select-placeholder.component select-item.component select-clear.component select-arrow.component option.component

    option-item.component option-item-group.component option-group.component option-container.component NG-Zorro Select component
  16. Compounding SelectContainer Component Option-item Component 1 Option-item Component 2 Implicit

    state selected 2 index matched add bold 3 index unmatched remove bold 1 send index send current state send current state
  17. <ng-container *ngIf="state | async as selectState"> <ng-container *ngTemplateOutlet=“template; context: selectState”>

    </ng-container> </ng-container> export class SelectContainerComponent { @ContentChild(TemplateRef, { static: false }) template!: TemplateRef<any>; state = new BehaviorSubject({ selectedOption: {} }); optionClick(selectedOption) { this.state.next({ selectedOption }); } }
  18. <ng-container *ngIf="state | async as selectState"> <ng-container *ngTemplateOutlet=“template; context: selectState”>

    </ng-container> </ng-container> export class SelectContainerComponent { @ContentChild(TemplateRef, { static: false }) template!: TemplateRef<any>; state = new BehaviorSubject({ selectedOption: {} }); optionClick(selectedOption) { this.state.next({ selectedOption }); } } SelectContainer Component Option 1 Option 2 optionClick(selectedOption) { this.state.next({ selectedOption }); <ng-container *ngIf="state | async as selectState"> <ng-container *ngTemplateOutlet=“template; context: selectState”> </ng-container> </ng-container>
  19. @Directive({ selector: “[optionItem]” }) export class OptionDirective @Input() data =

    {}; constructor( private element: ElementRef, @Inject(forwardRef(() => SelectContainerComponent)) private selectContainerComponent: SelectContainerComponent ) {} ngAfterViewInit() { fromEvent(this.element.nativeElement, "click") .pipe(takeUntil(this.destroy)) .subscribe(() => this.selectContainerComponent.optionClick(this.data)); } }
  20. @Directive({ selector: “[optionItem]” }) export class OptionDirective @Input() data =

    {}; constructor( private element: ElementRef, @Inject(forwardRef(() => ProviderSelectComponent)) private providerSelectComponent: ProviderSelectComponent ) {} ngAfterViewInit() { fromEvent(this.element.nativeElement, "click") .pipe(takeUntil(this.destroy)) .subscribe(() => this.providerSelectComponent.optionClick(this.data)); } } constructor( @Inject(forwardRef(() => SelectContainerComponent)) private SelectContainerComponent: SelectContainerComponent ) fromEvent(this.element.nativeElement, "click") .pipe(takeUntil(this.destroy)) .subscribe(() => this.selectContainerComponent.optionClick(this.data)); SelectContainer Component Option 1 Option 2 optionItem optionItem
  21. <select-container> <ng-template> <span selectTrigger> Please Select… </span> <ul optionList> <li

    [data]=“{value: 'v'}" optionItem> Volvo </li> <li [data]=“{value: 's'}" optionItem> Saab </li> </ul> </ng-template> </select-container> SelectContainer Component Option 1 Option 2 optionItem optionItem <select-container> <ng-template> <span selectTrigger> </span> <ul optionList> <li optionItem> </li> <li optionItem> </li> </ul> </ng-template> </select-container>
  22. <select-container> <ng-template let-isOpen=“isOpen” let-selectedOption=“selectedOption”> <span selectTrigger> Please Select… </span> <ul

    optionList *ngIf=“isOpen”> <li [data]=“{value: 'v'}" optionItem> Volvo </li> <li [data]=“{value: 's'}" optionItem> Saab </li> </ul> </ng-template> </select-container>
  23. <select-container> <ng-template> <span selectTrigger> Please Select… </span> <ul optionList> <li

    [data]=“{value: 'v'}" optionItem> Volvo </li> <li [data]=“{value: 's'}" optionItem> Saab </li> </ul> </ng-template> </select-container> <span selectTrigger> Please Select… </span> <ul optionList> <li [data]=“{value: 'v'}" optionItem> Volvo </li> <li [data]=“{value: 's'}" optionItem> Saab </li> </ul>
  24. 3LC’s Compounding Configuring Implementing Implement the Compound Components Mindset of

    “Configuration over code” component Prebuilt component with design & styling ready.
  25. <org-select [options]=“items” ></org-select> Implementing <select-container> <ng-template> <span selectTrigger> Please Select…

    </span> <ul optionList> <li [data]=“{value: 'v'}" optionItem> Volvo </li> <li [data]=“{value: 's'}" optionItem> Saab </li> </ul> </ng-template> </select-container>
  26. <select-container class=“org-select”> <ng-template let-isOpen=“isOpen” let-selectedOption=“selectedOption”> <span selectTrigger class=“org-select__trigger”> Please select…

    </span> <ng-container *ngIf=“isOpen”> <ul *ngFor=“let opt of items”> <li *ngIf=“opt.template else defaultOption”> <ng-container *ngTemplateOutlet=“opt.template; context: { selectedOption, data: opt }”> </ng-container> </li> <ng-template #defaultOption> <li optionItem [value]=“opt.value” class=“org-select__opt”> <i [name]=“opt.icon” class=“org-select__opt-icon”></i> <label class=“org-select__opt-label” >{{opt.label}}</label> </li> </ng-template> </ul> </ng-container> </ng-template> </select-container>
  27. <my-select class=“org-select”> <ng-template let-isOpen=“isOpen” let-selectedOption=“selectedOption”> <span selectTrigger class=“org-select__trigger”> Please select…

    </span> <ng-container *ngIf=“isOpen”> <ul *ngFor=“let opt of items”> <li *ngIf=“opt.template else defaultOption”> <ng-container *ngTemplateOutlet=“opt.template; context: { selectedOption, data: opt }”> </ng-container> </li> <ng-template #defaultOption> <li optionItem [value]=“opt.value” class=“org-select__opt”> <i [name]=“opt.icon” class=“org-select__opt-icon”></i> <label class=“org-select__opt-label” >{{opt.label}}</label> </li> </ng-template> </ul> </ng-container> </ng-template> </my-select> <li *ngIf=“opt.template else defaultOption”> <ng-container *ngTemplateOutlet=“opt.template; context: { selectedOption, data: opt }”> </ng-container> </li> <ng-template #defaultOption> <li optionItem [value]=“opt.value” class=“org-select__opt”> <i [name]=“opt.icon” class=“org-select__opt-icon”></i> <label class=“org-select__opt-label” >{{opt.label}}</label> </li> </ng-template> [ { value: ‘v’, label: ‘Volvo’ }, { value: ’s’, template: this.template } ]
  28. <my-select class=“org-select”> … <span selectTrigger class=“org-select__trigger”> Please select… </span> ….

    <li optionItem [value]=“opt.value” class=“org-select__opt”> <i [name]=“opt.icon” class=“org-select__opt-icon”></i> <label class=“org-select__opt-label” >{{opt.label}}</label> </li> </my-select> .org-select { &__trigger { /* custom style */ } &__opt { /* custom style */ } &__opt-icon { /* custom style */ } &__opt-label { /* custom style */ } }
  29. <org-select [options]=“[{ label: ‘Volvo’, value: ‘v’, disabled: false, italic: false,

    underline: false, items: [], selected: true, selectFn: …, hoverFn: …, }, {…}, {…}]” (valueChanged)=“onValueChange($event)” ></org-select> Configurations
  30. Summary 1st level component 2nd level component 3rd level components

    UI Behaviour and Logics Compounding Visual & Rendering Implementing Use-cases Configuring
  31. 15:01 / 38:46 10:47 / 35:31 Cheng Lau (FB) Cheng

    Lou - On the Spectrum of Abstraction at react-europe 2016 RailsConf 2014 - All the Little Things by Sandi Metz