UNPKG

@quixomatic/ui-renderer-react-simple

Version:

React 18 renderer for ServiceNow UI Framework with automatic setup and babel plugin patching

114 lines (94 loc) 2.81 kB
// React 18 renderer for ServiceNow UI Framework // Provides a drop-in replacement for @servicenow/ui-renderer-react // Compatible with React 18 hooks and features import React from 'react'; import ReactDOM from 'react-dom/client'; const noop = () => {}; // Helper function similar to @quixomatic/ui-internal const callAsync = (fn) => { if (fn) setTimeout(fn, 0); }; class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error) { const { element, helpers } = this.props; if (helpers && helpers.dispatch) { helpers.dispatch('COMPONENT_ERROR_THROWN', { error, location: 'VIEW', details: { boundaryError: true } }); } this.setState({ hasError: true }); console.error(`An Error occured in React component. COMPONENT_ERROR_THROWN action type is dispatched with error details.`, error); } render() { if (this.state.hasError) return null; return this.props.children; } } function onConnect(element, dispatch, next = noop) { callAsync(next); } // Store React roots on elements const REACT_ROOT_KEY = '__reactRoot18'; function onStateChange(element, Component, state = {}, helpers = {}) { // Create or reuse React 18 root if (!element[REACT_ROOT_KEY]) { element[REACT_ROOT_KEY] = ReactDOM.createRoot(element); } const root = element[REACT_ROOT_KEY]; // Clean the state object to remove any VNode structures const cleanState = {}; for (const key in state) { const value = state[key]; // Skip VNode objects (they have 'sel' property) if (value && typeof value === 'object' && 'sel' in value) { continue; } cleanState[key] = value; } // Pass the cleaned state object matching @quixomatic/ui-renderer-react format const componentProps = { ...cleanState, dispatch: helpers.dispatch || helpers, helpers: helpers, properties: cleanState.properties || {}, state: cleanState }; // Render using React 18 API root.render( React.createElement(ErrorBoundary, { helpers: helpers, element: element }, React.createElement(Component, componentProps) ) ); return root; } function onDisconnect(element, next = noop) { // Clean up React 18 root if (element[REACT_ROOT_KEY]) { element[REACT_ROOT_KEY].unmount(); delete element[REACT_ROOT_KEY]; } callAsync(next); } export const createElement = React.createElement; export const Fragment = React.Fragment; export const createRef = React.createRef; export { onConnect, onDisconnect, onStateChange }; // Match the export format of @quixomatic/ui-renderer-react and @servicenow/ui-renderer-react export default { Fragment: React.Fragment, createElement: React.createElement, createRef: React.createRef, onConnect, onDisconnect, onStateChange, deprioritizeStyles: true };