using createTheme I have created a theme for my project, it works fine.
My question is how can I use that particular theme for my other projects without copying it again n again.
I asked this Ques. with Mui team they replied " Concerning your question, you can store your theme in a "shared" repository and use this repo as a dependency on all your projects. Once the theme is changed in the shared repo, all other projects would get the changes."
please let me know an efficient way of using it.How to create shared Repository.
I tried to implement some solutions from the blog post Extending the theme in Material UI with TypeScript:
In the shared project/components lib I created a ThemeInterface.ts file. This file has the extra properties that I want in my projects.
import { Theme } from '#mui/material/styles';
export type Modify<T, R> = Omit<T, keyof R> & R;
export type CustomTheme = Modify<
Theme,
{
space: {
small: number,
general: number,
},
borderRadius: {
general: number
},
layout: {
sidebar: {
citizenBackGroundColor: React.CSSProperties['color'];
};
};
}
>;
Then I use it where I create the theme (this is still in the shared project)
import { createTheme } from '#mui/material';
import { CustomTheme } from './ThemeInterface';
export function createCustomTheme(): CustomTheme {
const baseTheme = createTheme({
//Here you can set your palettes etc..
});
return {
...baseTheme,
//Here comes the properties that we added before
space: {
small: 2,
general: 4,
},
borderRadius: {
general: 2,
},
layout: {
sidebar: {
//themeColors.secondary is just a const
citizenBackGroundColor: themeColors.secondary
}
},
}
}
I have setup my components lib with rollup an story book.
In the project that is consuming the shared theme you can now do this:
// App.tsx
const theme = createCustomTheme();
<ThemeProvider<CustomTheme> theme={theme}>
As a side note. When using storybook in your components you might need to useTheme this way otherwise it wont recognize your typings.. But this should not be needed in the consuming projects.
const theme = useTheme<CustomTheme>();
Related
Im implementing a mui theme through createStyles via `
import { createTheme, ThemeProvider } from '#mui/material/styles'
which looks something like
createTheme({
...other stuff
borders: { ... }
})
The theme gets created fine, and when using useTheme in a child component im able to see the custom borders object. However when logging the same from within the styled emotion component, it removes the non standard keys:
const t = useTheme()
console.log('t===',t)
const S = styled('div')`
backgroud-color: ${props => {
console.log('inside----', props.theme)
return 'red'
}}`
t=== logs fine with the borders
inside---- logs with the theme but without borders attached
Ive tried importing styled from #mui/material instead of #emotion/styled and both do the same.
Ive also created a theme.d.ts for defining the custom theme via module augmentation but that also doesnt assis
declare module '#mui/material/styles' {
interface CustomTheme {
borders?: {
lrg: any;
};
}
interface Theme extends CustomTheme {}
interface ThemeOptions extends CustomTheme {}
}
does anyone have any ideas?
I have added my own explorer view in my extension.
Here I added nodes/tree view items however I am not finding any way to customize and choose color my tree view items in explorer view.
Any idea how to achieve this?
There should be some way because when some file has error then its color is set to different compared to other open file.
[I assume this is your github issue: Not able to use FileDecorationProvider for tree view item.]
Here is my attempt at using a FileDecorationProvider for a custom TreeView. With the caveat that I am new to typescript and FileDecorations.
If you have seen Support proposed DecorationProvider api on custom views you know there are limitations on using a FileDecorationProvider for coloring TreeItem's - primarily that the decoration/coloration cannot be limited to your treeView - wherever that resourceUri apeears, like in the Explorer, your fileDecoration will be applied. That is very unfortunate but I don't believe there is any way to avoid that for now.
First, in your TreeItem class you will have to give whichever items you want decorated a resourceUri. Like this:
export class TreeTab extends vscode.TreeItem {
constructor( public readonly tab: vscode.Tab, public index: number = 0 ) {
super(tab.label, vscode.TreeItemCollapsibleState.None);
this.tab = tab;
if (tab.input instanceof vscode.TabInputText) {
this.resourceUri = tab.input.uri;
}
}
Ignore the specifics of the code for my extension, the point is:
this.resourceUri = <some vscode.Uri>;
Secondly, this is how I set up my FileDecoration class:
import {window, Tab, TabInputText, Uri, Disposable, Event, EventEmitter, FileDecoration, FileDecorationProvider, ThemeColor} from 'vscode';
export class TreeFileDecorationProvider implements FileDecorationProvider {
private disposables: Array<Disposable> = [];
private readonly _onDidChangeFileDecorations: EventEmitter<Uri | Uri[]> = new EventEmitter< Uri | Uri[]>();
readonly onDidChangeFileDecorations: Event<Uri | Uri[]> = this._onDidChangeFileDecorations.event;
constructor() {
this.disposables = [];
this.disposables.push(window.registerFileDecorationProvider(this));
}
async updateActiveEditor(activeTab: Tab): Promise<void> {
if (activeTab.input instanceof TabInputText)
this._onDidChangeFileDecorations.fire(activeTab.input.uri);
// filter to get only non-activeTabs
activeTab.group.tabs.map( tab => {
if (!tab.isActive && tab.input instanceof TabInputText)
this._onDidChangeFileDecorations.fire(tab.input.uri);
});
}
async provideFileDecoration(uri: Uri): Promise<FileDecoration | undefined> {
const activeEditor = window.activeTextEditor.document.uri;
if (uri.fsPath === activeEditor.fsPath) {
return {
badge: "⇐",
color: new ThemeColor("charts.red"),
// color: new vscode.ThemeColor("tab.activeBackground"),
// tooltip: ""
};
}
else return null; // to get rid of the custom fileDecoration
}
dispose() {
this.disposables.forEach((d) => d.dispose());
}
}
provideFileDecoration(uri: Uri) does the actual decorating. It finds only certain files and decorates them, and by returning null resets that previously decorated uri (as supplied by the uri argument).
updateActiveEditor() is an exported method that I call in other parts of the extension when I want to change a file decoration. So elsewhere I have this in another file:
import { TreeFileDecorationProvider } from './fileDecorator';
export class EditorManager {
public TreeItemDecorator: TreeFileDecorationProvider;
// and then on a listener that gets triggered when I need to make a change to some things including the FileDecoration for a uri
this.TreeItemDecorator.updateActiveEditor(activeTab);
this.TreeItemDecorator.updateActiveEditor(activeTab); that calls the updateActiveEditor method in the TreeFileDecorationProvider class which calls the this._onDidChangeFileDecorations.fire(<some uri>); method for uri's that need to have the decoration applied and also for uri's that need to have the decoration removed.
this._onDidChangeFileDecorations.fire(<some uri>); will call provideFileDecoration(uri: Uri) where the actual decoration will be applied or removed depending on some state of that uri.
I am sure there is a way to call onDidChangeFileDecorations() directly from another file in your project (if you don't need to do any pre-processing of the uri like I have to do. I just haven't figured out how to construct the argument for that function yet. Perhaps someone will help on that point.
You can see here:
color: new ThemeColor("charts.red"),
// color: new vscode.ThemeColor("tab.activeBackground"),
how a color is chosen - it must be some ThemeColor. The charts theme colors has a few basic colors that are handy to refer to. See theme color references, Charts therein.
The badge option can take up to 2 characters, but as you see I copied/pasted a unicode character for mine and that works.
As I mentioned my FileDecorationProvider is called from an eventListener, but you may not need that for your use case - if decorations do not have to added and removed based on user actions like in my case. So you may be able to call your FileDecorationProvider right from your extension.ts activate() like so:
import * as vscode from 'vscode';
import { TreeFileDecorationProvider } from './fileDecorator';
export async function activate(context: vscode.ExtensionContext) {
new TreeFileDecorationProvider();
}
Other references:
a treeDecorationProvider.ts example
part of the git extension that does file decorations
Custom view decorations in VSCode extension
i have App.tsx which is app root and then two tabs tab1.tsx and tab2.tsx.
The tab1.tsx has a variable declared as
const [coins, setCoins] = useState(0)
and tab2.tsx also i have declared the same
const [coins, setCoins] = useState(0)
but this is just a workaround as of now. how do i have it declared it at just one place be able to share it between the two tabs. i don't think passing it between the tabs as parameter is a good solution.
in ionic angular i used a service to delcare this kind of variables and easily referred then through out the application. what is the solution for ionic-react?
Use useContext React Hook.
https://reactjs.org/docs/hooks-reference.html#usecontext
1- Create a new file in the project, such as my-context.tsx
import React, { createContext, useState } from "react";
//create the context
export const MyContext = createContext<any>(undefined);
export const MyProvider: React.FC = ({ children }) => {
const [coins, setCoins] = useState(0)
let state = {
coins,
setCoins
};
//wrap the application in the provider
return <MyContext.Provider value={state}>{children}</MyContext.Provider>;
};
export default MyContext;
2- Wrap App.tsx inside <AuthProvider> </AuthProvider> like this:
const App: React.FC = () => {
return (
<IonApp>
<AuthProvider>
<IonReactRouter>
...
</IonReactRouter>
</AuthProvider>
</IonApp>
);
};
export default App;
3- Every time you want to use this state in other components/pages, import the context and use it like this:
const {
coins,
setCoins
} = React.useContext(MyContext);
In this way, you share states and set states through out the app.
I am new to the web development, and I am trying to use material-ui. I saw some demo codes use withStyle and some others use withTheme. Are there any differences between them? Thanks a lot!
I think the accepted answer is not well-explained, to be more clear:
1) withStyles also provides the theme object when creating css styles; the signature of creating function is like:
const styles = theme => ({
root: {
maxWidth: 600,
},
tabs: {
borderTopWidth: 1,
borderTopStyle: 'solid',
borderColor: theme.palette.divider,
width: '100%',
},
});
As one can see theme and everything inside it like theme.palette can be accessed. Official documentation and examples are everywhere so I just randomly picked this one. (Press this button to show the source codes: "< >")
2) The purpose of withTheme is to inject theme into props, so it could also be accessed inside component functions like render, sometimes it's useful. Official documentation here.
withStyles overrides the style of a specific component.
withTheme overrides the style of a specific component while also giving you access to the theme so that your style can be based on the theme's colors, typography, spacing, etc.
It can be confusing because you have to create a new component using these higher-order functions:
const MyCustomBottom = withStyles(styles)(Button);
const MyCustomThemeBasedButton = withTheme(theme)(Button);
This is the way I've been doing it for quite some time now:
export default class AttachmentCreator extends Component {
render() {
return <div>
<RaisedButton primary label="Add Attachment" />
</div>
}
}
AttachmentCreator.propTypes = {
id: PropTypes.string,
};
But I've seen people doing it this way:
export default class AttachmentCreator extends Component {
static propTypes = {
id: PropTypes.string,
};
render() {
return <div>
<RaisedButton primary label="Add Attachment" />
</div>
}
}
And in fact I've seen people setting initial state outside the constructor as well. Is this good practice? It's been bugging me, but I remember a discussion somewhere where someone said that setting default props as a static is not a good idea - I just don't remember why.
In fact, it's exactly the same in terms of performance. React.JS is a relatively new technology, so it's not clear yet what are considered good practices or don't. If you want to trust someone, check this AirBNB's styleguide:
https://github.com/airbnb/javascript/tree/master/react#ordering
import React, { PropTypes } from 'react';
const propTypes = {
id: PropTypes.number.isRequired,
url: PropTypes.string.isRequired,
text: PropTypes.string,
};
const defaultProps = {
text: 'Hello World',
};
class Link extends React.Component {
static methodsAreOk() {
return true;
}
render() {
return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>
}
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;
export default Link;
They are declaring a const with the propTypes object literals, keep the class pretty clean and assign them later to the static properties. I personally like this approach :)
Oh yes, it's totaly legit with Babel (or other transpilers)
class DataLoader extends React.Component {
static propTypes = {
onFinishedLoading: PropTypes.func
}
static defaultProps = {
onFinishedLoading: () => {}
}
}
...as it gets transpiled to this anyway.
class DataLoader extends React.Component {}
DataLoader.propTypes = {
onFinishedLoading: PropTypes.func
};
DataLoader.defaultProps = {
onFinishedLoading: () => {}
};
Static fields get transpiled as properties on the class object under the hood.
Look here at Babel REPL.
Moreover, assigning state or other class fields directly in the class body gets transpiled into the constructor.
non-function properties are not currently supported for es2015 classes. its a proposal for es2016. the second method is considerably more convenient, but a plugin would be required to support the syntax (theres a very common babel plugin for it).
On the other end, a hand full of open source projects are beginning to treat proptypes like TypeScript interfaces, or ActionConstants and actually create separate folders/files that house various component prop types and are then imported into the component.
So in summary, both syntaxes are ok to use. but if you want to only use strictly ES2015, the latter syntax is not yet supported in the specification.
If the component is state-less, meaning it does not change it's own state at all, you should declare it as a stateless component (export default function MyComponent(props)) and declare the propTypes outside.
Whether it's good practice to put initial state declaration in constructor is up to you. In our project we declare initial state in componentWillMount() just because we do not like the super(props) boilerplate you have to use with the constructor.