Styled component theme variable organization - themes

This may not be the best place to post this so please let me know if this should be posted elsewhere.
I currently am trying to organize my applications theme, since it has become a bit messy. I was looking to see how other developers were organizing their app's theme. We have color/padding variables for our app's theme and overrides for our organization's component library we use. I was thinking of organizing the theme file some thing like this, but feel it may not be sustainable:
// colors
const white = '#FFFFFF'
const black = '#333333'
...
const grey100 = '#F8F8F8'
...
const grey600 = '#94969A'
/**
* App Specific Components
*/
const consumerTheme = {
// Issue I'm not sure if I should separate the general items such as
// component/title into different objects and if I should also separate
// padding/margin and colors
component1: {
background: white,
footerPadding: 5px
},
title: black,
...
}
/**
* Component Library Specific Components
*/
const componentLibrary = {
// Feeling uncertain if these values should be used throughout the app.
// The main idea here is that even if we don't see these values
// throughout the app's codebase, these values are overriding our
// component library default values.
header: {
background: white,
},
error: '#C63527'
...
}

Related

What is the most performant way for dynamic styling in React-Native?

In React-Native, you can use Stylesheet to create css-like stylesheets. The main reason of using styleshee.create in favor of plain js-objects is increased performance. However, you often might want to style components dynamically, often based on their props. I basically found three approaches of doing this:
Note for the following examples: Consider const styles ... to be declared outside of the Component, as it's a common pattern and you might want to share styles between different Components. Consider everything below the tree dots as part of the render function.
Using an array of styles:
const styles = StyleSheet.create({viewStyle: {backgroundColor:'red'}})
...
return <View style={[styles.viewStyle, {color: this.props.color}]} />
Using Stylesheet.flatten:
const styles = StyleSheet.create({viewStyle: {backgroundColor:'red'}})
...
const flattenedStyle = StyleSheet.flatten(styles.viewStyle, {{color: this.props.color}})
return <View style={flattenedStyle} />
Using a function to create the stylesheet:
const styles = (color) => StyleSheet.create({
viewStyle: {
backgroundColor:'red',
color: color
}
})
...
const style = styles(this.props.color).viewStyle
return <View style={style} />
I am wondering which approach is the best regarding to performance, or if there even is another, more performant way? I think Option 2 and 3 are no way to go at all, because dynamically creating new stylesheets on prop-changes undermines the whole purpose of stylesheets. I am happy for any thought or hints on this subject!
Here you can do dynamic styling in react native for each styling.
Like this
<Text style={styles.simpleText('red')}>Required field</Text>
// In styling
const styles = StyleSheet.create({
simpleText: (colorProp = 'black') => ({ // default black set
fontSize: 14,
color: colorProp,
})
})
and you can also pass any data type for conditional styling
One of the approach
// homeSreen
<View style={styles.filterButton(isSelected)}>
<Text> Strawberry </Text>
</View>
// styles.js
import { StyleSheet } from 'react-native';
import { Colors } from '../../theme';
export default StyleSheet.create({
container: {
backgroundColor: Colors.lighter,
},
filterButton: isSelected => ({
padding: 15,
backgroundColor: isSelected? Colors.background.primary: Colors.background.secondary
}),
});
You could memoize stylesheet creation using React hooks, but first you need to do some performance checking in order to determine if stylesheet creation is in fact a CPU and/or memory hog worth optimizing.
Here's an example:
const styles = (color) => StyleSheet.create({
viewStyle: {
backgroundColor:'red',
color: color
}
})
/*
even though makeStyle is defined in EVERY render,
React will only run it ONCE for any given props.color distinct value.
The resulting value `styles` survives re-renders
*/
const makeStyle = () => styles(props.color)
const styles = useMemo(makeStyle, [props.color]);
And here's the official documentation.
Did you consider CSS in JS libraries like Styled components?
You can pass props and get dynamic style regard that:
https://styled-components.com/docs/basics#passed-props
Possibly a bit overkill for simple dynamic styling but Reanimated is very performant and will run the style transition at 60fps https://github.com/software-mansion/react-native-reanimated
It archives this by declaring all the styles needed for an animation/transition ahead of time and runs them on the native thread so there is minimal communication across the JS->Native code bridge.
There is a better explanation on their about page here https://docs.swmansion.com/react-native-reanimated/docs/about

Amcharts 4 treemap balloon

How do I change the text/style in the balloon on the Treemap chart from amchart 4 ?
In this example below, how do I remove the "Ford" from the balloon?
My sincere apologies for the super late answer, the question showed up recently related to another, not sure how this slipped through the cracks.
This is a good question for at least 2 reasons:
At the time we did not have a guide on modifying tooltip background color.
TreeMap charts are not like others, we're not working directly with an actual TreeMapSeries.
If you're just looking to edit the tooltip's text, we can do this via the TreeMapSeries template, specifically on its column template, i.e. columns.template.tooltipText, e.g. using the original demo as a base:
// The default `tooltipText` for all columns, e.g.
// `chart.series.getIndex(0).columns.template.tooltip`, is
// `"{parentName} {name}: {value}"`
//
// Let's keep {parentName} on a separate line in `tooltipText`, and play with
// font size, colors, and style. (Note we cannot nest formatting brackets.)
//
// More on string and visual formatting:
// https://www.amcharts.com/docs/v4/concepts/formatters/formatting-strings/
level1SeriesTemplate.columns.template.tooltipText =
"[bold font-size: 22px; #fff]{parentName}[/]\n[font-size: 20px]{name}:[/] [font-size: 20px #fff]{value}[/]";
But if you're looking to do more than that, e.g. modify the background, you'll need to work on the actual columns themselves, since actual tooltip objects are not available on column templates. Here's a way of going about this for TreeMapSeries and their columns as soon as they're ready:
// Looking over this chart type, i.e. TreeMap, we find it has a
// seriesContainer property:
// https://www.amcharts.com/docs/v4/reference/treemap/#seriesContainer_property
//
// and all containers have a "childadded" event:
// https://www.amcharts.com/docs/v4/reference/container/#childadded_event
//
// which works just as expected.
//
// More on events here:
// https://www.amcharts.com/docs/v4/concepts/event-listeners/
chart.seriesContainer.events.on("childadded", function(event) {
// The chart will load with the initial series at first,
// we're not interested in that.
if (chart.series.length === 1) return;
// Once we click a car company / TreeMap column, a new series will be generated
// and added to the seriesContainer. Here, event.target will be the seriesContainer,
// and event.newValue will always be the new TreeMapSeries.
var series = event.newValue;
// level-/depth-specific code, if you wanted
// if (series.level === 1) {
// }
// The series exists, but is not ready/populated yet. In general, datavalidated
// is a good event to check against for initial load/readiness of a series.
series.events.once("datavalidated", function() {
series.columns.each(function(column) {
// In order to customize tooltip colors, we need to set getFillFromObject to false,
// otherwise as it sounds, it'll grab color data from the parent object.
// https://www.amcharts.com/docs/v4/reference/tooltip/#getFillFromObject_property
// https://www.amcharts.com/docs/v4/reference/tooltip/#getStrokeFromObject_property
column.tooltip.getFillFromObject = false;
// column.tooltip.getStrokeFromObject = false; // not needed, since it defaults to false
column.tooltip.background.stroke = am4core.color("#fff");
column.tooltip.background.strokeWidth = 3;
column.tooltip.background.strokeOpacity = 0.3;
// background of tooltip, let's make it darker than the column's bg.
column.tooltip.background.fill = am4core.color(
am4core.colors.brighten(column.fill.rgb, -0.3)
);
// let's also make it slightly transparent.
column.tooltip.background.fillOpacity = 0.8;
// tooltip text color, we can also set this via string visual formatting,
// see `tooltipText` assignment further below.
// Every Tooltip has a Label:
// https://www.amcharts.com/docs/v4/reference/tooltip/#label_property
// https://www.amcharts.com/docs/v4/reference/label/
//
// Let's make the default color brighter than the column bg color.
column.tooltip.label.fill = am4core.color(
am4core.colors.brighten(column.fill.rgb, 0.7)
);
// alignment of text within tooltip (cannot use string visual formatting for this).
// Let's center the text, mainly the title/parent company.
column.tooltip.label.textAlign = "middle";
});
});
});
I've prepared a demo here:
https://codepen.io/team/amcharts/pen/07c3ca3e33b4ad955246893d19df3a6c/
Hope this covers the things you may have been interested in modifying.

dynamic html into a view using ui router

Ok so i am not looking for an example more of help with an approach i am primarily a java developer so please excuse (and correct) the terminology if it need be. This is also why i need help as i am still early on into my journey into angular.
So i am using angular 5, along with ui-router. I am trying to design a three tabbed page [view, html, css] where the html and css will be text areas where a user will enter said thing, then , the view will be the rendering of that. There will be data (can be fetched prior to or at the time of rendering the view) that will bind to that html. The user will basically be putting in angular templates.
I have been reading this example but not sure if that is the proper approach.
this article had the solution
https://blog.angularindepth.com/here-is-what-you-need-to-know-about-dynamic-components-in-angular-ac1e96167f9e
basically it looks like this
#ViewChild("ancc", { read: ViewContainerRef }) container;
#Input() property:Property = new Property();
constructor(private resolver: ComponentFactoryResolver,private _compiler: Compiler){
console.log("hit layout constructor");
}
view(){
// create the template
const template = '<span>generated on the fly: {{property.label}}</span>';
//clear out the old instance
this.container.clear();
const tmpCmp = Component({template: template})(class {
});
const tmpModule = NgModule({declarations: [tmpCmp]})(class {
});
this._compiler.compileModuleAndAllComponentsAsync(tmpModule)
.then((factories) => {
const f = factories.componentFactories[0];
//attach the component to the view
const cmpRef = this.container.createComponent(f);
//bind the data
cmpRef.instance.property = this.property;
})
}
hope this helps someone!

how to implement complex models in aframe

I'm pretty new to aframe and the ECS-modeling technique, so I probably didn't fully grasp how the architecture should be used.
I want to model something like a robotic arm: in a simplified version that is a base, on top of that a rotator and the arm itself. The model is loaded from a single json-file and consist of several nested objects for the different parts.
How would something like this be implemented in aframe if I want to be able to control the different degrees of freedom independently (which means setting object.rotation-values on the different childs of the object itself)?
One thing I thought of was to implement the loading of the model-file as one component and each degree-of-freedom as a seperate component. So basically something like this:
<a-entity robot-model="..." base-rotation="123" arm-pitch="10" />
Or would it be a better way to use registerPrimitive for something like this?
My first take on it looks like this:
registerComponent('robot', {
schema: {type: 'asset'},
update() {
// - load and parse model using THREE.ObjectLoader
// - once ready, assign property this.parts with the various
// parts of the robot-arm
}
});
registerComponent('dof-1', {
schema: {type: 'number'},
dependencies: ['robot'],
init() {
this.robot = this.el.components.robot;
},
tick(t, dt) {
if (!this.robot.parts) { return; } // not ready yet
// update values (left out here: acceleration etc)
this.robot.parts.dof1.rotation.x = this.data;
}
});
// more parts / dof implemented likewise
I'm assuming you've already created and rigged a 3D model using software like Blender, Maya, or Cinema4D. If not, the article Animation from Blender to three.js is a good starting point.
Once you've done that, you can import the model into A-Frame with any format that supports skinning/rigging. THREE.ObjectLoader (.json) or THREE.GLTFLoader (.gltf) are good options, and there are already A-Frame components that wrap these loaders. Assuming you're using JSON and the object-model component from A-Frame Extras, you could do:
<a-entity object-model="src: url(my-model.json)"></a-entity>
At this point you should see a model in the scene, without having written any JavaScript, but it won't be animating yet. If you know what animation you want up front, you can create the animations in keyframes or morph targets using the same modeling software: Blender, Maya, or Cinema4D. Assuming you included the animations when you exported the model, you can use the animation-mixer component (also from A-Frame Extras) as follows:
<a-entity object-model="src: url(my-model.json)"
animation-mixer="clip: *;"></a-entity>
This will play all animations at once. You could use a clip name, instead of *, to play a specific animation.
If your animations need to be computed at runtime, and can't be baked into the model, you'll need to write a custom component. This gets complicated quickly, but the basics aren't too bad:
<a-entity object-model="src: url(my-model.json)"
custom-animation></a-entity>
And the JS:
AFRAME.registerComponent('custom-animation', {
tick: function (t, dt) {
var mesh = this.el.getObject3D('mesh');
// With complex models, you may need to loop over `mesh.children`
// in case the mesh you want to animate is a child of another
// object in your model file.
if (!mesh || !mesh.isSkinnedMesh) { return; }
mesh.traverse(function (node) {
if (node.isBone && node.name === 'arm') {
node.rotation.x += dt * Math.PI / 1000;
}
});
}
});

Google Apps Script User Interface

Well, I've been reading the documentation and I believe that I'm calling functions and passing parameters correctly, but for the life of me I can't get this simple UI code to work.
I'm generating a UI for a Spreadsheet using the following code:
function checkOut() {
var app = buildUI();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function buildUI() {
var gui = UiApp.createApplication();
gui.setTitle("Check-Out/Check-In");
gui.setStyleAttribute("background", "lavender");
// Absolute panel for setting specific locations for elements
var panel = gui.createAbsolutePanel();
// Equipment ID#s Label
var equipmentIDLabel = gui.createLabel("Equipment ID#s");
equipmentIDLabel.setHorizontalAlignment(UiApp.HorizontalAlignment.CENTER);
equipmentIDLabel.setSize("20px", "125px");
equipmentIDLabel.setStyleAttributes({background: "SteelBlue", color: "white"});
// Add all components to panel
panel.add(equipmentIDLabel, 10, 0);
gui.add(panel);
return gui;
}
function getUIdata(eventInfo) {
// I know how to get the data from each element based on ID
}
It generates the Absolute Panel correctly when checkOut() is called, but the EquipmentIDLabel is never added to the panel. I am basing the code on the simplistic design I created in the GUI builder (that will be deprecated in a few days, which is why I am writing the code so that I can change it later):
So what exactly is going wrong here? If I can figure out how to add one element, I can infer the rest by looking at the docs. I've never been any good at GUI development!
You could maybe use grid as an interesting alternative... here is an example :
// define styles
var labelStyle = {background: "SteelBlue", color: "white",'textAlign':'center','line-height':'20px','vertical-align':'middle','font-family':"Arial, sans-serif",'fontSize':'10pt'};// define a common label style
var fieldStyle = {background: "white", color: "SteelBlue",'font-family':"Courrier, serif",'fontSize':'11pt'};// define a common label style
function checkOut() {
var app = buildUI();
var spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
spreadsheet.show(app);
}
function buildUI() {
var gui = UiApp.createApplication();
gui.setTitle("Check-Out/Check-In");
gui.setStyleAttribute("background", "lavender");
var panel = gui.createAbsolutePanel().setStyleAttribute('padding','10px');
var grid = gui.createGrid(4,2).setWidth('300').setCellPadding(10);//define grid size in number of row & cols
var equipmentID = ['equipmentIDLabel','equipmentIDLabel1','equipmentIDLabel2','equipmentIDLabel3'];// define labels in an array of strings
for(var n=0 ;n<equipmentID.length ; n++){;// iterate
var equipmentIDLabel = gui.createLabel(equipmentID[n]).setWidth('125').setStyleAttributes(labelStyle);
var equipmentIDField = gui.createTextBox().setText('Enter value here').setName(equipmentID[n]).setSize("125", "20").setStyleAttributes(fieldStyle);
grid.setWidget(n,0,equipmentIDLabel).setWidget(n,1,equipmentIDField);
}
gui.add(panel.add(grid));
return gui;
}
It looks like the absolute panel offset method is a little capricious and take control of your positioning, in my tests I have been able to position panels that are visible in the following way:
panel.add(equipmentIDLabel);
panel.add(equipmentIDField,150,0);
panel.add(otherLabel);
panel.add(otherField, 150, 20);
Try it out with trial and error, you may get the UI you need, if not I would move to an alternate layout, verticalPanel is a little better behaved and of course you can use forms as well.
Another small bug is that you inverted the length and hight in equipmentIDLabel.setSize("20px", "125px");
Let me know if I can be of more assitance
The specific problem in your code is the following line :
// Add all components to panel
panel.add(equipmentIDLabel, 10, 0);
Simply change it to : panel.add(equipmentIDLabel);
..and you will see the field (at position 0,0).
As patt0 observes, you can then add OTHER components and use positioning. It seems to be a limitation of adding the first field to an absolutePanel.
Of course, the Google Script gui is now deprecated (since December 2014) but I was interested to try your code and see that it still basically executes (as at Feb 2016).

Resources