Simplify React components loader
This commit is contained in:
parent
39afa6659c
commit
2cf415dc41
10 changed files with 107 additions and 147 deletions
8
app/javascript/components/Loadable.js
Normal file
8
app/javascript/components/Loadable.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
import React from 'react';
|
||||
import Loadable from 'react-loadable';
|
||||
|
||||
const loading = () => <div className="spinner left" />;
|
||||
|
||||
export default function(loader) {
|
||||
return Loadable({ loader, loading });
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { library } from '@fortawesome/fontawesome-svg-core';
|
||||
import {
|
||||
faArrowCircleDown,
|
||||
faArrowDown,
|
||||
faArrowsAltV,
|
||||
faArrowUp,
|
||||
faPlus,
|
||||
faTrash
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
|
||||
import Flash from './Flash';
|
||||
import OperationsQueue from './OperationsQueue';
|
||||
import TypeDeChamps from './components/TypeDeChamps';
|
||||
|
||||
library.add(
|
||||
faArrowCircleDown,
|
||||
faArrowDown,
|
||||
faArrowsAltV,
|
||||
faArrowUp,
|
||||
faPlus,
|
||||
faTrash
|
||||
);
|
||||
|
||||
class TypesDeChampEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const defaultTypeDeChampAttributes = {
|
||||
type_champ: 'text',
|
||||
types_de_champ: [],
|
||||
private: props.isAnnotation,
|
||||
libelle: `${
|
||||
props.isAnnotation ? 'Nouvelle annotation' : 'Nouveau champ'
|
||||
} ${props.typeDeChampsTypes[0][0]}`
|
||||
};
|
||||
this.state = {
|
||||
flash: new Flash(props.isAnnotation),
|
||||
queue: new OperationsQueue(props.baseUrl),
|
||||
defaultTypeDeChampAttributes,
|
||||
typeDeChampsTypes: props.typeDeChampsTypes,
|
||||
directUploadUrl: props.directUploadUrl,
|
||||
isAnnotation: props.isAnnotation
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TypeDeChamps state={this.state} typeDeChamps={this.props.typeDeChamps} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TypesDeChampEditor.propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
directUploadUrl: PropTypes.string,
|
||||
isAnnotation: PropTypes.bool,
|
||||
typeDeChamps: PropTypes.array,
|
||||
typeDeChampsTypes: PropTypes.array
|
||||
};
|
||||
|
||||
export default TypesDeChampEditor;
|
|
@ -1,66 +1,3 @@
|
|||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { library } from '@fortawesome/fontawesome-svg-core';
|
||||
import {
|
||||
faArrowDown,
|
||||
faArrowsAltV,
|
||||
faArrowUp,
|
||||
faArrowCircleDown,
|
||||
faPlus,
|
||||
faTrash
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import Loadable from '../Loadable';
|
||||
|
||||
import Flash from './Flash';
|
||||
import OperationsQueue from './OperationsQueue';
|
||||
import TypeDeChamps from './components/TypeDeChamps';
|
||||
|
||||
library.add(
|
||||
faArrowDown,
|
||||
faArrowsAltV,
|
||||
faArrowUp,
|
||||
faArrowCircleDown,
|
||||
faPlus,
|
||||
faTrash
|
||||
);
|
||||
|
||||
class TypesDeChampEditor extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const defaultTypeDeChampAttributes = {
|
||||
type_champ: 'text',
|
||||
types_de_champ: [],
|
||||
private: props.isAnnotation,
|
||||
libelle: `${
|
||||
props.isAnnotation ? 'Nouvelle annotation' : 'Nouveau champ'
|
||||
} ${props.typeDeChampsTypes[0][0]}`
|
||||
};
|
||||
this.state = {
|
||||
flash: new Flash(props.isAnnotation),
|
||||
queue: new OperationsQueue(props.baseUrl),
|
||||
defaultTypeDeChampAttributes,
|
||||
typeDeChampsTypes: props.typeDeChampsTypes,
|
||||
directUploadUrl: props.directUploadUrl,
|
||||
isAnnotation: props.isAnnotation
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<TypeDeChamps state={this.state} typeDeChamps={this.props.typeDeChamps} />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TypesDeChampEditor.propTypes = {
|
||||
baseUrl: PropTypes.string,
|
||||
directUploadUrl: PropTypes.string,
|
||||
isAnnotation: PropTypes.bool,
|
||||
typeDeChamps: PropTypes.array,
|
||||
typeDeChampsTypes: PropTypes.array
|
||||
};
|
||||
|
||||
export function createReactUJSElement(props) {
|
||||
return React.createElement(TypesDeChampEditor, props);
|
||||
}
|
||||
|
||||
export default TypesDeChampEditor;
|
||||
export default Loadable(() => import('./TypesDeChampEditor'));
|
||||
|
|
|
@ -6,9 +6,7 @@ import '@rails/actiontext';
|
|||
import 'whatwg-fetch'; // window.fetch polyfill
|
||||
import Chartkick from 'chartkick';
|
||||
import Highcharts from 'highcharts';
|
||||
|
||||
import ReactUJS from '../shared/react-ujs';
|
||||
import reactComponents from '../shared/react-components';
|
||||
import ReactRailsUJS from 'react_ujs';
|
||||
|
||||
import '../shared/page-update-event';
|
||||
import '../shared/activestorage/ujs';
|
||||
|
@ -61,8 +59,18 @@ Rails.start();
|
|||
Turbolinks.start();
|
||||
ActiveStorage.start();
|
||||
|
||||
const loader = new ReactUJS(reactComponents);
|
||||
loader.start();
|
||||
// If Turbolinks is imported via Webpacker (and thus not available globally),
|
||||
// ReactRailsUJS will be unable to locate it.
|
||||
// https://github.com/reactjs/react-rails#event-handling
|
||||
|
||||
// eslint-disable-next-line no-undef
|
||||
ReactRailsUJS.useContext(require.context('components', true));
|
||||
// Add Turbolinks to the global namespace:
|
||||
window.Turbolinks = Turbolinks;
|
||||
// Remove previous event handlers and add new ones:
|
||||
ReactRailsUJS.detectEvents();
|
||||
// (Optional) Clean up global namespace:
|
||||
delete window.Turbolinks;
|
||||
|
||||
// Expose globals
|
||||
window.DS = window.DS || DS;
|
||||
|
|
8
app/javascript/shared/react-components.js
vendored
8
app/javascript/shared/react-components.js
vendored
|
@ -1,8 +0,0 @@
|
|||
export default function reactComponents(className) {
|
||||
switch (className) {
|
||||
case 'TypesDeChampEditor':
|
||||
return import('components/TypesDeChampEditor').then(
|
||||
mod => mod.createReactUJSElement
|
||||
);
|
||||
}
|
||||
}
|
61
app/javascript/shared/react-ujs.js
vendored
61
app/javascript/shared/react-ujs.js
vendored
|
@ -1,61 +0,0 @@
|
|||
import ReactDOM from 'react-dom';
|
||||
|
||||
// This attribute holds the name of component which should be mounted
|
||||
// example: `data-react-class="MyApp.Items.EditForm"`
|
||||
const CLASS_NAME_ATTR = 'data-react-class';
|
||||
|
||||
// This attribute holds JSON stringified props for initializing the component
|
||||
// example: `data-react-props="{\"item\": { \"id\": 1, \"name\": \"My Item\"} }"`
|
||||
const PROPS_ATTR = 'data-react-props';
|
||||
|
||||
// This attribute holds which method to use between: ReactDOM.hydrate, ReactDOM.render
|
||||
const RENDER_ATTR = 'data-hydrate';
|
||||
|
||||
function findDOMNodes() {
|
||||
return document.querySelectorAll(`[${CLASS_NAME_ATTR}]`);
|
||||
}
|
||||
|
||||
export default class ReactUJS {
|
||||
constructor(loadComponent) {
|
||||
this.loadComponent = loadComponent;
|
||||
}
|
||||
|
||||
async mountComponents() {
|
||||
const nodes = findDOMNodes();
|
||||
|
||||
for (let node of nodes) {
|
||||
const className = node.getAttribute(CLASS_NAME_ATTR);
|
||||
const createReactUJSElement = await this.loadComponent(className).catch(
|
||||
() => null
|
||||
);
|
||||
|
||||
if (!createReactUJSElement) {
|
||||
const message = "Cannot find component: '" + className + "'";
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
'%c[react-rails] %c' + message + ' for element',
|
||||
'font-weight: bold',
|
||||
'',
|
||||
node
|
||||
);
|
||||
throw new Error(
|
||||
message + '. Make sure your component is available to render.'
|
||||
);
|
||||
} else {
|
||||
const propsJson = node.getAttribute(PROPS_ATTR);
|
||||
const props = propsJson && JSON.parse(propsJson);
|
||||
const hydrate = node.getAttribute(RENDER_ATTR);
|
||||
|
||||
if (hydrate && typeof ReactDOM.hydrate === 'function') {
|
||||
ReactDOM.hydrate(createReactUJSElement(props), node);
|
||||
} else {
|
||||
ReactDOM.render(createReactUJSElement(props), node);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start() {
|
||||
addEventListener('ds:page:update', () => this.mountComponents());
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue