diff --git a/examples/rollup.config.mjs b/examples/rollup.config.mjs index eead0c2b883..9fe2c1c503c 100644 --- a/examples/rollup.config.mjs +++ b/examples/rollup.config.mjs @@ -261,6 +261,17 @@ const APP_TARGETS = [{ format: 'umd' }, treeshake: 'smallest', + onwarn(warning, warn) { + // Suppress "use client" directive warnings from react-router v7+. + // These directives are for React Server Components which we don't use. + // The directive is safely ignored and has no effect on client-only builds. + // This can be removed if Rollup adds native support for "use client" directives, + // or if we switch to a bundler that supports them (e.g., Vite, webpack 5+). + if (warning.code === 'MODULE_LEVEL_DIRECTIVE' && warning.message.includes('"use client"')) { + return; + } + warn(warning); + }, plugins: [ commonjs(), treeshakeIgnore([/@playcanvas\/pcui/g]), // ignore PCUI treeshake diff --git a/examples/src/app/components/ErrorBoundary.mjs b/examples/src/app/components/ErrorBoundary.mjs index de63e82c77a..4a7221b3e2f 100644 --- a/examples/src/app/components/ErrorBoundary.mjs +++ b/examples/src/app/components/ErrorBoundary.mjs @@ -1,7 +1,7 @@ import { Label } from '@playcanvas/pcui/react'; import { Component } from 'react'; -import { fragment, jsx } from '../jsx.mjs'; +import { jsx } from '../jsx.mjs'; /** @@ -83,12 +83,10 @@ class ErrorBoundary extends TypedComponent { render() { if (this.state.hasError) { - return fragment( - jsx(Label, { - id: 'errorLabel', - text: 'RENDER FAILED' - }) - ); + return jsx(Label, { + id: 'errorLabel', + text: 'RENDER FAILED' + }); } return this.props.children; } diff --git a/examples/src/app/components/Example.mjs b/examples/src/app/components/Example.mjs index 4bf70d15d32..7b00f551a98 100644 --- a/examples/src/app/components/Example.mjs +++ b/examples/src/app/components/Example.mjs @@ -309,7 +309,9 @@ class Example extends TypedComponent { renderPortrait() { const { collapsed, show, files, description } = this.state; - return fragment( + return jsx( + 'div', + { style: { display: 'contents' } }, jsx( Panel, { @@ -370,7 +372,9 @@ class Example extends TypedComponent { renderLandscape() { const { collapsed } = this.state; - return fragment( + return jsx( + 'div', + { style: { display: 'contents' } }, jsx( Panel, { diff --git a/examples/src/app/components/MainLayout.mjs b/examples/src/app/components/MainLayout.mjs index 901ae750cfe..d9b867c1d9a 100644 --- a/examples/src/app/components/MainLayout.mjs +++ b/examples/src/app/components/MainLayout.mjs @@ -7,7 +7,7 @@ import { Example } from './Example.mjs'; import { Menu } from './Menu.mjs'; import { SideBar } from './Sidebar.mjs'; import { iframe } from '../iframe.mjs'; -import { jsx, fragment } from '../jsx.mjs'; +import { jsx } from '../jsx.mjs'; import { getOrientation } from '../utils.mjs'; // eslint-disable-next-line jsdoc/require-property @@ -75,7 +75,9 @@ class MainLayout extends TypedComponent { }), jsx(Route, { path: '/:category/:example', - element: fragment( + element: jsx( + 'div', + { id: 'appInner-router', style: { display: 'contents' } }, jsx(SideBar, null), jsx( Container, diff --git a/examples/src/app/components/Sidebar.mjs b/examples/src/app/components/Sidebar.mjs index 6ed11464ffd..632fd479d44 100644 --- a/examples/src/app/components/Sidebar.mjs +++ b/examples/src/app/components/Sidebar.mjs @@ -1,7 +1,7 @@ import { Observer } from '@playcanvas/observer'; import { BindingTwoWay, BooleanInput, Container, Label, LabelGroup, Panel, TextInput } from '@playcanvas/pcui/react'; import { Component } from 'react'; -import { Link } from 'react-router-dom'; +import { Link, useLocation } from 'react-router-dom'; import { exampleMetaData } from '../../../cache/metadata.mjs'; import { MIN_DESKTOP_WIDTH, VERSION } from '../constants.mjs'; @@ -10,16 +10,15 @@ import { jsx } from '../jsx.mjs'; import { thumbnailPath } from '../paths.mjs'; import { getOrientation } from '../utils.mjs'; -// eslint-disable-next-line jsdoc/require-property /** * @typedef {object} Props + * @property {{ pathname: string, hash: string }} location - The router location. */ /** * @typedef {object} State * @property {Record>} defaultCategories - The default categories. * @property {Record>|null} filteredCategories - The filtered categories. - * @property {string} hash - The hash. * @property {Observer} observer - The observer. * @property {boolean} collapsed - Collapsed or not. * @property {string} orientation - Current orientation. @@ -52,7 +51,6 @@ class SideBar extends TypedComponent { state = { defaultCategories: getDefaultExampleFiles(), filteredCategories: null, - hash: location.hash, observer: new Observer({ largeThumbnails: false }), // @ts-ignore collapsed: localStorage.getItem('sideBarCollapsed') === 'true' || window.top.innerWidth < MIN_DESKTOP_WIDTH, @@ -99,9 +97,6 @@ class SideBar extends TypedComponent { if (!sideBar) { return; } - window.addEventListener('hashchange', () => { - this.mergeState({ hash: location.hash }); - }); this.state.observer.on('largeThumbnails:set', () => { let minTopNavItemDistance = Number.MAX_VALUE; @@ -207,7 +202,7 @@ class SideBar extends TypedComponent { if (Object.keys(categories).length === 0) { return jsx(Label, { text: 'No results' }); } - const { hash } = this.state; + const { pathname } = this.props.location; return Object.keys(categories) .sort((a, b) => (a > b ? 1 : -1)) .map((category) => { @@ -229,7 +224,7 @@ class SideBar extends TypedComponent { .sort((a, b) => (a > b ? 1 : -1)) .map((example) => { const path = `/${category}/${example}`; - const isSelected = new RegExp(`${path}$`).test(hash); + const isSelected = pathname === path; const className = `nav-item ${isSelected ? 'selected' : null}`; return jsx( Link, @@ -303,4 +298,13 @@ class SideBar extends TypedComponent { } } -export { SideBar }; +/** + * Wrapper component to provide router location to the class component. + * @returns {JSX.Element} The SideBar component with router location. + */ +function SideBarWithRouter() { + const location = useLocation(); + return jsx(SideBar, { location }); +} + +export { SideBarWithRouter as SideBar };