I am trying to implement the plugins for the Filepond library for React.js using Firebase on the backend. The documentation is thin in regards to implementing the cropping plugin. All I want to do is force a 1:1 crop ratio on every image added as a profile picture, but with the current code, it is hanging at Waiting for size - Loading...
Mentioned in the docs here there is a hint at using transform plugin in conjunction to get the crop functionality, but not sure how to use the create() function to get this.
Is there any examples of implementing the crop to work as I intend? Or can someone show me how they got it to work? Thanks!
Code:
import React, { useState, Component } from "react";
// Filepond / Upload
import * as upload from "../../utils/upload";
import { FilePond, registerPlugin } from "react-filepond";
import "filepond/dist/filepond.min.css";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import FilePondPluginImageResize from "filepond-plugin-image-resize";
import FilePondPluginImageValidateSize from "filepond-plugin-image-validate-size";
import FilePondPluginFileValidateSize from "filepond-plugin-file-validate-size";
import "filepond/dist/filepond.min.css";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css";
import FilePondPluginImageTransform from "filepond-plugin-image-transform";
import FilePondPluginImageEdit from "filepond-plugin-image-edit";
registerPlugin(
FilePondPluginImageResize,
FilePondPluginImagePreview,
FilePondPluginImageValidateSize,
FilePondPluginFileValidateSize,
FilePondPluginImageTransform,
FilePondPluginImageEdit
);
export class Personal extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.updateProfPicUrl = this.updateProfPicUrl.bind(this);
this.user = this.props.user;
this.files = [];
this.pathToUrl = {};
this.basePath = `/users/${this.props.user.id}/images/profPic`;
this.process = upload.process(
this.basePath,
this.pond,
this.pathToUrl,
this.files
);
this.revert = upload.revert(this.pathToUrl, this.files);
}
updateProfPicUrl() {
if (this.files > 0) {
this.props.updateProfPicUrl(this.files, this.pathToUrl);
this.props.handleCloseModal();
} else {
alert("Please choose a file from your computer to upload first!");
}
this.files = [];
this.pathToUrl = {};
}
handleChange(e) {
this.setState({ [e.target.name]: e.target.value });
}
render() {
return (
<div>
<FilePond
ref={ref => (this.pond = ref)}
files={this.files}
allowMultiple={false}
imageEditInstantEdit={true}
imageCropAspectRatio={1}
onupdatefiles={fileItems => {
// Set current file objects to this.state
this.files = fileItems.map(function(fileItem) {
let file = fileItem;
file.uuid = uuid().toString();
return file;
});
}}
server={{
process: this.process,
revert: this.revert
}}
/>
<button
onClick={() => {
this.props.updateProfPicUrl(
this.files,
this.pathToUrl
);
}}
className="s-btn"
>
Update
</button>
</div>
);
}
}
Was finally able to revisit this, and I was able to easily do it. I did not need all the plugins, but just needed the ImageTransform and ImageCrop plugins. I just passed the properties:
allowImageCrop={true}
allowImageTransform={true}
imageCropAspectRatio={'1:1'}
to my <FilePond /> component. And imported:
import { FilePond, registerPlugin } from "react-filepond";
import "filepond/dist/filepond.min.css";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css";
import FilePondPluginImageCrop from 'filepond-plugin-image-crop'; // Crops image
import FilePondPluginImageTransform from 'filepond-plugin-image-transform'; // Changes image to match crop
registerPlugin(FilePondPluginImagePreview, FilePondPluginImageCrop, FilePondPluginImageTransform);
Related
Wassup Guys,
I have a reusable component, that translates keys into a choosen language through keynames as string or a binded var.
Usually I use a tag for this, but because of different reasons I am switching/replacing current translations with {t('...')}.
Here is the code of the component:
import React from 'react';
import { useTranslation as defaultTranslation } from 'react-i18next';
import i18next from 'i18next';
export const useTranslation = (ns = 'common', options) => {
return defaultTranslation(ns, {
useSuspense: false,
...options,
});
};
export const withTranslation = (Component, ns, options) => {
const TranslatedHOC = (props) => {
const translationProps = useTranslation(ns, options);
return <Component {...translationProps} {...props} />;
};
return TranslatedHOC;
};
export const getCurrentLanguage = () =>
i18next.language || localStorage.getItem('language') || 'de-DE';
First of all I define the const for the used imported function:
const {t} = useTranslation();
normal case: importing my component in the file, where I want to use it and add code above.
Code of my component, where I want to replace the Tags.
// Import React Table
import ReactTable from 'react-table';
import 'react-table/react-table.css';
import LocalizedText from '#components/i18n/LocalizedText';
class T extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
pages: null,
loading: true,
};
this.fetchData = this.fetchData.bind(this);
}
fetchData(state, instance) {
this.props.onFetchData(state, instance).then(() => {
this.setState({
loading: false,
});
});
}
render() {
return (
<ReactTable
{...this.props}
previousText={
<LocalizedText textKey="caseoverview.orderproduct.back" />
}
nextText={
<LocalizedText textKey="caseoverview.orderproduct.continue" />
}
loadingText={<LocalizedText textKey="loading" />}
noDataText={<LocalizedText textKey="placeholders.nodata" />}
pageText={
<LocalizedText textKey="reservationcalculator.search.result.page" />
}
ofText={<LocalizedText textKey="from" />}
rowsText={<LocalizedText textKey="rows" />}
className="case-search-table"
/>
);
}
}
export default T;
...
previousText={
<LocalizedText textKey="caseoverview.orderproduct.back" />
}
...
should change to:
...
previousText={
t('caseoverview.orderproduct.back')
}
...
The problem is, that I can't use the code quoted above without getting any issues regarding invalid hook calls. If I move it out somehow, I get errors telling me that my 't' is either not defined or an unexpected token. Could someone help me out? Searched online for solutios without any result.
A hook can only be used in a functional component. You can change this class component to a functional component, or you can use react-i18next's withTranslation HOC to wrap your class component. See https://react.i18next.com/latest/withtranslation-hoc#when-to-use
#kevin asworth answer helped me out.
Using withTranslation with passing t as prop
const {t} = this.props;
inside the render method worked for me.
I am trying to get EditorJS working in NextJS. The editor loads fine without plugins, having the only paragraph as a block option. However, when I attempt to add plugins via tools prop console throws the following warning:
editor.js?9336:2 Module Tools was skipped because of TypeError: Cannot read property 'prepare' of undefined
When I click on the editor in the browser, it is throwing:
Uncaught TypeError: Cannot read property 'holder' of undefined
I have tested editor plugins in the normal React app, and they load fine. Meaning that the problem is in EditorJS and NextJS import and handling of plugins. I have tried to import editor and plugins in componentDidMount hook using require but had the same problem as with NextJS dynamic imports. Attempted to get component using React ref but found that currently NextJS has problems with getting components' refs, Tried suggested workaround but still had no result. The instance of the editor is not available until onChange is triggered, so plugins just cannot hook into the editor due to that 'prepare' property or the whole editor are being undefined until an event on editor has happened, but the editor outputs into the console that it is ready.
My component's code:
import React from "react";
import dynamic from "next/dynamic";
const EditorNoSSR = dynamic(() => import("react-editor-js"), { ssr: false });
const Embed = dynamic(() => import("#editorjs/embed"), { ssr: false });
class Editor extends React.Component {
state = {
editorContent: {
blocks: [
{
data: {
text: "Test text",
},
type: "paragraph",
},
],
},
};
constructor(props) {
super(props);
this.editorRef = React.createRef();
}
componentDidMount() {
console.log(this.editorRef.current);
console.log(this.editorInstance);
}
onEdit(api, newData) {
console.log(this.editorRef.current);
console.log(this.editorInstance);
this.setState({ editorContent: newData });
}
render() {
return (
<EditorNoSSR
data={this.state.editorContent}
onChange={(api, newData) => this.onEdit(api, newData)}
tools={{ embed: Embed }}
ref={(el) => {
this.editorRef = el;
}}
instanceRef={(instance) => (this.editorInstance = instance)}
/>
);
}
}
export default Editor;
Is there any solution to this problem? I know SSR is challenging with client side rendering of components that access DOM, but there was condition used that checked whether window object is undefined, however, it does not look like an issue in my situation.
UPDATE:
I have found a solution but it is rather not a NextJS way of solving the problem, however, it works. It does not require a react-editorjs and implemented as creation of EditorJS instance as with normal EditorJS.
class Editor extends React.Component {
constructor(props) {
super(props);
this.editor = null;
}
async componentDidMount() {
this.initEditor();
}
initEditor = () => {
const EditorJS = require("#editorjs/editorjs");
const Header = require("#editorjs/header");
const Embed = require("#editorjs/embed");
const Delimiter = require("#editorjs/delimiter");
const List = require("#editorjs/list");
const InlineCode = require("#editorjs/inline-code");
const Table = require("#editorjs/table");
const Quote = require("#editorjs/quote");
const Code = require("#editorjs/code");
const Marker = require("#editorjs/marker");
const Checklist = require("#editorjs/checklist");
let content = null;
if (this.props.data !== undefined) {
content = this.props.data;
}
this.editor = new EditorJS({
holder: "editorjs",
logLevel: "ERROR",
tools: {
header: Header,
embed: {
class: Embed,
config: {
services: {
youtube: true,
coub: true,
},
},
},
list: List,
inlineCode: InlineCode,
code: Code,
table: Table,
quote: Quote,
marker: Marker,
checkList: Checklist,
delimiter: Delimiter,
},
data: content,
});
};
async onSave(e) {
let data = await this.editor.saver.save();
this.props.save(data);
}
render() {
return (
<>
<button onClick={(e) => this.onSave(e)}>Save</button>
<div id={"editorjs"} onChange={(e) => this.onChange(e)}></div>
</>
);
}
}
This implementation works in NextJS
I will update code if I find a better solution.
UPDATE 2:
The answer suggested by Rising Odegua is working.
You have to create a seperate component and then import all your tools there:
import EditorJs from "react-editor-js";
import Embed from "#editorjs/embed";
import Table from "#editorjs/table";
import List from "#editorjs/list";
import Warning from "#editorjs/warning";
import Code from "#editorjs/code";
import LinkTool from "#editorjs/link";
import Image from "#editorjs/image";
import Raw from "#editorjs/raw";
import Header from "#editorjs/header";
import Quote from "#editorjs/quote";
import Marker from "#editorjs/marker";
import CheckList from "#editorjs/checklist";
import Delimiter from "#editorjs/delimiter";
import InlineCode from "#editorjs/inline-code";
import SimpleImage from "#editorjs/simple-image";
const CustomEditor = () => {
const EDITOR_JS_TOOLS = {
embed: Embed,
table: Table,
marker: Marker,
list: List,
warning: Warning,
code: Code,
linkTool: LinkTool,
image: Image,
raw: Raw,
header: Header,
quote: Quote,
checklist: CheckList,
delimiter: Delimiter,
inlineCode: InlineCode,
simpleImage: SimpleImage
};
return (
<EditorJs tools={EDITOR_JS_TOOLS} />
);
}
export default CustomEditor;
Then in your NextJS page, use a dynamic import like this:
let CustomEditor;
if (typeof window !== "undefined") {
CustomEditor = dynamic(() => import('../src/components/CustomEditor'));
}
And you can use your component:
return (
{CustomEditor && <CustomEditor />}
)
Source : https://github.com/Jungwoo-An/react-editor-js/issues/31
I'm trying to make a music player application with Electron & React. I have been able to access music files in a resources/music folder when built and installed but I have to give the exact path to an mp3.
I have been trying ways to scan the directory and get all music file names to put in a JSON as the idea is the user could add their own music files to the music folder to be picked up by the app and displayed in a list.
Most solutions I see use node fs but I just can't get it to work. I keep getting this error:
TypeError: fs.readdir is not a function
Any help would be greatly appreciated.
import React, { Component } from 'react';
import { Link } from "react-router-dom"
import Testpage from "./Test";
import song from '../Music/Taxi.mp3'
import FileSearch from "../filesearch";
const fileSearch = new FileSearch();
const dataPath =
process.env.NODE_ENV === 'development'
? song
: 'file:///resources/Music/Taxi.mp3';
class Home extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
fileSearch.search()
}
render() {
return (
<div id="page">
<h1>laceHolder Home</h1>
<div>
<Testpage song={dataPath}/>
</div>
</div>
);
}
}
export default Home;
const testFolder = './';
const fs = require('fs');
export default class FileSearch {
search = () => {
fs.readdir(testFolder, (err, files) => {
files.forEach(file => {
console.log(file);
});
});
}
}
Solved, after hours of looking (im pretty new to react and electron),
I used the below instead of vanilla fs import and it worked!
const remote = window.require('electron').remote;
const electronFs = remote.require('fs');
const electronDialog = remote.dialog;
Thanks for your comments to look at window.require
import React, { Component } from 'react';
import ChatBot from 'react-simple-chatbot';
import { Switch, Route, BrowserRouter } from 'react-router-dom';
import Dropzone from 'react-dropzone';
class Form extends Component {
constructor(props){
super(props);
this.state = {
// some other states
file: ''
};
}
onDrop(acceptedFiles){
var file = acceptedFiles[0];
const reader = new FileReader();
reader.onload = () => {
const fileAsBinaryString = reader.result;
this.setState({
file: fileAsBinaryString
});
//console.log(fileAsBinaryString);
}
reader.readAsBinaryString(file);
//console.log(file);
}
render() {
return(
<ChatBot
steps={[
{
id: '1',
message: 'You can add custom components',
trigger: '2',
},
{
id: '2',
component: (
<div>
<Dropzone onDrop={this.onDrop.bind(this)} />
</div>
),
end: true,
},
]}
/>
)
}
}
I am trying to use react-dropzone within react-simple-chatbot, but when I upload a file it shows 2 warnings:
React does not recognize the previousStep prop on a DOM element.
React does not recognize the triggerNextStepenter image description here prop on a DOM element.
I am able to find similar problems but their solutions are not working out for me. How should I make it work?
Edit: I have added an example similar to my approach.
Hello Dear your question is not not clear to me as it lacks lots of information,It would have better if you put your code here. I don't know did you follow react-dropzone documentation. In their documentation they cleared how to use it in your application. Try to do below procedure. In my case it is working without showing any warning.
import Dropzone from 'react-dropzone'
//OTHERS IMPORT FILE
// ... ... ...
class AddEmployee extends Component {
constructor(props) {
super(props);
this.state = {
photo: ""
}
}
// OTHERS FUNCTIONS
// ... ... ....
onDrop(files) {
const file = files.find(f => f)
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = () => {
this.setState({
photo: reader.result,
})
}
}
render() {
return (
// OTHERS DIV
// ... ... ... ...
<div className="dropzone">
<Dropzone onDrop={(e) => this.onDrop(e)}>
{this.state.photo != "" ? <img width={195} height={195} src={this.state.photo} /> : <p>Try dropping some photo here or click to select files to upload</p>
}
</Dropzone>
</div>
// OTHERS DIV
// ... ... ... ...
)
}
}
In React Native, I'm loading in a local JSON file with data as an array via import (and then shuffling the array), but would somehow like this to happen in the AppLoading stage, not after the AppLoading, when I'm trying to render the main app.
In the current state, the App takes too long to read in the local JSON file AFTER the App Loading screen, not DURING (i have 'intro sliders' after the app loading screen, but before the main body of the app. Is that possible to do?
Here is my code (abbreviated):
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Image,
Dimensions,
Alert
} from 'react-native';
import { Font } from 'expo';
import CardStack, { Card } from 'react-native-card-stack-swiper';
import AppIntroSlider from 'react-native-app-intro-slider';
import imagedata from './assets/cleaned_imagesdata.json';
//Here is where I'm importing in data from a local JSON
var shuffle = require('shuffle-array'),
collection = imagedata;
shuffle(collection);
export default class App extends Component<{}> {
constructor(props) {
super(props);
this.state = {
fontLoaded: false,
showRealApp: false
};
}
async componentDidMount() {
await Font.loadAsync({
'proxima-nova': require('./assets/fonts/proxima-nova-soft-light-webfont.ttf'),
'proxima-nova-bold': require('./assets/fonts/ProximaNovaBold.ttf')
});
this.setState({fontLoaded: true});
}
_onDone = () => {
this.setState({showRealApp: true});
};
render() {
if (!this.state.fontLoaded) {
return <Expo.AppLoading />; //THIS IS THE PART
}
if (this.state.showRealApp) {
const contents = collection.map((item, index) => {
return (
<Card key={index}>
....
</Card>
)
});
return (
<View style={{flex:1}}>
....
{contents}
....
</View>
);
} else {
return <AppIntroSlider slides={intro_slides} onDone={this._onDone}/>;
}
}
}
I've looked at the docs for Preloading assets in Expo's AppLoading component and tried mimicking by having _loadAssetsAsync() set the JSON file/array to a variable, but this makes the loading take much longer. Is there a better way to 'read in the local JSON file as an array and preload/cache it'?
async _loadAssetsAsync() {
const collection = imagedata;
await Promise.all([collection]);
}
render() {
if (!this.state.fontLoaded || !this.state.isReady) {
return <Expo.AppLoading
startAsync={this._loadAssetsAsync}
onFinish={() => this.setState({ isReady: true })}
onError={console.warn}
/>;
}
....
From the expo docs it looks like your second part of the post is the way to go:
<Expo.AppLoading
startAsync={this._loadAssetsAsync}
onFinish={() => this.setState({ isReady: true })}
As for loading the JSON data:
import imageData from './assets/cleaned_imagesdata.json';
const shuffle = require('shuffle-array');
shuffle(imageData);
You should do this in your application logic, for example in _loadAssetsAsync so that React knows when it's done rather than using an import statement at the top level.
this makes the loading take much longer
How big is the JSON file you're loading? If performance is an issue, can you split it into several smaller JSON files and load the rest of the data only when it's needed, e.g. just before the user can see that data?