What's the difference between withStyle and withTheme in material ui? - material-ui

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);

Related

How to search for and highlight a substring in Codemirror 6?

I'm building a simple code editor to help children learn HTML. One feature I'm trying to add is that when users mouseover their rendered code (in an iframe), the corresponding HTML code in the editor is highlighted. So, for example, if a user mouses-over an image of kittens, the actual code, , would be highlighted in the editor.
Mousing-over the iframe to get the html source for that element is the easy part, which I've done (using document.elementFromPoint(e.clientX, e.clientY in the iframe itself, and posting that up to the parent) - so that's not the part I need help with. The part I can't figure out is how to search for and highlight that string of selected code in the code editor.
I'm using Codemirror 6 for this project, as it seems as it will give me the most flexibility to create such a feature. However, as a Codemirror 6 novice, I'm struggling with the documentation to find out where I should start. It seems like the steps I need to complete to accomplish this are:
Search for a range in the editor's text that matches a string (ie.'<img src="kittens.gif"').
Highlight that range in the editor.
Can anyone out there give me some advice as to where in the Codemirror 6 API I should look to start implementing this? It seems like it should be easy, but my unfamiliarity with the Codemirror API and the terse documentation is making this difficult.
1. Search for a range in the editor's text that matches a string (ie.'<img src="kittens.gif"').
You can use SearchCursor class (iterator) to get the character's range where is located the DOM element in your editor.
// the import for SearchCursor class
import {SearchCursor} from "#codemirror/search"
// your editor's view
let main_view = new EditorView({ /* your code */ });
// will create a cursor based on the doc content and the DOM element as a string (outerHTML)
let cursor = new SearchCursor(main_view.state.doc, element.outerHTML);
// will search the first match of the string element.outerHTML in the editor view main_view.state.doc
cursor.next()
// display the range where is located your DOM element in your editor
console.log(cursor.value);
2. Highlight that range in the editor.
As described in the migration documentation here, marked text is replace by decoration. To highlight a range in the editor with codemirror 6, you need to create one decoration and apply it in a dispatch on your view. This decoration need to be provide by an extension that you add in the extensions of your editor view.
// the import for the 3 new classes
import {StateEffect, StateField} from "#codemirror/state"
import {Decoration} from "#codemirror/view"
// code mirror effect that you will use to define the effect you want (the decoration)
const highlight_effect = StateEffect.define();
// define a new field that will be attached to your view state as an extension, update will be called at each editor's change
const highlight_extension = StateField.define({
create() { return Decoration.none },
update(value, transaction) {
value = value.map(transaction.changes)
for (let effect of transaction.effects) {
if (effect.is(highlight_effect)) value = value.update({add: effect.value, sort: true})
}
return value
},
provide: f => EditorView.decorations.from(f)
});
// this is your decoration where you can define the change you want : a css class or directly css attributes
const highlight_decoration = Decoration.mark({
// attributes: {style: "background-color: red"}
class: 'red_back'
});
// your editor's view
let main_view = new EditorView({
extensions: [highlight_extension]
});
// this is where the change takes effect by the dispatch. The of method instanciate the effect. You need to put this code where you want the change to take place
main_view.dispatch({
effects: highlight_effect.of([highlight_decoration.range(cursor.value.from, cursor.value.to)])
});
Hope it will help you to implement what you want ;)
Have a look at #codemirror/search.
Specifically, the source code implementation of Selection Matching may be of use for you to adapt.
It uses Decoration.mark over a range of text.
You can use SearchCursor to iterate over ranges that match your pattern (or RegExpCursor)
Use getSearchCursor, something like this:
var cursor = cmEditor.getSearchCursor(keyword , CodeMirror.Pos(cmEditor.firstLine(), 0), {caseFold: true, multiline: true});
if(cursor.find(false)){ //move to that position.
cmEditor.setSelection(cursor.from(), cursor.to());
cmEditor.scrollIntoView({from: cursor.from(), to: cursor.to()}, 20);
}
Programmatically search and select a keyword
Take a look at getSearchCursor source code it it give some glow about how it works and its usage.
So use getSearchCursor for finding text and optionally use markText for highlighting text because you can mark text with setSelection method of editor.
Selection Marking Demo
var editor = CodeMirror.fromTextArea(document.getElementById("code"), {
lineNumbers: true,
styleSelectedText: true
});
editor.markText({line: 6, ch: 26}, {line: 6, ch: 42}, {className: "styled-background"});
And it seem this is what you are looking for:
codemirror: search and highlight multipule words without dialog
RegExpCursor is another option that you can use:
new RegExpCursor(
text: Text,
query: string,
options⁠?: {ignoreCase⁠?: boolean},
from⁠?: number = 0,
to⁠?: number = text.length
)
Sample usage at:
Replacing text between dollar signs for Mathml expression.

How do I make the MUI Dialog title an H1 element so the modal is accessible

I'm working on making my app more accessible and am struggling with the MUI Dialog component. I'm using the DialogTitle component, which creates an H2 element and am getting an issue of "page doesn't contain a level-one heading". Should I be creating my modal in some other way, or are MUI Dialogs just not accessible?
import { Dialog, DialogTitle } from '#mui/material';
const MyModal = () => {
return (
<Dialog open={true}>
<DialogTitle>
My Title
</DialogTitle>
</Dialog>
);
};
export default MyModal;
Updated for MUI v5:
The Dialog component API includes a helper DialogTitle component which, by default, renders its contents within an h2 element. To change this functionality, you can pass the component property to the DialogTitle to have the DialogTitle rendered using whatever elementType that you wish. For example:
<DialogTitle component="h1">
My Dialog Title
</DialogTitle>
This is currently an undocumented feature of DialogTitle, but it can been seen in the source code that properties that are passed to DialogTitle are spread onto the underlying Typography component -- By passing component, you are essentially overwriting the hardcoded component="h2" prop with your own value.
Working example: https://codesandbox.io/s/simpledialog-material-demo-forked-kpq9k?file=/demo.js
Original answer for MUI v4:
The Dialog component API includes a helper DialogTitle component which, by default, renders its contents within an h2 element. To disable this functionality, you can use the DialogTitle component with the disableTypography prop (to disable the h2 wrapping behavior) and then include your own Typography component set to h1. For example:
<DialogTitle disableTypography>
<Typography variant="h1">My Dialog Title</Typography>
</DialogTitle>
Working example: https://codesandbox.io/s/material-demo-forked-7pso2?file=/demo.js
Extra Credit: You may then come across the problem that the h1 is styled "too large" for your design. If so, and you prefer the h2 look, you can use the Typography prop named component in combination with the variant prop to visually style it back to an h2, while maintaining the underlying h1 element. For example:
<DialogTitle disableTypography>
<Typography variant="h2" component="h1">My Dialog Title</Typography>
</DialogTitle>
In the case of TypeScript there's no typing provided so you need to do a hack:
<DialogTitle {...{ component: 'div' } as any}>
<Typography variant="h1">My Dialog Title</Typography>
</DialogTitle>
This is a temporary hack until they add the typing for all the props there.
As #Steve mentionned, in Mui v5, the job is harder. Even if you specify a component prop (which won't work in TS, moreover it's a bad practice), it won't change the style as it renders a h2 with a h6-style.
The cleanest workaround would be to mess with CSS (in a styled component for eg)
// Styling
import { styled } from "#mui/system";
// UI
import { DialogTitle as MuiDialogTitle } from "#mui/material";
const DialogTitle = styled(MuiDialogTitle)(({ theme }) => ({
"&.MuiDialogTitle-root.MuiTypography-root": {
fontSize: 25,
fontWeight: "bold",
},
}));

How to add style class and icon to TabContainerItem in openui5

How to add style class and icon to the TabContainerItem in openui5?
In TabContainerItem documentation there is no addStyleClass and icon properties which is possible in tabstrip by using tab title.
but I need to use TabContainerItem because it is having tabs menu which is useful in mobile device.
Can any one please help me
oTabContainer = new sap.m.TabContainer("tabContainer", {
items:
[
new sap.m.TabContainerItem({name: "tab1",
content: [
new sap.ui.core.mvc.JSView({id:"tab1",viewName:"oui5mvc.tab1"})
]}),
new sap.m.TabContainerItem({name: "tab2",
content: [
new sap.ui.core.mvc.JSView({id:"tab2",viewName:"oui5mvc.home"})
]}),
]
}).placeAt("content").addStyleClass("tabContainer");
Here is an example that i have tried.
Since sap.m.TabContainerItem inherits from Element directly and not from Control it does not offer addStyleClass.
However, you can still apply custom CSS to the TabContainerItem by adding a style class to the sap.m.TabContainer which targets its TabContainerItem children, like:
/* class tabContainer as your custom class added to the TabContainer */
/* custom TabContainerItem (selected) */
.tabContainer
.sapMTabStrip
.sapMTSTabsContainer
.sapMTSTabs
.sapMTabStripItem.sapMTabStripItemSelected {
color : green;
background : yellow;
}
/* custom TabContainerItem (unselected) */
.tabContainer
.sapMTabStrip
.sapMTSTabsContainer
.sapMTSTabs
.sapMTabStripItem {
color : white;
background : grey;
}
Here`s your adapted example. You can adjust this to your needs with basic CSS rules, then.
As far as I know, it is currently not supported to add an icon/image to the TabContainerItem. You can create a feature request for that on the issue tracker of the OpenUI5 project with the enhancement label or contribute it by yourself.

Is it fine to mutate attributes of React-controlled DOM elements directly?

I'd like to use headroom.js with React. Headroom.js docs say:
At it's most basic headroom.js simply adds and removes CSS classes from an element in response to a scroll event.
Would it be fine to use it directly with elements controlled by React? I know that React fails badly when the DOM structure is mutated, but modifying just attributes should be fine. Is this really so? Could you show me some place in official documentation saying that it's recommended or not?
Side note: I know about react-headroom, but I'd like to use the original headroom.js instead.
EDIT: I just tried it, and it seems to work. I still don't know if it will be a good idea on the long run.
If React tries to reconcile any of the attributes you change, things will break. Here's an example:
class Application extends React.Component {
constructor() {
super();
this.state = {
classes: ["blue", "bold"]
}
}
componentDidMount() {
setTimeout(() => {
console.log("modifying state");
this.setState({
classes: this.state.classes.concat(["big"])
});
}, 2000)
}
render() {
return (
<div id="test" className={this.state.classes.join(" ")}>Hello!</div>
)
}
}
ReactDOM.render(<Application />, document.getElementById("app"), () => {
setTimeout(() => {
console.log("Adding a class manually");
const el = document.getElementById("test");
if (el.classList)
el.classList.add("grayBg");
else
el.className += ' grayBg';
}, 1000)
});
And here's the demo: https://jsbin.com/fadubo/edit?js,output
We start off with a component that has the classes blue and bold based on its state. After a second, we add the grayBg class without using React. After another second, the component sets its state so that the component has the classes blue, bold, and big, and the grayBg class is lost.
Since the DOM reconciliation strategy is a black box, it's difficult to say, "Okay, my use case will work as long as React doesn't define any classes." For example, React might decide it's better to use innerHTML to apply a large list of changes rather than setting attributes individually.
In general, if you need to do manual DOM manipulation of a React component, the best strategy is to wrap the manual operation or plugin in its own component that it can 100% control. See this post on Wrapping DOM Libs for one such example.

Summernote WYSIWYG : set code view as default view

I can't find anything about this on the web. Is there a way to set the default view of Summernote (WYSIWYG jQuery text editor) to be the code/html view. I want to see directly the HTML code when landing on the form page.
Thank you
You can simulate a click on the codeview button (after summernote initialization), it works for me :
$('.summernote').summernote({
oninit: function() {
$("div.note-editor button[data-event='codeview']").click();
}
});
From Summernote documentation:
After v0.7.0, every callbacks should be wrapped by callbacks object.
So, in order to work, the js should be like this:
$('.summernote_editor').summernote({
callbacks: {
onInit: function() {
$("div.note-editor button.btn-codeview").click();
}
}
});
Not very elegant and I don't know if there is a proper way to do it but give this a try if you like:
From what I can tell, and I didn't look very hard, the codeview button does this:
adds a 'codeview' class to div.note-editor
disables all the buttons
adds an 'active' class to the codeview button elemment.
You may discover that it does other things as well but this should put you on a workable path.
$('div.note-editor').addClass('codeview');
$('div.note-editor.codeview button').addClass('disabled');
$("div.note-editor.codeview button[data-event='codeview']").removeClass('disabled').addClass('active');
Well, you can use the init callback.
$('.summernote').on('summernote.init', function () {
$('.summernote').summernote('codeview.activate');
}).summernote({
height: 300,
placeholder: 'Paste content here...',
codemirror: {
theme: 'monokai'
}
});