In my React application, I am using 'Editor.jsx component (which is just a wrapper around code-mirror, in case I need to provide frills around the actual CodeMirror-view).
The in which the rendered component from attached file is added to, has height of 100% and other components similar to CodeMirror do use that full height.
The CodeMirror component however only shows 15 lines (and i have to scroll to get to the ones below).
The code is very similar to the sample from github. The height property in getInitialState() also has no effect (neither does the containing ).
import React from 'react';
var CodeMirror = require('react-codemirror');
// fishing this 'require' out has caused severe headache and cost time.
// IF not included, default bootstrap style used. must override it with this.
// but for react-codemirror component we need this one!!!
// REF http://dorianpula.ca/2015/10/07/adding-a-code-editor-to-rookeries/
require("codemirror/lib/codemirror.css");
require('codemirror/mode/javascript/javascript');
require('codemirror/mode/python/python');
var DFLTS = {
javascript: 'var component = {\n\tname: "react-codemirror",\n\tauthor: "Jed Watson",\n\tforUseBy: "KB"}',
python: 'print "hello python world"'
}
export default React.createClass ({
localOnCodeChange(newCode) {
this.props.onCodeChange(newCode)
},
getInitialState() {
return {
code: DFLTS.javascript,
readOnly: false,
mode: 'javascript',
height:"100%",
viewportMargin: "Infinity"
};
},
componentDidMount() {
CodeMirror.setSize("100%", 1000);
},
changeMode(e) {
// add python later.
// no-op
},
toggleRreadOnly() {
this.setState({
readOnly: !this.state.readOnly
}, () => this.refs.editor.focus());
},
interact(cm) {
console.log(cm.getValue());
},
render() {
var options = {
lineNumbers: true,
readOnly: this.state.readOnly,
mode: this.state.mode
};
return (
<CodeMirror ref="editor" value={this.props.code} onChange={this.props.onCodeChange} options={options} interact={this.interact}/>
)
}
});
Any pointers, greatly appreciated.
The .CodeMirror class in this library appears to have a hard-coded height: 300px in it and there's an unanswered question in their issues about being able to set the height. If you put .CodeMirror { min-height: 100% } in your CSS that might do the trick.
Alternatively pass a className to <CodeMirror> (it will get added to the classes) that sets a min height, or a height with !important, or just greater specificity.
(Tsk tsk to components that you have to fight with :))
if you need to dynamically change the height, or simply dont want to use css you can use ref
const codemirrorRef = React.useRef();
React.useEffect(() => {
const current = codemirrorRef.current.editor.display.wrapper.style.height = "1000px";
});
<CodeMirror
[...]
ref={codemirrorRef}
/>
codemirrorRef.current.editor.display.wrapper contains the div element. From there you can do anything you would do if you did document.getElementById('#id')
I was able to get the height to override by adding an addition to the existing CodeMirror class in my CSS file as follows:
.CodeMirror {
height: 100% !important
}
it only applied the change after adding !important to force it to override the existing class which is hard coded to 300 pixels.
Related
I'm working with Next.js and using a react-spring library to get an animation for a bottomsheet component. It works, however there is a warning appears:
Warning: Prop style did not match. Server: "transform:translate3d(0,Infinitypx,0)" Client: "transform:translate3d(0,652px,0)"
I've carefully investigated this warning and know that it's about incorrect rendering of the HTML element on the server and on the client side. It's clear that on the server side there is no viewport height and thus react-spring can't calculate normally the final value and Next.js registers it as an one value with Infinity and then blames on the client side when the value is calculated correctly due to available viewport height.
I'm wondering what is the best way to rid of this error?
Unfortunatelly I can't catch the react-spring calculation stage and to set a correct value.Tere is no API to do it and basically I just don't know the user's viewport height.
I've thinking about the using indexOf for the value and check if the Infinity presented and replace it for ex: by 0
however it still doesn't solve a problem as the final value will be different anyway.
Maybe someone has an idea or some link to docs etc. where I could find a solution for that?
Basically it's just a warning but I'd like to fix it anyway.
Here is the example code:
import { a, config, useSpring } from '#react-spring/web';
export function BottomSheet({propsHeight}) {
const finalHeight = propsHeight || height - 62;
const display = y.to((py) => (py < finalHeight ? 'flex' : 'none'));
const [{ y }, api] = useSpring(() => ({ y: finalHeight }));
const open = (dragEvent?: any) => {
const canceled = dragEvent?.canceled;
// when cancel is true, it means that the user passed the upwards threshold
// so need to change the spring config to create a nice wobbly effect
api.start({
y: 0,
immediate: false,
config: canceled ? config.wobbly : config.stiff,
});
};
const close = (velocity = 0) => {
api.start({
y: finalHeight,
immediate: false,
onResolve() {
if (onClose) {
onClose();
}
},
config: { ...config.stiff, velocity },
});
};
useEffect(() => {
// provide open/close actions to parent control
getActions(open, close);
}, []);
// pseudo hmtl. Removed all other markup to simplify things
return (<a.div
style={{
y, // Here is the problem of the server & client incorrect values
}}
/>)
}
I highly appreciate any help!
Kind Regards
The only one solution I've found so far for this use case it's rendering the component on client side only and, basically, it makes sense because this code is based on the browser API. I don't see any other possible solutions
To achieve it you can use dymanic imports and Next.js supports them well: here is the docs
You should disable the SSR in the import options and the component will be rendered on the client side only.
Like this:
import dynamic from 'next/dynamic';
const BottomSheetDynamic = dynamic(
() =>
import('#mylibrary/components/bottomsheet/BottomSheet').then(
//this component doesn't have default import so should do it in this way
(mod) => mod.BottomSheetexport
),
{
ssr: false,
}
);
I want to add a watermark over an image file. I'm using the "https://libraries.io/npm/react-watermark-component" npm library to achieve the result. so far I have:
render() {
const waterMarkOptions = {
chunkWidth: 200,
chunkHeight: 60,
textAlign: "left",
textBaseline: "bottom",
globalAlpha: 0.17,
font: "14px Microsoft Yahei",
rotateAngle: -0.26,
fillStyle: "#666"
};
<ReactWaterMark
waterMarkText="Confidenatiality"
openSecurityDefense
options={waterMarkOptions}>
<MyComponent>
.
.
.
</MyComponent>
</ReactWaterMark>
}
But doing this it does nothing, it does not add any watermark to the component.
I also tried the watermar.js - https://github.com/brianium/watermarkjs
but I'm sure of its usage inside a ReactComponent.
This is the usage:
const options = {
init(img) {
img.crossOrigin = 'anonymous'
}
};
watermark(['http://host.com/photo.jpg', 'http://host.com/logo.png'], options)
.image(watermark.image.lowerRight(0.5))
.then(img => document.getElementById('container').appendChild(img));
Mycomponent:
export default class Dialog extends React.Component {
render() {
return <div>
//where should I insert the watermark script?
</div>
}
}
Just FYI, my component is a dialog box and I have text/images inside.
Note: For testing purpose I have added water mark to the entire component, however I;d want to add water precisely on the image. But before that I want to see if I''m making use of component correctly.
any idea?
I have to test a very unusual case, in my test I should click to some component which is wrapped by from material-ui and it is inside the List from react-vertualized.
I have dived to it -
wrapper
.find(TreeView)
.dive()
.find(AutoSizer)
.renderProp('children', {})
.find(VirtualizedTree)
.dive()
.renderProp('rowRenderer', { index: 0, props: {...} });
And if I debug it I see this result -
<WithStyles(TreeNode) data-test="projected-tree" components={{...}} onSelectToggle={[Function]} onExpandToggle={[Function]} width={...} style={...} node={{...}} level={0} isOdd={true} />
The component which I want to click is inside the TreeNode, but when I try to dive I receive the error related to my custom theme which I use in my project, this happening because has lost the connection to the custom theme.
I think this happening because it has been rendered through the rowRenderer property of List.
Maybe somebody has any ideas on how to pass the custom theme inside the List.rowRenderer?
you need to mock the width and height to make AutoSizer return a width to children can showup
you can use this function mockOffsetSize
// AutoSizer uses offsetWidth and offsetHeight.
// Jest runs in JSDom which doesn't support measurements APIs.
function mockOffsetSize(width, height) {
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
configurable: true,
value: height,
});
Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
configurable: true,
value: width,
});
}
ref: https://github.com/bvaughn/react-virtualized/blob/master/source/AutoSizer/AutoSizer.jest.js#L68
I'm trying to build a simple object-viewer in React with Meteor that can import .obj and .mtl Files using the following npm modules:
three(0.87.1)
react(15.6.1)
three-obj-loader(1.1.3)
three-mtl-loader(1.0.1)
So far i have managed to display an object using the OBJLoader.
But when i try to render an object after applying a texture with MTLLoader, i get this error from console:
Uncaught TypeError: Cannot read property 'toString' of undefined
at WebGLPrograms.getProgramCode (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:50707)
at initMaterial (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:54628)
at setProgram (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:54820)
at WebGLRenderer.renderBufferDirect (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:53883)
at renderObject (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:54613)
at renderObjects (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:54586)
at WebGLRenderer.render (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:54350)
at WebGlDisplay.renderScene (WebGlDisplay.jsx:86)
at onClick (WebGlDisplay.jsx:90)
at HTMLUnknownElement.boundFunc (modules.js?hash=eae498e3ee56e21f967b663c5bed3444c66eaef2:8794)
Cause: material.onBeforeCompile in getProgramCode is undefined
My code looks like this:
import React, { Component } from 'react'
import THREE from 'three'
const MTLLoader = require('three-mtl-loader');
const OBJLoader = require('three-obj-loader')(THREE);
export default class WebGlDisplay extends Component {
constructor(props) {
super(props)
}
//init canvas
init(){
const width = this.mount.clientWidth;
const height = this.mount.clientHeight;
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
renderer.setClearColor('#000000', 0.2);
renderer.setSize(width, height);
camera.position.set(3,4,6);
camera.lookAt(new THREE.Vector3());
this.scene = scene;
this.camera = camera;
this.renderer = renderer;
this.mount.appendChild(this.renderer.domElement);
}
//load & render object
drawOBJ(){
const mtlLoader = new MTLLoader();
let onProgress = function(e){console.log("rendering:" + e)};
let onError = function(e){console.log("error:" + e)};
mtlLoader.load("eagle.mtl", materials => {
materials.preload();
// OBJ Loader
const objLoader = new THREE.OBJLoader();
this.materials = materials;
objLoader.setMaterials(materials);
objLoader.load("eagle.obj", object => {
this.object = object;
this.scene.add(object);
}, onProgress, onError);
}, onProgress,onError);
this.renderScene();
}
componentDidMount() {
this.init();
this.drawOBJ();
}
renderScene() {
this.renderer.render(this.scene, this.camera)
}
render() {
return (
<div onClick={(e) => this.renderScene()}
style={{ width: '800px', height: '600px' }}
ref={(mount) => { this.mount = mount }}
/>
)
}
}
Does anyone have an idea why i get this error?
I've tried to use different .obj- and .mtl-files, but the error remains (whenever i try to call renderScene()).
By any chance, could it be a problem with the module versions, or maybe some timing problems while loading?
Any help would be appreciated.
The problem seems to be that the three-mtl-loader NPM package is referencing an outdated three.js version in it's package.json, so even though you are using the latest version of three, the plugin isn't!
Obviously this isn't a viable long-term fix, but I changed the version for three in node_modules/three-mtl-loader/package.json to 0.87.1 and deleted the directory node_modules/three-mtl-loader/node_modules for good measure and ran my example and it worked straight away, textures and all.
Clearly the plugin needs to be updated. I also saw at least one functional difference between the source in the plugin and in the three examples folder ('Tr' vs 'tr' in a case statement), and it doesn't follow the same initialization behavior as other loader plugins (specifically it isn't initialized by calling require("three-mtl-loader")(THREE)), so there's a bit of work to get it ship-shape.
Alternately, it appears that the author has updated the version number to 0.86.0 in their repo (which is high enough), just hasn't done a deploy to NPM. So, if you feel brave, you can just change your package.json to have the line
"dependencies": {
...
"three-mtl-loader": "git+https://git#github.com/nascherman/three-mtl-loader.git",
...
}
As a workaround, what i ended up doing is to get a local copy of the newest MTLLoader Version and slightly modifing it, as it seems to be a problem with the version pointed out by #user1691694.
In case somebody needs this here my way of importing it:
In the MTLLoader file, add the following line at the top:
import THREE from 'three';
and at the bottom:
module.exports.default = THREE.MTLLoader
Use it like in the drawOBJ function in the question post and import it in the target file like this:
import MTLLoader from './MTLLoader.js';
I have a few components and some of them are sized with px. The others I want to be variable size. However, the ones that are variable size are not a constant percentage of the page because of the components with a fixed px height. So I want a component to be about 80% of the screen height('80vh') minus the height of the other component. I was hoping to use something like
style={{height:'80vh-40px'}}
but that does not work.
I found this page which gets close but that my program does not recognize that calc function. Do I need to require it from some library maybe?
Any ideas on how to make this work?
Thanks!
I use syntax like this in my React.js components:
<div style={{height: 'calc(100vh - 400px)'}}></div>
it works for me.
Inside CSS code with LESS preprocessor I use the same syntax, but not equal:
.right_col {
height: calc(~"100vh - 400px");
}
In my experiments, I found that symbol "~" doesn't work in React.js components.
A way to solve it is by using style={} in your component.
const styles = {targetDiv: { height: 'calc(100vh - Xpx)'}}
then...
<div style={styles.targetDiv}>
...
</div>
Note - you can get the window.innerHeight (see http://ryanve.com/lab/dimensions/ for height and width options in javascript) and just calculate this yourself in react and set the width or height in pixels.
If you do this with height, you'd need to recalculate if it changes
state = {
windowHeight: window.innerHeight
}
componentWillMount () {
window.addEventListener('resize', this.handleResize)
}
componentWillUnmount () {
window.removeEventListener('resize', this.handleResize)
}
handleResize = () => {
this.setState({ windowHeight: window.innerHeight })
}
in your div
<div style={{height: this.state.windowHeight}} > ... </div>
You wouldn't want to do this everywhere, but it's very handy for some situations. For example - setting 100% height on Android mobile web, where 100vh does not work and device buttons cover up part of the screen.