# Next Meeting 2020-11-22/3? # 2020-11-20 ### Perf - [1] Must have build time optimizations - Even if not solved, must prove it CAN be added soon - Runtime, obviously fast as possible :/ ### Specificity Specificity is in JS, not CSS selectors in sheet - User can't see it to work around it - User has no control over it when it doesn't work - Underlying changes break the user (atomic plus stylex) Render/write order of styles at runtime (overrides, new theme, etc) - [1] CSS insertion at runtime (support proper document) - [2] SSR support (req stable classes) ### Dynamic Styles Enable build-time optimizations, no runtime values? - No props - No conditional styles (ie Teams variables usage) - Caveat, themes are OK, they're available at build time - [X] Theme "swtiching" live must work ## Next Try stylex as mid-solution that uses atomic but also provides ordering for specificity as well as build time optimizations. - [ ] Miro and/or Shift to get stylex algorithm working, try makeStyles() api updates first # makeStyles 2020-11-16 CONCLUSION: Miro - test makeStyles in v0 Docs Avatar Levi - test makeStyles in Teams Avatar David - test makeStyles in Ribbon Button REQUIREMENT: Deterministic styles due to deterministic order of dep graph. ASSUMES top-level imports are 1:1 with dep graph order. Caveats where makeStyles call order doesn't follow dep graph: - Execution order of the graph is non-deterministic when lazy loading components since top-level execution order is based on runtime logic. - If the requirement is not ALWAYS true, this solution will not work. ## Tests ### iFrame/Multi-Window How will we render parent styles in iframe? 1. iframe src 2. iframe injection (Teams) - BaseButton (F) - Button (T) - CallingButton -> iFrame ### Multiple Experiences Override styles are dependent on dependency graph. ``` A: .ui-button { border: 1px } B: ... Style: A B C D E ... \ / \ / \ / Comp: X (has overrides that work for A styles) | BaseX - X has overrides that assume stylesheet A exists FIRST - X breaks when overrides written to stylesheet B ``` ## Async Imports This makes the _execution order_ of dependency graph non-deterministic. The graph itself is still deterministic. ``` import { fooButtonStyles, barButtonStyles } fooButtonStyles() barButtonStyles() const Base = if foo import 'foo-button' () else if bar import 'bar-button' () makeStyles { button overrides } ``` ### Workaround The solution (entirely resolvable by the consumer dev) is to avoid using styles from the parent across the async boundary. Bad: Need to automate preventing this pattern - Cannot apply top-level makeStyles classes to lazy components - Instead, load the styles at the same time as the component (lazy) ```tsx= const MyDialog = React.lazy(() => import('./OtherComponent')); const useAppClasses = makeStyles({ dialog: { background: 'red' } }) const App = () => { const classes = useAppClasses(); return ( <div> <Suspense fallback={<h1>Loading profile...</h1>}> <MyDialog className={classes.dialog} slot={{ className: classes.foo }} /> </Suspense> </div>; ); } ``` Better: no classes across boundaries My dialog self-contained in another `MyDialog.tsx` file: ```tsx import { Dialog } from 'fluentui'; const useAppClasses = makeStyles({ dialog: { background: 'red' } }) export const MyDialog = () => { const classes = useClasses(); return <Dialog className={classes.dialog }/> ``` Dialog is async imported without classes: ```tsx const MyDialog = React.lazy(() => import('./MyDialog')); const App = () => { const classes = useAppClasses(); return ( <div> <Suspense fallback={<h1>Loading profile...</h1>}> <MyDialog /> </Suspense> </div>; ); } ``` ## Sharing styles dictates style import order Just like CSS stylesheets, the import order of the styles MUST be maintained to ensure specificity is maintained. ```jsx focusRing.ts export const focusRing = makeStyles({ring: { outline: '1px solid red'}}) export const focusRingOverrides = {ring: { outline: '1px solid red'}} fileA.ts import {Button} import focusRing const focusRing2 <Button className={focusRing} /> fileB.ts import {MenuButton} import focusRing <MenuButton className={focusRing} /> Dialog: uses A first, then b: .Button .focusRing .MenuButton Toolbar: uses B first, then a: .Button .MenuButton .focusRing expected: .Button .MenuButton .focusRing ``` Thought: is this a restriction we can live with? Essentially, we're saying: when you override stuff, it should live in the same file that imports the thing it overides. That is; if focusRing should be shared by both things, it would be resolved by having the focusRing import both things it overrides (Button and MenuButton) before makeStyles is called. Alternative idea: How override classes could solve specificity: ```tsx const useClasses = makeStyles({...}); const Button = (props) => { const classes = useClasses({ overrideClasses: { root: props.className } }); return <button className={classes.root} /> } ``` Downsides mentioned: * Every override layer would need to pass along the styles this way, adds complexity: ``` A5 A6.2 A6.1 A6 A7 <Avatar className={myOverrides.avatar} ``` ```jsx MyButton.ts import Button makeStyles({ ... }) MyExp.ts import MyButton .Button .overrides OtherExpButton.ts import Button makeStyles({ ... }) OtherExp.ts import OtherExpButton .Button .OtherExpButton (overrides) import MyButton .MyButton . overrides break because they don't know about ^^^ ```