Should all react-admin field component props types extend TypographyProps besides PublicFieldProps and InjectedFieldProps? - react-admin

I've noticed this type pattern in react-admin field component props types:
export interface MyCustomFieldProps
extends PublicFieldProps,
InjectedFieldProps,
TypographyProps {
[myCustomFieldExtraProp: string]: any
}
But sometimes TypographyProps is not extended. I have no clue why. I thought maybe a field component props type should only extend TypographyProps when it returns a Typography component.
Some examples:
DateField
export interface DateFieldProps
extends PublicFieldProps,
InjectedFieldProps,
TypographyProps {
locales?: string | string[];
options?: object;
showTime?: boolean;
}
FileField
export interface FileFieldProps extends PublicFieldProps, InjectedFieldProps {
src?: string;
title?: string;
target?: string;
download?: boolean | string;
ping?: string;
rel?: string;
classes?: object;
}
But then I've found some field components that return a Typography but do not extend TypographyProps. Therefore invalidating my thought.
Like this one:
EmailField
export interface EmailFieldProps
extends PublicFieldProps,
InjectedFieldProps,
AnchorHTMLAttributes<HTMLAnchorElement> {}

Well, I took some time to further investigate. It looks like fields that return a Typography component only are the only ones that extends TypographyProps.
TextField - Returns Typography for both value and emptyText.
NumberField - Returns Typography for both value and emptyText.
DateField - Returns Typography for both value and emptyText.
Fields that may return another component than Typography do not extend TypographyProps:
UrlField - Returns Link for value. Typography for emptyText.
EmailField - Returns Link for value. Typography for emptyText.
FileField - Returns div for value. Typography for emptyText.
I guess it's implemented that way so we don't get confused when passing Typograph props to a field component expecting change in the value component (not Typography). Because it's only applied to the emptyText component (Typography).

Related

From when is #Watch() active?

I'm trying to understand the #Watch() part of the Stencil lifecycle docs: https://stenciljs.com/docs/component-lifecycle
To me, the illustration above does not clearly show from when #Watch() actually starts watching.
There seem to be cases where a #Watch() hook is triggered even before componentWillLoad(), for example when a Stencil component is used in React with React.createRef(). These cases are not always reproducible - meaning that it could be a race condition.
That's why I'd like to know from what particular point in time #Watch() becomes active?
As stated on stencil change #Prop() detection, #Watch decorator of a property triggers when the property value changes, but not when the property is initially set.
To capture the initialization you have to trigger the handler on componentWillLoad passing the property value.
#Watch('name')
onNameChanged(newValue: string, oldValue: string) {
this._name = newValue;
}
componentWillLoad(){
this.onNameChanged(this.name);
}
As can be seen in the graphic of your linked doc page, a #Watch() decorated method is called every time a change in the value of prop or state you watch occurs. That is independent from the willLoad/willRender/render/didRender/didLoad/didUpdate cycle that occurs when the component is attached to the DOM.
#Component({ tag: 'my-comp' })
export class MyComp {
#Prop() input = 'foo';
#State() repeated: string;
#Watch('input')
onInputChange() {
this.repeated = this.input + this.input;
}
componentWillLoad() {
this.onInputChange(); // can manually call the watcher here
}
render() {
return this.repeated;
}
}
<script>
const myComp = document.createElement('my-comp');
// currently `repeated` would be undefined because the component has not yet rendered
myComp.input = 'foobar'; // now `repeated` *should* be `foobarfoobar`
</script>
(saying *should* because I haven't tested this)

Binding to a method which takes a string literal parameter

In the below code VUE is interpreting "foo" as a function...therefore I get an error foo is not a function, but in fact I just need the string value "foo" passed to my method.
What is the correct syntax please?
<BlokMenu
:menu="MenuBuilder.filterMenuItems('foo')"
/>
Screen shot of code from my view component
and the MenuBuild which is in MenuBuilder.js
MenuBuilder.js
bind object needs to belong to Vue component itself. In case of external module, you can bind it to data or computed properties
// Vue components
import MenuBuilder from 'MenuBuilder.js'
export default {
data: function() {
return {
MenuBuilder: MenuBuilder
}
}
}
and then
<BlokMenu :menu="MenuBuilder.filterMenuItems('foo')"/>

How to define property types when passing props to grandchildren in Vue.js?

I have a Vue component foo inside my HTML and I pass a parameter to it like this:
<foo some="Some String"></foo>
Now inside the foo component I define the property type and default value like so:
export default {
name: "foo",
props: {
some: {
type: String,
default() { return '' }
}
}
}
The foo component's template has another component bar which I pass the some property: <bar :some="some"></bar>.
Now my question is: do I need to again define the type and default value for the some property, this time inside the bar component? So basically copy the props code from the foo component and paste it into the bar component or is there another way?
foo has ensured the type and default value, so there is no need to validate them in bar. If the type were something that has special behavior (e.g., boolean), you would need to specify it, but there's nothing special about string.
Every component instance has its own isolated scope. This means you cannot (and should not) directly reference parent data in a child component’s template. Data can be passed down to child components using props.
Passing data with props
What you need here is to use scoped slot:
Scoped slots allows you to pass props down from Parent components to Child components without coupling them together.

Are there any flow types definition for react-native styles?

I'm making a react native component and using Flow to define the property types like this:
type Props = {
text: string,
textStyle: object
}
Those properties are then passed to the Text component inside my component. Are there any Flow type definitions for react-native that will allow me to do something like this:
textStyle: TextStyle
Now Flow would be able to check that the textStyle value contains only keys that are allowed for Text component style.
I see that there are interface definitions for TypeScript (React.TextStyle) but can't find anything for Flow.
Update 3:
Current best practice is:
import type {
ViewStyleProp,
TextStyleProp,
ImageStyleProp,
} from 'react-native/Libraries/StyleSheet/StyleSheet';
Update 2: The following PR makes things simpler, as of today flowtype styles are as follow.
type StyleValue = {[key: string]: Object} | number | false | null;
type StyleProp = StyleValue | Array<StyleValue>;
Obsolete: The following PR fixes it, can be found from v0.52.0
It is possible to do the following:
// #flow
import type { StyleObj } from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
type Props = {
style?: StyleObj
};
Following discussion on: https://github.com/flowtype/flow-typed/issues/631#issuecomment-282009393
Update
StyleObj is no longer part of StyleSheetTypes.
Now import:
{LayoutStyle, TransformStyle, ShadowStyle, ViewStyle, TextStyle, ImageStyle, DangerouslyImpreciseStyle} from 'react-native/Libraries/StyleSheet/StyleSheetTypes';
In your case, you should:
import { TextStyle } from 'react-native/Libraries/StyleSheet/StyleSheetTypes';

Getting element height

I was curious if I can get element properties form component template.
So I have made simple div with class and I've made this class:
export class viewApp{
elementView: any;
viewHeight: number;
myDOM: Object;
constructor() {
this.myDOM = new BrowserDomAdapter();
}
clickMe(){
this.elementView = this.myDOM.query('div.view-main-screen');
this.viewHeight = this.myDOM.getStyle(this.elementView, 'height');
}
}
getStyle(), query() are from BrowserDomAdapter.
My problem is when I try to get height it is null, but when I set some height by setStyle() and then I get it by getStyle() it returns proper value.
After checking DOM and styles in browser I discovered that is because of two CSS elements. One is: .view-main-screen[_ngcontent-aer-1]{} and second one is element{}.
.view-main-screen has some stylings, but element is empty. When I add styles by setStyle() it appears in element{}. Why is that? How can I get element properties by using Angular2?
The correct way is to use #ViewChild() decorator:
https://angular.io/docs/ts/latest/api/core/index/ViewChild-decorator.html
Template:
<div class="view-main-screen" #mainScreen></div>
Component:
import { ElementRef, ViewChild } from '#angular/core';
export class viewApp{
#ViewChild('mainScreen') elementView: ElementRef;
viewHeight: number;
constructor() {
}
clickMe(){
this.viewHeight = this.elementView.nativeElement.offsetHeight;
}
}
That should do it but obviously you need to add your Component decorator.
Edit:
For Angular 8 or later you need to provide the 2nd parameter in ViewChild
#ViewChild('mainScreen', {read: ElementRef, static:false}) elementView: ElementRef;
update2
constructor(private elementRef:ElementRef) {}
someMethod() {
console.log(this.elementRef.nativeElement.offsetHeight);
}
Accessing nativeElement directly is discouraged but current Angular doesn't provide other ways as far as I know.
update
https://github.com/angular/angular/pull/8452#issuecomment-220460761
mhevery commented 12 days ago
We have decided to remove Ruler service, and so it is not part of the public API.
original
As far as I know the Ruler class should provide that functionality
https://github.com/angular/angular/blob/master/modules/angular2/src/platform/browser/ruler.ts if this isn't enought you probably need to access elementRef.nativeElement and use direct DOM access and functions provided by the elements.
new Ruler(DOM).measure(this.elRef).then((rect: any) => {
});
Rules service is safe in WebWorker.
See also the comments on https://github.com/angular/angular/issues/6515#issuecomment-173353649
<div #getElementHeight>
Height
</div>
Height of element is {{ getElementHeight.offsetHeight }}
<div *ngFor="let item of items" (click)="itemClick($event.currentTarget)"></div>
itemClick(dom){
var height=dom.clientHeight;
// ...
}