How to make chat like UI with chat bubbles in React JS - javascript

I have some JSON data in dummyData. I am not sure how can I place the chat bubbles on left and right according to the direction. I am using Material UI and context API. Image for the reference. I don't want to use any library other than material UI.
Currently, every chat bubble is positioned to the left. How to position bubbles according to the direction. Code so far (CodeSandbox):
import React from 'react';
import makeStyles from '#material-ui/core/styles/makeStyles';
const useStyles = makeStyles(theme => ({
container: {
bottom: 0,
position: 'fixed'
},
bubbleContainer: {
width: '100%'
},
bubble: {
border: '0.5px solid black',
borderRadius: '10px',
margin: '5px',
padding: '10px',
display: 'inline-block'
}
}));
const ChatLayout = () => {
const classes = useStyles();
const dummyData = [
{
message: '1: This should be in left',
direction: 'left'
},
{
message: '2: This should be in right',
direction: 'right'
},
{
message: '3: This should be in left again',
direction: 'left'
}
];
const chatBubbles = dummyData.map((obj, i = 0) => (
<div className={classes.bubbleContainer}>
<div key={i++} className={classes.bubble}>
<div className={classes.button}>{obj.message}</div>
</div>
</div>
));
return <div className={classes.container}>{chatBubbles}</div>;
};
export default ChatLayout;

You can create separate div of chat bubble and apply CSS. And where you are receiving messages append the bubble div to your user list.

Related

How to send props dynamically to styles hook in material UI?

I am trying to add dynamic background images to divs. I am mapping over an array of objects to return divs. How do I add a background image to the div based on the image URL in the object?
Here is the code.
const useStyles = makeStyles({
div: (props) => ({
width: "100px",
height: 0,
paddingBottom: "100px",
backgroundImage: "how do i know which image to pull",
}),
});
let arr = [
{ photo_url: "some url" },
{ photo_url: "some url" },
{ photo_url: "some url" },
];
function Test() {
const classes = useStyles("how do i send image of that specific object");
return arr.map((obj) => <div className={classes.div}></div>);
}
EDIT: For the sake of simplicity, I chose to use style prop to add dynamic styles and className prop to add generic styles that are common to all divs.
Send the array to useStyles:
const classes = useStyles(array);
Now inside the makeStyles receive the array:
const useStyles = makeStyles(array=>{
let divStyles={}
// create dynamic styles based on the index of the .div class:
array.forEach((bgUrl,index)=>{
divStyles[`&:nth-child(${index+1})`]={ // because the index starts at zero
width: "100px",
height: 0,
paddingBottom: "100px",
backgroundImage: bgUrl,
}
})
return {div:divStyles}
});

How can I add remove icon on Fabric element Reactjs?

I'm using fabric in my react app. I have a button which add text to canvas. Now I want to set remove icon on top left of fabric Text and remove that text when clicked on icon Reactjs? I exactly don't know how to handle event listeners when click on canvas elements.
import React from 'react';
import { fabric } from 'fabric';
class Designer extends React.Component {
componentDidUpdate() {
console.log('componentDidUpdate ');
}
componentDidMount() {
// Make a New Canvas
this.__canvas = new fabric.Canvas('meCanvas', {
preserveObjectStacking: true,
height: 812,
width: 375,
backgroundColor: 'gray'
});
let rect = new fabric.Rect({
left: 100,
top: 150,
fill: 'red',
width: 200,
height: 200
});
this.__canvas.add(rect);
}
addText() {
let newID = new Date().getTime().toString().substr(5);
let text = new fabric.IText('текст', {
fontFamily: 'arial black',
left: 100,
top: 100,
myid: newID,
objecttype: 'text'
});
this.__canvas.add(text);
//this.addLayer(newID, 'text');
}
render() {
console.log('render');
return (
<div>
<button id="texts" onClick={() => this.addText()}>
TEXT PLEASE
</button>
<canvas id="meCanvas" ref="myFabric" onClick={console.log('onClick')} />
</div>
);
}
}
export default Designer;

Attempting to display globe using React.js and Cesium.js?

I've followed every guide I can find on the topic, and none of them seem to be able to help my specific problem. I can display the the Cesium app on my React webpage, but the globe, background, and thumbnails will not display, however, all of the other widgets will display (home button, time controller, etc.). If you all need more code, I will be happy to provide more :)
Here is my code:
project/src/App.js:
import React, {Component} from "react";
import Viewer from "cesium/Source/Widgets/Viewer/Viewer";
import BingMapsImageryProvider from "cesium/Source/Scene/BingMapsImageryProvider";
import CesiumTerrainProvider from "cesium/Source/Core/CesiumTerrainProvider";
const BING_MAPS_URL = "//dev.virtualearth.net";
const BING_MAPS_KEY = process.env.BING_MAPS_KEY;
const STK_TERRAIN_URL = "//assets.agi.com/stk-terrain/world";
export default class CesiumGlobe extends Component {
state = {viewerLoaded : false}
componentDidMount() {
const imageryProvider = new BingMapsImageryProvider({
url : BING_MAPS_URL,
key : BING_MAPS_KEY,
});
const terrainProvider = new CesiumTerrainProvider({
url : STK_TERRAIN_URL
});
this.viewer = new Viewer(this.cesiumContainer, {
animation : true,
baseLayerPicker : false,
fullscreenButton : false,
geocoder : false,
homeButton : true,
infoBox : false,
sceneModePicker : false,
selectionIndicator : true,
timeline : true,
navigationHelpButton : false,
scene3DOnly : true,
imageryProvider,
terrainProvider
})
}
componentWillUnmount() {
if(this.viewer) {
this.viewer.destroy();
}
}
render() {
const containerStyle = {
const containerStyle = {
width: '100%',
height: '100%',
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'fixed',
display : "flex",
alignItems : "stretch",
};
const widgetStyle = {
flexGrow : 2
}
return (
<div className="cesiumGlobeWrapper" style={containerStyle}>
<div
className="cesiumWidget"
ref={ element => this.cesiumContainer = element }
style={widgetStyle}
/>
</div>
);
}
}
Note: I generated the BingMapsApi key very recently, so this likely isn't the issue.

How to create button with text under icon by reactjs?

Now, I have component like this:
code of it:
import React from "react";
import {withStyles} from "material-ui/styles";
import Settings from "material-ui-icons/Settings";
import Button from "material-ui/Button";
const styles = {
button: {
color: "primary",
height: 95,
width: 95,
disableRipple: "true",
focusRipple: "true",
},
icon: {
height: 35,
width: 35,
display: "block",
float: "none",
},
text: {
height: 35,
width: 35,
display: "block",
float: "none",
marginTop: 10,
},
};
/* eslint-disable react/prop-types */
const IconedLabel = ({classes}) => (
<section>
<Button className={classes.iconButton} variant="raised" color="primary">
<Settings className={classes.icon}/>
<div className={classes.text}>Message</div>
</Button>
</section>
);
export default withStyles(styles)(IconedLabel);
But need to button, that in top part contains icon and text message in bottom.
I use reactjs and material-ui lib from here https://material-ui-next.com/demos/buttons/
The Button component uses flexbox to control the layout/alignment of content. To align the content vertically (so the icon is above the text), you can simply change the flex-direction to column.
This style needs to be applied to an element inside the button component, not to the root element. You can use the classes property to override all of the styles in a component.
In this case, you want to add flexDirection: column to the label class.
Documentation on class overrides in material ui v1
Here's a working example. Hope it helps.
const [React, ReactDOM, Button, Settings, withStyles] = [window.React, window.ReactDOM, window['material-ui'].Button, ({className}) => <i className={`material-icons ${className}`}>settings</i>, window['material-ui'].withStyles]
// Ignore code above this line
const styles = theme => ({
button: {
height: 95, // setting height/width is optional
},
label: {
// Aligns the content of the button vertically.
flexDirection: 'column'
},
icon: {
fontSize: '32px !important',
marginBottom: theme.spacing.unit
}
})
const CustomButton = ({ classes }) => (
<Button
/* Use classes property to inject custom styles */
classes={{ root: classes.button, label: classes.label }}
variant="raised"
color="primary"
disableRipple={true}
>
<Settings className={classes.icon} />
Message
</Button>
)
const WrappedCustomButton = withStyles(styles)(CustomButton)
ReactDOM.render(<WrappedCustomButton />, document.querySelector('#root'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script><script src="https://unpkg.com/material-ui#1.0.0-beta.40/umd/material-ui.production.min.js"></script><link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons"><div id="root" />
A (potentially bad) solution would simply be:
.MuiIconButton-label {
flex-direction: column
}
I say bad, because you might want to use it in it's standard format elsewhere.
What I opted to do was add a class name nav-bar-icon-wrapper to the IconButton & set the flex direction in it's parent:
.nav-bar-icon-wrapper {
flex-direction: column
}
.MuiIconButton-label {
flex-direction: inherit
}
If I run into instance later where I want the icon/label button to be standard, I'll just add a new class default-icon-wrapper and css that handles that:
.default-icon-wrapper {
flex-direction: row
}
FWIW:
I preach the BEM http://getbem.com/introduction/ convention AND that whenever you make a component, you add an optional modifier prop.
I have functions in a shared dir that looks these:
export function BEMifyThis(modifier) {
return (klass) => BEMify(klass, modifier)
}
export function BEMify(klass, modifier=false) {
if (modifier) {
klass += ` ${klass}-${modifier}`
}
return klass
}
Then I use that everywhere in my component so the user can access the component elements as a group or individually using their modifiers.
import {BEMifyThis} from '../shared/bem'
const BEMify = BEMifyThis(this.props.modifier)
className={"navbar__menu_item")}
becomes
className={BEMify("navbar__menu_item")}
so something like navbar__menu_item becomes navbar__menu_item navbar__menu_item-logout

How to appendTo React Components as simple as jQuery can

As I try to get into React I find I'm running through lists of things I can do very simply in jQuery but are an absolute nightmare in React.
https://codepen.io/PocketNinjaDesign/pen/boJoEd
have modified the goal from 2 elements to nth
The goal is that nth elements on the page can popup inside of any element / component I want on the page. I achieve this the good old fashion way by adding a data attribute containing Json with an array of components to appendTo.
You can also use JS to turn a component into a ninja and passing an object through containing the list of components to appear in.
$(function() {
$('.other-ninja').Ninja({
components: ['title', 'header', 'angry']
});
});
So, imagining these are React Components now, all different kinds of components, but the ninja block(s) can be told they can appear in any components they want.
How is that possible with React without going through a ball ache of declaration and indigestion?
Here is my code for the jQuery popup appendTo script as what I want to achieve in React.
Have altered the code since the answer I received as I don't think I
was putting my question across correctly.
HTML
<div class="ninja" data-ninja='{"components": ["title", "happy", "sad", "stinky", "header", "AnotherComponent"]}'></div>
<div class="mongoose" data-ninja='{"components": ["happy", "sad", "stinky", "angry", "footer"]}'></div>
<div class="other-ninja"></div>
<h1 class="title">Getting React to work like simple jQuery :-D</h1>
<p>Where ALL HTML elements on this page represent React Components. All components being
split into different files and imported using babel es6 compiler</p>
<div class="header">
<div class="angry"></div>
</div>
<div class="content">
<ul>
<li>Just a list showing more component depth</li>
<li>
<div class="someOtherComponent">
<div class="sad"></div>
</div>
</li>
<li>Trying to show the code works regardless of where the elements are</li>
</ul>
<div class="AnotherComponent">
<div class="SomeOtherComponent">
<div class="WhatAnotherComponent"><div class="happy"></div></div>
</div>
</div>
</div>
<div class="footer">
<div class="whatever">
<div class="stinky"></div>
</div>
</div>
SCSS
Removed the SCSS as it was detracting from the main focus of markup and javascript
Script
$(function() {
function Ninja(e, options) {
var $this = $(e);
options = $.extend({}, $this.data('ninja'), options);
var componentList = options.components;
setInterval(function() {
var randomNum = Math.floor(Math.random() * componentList.length);
$this.appendTo('.' + componentList[randomNum]);
}, 1000);
}
$.fn.Ninja = function(options) {
$(this).each(function(i, e) {
Ninja(e, options);
});
};
$('[data-ninja]').each(function(i, e) {
$(e).Ninja();
});
});
$(function() {
$('.other-ninja').Ninja({
components: ['title', 'header', 'angry']
});
});
React might seem like "nightmare" when you used to use jQuery but actually using React is really easy. You just need to adjust your coding logic to suit React guidelines.
The code you shared can be implemented in React many different ways. I did a small working version for you to compare. At first-look it might seem a lot more code to achieve same simple affect but React has a lot more control over the DOM (Virtual DOM) and can be manipulated a lot more different ways. Most of the code in this example is same for all components. You just need to put consideration render method. Appending or removing a component/element can be achieved by just a simple if statement. Also component logic gives you a big flexibility and re-usability. There are a lot of good examples and tutorials online that can show you how you can solve thing in react way. A really good start point is React Docs and awesome-react.
import React from 'react';
import { render } from 'react-dom';
const styles = {
component: {
position: 'absolute',
width: 100,
height: 100
},
happy: {
position: 'absolute',
width: 100,
height: 100,
top: 100,
left: 40,
backgroundColor: 'yellow'
},
sad: {
position: 'absolute',
width: 100,
height: 100,
top: 20,
left: 180,
backgroundColor: 'blue'
},
angry: {
position: 'absolute',
width: 100,
height: 100,
top: 160,
left: 500,
backgroundColor: 'red',
},
stinky: {
position: 'absolute',
width: 100,
height: 100,
top: 210,
left: 300,
backgroundColor: 'green'
},
ninja: {
position: 'absolute',
zIndex: 100,
width: 50,
height: 50,
backgroundColor: '#000'
},
deathstar: {
position: 'absolute',
zIndex: 100,
width: 20,
height: 20,
backgroundColor: '#444'
}
};
const Ninja = () => (<div style={styles.ninja}></div>);
const DeathStar = () => (<div style={styles.deathstar}></div>);
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
types: ['happy', 'sad', 'angry', 'stinky'],
ninja: 0,
deathstar: 0
};
this.intervalNinja = null;
this.intervalDeathstart = null;
}
randomNumber() {
return Math.floor(Math.random() * (3 - 0 + 1)) + 0;
}
componentWillUnmount() {
clearInterval(this.intervalNinja);
clearInterval(this.intervalDeathstart);
this.intervalNinja = null;
this.intervalDeathstart = null;
}
componentDidMount() {
this.intervalNinja = setInterval(() => {
this.setState({
ninja: this.randomNumber()
});
}, 1082);
this.intervalDeathstart = setInterval(() => {
this.setState({
deathstar: this.randomNumber()
});
}, 987);
}
render() {
return(
<div>
{this.state.types.map((type, index) => (
<div style={styles[type]}>
{this.state.ninja === index && <Ninja />}
{this.state.deathstar === index && <DeathStar />}
</div>
))}
</div>
)
}
}
render(<App />, document.getElementById('root'));

Categories

Resources