Finished task 1. Added task for backwards compatibility on existing Noodl projects

This commit is contained in:
Richard Osborne
2025-12-06 23:24:55 +01:00
parent 9a5952ec13
commit 2153baf627
14 changed files with 1147 additions and 84 deletions

View File

@@ -40,7 +40,7 @@ export function SideNavigationButton({
menuItems
}: SideNavigationButtonProps) {
const context = useSideNavigationContext();
const iconRef = useRef();
const iconRef = useRef<HTMLDivElement>(null);
const hasMenu = Boolean(menuItems);
const [isMenuVisible, setIsMenuVisible] = useState(false);

View File

@@ -104,10 +104,7 @@ export function Columns({
flexGrow: 0
}}
>
{
// @ts-expect-error
React.cloneElement(child)
}
{React.cloneElement(child)}
</div>
);
})}

View File

@@ -36,7 +36,7 @@ export function ContextMenu({
renderDirection
}: ContextMenuProps) {
const [isContextMenuVisible, setIsContextMenuVisible] = useState(false);
const toggleRef = useRef();
const toggleRef = useRef<HTMLDivElement>(null);
useEffect(() => {
if (isContextMenuVisible) {

View File

@@ -1,4 +1,4 @@
import React, { useRef, useState, useEffect } from 'react';
import React, { useRef, useState, useEffect, isValidElement } from 'react';
import { ForEachComponent } from '../../../nodes/std-library/data/foreach';
import { Noodl, Slot } from '../../../types';
@@ -110,18 +110,21 @@ export function Columns(props: ColumnsProps) {
props.marginX
);
let children = [];
let forEachComponent = null;
let children: React.ReactElement[] = [];
let forEachComponent: React.ReactElement | null = null;
// ForEachCompoent breaks the layout but is needed to send onMount/onUnmount
if (!Array.isArray(props.children)) {
// @ts-expect-error props.children.type is any
if (props.children.type !== ForEachComponent) {
if (isValidElement(props.children) && props.children.type !== ForEachComponent) {
children = [props.children]
}
} else {
children = props.children.filter((child) => child.type !== ForEachComponent);
forEachComponent = props.children.find((child) => child.type === ForEachComponent);
children = props.children.filter((child): child is React.ReactElement =>
isValidElement(child) && child.type !== ForEachComponent
);
forEachComponent = props.children.find((child): child is React.ReactElement =>
isValidElement(child) && child.type === ForEachComponent
) || null;
}
return (

View File

@@ -22,6 +22,8 @@ export interface DragProps extends Noodl.ReactProps {
positionY?: (value: number) => void;
deltaX?: (value: number) => void;
deltaY?: (value: number) => void;
children?: React.ReactNode;
}
function setDragValues(event, props) {

View File

@@ -2,7 +2,6 @@ import BScroll from '@better-scroll/core';
import MouseWheel from '@better-scroll/mouse-wheel';
import ScrollBar from '@better-scroll/scroll-bar';
import React from 'react';
import ReactDOM from 'react-dom';
import Layout from '../../../layout';
import PointerListeners from '../../../pointerlisteners';
@@ -17,7 +16,7 @@ BScroll.use(MouseWheel);
BScroll.use(Slide);
export interface GroupProps extends Noodl.ReactProps {
as?: keyof JSX.IntrinsicElements | React.ComponentType<unknown>;
as?: keyof React.JSX.IntrinsicElements | React.ComponentType<unknown>;
scrollSnapEnabled: boolean;
showScrollbar: boolean;
@@ -34,6 +33,8 @@ export interface GroupProps extends Noodl.ReactProps {
onScrollPositionChanged?: (value: number) => void;
onScrollStart?: () => void;
onScrollEnd?: () => void;
children?: React.ReactNode;
}
type ScrollRef = HTMLDivElement & { noodlNode?: Noodl.ReactProps['noodlNode'] };
@@ -97,8 +98,11 @@ export class Group extends React.Component<GroupProps> {
scrollToElement(noodlChild, duration) {
if (!noodlChild) return;
// eslint-disable-next-line react/no-find-dom-node
const element = ReactDOM.findDOMNode(noodlChild.getRef()) as HTMLElement;
// Get the ref - in React 19, we need to access the DOM element directly
// rather than using the deprecated findDOMNode
const ref = noodlChild.getRef();
// The ref might be a DOM element directly, or a ref object with a current property
const element = (ref instanceof HTMLElement ? ref : ref?.current) as HTMLElement | null;
if (element && element.scrollIntoView) {
if (this.iScroll) {
this.iScroll.scrollToElement(element, duration, 0, 0);

View File

@@ -5,7 +5,7 @@ import PointerListeners from '../../../pointerlisteners';
import { Noodl } from '../../../types';
export interface TextProps extends Noodl.ReactProps {
as?: keyof JSX.IntrinsicElements | React.ComponentType<unknown>;
as?: keyof React.JSX.IntrinsicElements | React.ComponentType<unknown>;
textStyle: Noodl.TextStyle;
text: string;
@@ -21,7 +21,7 @@ export interface TextProps extends Noodl.ReactProps {
}
export function Text(props: TextProps) {
const { as: Component = 'div' } = props;
const Component = props.as || 'div';
const style = {
...props.textStyle,

View File

@@ -1,4 +1,4 @@
import React, { ReactElement, ReactFragment, ReactPortal } from 'react';
import React, { ReactElement, ReactPortal } from 'react';
import type { NodeConstructor } from '../typings/global';
@@ -33,6 +33,6 @@ export namespace Noodl {
}
}
export type SingleSlot = ReactElement<unknown> | ReactFragment | ReactPortal | boolean | null | undefined;
export type SingleSlot = ReactElement<unknown> | Iterable<React.ReactNode> | ReactPortal | boolean | null | undefined;
export type Slot = SingleSlot | SingleSlot[];