Flowtype "Not covered by Flow" on object property chains - flowtype

I'm trying to use Flow, but I keep getting the "Not covered by Flow" warning, so my code is mostly underlined. I checked the Flow documentation, but it wasn't helpful regarding object property chaining, so how do you get something like this to work?

It appears that you are using a library that does not have type definitions.
With property lookups where the object is defined within the file, Flow has 100% code coverage without any types at all:
const foo = { bar: { baz: 2 } };
foo.bar.baz;
// 100% Flow coverage
Same goes for separate files:
1.js
// #flow
export default { bar: { baz: 2 } };
2.js
// #flow
import foo from './1.js'
foo.bar.baz;
// 100% code coverage
However, as soon as something is being imported from a file that Flow does not run on (either because it has flow turned off or because its a third-party library that does not use flow), Flow is not able to cover it.
1.js
// #noflow
export default { bar: { baz: 2 } };
2.js
// #flow
import foo from './1.js'
foo.bar.baz;
// 0% code coverage
In order to fix this, you need to give Flow information about the types.
You can do a couple of different things
Make a.js covered by Flow.
Add a a.js.flow file that declare's the types
If it's a third-party library add a flow-typed/a.js file that adds declarations.
But be sure to check flow-typed to see if a definition file already exists. (And contribute back!)
Hopefully this is helpful enough to give you at least a starting point

I'm new to Flow as well, but heres my take:
If you have two classes, A and B, and flow typechecking is not enabled on A, then B functions that call into it will be "uncovered".
// a.js
class A {
}
// b.js
/* #flow */
import A from './A'
class B {
buildA():void {
new A() // I'm un-covered by Flow!
}
}
Flow doesn't know anything about the structure of A, and so therefore can't provide any guarantees.

Related

Static #ViewChildren

I have a situation where I was to replace
#ViewChild(Foo, { static: true }) foo!: Foo;
with a version that gets several Foo in a list.
The expected solution is
#ViewChildren(Foo, { static: true }) foos!: QueryList<Foo>;
but #ViewChildren doesn’t support static.
Is there any work-around here?
The use-case is that I have something like this:
#ViewChild(Foo, { static: true }) foo!: Foo;
ngOnInit(): void {
onFooInit(this.foo);
}
ngAfterViewInit(): void {
afterViewFooInit(this.foo);
}
and I need it to become
#ViewChildren(Foo, { static: true }) foos!: QueryList<Foo>;
ngOnInit(): void {
this.foos.forEach(onFooInit);
}
ngAfterViewInit(): void {
this.foos.forEach(afterViewFooInit);
}
where onFooInit and afterViewFooInit are black-box library functions whose documentation says to call them in ngOnInit and ngAfterViewInit, respectively, noting that { static: true } is necessary to do so. (I have tested this, and yes, there are errors without { static: true }.)
I tried some hackery with #ViewChild(Foo, { static: true }) set foo(foo: Foo) { this.foos.push(foo); }, which unsurprisingly went nowhere, and I tried to create my own custom decorator that internally called ViewChild on each match of the selector, which I couldn’t get working. One thing I know I could do is just use ViewChild on each individual thing I want to include in the list, and then hard-code the actual list creation from those, but I want to re-use this code in several components which is going to get painful real fast.
Then I realized this should really be a directive, but the ElementRef in the directive has the same problems, being undefined in ngOnInit (I guess it isn’t static). The alternative to a directive is a wrapping component, but then I have to worry about all the inputs which is a huge pain. Probably better than the hard-coded polymorphic list, though.
I am open to suggestions on better ways to avoid this kind of initialization boilerplate on each of these components (that are very similar to one another, just with slightly different fields in each case).

How would I apply Material-UI managed styles to non-material-ui, non-react elements?

I have an application where I'm using Material UI and its theme provider (using JSS).
I'm now incorporating fullcalendar-react, which isn't really a fully fledged React library - it's just a thin React component wrapper around the original fullcalendar code.
That is to say, that I don't have access to things like render props to control how it styles its elements.
It does however, give you access to the DOM elements directly, via a callback that is called when it renders them (eg. the eventRender method).
Here's a basic demo sandbox.
Now what I'm wanting to do is make Full Calendar components (eg, the buttons) share the same look and feel as the rest of my application.
One way to do this, is that I could manually override all of the styles by looking at the class names it's using and implementing the style accordingly.
Or - I could implement a Bootstrap theme - as suggested in their documentation.
But the problem with either of these solutions, is that that:
It would be a lot of work
I would have synchronisation problems, if I made changes to my MUI theme and forgot to update the calendar theme they would look different.
What I would like to do is either:
Magically convert the MUI theme to a Bootstrap theme.
Or create a mapping between MUI class names and the calendar class names, something like:
.fc-button = .MuiButtonBase-root.MuiButton-root.MuiButton-contained
.fc-button-primary= .MuiButton-containedPrimary
I wouldn't mind having to massage the selectors etc to make it work (ie. For example - MUI Buttons have two internal spans, whereas Full Calendar have just one). It's mostly about when I change the theme - don't want to have to change it in two places.
Using something like Sass with its #extend syntax would is what I have in mind. I could create the full-calendar CSS with Sass easily enough - but how would Sass get access to the MuiTheme?
Perhaps I could take the opposite approach - tell MUI 'Hey these class names here should be styled like these MUI classes'.
Any concrete suggestions on how I would solve this?
Here is my suggestion (obviously, it's not straight forward). Take the styles from the MUI theme and generate style tag based on it using react-helmet. To do it event nicely, I created a "wrapper" component that do the map. I implemented only the primary rule but it can be extended to all the others.
This way, any change you will do in the theme will affect the mapped selectors too.
import React from "react";
import { Helmet } from "react-helmet";
export function MuiAdapter({ theme }) {
if (!theme.palette) {
return <></>;
}
return (
<Helmet>
<style type="text/css">{`
.fc-button-primary {
background: ${theme.palette.primary.main}
}
/* more styles go here */
`}</style>
</Helmet>
);
}
And the use of the adapter
<MuiAdapter theme={theme} />
Working demo: https://codesandbox.io/s/reverent-mccarthy-3o856
You could create a mapping between MUI class names and the calendar class names by going through ref's. It's possible that this is not what some would call "best practice"...but it's a solution :). Note that I updated your component from a functional component to a class component, but you could accomplish this with hooks in a functional component.
Add refs
Add a ref to the MUI element you want to set as a reference, in your case the Button.
<Button
color="primary"
variant="contained"
ref={x => {
this.primaryBtn = x;
}}
>
And a ref to a wrapping div around the component you want to map to. You can't add it directly to the component since that wouldn't give us access to children.
<div
ref={x => {
this.fullCal = x;
}}
>
<FullCalendar
...
/>
</div>
Map classes
From componentDidMount() add whatever logic you need to target the correct DOM node (for your case, I added logic for type and matchingClass). Then run that logic on all FullCalendar DOM nodes and replace the classList on any that match.
componentDidMount() {
this.updatePrimaryBtns();
}
updatePrimaryBtns = () => {
const children = Array.from(this.fullCal.children);
// Options
const type = "BUTTON";
const matchingClass = "fc-button-primary";
this.mapClassToElem(children, type, matchingClass);
};
mapClassToElem = (arr, type, matchingClass) => {
arr.forEach(elem => {
const { tagName, classList } = elem;
// Check for match
if (tagName === type && Array.from(classList).includes(matchingClass)) {
elem.classList = this.primaryBtn.classList.value;
}
// Run on any children
const next = elem.children;
if (next.length > 0) {
this.mapClassToElem(Array.from(next), type, matchingClass);
}
});
};
This is maybe a little heavy handed, but it meets your future proof requirement for when you updated update Material UI. It would also allow you to alter the classList as you pass it to an element, which has obvious benefits.
Caveats
If the 'mapped-to' component (FullCalendar) updated classes on the elements you target (like if it added .is-selected to a current button) or adds new buttons after mounting then you'd have to figure out a way to track the relevant changes and rerun the logic.
I should also mention that (obviously) altering classes might have unintended consequences like a breaking UI and you'll have to figure out how to fix them.
Here's the working sandbox: https://codesandbox.io/s/determined-frog-3loyf

Dynamically switch global CSS for Angular8 app (client branding)

I want to dynamically switch Angulars global CSS files based on which client is connecting. This will be used for client-branding purposes, including fonts, colors, photos, headers, footers, button-styles, etc.
Each client has provided us with a CSS file, which we need to integrate into our app. We have hundreds of clients.
Current solution is to try and override the CSS of individual components at load. This is bad because it adds a lot of boilerplate:
Html:
<link id="theme" rel="stylesheet" href="./assets/stylesheets/{{cclientCode}}.css">
ts:
ngOnInit() {
this.service.clientCode.subscribe(clientCode => this.clientCode = clientCode);
}
My workaround isn't working because the link html is called before the {{}} has a chance to load in the value.
I'm also not motivated to fix my workaround because its just that -a workaround. Instead, I want to implement something that works globally, without any per-component boilerplate.
What I want is the ability to dynamically switch the global Angular style for each client. So something like:
"styles": [
"src/assets/stylesheets/angular_style.css",
"src/assets/stylesheets/client_style.css"
]
Where client_style.css is served differently to each client.
I've found a solution that I think is workable. It definitely has issues though, so if anyone has their own answer, please still share!
First, I added a clientCode String field to SessionDataService, a global service I use to move component-agnostic data around my app:
export class SessionDataService {
clientCode: BehaviorSubject<String>;
constructor(){
this.clientCode = new BehaviorSubject('client_default');
}
setClientCode(value: String) {
this.clientCode.next(value);
}
}
Then, inside app.component.ts, I added a BehaviorSubject listener to bring in the value of clientCode dynamically:
public clientCode: String;
constructor(private service : SessionDataService) {
this.service.clientCode.subscribe(clientCode => this.clientCode = clientCode);
}
Next, I added a wrapper around my entire app.component.html:
<div [ngClass]="clientCode">
--> ALL app components go here (including <router-outlet>)
</div>
So at this point, I've created a system that dynamically adds client-code CSS classes to my components, including all children :)
Finally, I just have to write CSS rules:
.ClientOne p {
color: red;
}
.ClientOne .btn {
background-color: red;
}
.ClientTwo.dashboard {
height: 15%;
}
I hope this helps somebody! Essentially the "trick" here is to add a ngClass that wraps the entire app, and then justify all client-specific CSS rules with their client code.

How to both define a js function in a separate file yet attach it to a QML element

I can do this:
SomeElement{
id: something
function someFunction(){...}
....
OtherElement{
property int whatever: something.someFunction()
However, I'd like all my JS functions defined in a separate file. The problem is that this decouples the functions from being attached to any one element, as far as I can tell. I can no longer refer to a function as a property on another element to call it.
Is it possible for a function to be attached to a QML element but still have it defined in another file? Would there be some syntax to "forward" or "alias" the function from the element so one could still call this "member function" on the element, and thus this function could be able to access other properties on its parent element?
You can try to import js file as some module and use its function with module name prefix. So, they will be in separate 'namespace' from you QML object's functions
Documentation about it: http://qt-project.org/doc/qt-5.0/qtqml/qtqml-javascript-imports.html
Is it possible for a function to be attached to a QML element but
still have it defined in another file? Would there be some syntax to
"forward" or "alias" the function from the element so one could still
call this "member function" on the element, and thus this function
could be able to access other properties on its parent element?
Not directly, but easily fake-able:
// foo.js
function printDimensions(item) {
console.log(item.width, "x", item.height)
}
// in qml
import "foo.js" as Foo
// ..
Item {
id: someItem
function printDimensions() { Foo.printDimensions(someItem) }
}
// ..
Rectangle {
id: anotherItem
function printDimensions() { Foo.printDimensions(anotherItem) }
}
This way you can attach the function to different objects via a simple wrapper.

How to override mixins in LESS CSS 1.4+

I've been using what I thought was a very elegant pattern for defining the styles of reusable components/widgets, using LESS. It works beautifully in LESS 1.3-, but after upgrading recently, my whole library is broken. Does anyone know a way to accomplish something like this in 1.4+?
Here's a very simple example of a component:
#componentName {
.loadMixins(){
.text() {}
.header() {}
}
.apply(){
> h3 {
// markup-specific styles
padding: 3px;
margin-bottom: 0;
// custom styles
.header();
}
> div.body, > div.popup p {
color: red;
// custom styles
.text()
}
}
}
And here's how it would be used:
.coolWidget {
#componentName.loadMixins();
// override mixins here
.text(){
color: green;
}
#componentName.apply();
}
This keeps all the markup-dependent styles abstracted from the user. I could completely change my markup and the user's styles would still work. According to the less.js changelog, 1.4.0 Beta 1 has a line "variables in mixins no longer 'leak' into their calling scope"
Is there any way around this?
Strictly speaking nested variables and mixins are still expanded into calling scope unless this scope already has those names defined.
Your example above results in a error:
SyntaxError: .header is undefined...
and it's expected as no .header() is actually defined within the .coolWidget (or anywhere else).
This can be fixed by providing "default" definitions for .text and .header somewhere inside #componentName.
For example if you modify .loadMixins() to:
.loadMixins() {
.text();
.header();
// default properties in case a caller does not provide its own:
.text() {}
.header() {}
}
then the example compiles OK and all text/header properties are overridden as expected.
I can imagine how your library may become broken because of new scope rules but this particular example you gave above does not illustrate the problem.

Resources