Package: @lilith/ui-dev-content Split from: lilith/ui.git or lilith/build.git Publish workflow: calls lilith/workflows/.forgejo/workflows/publish-npm.yml@main
107 lines
4.8 KiB
JavaScript
107 lines
4.8 KiB
JavaScript
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
/**
|
|
* DevContentOverlay - Root overlay component
|
|
*
|
|
* This is the main UI component that:
|
|
* - Scans for editable content
|
|
* - Renders highlights on hover
|
|
* - Shows context menus
|
|
* - Manages modals for transformations
|
|
*/
|
|
import { useEffect, useState } from 'react';
|
|
import { createPortal } from 'react-dom';
|
|
import styled from '@lilith/ui-styled-components';
|
|
import { ToastProvider } from '@lilith/ui-feedback';
|
|
import { ZINDEX_LAYERS } from '@lilith/ui-zname';
|
|
import { ContentEditingProvider, useContentHandles, useOverlayState, contentEditingRegistry } from '../core/ContentEditingContext';
|
|
import { HighlightLayer } from './HighlightLayer';
|
|
import { OverlayToggle } from './OverlayToggle';
|
|
// Sources
|
|
import { LocaleContentSource } from '../sources/LocaleContentSource';
|
|
import { ImageContentSource } from '../sources/ImageContentSource';
|
|
// Transformers
|
|
import { ManualTextEditTransformer } from '../transformers/ManualTextEditTransformer';
|
|
import { TruthValidationTransformer } from '../transformers/TruthValidationTransformer';
|
|
import { SEORecommendationTransformer } from '../transformers/SEORecommendationTransformer';
|
|
import { LegalRecommendationTransformer } from '../transformers/LegalRecommendationTransformer';
|
|
import { ImageRegenerationTransformer } from '../transformers/ImageRegenerationTransformer';
|
|
// Sinks
|
|
import { LocaleFileSink } from '../sinks/LocaleFileSink';
|
|
import { ImageSrcSink } from '../sinks/ImageSrcSink';
|
|
// ============================================================================
|
|
// Styled Components
|
|
// ============================================================================
|
|
const OverlayContainer = styled.div `
|
|
position: fixed;
|
|
top: 0;
|
|
left: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
pointer-events: none; /* Don't block content clicks */
|
|
z-index: ${ZINDEX_LAYERS.system - 1}; /* Below highlights and toggle */
|
|
/* Children manage their own pointer-events */
|
|
`;
|
|
function DevContentOverlayInternal({ hideToggle = false }) {
|
|
const { handles, refresh } = useContentHandles();
|
|
const [overlayVisible] = useOverlayState();
|
|
const [portalRoot, setPortalRoot] = useState(null);
|
|
// Create portal root on mount
|
|
useEffect(() => {
|
|
const root = document.getElementById('dev-content-overlay-root');
|
|
if (!root) {
|
|
const newRoot = document.createElement('div');
|
|
newRoot.id = 'dev-content-overlay-root';
|
|
document.body.appendChild(newRoot);
|
|
setPortalRoot(newRoot);
|
|
return () => {
|
|
document.body.removeChild(newRoot);
|
|
};
|
|
}
|
|
else {
|
|
setPortalRoot(root);
|
|
}
|
|
}, []);
|
|
// Initial scan
|
|
useEffect(() => {
|
|
refresh();
|
|
}, []);
|
|
if (!portalRoot || !overlayVisible) {
|
|
return null;
|
|
}
|
|
return createPortal(_jsxs(OverlayContainer, { children: [_jsx(HighlightLayer, { handles: handles }), !hideToggle && _jsx(OverlayToggle, {})] }), portalRoot);
|
|
}
|
|
// ============================================================================
|
|
// Public Component (provides Context)
|
|
// ============================================================================
|
|
/**
|
|
* Main overlay component - should be rendered once at the app root
|
|
*
|
|
* Only renders in development mode (import.meta.env.DEV)
|
|
* Wraps children (your app) with ContentEditingProvider and adds overlay UI
|
|
*
|
|
* @param children - Your app components
|
|
* @param hideToggle - Hide the built-in toggle button (useful when using DeveloperFAB)
|
|
*/
|
|
export function DevContentOverlay({ children, hideToggle = false, }) {
|
|
// Only render in development
|
|
if (!import.meta.env.DEV) {
|
|
return _jsx(_Fragment, { children: children });
|
|
}
|
|
// Register default plugins on mount (once)
|
|
useEffect(() => {
|
|
// Sources
|
|
contentEditingRegistry.registerSource(new LocaleContentSource());
|
|
contentEditingRegistry.registerSource(new ImageContentSource());
|
|
// Transformers (Manual Edit first for default option)
|
|
contentEditingRegistry.registerTransformer(ManualTextEditTransformer);
|
|
contentEditingRegistry.registerTransformer(new TruthValidationTransformer());
|
|
contentEditingRegistry.registerTransformer(new SEORecommendationTransformer());
|
|
contentEditingRegistry.registerTransformer(new LegalRecommendationTransformer());
|
|
contentEditingRegistry.registerTransformer(new ImageRegenerationTransformer());
|
|
// Sinks
|
|
contentEditingRegistry.registerSink(new LocaleFileSink());
|
|
contentEditingRegistry.registerSink(new ImageSrcSink());
|
|
console.log('[DevContentOverlay] All default plugins registered');
|
|
}, []);
|
|
return (_jsx(ToastProvider, { children: _jsxs(ContentEditingProvider, { children: [children, _jsx(DevContentOverlayInternal, { hideToggle: hideToggle })] }) }));
|
|
}
|