From 9fc3b8e6350aa66e509debd8c53b7b02acb505f6 Mon Sep 17 00:00:00 2001 From: Oscar Beaumont Date: Wed, 10 Jan 2024 17:40:18 +0800 Subject: [PATCH] Solid Iterop v2 (#1925) * portals all the way * CI for mobile JS * whoops * do install plz * Solid JSX on mobile * Cleanup portals + file structure * wip * reset explorer changes * fail * make it work betterer * cleanup * It's not a `useEffect` bug, no way * Fix `useSubscribeToThemeStore` --- .github/workflows/mobile-ci.yml | 21 ++++ apps/mobile/babel.config.js | 3 +- apps/mobile/package.json | 3 + interface/app/demo.react.tsx | 48 +++++++- interface/app/demo.solid.tsx | 37 +++++- interface/index.tsx | 21 ++-- packages/client/src/solid/context.tsx | 14 +-- .../{interop.ts => createPersistedMutable.ts} | 12 +- packages/client/src/solid/index.ts | 6 +- packages/client/src/solid/portals.tsx | 88 ++++++++++++++ packages/client/src/solid/react.tsx | 90 ++++++++++++-- packages/client/src/solid/solid.solid.tsx | 110 ++++++++++++------ packages/client/src/solid/useObserver.ts | 17 ++- packages/client/src/solid/useSolidStore.ts | 11 ++ .../src/solid/{rq.ts => useUniversalQuery.ts} | 0 packages/client/src/stores/themeStore.ts | 11 +- pnpm-lock.yaml | 51 ++++++-- 17 files changed, 443 insertions(+), 100 deletions(-) rename packages/client/src/solid/{interop.ts => createPersistedMutable.ts} (76%) create mode 100644 packages/client/src/solid/portals.tsx create mode 100644 packages/client/src/solid/useSolidStore.ts rename packages/client/src/solid/{rq.ts => useUniversalQuery.ts} (100%) diff --git a/.github/workflows/mobile-ci.yml b/.github/workflows/mobile-ci.yml index b8262e0c2..f355ab5b5 100644 --- a/.github/workflows/mobile-ci.yml +++ b/.github/workflows/mobile-ci.yml @@ -25,6 +25,27 @@ concurrency: cancel-in-progress: true jobs: + js: + name: JS + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v3 + + - name: Install Node.js + uses: actions/setup-node@v3 + with: + node-version: latest + + - uses: pnpm/action-setup@v2 + name: Install pnpm + with: + version: latest + run_install: true + + - name: Build mobile JS + run: pnpm mobile export + # Disabled until I can figure out why our app on x86_64 crashes on startup. # android: # name: Android diff --git a/apps/mobile/babel.config.js b/apps/mobile/babel.config.js index 123f8b03f..7f2ad4da0 100644 --- a/apps/mobile/babel.config.js +++ b/apps/mobile/babel.config.js @@ -23,6 +23,7 @@ module.exports = function (api) { } } ] - ] + ], + overrides: [{ test: /\.solid.tsx$/, presets: ['solid'] }] }; }; diff --git a/apps/mobile/package.json b/apps/mobile/package.json index a7c34ad69..88db05897 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -13,6 +13,7 @@ "android-studio": "open -a '/Applications/Android Studio.app' ./android", "lint": "eslint src --cache", "test": "cd ../.. && ./apps/mobile/scripts/run-maestro-tests ios", + "export": "expo export", "typecheck": "tsc -b" }, "dependencies": { @@ -30,6 +31,7 @@ "@sd/client": "workspace:*", "@shopify/flash-list": "1.4.3", "@tanstack/react-query": "^4.36.1", + "babel-preset-solid": "^1.8.9", "class-variance-authority": "^0.7.0", "dayjs": "^1.11.10", "event-target-polyfill": "^0.0.3", @@ -58,6 +60,7 @@ "react-native-screens": "~3.22.1", "react-native-svg": "14.1.0", "react-native-wheel-color-picker": "^1.2.0", + "solid-js": "^1.8.8", "twrnc": "^3.6.4", "use-count-up": "^3.0.1", "use-debounce": "^9.0.4", diff --git a/interface/app/demo.react.tsx b/interface/app/demo.react.tsx index 662229dca..01e3309c2 100644 --- a/interface/app/demo.react.tsx +++ b/interface/app/demo.react.tsx @@ -1,19 +1,19 @@ -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { WithSolid } from '@sd/client'; -import { Demo3, demoCtx } from './demo.solid'; +import { Demo3, demoCtx, SolidSquare } from './demo.solid'; export function Demo(props: { demo: string }) { const [count, setCount] = useState(0); - const ctx = demoCtx.useContext(); - console.log('FROM REACT 1', ctx()); return (
<> - +
Hello from React: {count}
{props.demo}
CTX: {ctx()}
@@ -22,16 +22,52 @@ export function Demo(props: { demo: string }) {
+
); } function Inner() { const ctx = demoCtx.useContext(); - console.log('FROM REACT 2', ctx()); return null; } export function Demo2() { return null; } + +export function ReactSquare(props: { x: number; y: number }) { + return ( +
+ ); +} + +export function SolidSquareManager() { + const [pos, setPos] = useState({ x: 75, y: 0, enabled: true }); + + useEffect(() => { + const interval = setInterval( + () => + setPos((p) => { + if (!p.enabled) return p; + if (p.x > window.innerWidth) return { x: 100, y: 0, enabled: true }; + if (p.y > window.innerHeight) return { x: 0, y: 0, enabled: true }; + return { x: p.x + 1, y: p.y + 1, enabled: true }; + }), + 10 + ); + return () => clearInterval(interval); + }); + + return ( + <> + + + + ); +} diff --git a/interface/app/demo.solid.tsx b/interface/app/demo.solid.tsx index af121795c..3cd200424 100644 --- a/interface/app/demo.solid.tsx +++ b/interface/app/demo.solid.tsx @@ -3,7 +3,7 @@ import { createSignal } from 'solid-js'; import { createSharedContext, WithReact } from '@sd/client'; -import { Demo as ReactDemo, Demo2 as ReactDemo2 } from './demo.react'; +import { Demo as ReactDemo, Demo2 as ReactDemo2, ReactSquare } from './demo.react'; export const demoCtx = createSharedContext('the ctx was not set'); @@ -23,16 +23,16 @@ export function Demo(props: { demo: string }) {
Hello from Solid: {count()}
CTX: {props.demo}
- + +
); } function Inner() { const ctx = demoCtx.useContext(); - console.log('FROM SOLID', ctx()); return
CTX: {ctx()}
; } @@ -50,3 +50,34 @@ export function Demo3(props: { demo: string }) { ); } + +export function SolidSquare(props: { x: number; y: number }) { + return ( +
+ ); +} + +export function ReactSquareManager() { + const [pos, setPos] = createSignal({ x: 100, y: 0, enabled: true }); + + setInterval(() => { + setPos((p) => { + if (!p.enabled) return p; + if (p.x > window.innerWidth) return { x: 100, y: 0, enabled: true }; + if (p.y > window.innerHeight) return { x: 0, y: 0, enabled: true }; + return { x: p.x + 1, y: p.y + 1, enabled: true }; + }); + }, 10); + + return ( + <> + + + + ); +} diff --git a/interface/index.tsx b/interface/index.tsx index c78c3f027..8e4121b87 100644 --- a/interface/index.tsx +++ b/interface/index.tsx @@ -7,6 +7,7 @@ import relativeTime from 'dayjs/plugin/relativeTime'; import { PropsWithChildren, Suspense } from 'react'; import { RouterProvider, RouterProviderProps } from 'react-router-dom'; import { + InteropProviderReact, P2PContextProvider, useBridgeSubscription, useInvalidateQuery, @@ -89,15 +90,17 @@ export function SpacedriveInterfaceRoot({ children }: PropsWithChildren) { return ( - - - - - - - {children} - - + + + + + + + + {children} + + + ); diff --git a/packages/client/src/solid/context.tsx b/packages/client/src/solid/context.tsx index 5bf51a5ec..8bd393864 100644 --- a/packages/client/src/solid/context.tsx +++ b/packages/client/src/solid/context.tsx @@ -2,7 +2,6 @@ import { createElement, createContext as createReactContext, isValidElement, - PropsWithChildren, JSX as ReactJSX, useEffect, useContext as useReactContext, @@ -11,7 +10,6 @@ import { import { children, createContext as createSolidContext, - getOwner, Owner, JSX as SolidJSX, useContext as useSolidContext @@ -109,16 +107,12 @@ export function useWithContextReact(): (elem: () => SolidJSX.Element) => SolidJS }); } -export function useWithContextSolid(): (elem: ReactJSX.Element) => ReactJSX.Element { - const owner = getOwner()!; - return (elem) => createElement(WithContext, { owner }, elem); -} - -function WithContext(props: PropsWithChildren<{ owner: Owner }>) { - const globalCtx = useObserverWithOwner(props.owner, () => { +export function withReactCtx(owner: Owner, elem: ReactJSX.Element) { + // eslint-disable-next-line react-hooks/rules-of-hooks + const globalCtx = useObserverWithOwner(owner, () => { // eslint-disable-next-line react-hooks/rules-of-hooks return useSolidContext(solidGlobalContext)(); }); - return createElement(reactGlobalContext.Provider, { value: globalCtx }, props.children); + return createElement(reactGlobalContext.Provider, { value: globalCtx }, elem); } diff --git a/packages/client/src/solid/interop.ts b/packages/client/src/solid/createPersistedMutable.ts similarity index 76% rename from packages/client/src/solid/interop.ts rename to packages/client/src/solid/createPersistedMutable.ts index f226e9d3f..68b5d4d33 100644 --- a/packages/client/src/solid/interop.ts +++ b/packages/client/src/solid/createPersistedMutable.ts @@ -1,16 +1,6 @@ import { trackDeep } from '@solid-primitives/deep'; import { createEffect, createRoot } from 'solid-js'; -import { type Store, type StoreNode } from 'solid-js/store'; - -import { useObserver } from './useObserver'; - -export function useSolidStore(store: Store) { - const state = useObserver(() => ({ ...store })); - return new Proxy(state, { - get: (target, prop) => Reflect.get(target, prop), - set: (_, prop, value) => Reflect.set(store, prop, value) - }); -} +import { type StoreNode } from 'solid-js/store'; type CreatePersistedMutableOpts = { onSave?: (value: T) => T; diff --git a/packages/client/src/solid/index.ts b/packages/client/src/solid/index.ts index 60f04f19a..dad153583 100644 --- a/packages/client/src/solid/index.ts +++ b/packages/client/src/solid/index.ts @@ -1,6 +1,8 @@ -export * from './interop'; +export * from './createPersistedMutable'; export * from './react'; export * from './solid.solid'; export * from './useObserver'; -export * from './rq'; +export * from './useUniversalQuery'; +export * from './useSolidStore'; +export { InteropProviderReact } from './portals'; export { createSharedContext } from './context'; diff --git a/packages/client/src/solid/portals.tsx b/packages/client/src/solid/portals.tsx new file mode 100644 index 000000000..ce050d0e2 --- /dev/null +++ b/packages/client/src/solid/portals.tsx @@ -0,0 +1,88 @@ +import { + createElement, + createContext as createReactContext, + Fragment, + PropsWithChildren, + ReactPortal, + useEffect, + useRef +} from 'react'; +import { + children, + createSignal, + createContext as createSolidContext, + For, + Setter, + JSX as SolidJSX, + type Accessor +} from 'solid-js'; +import { render } from 'solid-js/web'; + +import { useObserver } from './useObserver'; + +export type PortalCtx = { + setSolidPortals: Setter[]>; + setReactPortals: Setter[]>; +}; + +export type Portal = { + id: string; + portal: T; +}; + +export const solidPortalCtx = createSolidContext(undefined! as PortalCtx); +export const reactPortalCtx = createReactContext(undefined! as PortalCtx); + +// TODO: It would be pog to remove this +export function InteropProviderReact(props: PropsWithChildren) { + const state = useRef({ + solidPortals: createSignal([] as Portal[]), + reactPortals: createSignal([] as Portal[]), + // We only render portals in this so it's never rendered to the DOM + solidRoot: document.createElement('div'), + didFireFirstRender: false + }); + + useEffect(() => { + // This is to avoid double-rendering SolidJS when used in `React.StrictMode`. + if (!state.current.didFireFirstRender) { + state.current.didFireFirstRender = true; + return; + } + + let cleanup = () => {}; + cleanup = render( + () => + For({ + get each() { + return state.current.solidPortals[0](); + }, + children: (p) => children(() => p.portal) as any + }), + state.current.solidRoot + ); + return cleanup; + }, []); + + const value: PortalCtx = { + setSolidPortals: state.current.solidPortals[1], + setReactPortals: state.current.reactPortals[1] + }; + const portals = createElement(RenderPortals, { portals: state.current.reactPortals[0] }); + return createElement( + reactPortalCtx.Provider, + { + value + }, + props.children, + portals + ); +} + +function RenderPortals(props: { portals: Accessor[]> }) { + const portals = useObserver(() => props.portals()); + return portals.map((p) => createElement(Fragment, { key: p.id }, p.portal)); +} + +// TODO: Right now we have React as our app's root so we don't need this but it would be the opposite of `InteropProviderReact` +// export function InteropProviderSolid(props: ParentProps) {} diff --git a/packages/client/src/solid/react.tsx b/packages/client/src/solid/react.tsx index 932bb66b4..708ade712 100644 --- a/packages/client/src/solid/react.tsx +++ b/packages/client/src/solid/react.tsx @@ -1,8 +1,19 @@ -import { useEffect, useRef } from 'react'; -import { JSX as SolidJSX } from 'solid-js'; -import { render } from 'solid-js/web'; +import { + createElement, + Fragment, + ReactPortal, + useEffect, + useId, + useContext as useReactContext, + useRef +} from 'react'; +import { Accessor, createSignal, JSX as SolidJSX } from 'solid-js'; +import { createStore } from 'solid-js/store'; +import { Portal as SolidPortal } from 'solid-js/web'; import { useWithContextReact } from './context'; +import { reactPortalCtx, solidPortalCtx, type Portal } from './portals'; +import { useObserver } from './useObserver'; type Props = | ({ @@ -13,18 +24,73 @@ type Props = }; export function WithSolid(props: Props) { + const portalCtx = useReactContext(reactPortalCtx); + if (!portalCtx) throw new Error('Missing portalCtx in WithSolid'); + + const id = useId(); const ref = useRef(null); + const state = useRef({ + hasFirstRender: false, + trackedProps: createStore(props), + reactPortals: createSignal([] as Portal[]) + }); + const applyCtx = useWithContextReact(); useEffect(() => { - let cleanup = () => {}; - if (ref.current) - cleanup = render(() => { - const { root, ...childProps } = props; - return applyCtx(() => root(childProps as any)); - }, ref.current); - return cleanup; - }, [props, applyCtx]); + state.current.trackedProps[1](props); + }, [props]); - return
; + useEffect(() => { + if (!ref.current) return; + + const hasFirstRender = state.current.hasFirstRender; + if (!hasFirstRender) { + state.current.hasFirstRender = true; + return; + } + + portalCtx.setSolidPortals((portals) => [ + ...portals, + { + id, + portal: (() => { + return SolidPortal({ + mount: ref.current!, + get children() { + return solidPortalCtx.Provider({ + value: { + setSolidPortals: portalCtx.setSolidPortals, + setReactPortals: state.current.reactPortals[1] + }, + get children() { + return applyCtx(() => + props.root(state.current.trackedProps[0] as T) + ); + } + }); + } + }); + }) as any + } + ]); + + return () => { + if (!hasFirstRender) return; + portalCtx.setSolidPortals((portals) => portals.filter((p) => p.id !== id)); + }; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); // TODO: props.root + + return ( + <> +
+ + + ); +} + +function RenderPortals(props: { portals: Accessor[]> }) { + const portals = useObserver(() => props.portals()); + return portals.map((p) => createElement(Fragment, { key: p.id }, p.portal)); } diff --git a/packages/client/src/solid/solid.solid.tsx b/packages/client/src/solid/solid.solid.tsx index dadd833d3..4e0f385ca 100644 --- a/packages/client/src/solid/solid.solid.tsx +++ b/packages/client/src/solid/solid.solid.tsx @@ -2,10 +2,30 @@ import { trackDeep } from '@solid-primitives/deep'; import { createElement, StrictMode, type FunctionComponent } from 'react'; -import ReactDOM from 'react-dom/client'; -import { createEffect, onCleanup, splitProps } from 'solid-js'; +import { createPortal } from 'react-dom'; +import { + children, + createSignal, + createUniqueId, + For, + getOwner, + onCleanup, + onMount, + Owner, + splitProps, + useContext as useSolidContext, + type JSX as SolidJSX +} from 'solid-js'; -import { useWithContextSolid } from './context'; +import { withReactCtx as withReactContextProvider } from './context'; +import { Portal, reactPortalCtx, solidPortalCtx } from './portals'; +import { useObserverWithOwner } from './useObserver'; + +type AllowReactiveScope = T extends object + ? { + [P in keyof T]: AllowReactiveScope; + } + : T | (() => T); type Props = | { @@ -13,47 +33,71 @@ type Props = } | ({ root: FunctionComponent; - } & T); + } & AllowReactiveScope); export function WithReact(props: Props) { + const portalCtx = useSolidContext(solidPortalCtx); + if (!portalCtx) throw new Error('Missing portalCtx in WithReact'); + + const [solidPortals, setSolidPortals] = createSignal([] as Portal[]); + const id = createUniqueId(); let ref: HTMLDivElement | undefined; - let root: ReactDOM.Root | undefined; - let cleanup: (() => void) | undefined = undefined; - const applyCtx = useWithContextSolid(); - const [_, childProps] = splitProps(props, ['root']); - - // TODO: Inject all context's - const render = (childProps: any) => { + onMount(() => { if (!ref) return; - if (!root) { - root = ReactDOM.createRoot(ref); - // The `setTimeout` is to ensure React has time to do the intial render. - // React doesn't like when you unmount it while it's rendering. - cleanup = () => { - setTimeout(() => root?.unmount()); - root = undefined; - }; - } - root.render( + const elem = createElement( + StrictMode, + null, createElement( - StrictMode, - null, - applyCtx(createElement(props.root as any, childProps, null)) + reactPortalCtx.Provider, + { + value: { + setReactPortals: portalCtx.setReactPortals, + setSolidPortals: setSolidPortals + } + }, + createElement( + Wrapper, + { + root: props.root as any, + owner: getOwner()!, + childProps: () => splitProps(props, ['root'])[1] + }, + null + ) ) ); - }; - createEffect(() => { - const trackedProps = trackDeep(childProps); - render({ ...trackedProps }); + const portal = createPortal(elem, ref); + portalCtx.setReactPortals((portals) => [ + ...portals, + { + id, + portal + } + ]); }); - onCleanup(() => { - cleanup?.(); - cleanup = undefined; - }); + onCleanup(() => portalCtx.setReactPortals((portals) => portals.filter((p) => p.id !== id))); - return
; + return ( + <> +
+ {(p) => children(() => p.portal) as any} + + ); +} + +function Wrapper(props: { + root: FunctionComponent; + owner: Owner; + childProps: () => T; +}) { + // This is a React component SolidJS reactivity don't matter. + + // eslint-disable-next-line solid/reactivity + const childProps = useObserverWithOwner(props.owner, () => trackDeep(props.childProps())); + // eslint-disable-next-line solid/reactivity + return withReactContextProvider(props.owner, createElement(props.root, childProps, null)); } diff --git a/packages/client/src/solid/useObserver.ts b/packages/client/src/solid/useObserver.ts index 01bb4d2d9..056ac71bf 100644 --- a/packages/client/src/solid/useObserver.ts +++ b/packages/client/src/solid/useObserver.ts @@ -8,9 +8,12 @@ import { createReaction, createRoot, Owner, runWithOwner } from 'solid-js'; export function useObserver(fn: () => T) { const [_, setTick] = useState(0); const state = useRef({ - onUpdate: () => {}, + onUpdate: () => { + state.current.firedDuringRender = true; + }, // An really ugly workaround for React `StrictMode`'s double firing of `useEffect`. - doneFirstFire: false + doneFirstFire: false, + firedDuringRender: false }); const reaction = useRef<{ dispose: () => void; track: (fn: () => void) => void }>(); if (!reaction.current) { @@ -21,12 +24,20 @@ export function useObserver(fn: () => T) { } useEffect(() => { + if (state.current.firedDuringRender) setTick((t) => t + 1); + // We set this after a `useEffect` to ensure we don't trigger an update prior to mount // cause that makes React madge. - state.current.onUpdate = () => setTick((t) => t + 1); + state.current.onUpdate = () => { + setTick((t) => t + 1); + }; state.current.doneFirstFire = true; return () => { + state.current.onUpdate = () => { + state.current.firedDuringRender = true; + }; + if (!state.current.doneFirstFire) { reaction.current?.dispose(); reaction.current = undefined; diff --git a/packages/client/src/solid/useSolidStore.ts b/packages/client/src/solid/useSolidStore.ts new file mode 100644 index 000000000..20c3d1170 --- /dev/null +++ b/packages/client/src/solid/useSolidStore.ts @@ -0,0 +1,11 @@ +import { Store } from 'solid-js/store'; + +import { useObserver } from './useObserver'; + +export function useSolidStore(store: Store) { + const state = useObserver(() => ({ ...store })); + return new Proxy(state, { + get: (target, prop) => Reflect.get(target, prop), + set: (_, prop, value) => Reflect.set(store, prop, value) + }); +} diff --git a/packages/client/src/solid/rq.ts b/packages/client/src/solid/useUniversalQuery.ts similarity index 100% rename from packages/client/src/solid/rq.ts rename to packages/client/src/solid/useUniversalQuery.ts diff --git a/packages/client/src/stores/themeStore.ts b/packages/client/src/stores/themeStore.ts index 963261e8e..4e9e3289e 100644 --- a/packages/client/src/stores/themeStore.ts +++ b/packages/client/src/stores/themeStore.ts @@ -1,3 +1,5 @@ +import { deepEqual } from 'fast-equals'; +import { useRef } from 'react'; import { createMutable } from 'solid-js/store'; import { createPersistedMutable, useObserver, useSolidStore } from '../solid'; @@ -18,11 +20,16 @@ export function useThemeStore() { } export function useSubscribeToThemeStore(callback: () => void) { + const ref = useRef(themeStore); useObserver(() => { // Subscribe to store - const _ = { ...themeStore }; + const store = { ...themeStore }; - callback(); + // Only trigger React if it did in fact change. + if (!deepEqual(store, ref.current)) { + ref.current = store; + callback(); + } }); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 733dbedfd..cf1ad45c1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -358,6 +358,9 @@ importers: '@tanstack/react-query': specifier: ^4.36.1 version: 4.36.1(react-dom@18.2.0)(react-native@0.72.6)(react@18.2.0) + babel-preset-solid: + specifier: ^1.8.9 + version: 1.8.9(@babel/core@7.23.2) class-variance-authority: specifier: ^0.7.0 version: 0.7.0 @@ -442,6 +445,9 @@ importers: react-native-wheel-color-picker: specifier: ^1.2.0 version: 1.2.0 + solid-js: + specifier: ^1.8.8 + version: 1.8.8 twrnc: specifier: ^3.6.4 version: 3.6.4(react-native@0.72.6) @@ -1678,7 +1684,6 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.6 - dev: true /@babel/helper-module-imports@7.22.15: resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} @@ -2427,6 +2432,16 @@ packages: '@babel/core': 7.23.7 '@babel/helper-plugin-utils': 7.22.5 + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.2): + resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-plugin-utils': 7.22.5 + dev: false + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.7): resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} engines: {node: '>=6.9.0'} @@ -6658,7 +6673,7 @@ packages: magic-string: 0.27.0 react-docgen-typescript: 2.2.2(typescript@5.3.3) typescript: 5.3.3 - vite: 5.0.10(@types/node@18.17.19) + vite: 5.0.10(less@4.2.0) /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} @@ -9939,7 +9954,7 @@ packages: magic-string: 0.30.5 rollup: 3.29.4 typescript: 5.3.3 - vite: 5.0.10(@types/node@18.17.19) + vite: 5.0.10(less@4.2.0) transitivePeerDependencies: - encoding - supports-color @@ -10292,7 +10307,7 @@ packages: react: 18.2.0 react-docgen: 6.0.4 react-dom: 18.2.0(react@18.2.0) - vite: 5.0.10(@types/node@18.17.19) + vite: 5.0.10(less@4.2.0) transitivePeerDependencies: - '@preact/preset-vite' - encoding @@ -11694,7 +11709,7 @@ packages: '@babel/plugin-transform-react-jsx-source': 7.22.5(@babel/core@7.23.2) magic-string: 0.27.0 react-refresh: 0.14.0 - vite: 5.0.10(@types/node@18.17.19) + vite: 5.0.10(less@4.2.0) transitivePeerDependencies: - supports-color @@ -12366,6 +12381,19 @@ packages: validate-html-nesting: 1.2.2 dev: true + /babel-plugin-jsx-dom-expressions@0.37.13(@babel/core@7.23.2): + resolution: {integrity: sha512-oAEMMIgU0h1DmHn4ZDaBBFc08nsVJciLq9pF7g0ZdpeIDKfY4zXjXr8+/oBjKhXG8nyomhnTodPjeG+/ZXcWXQ==} + peerDependencies: + '@babel/core': ^7.20.12 + dependencies: + '@babel/core': 7.23.2 + '@babel/helper-module-imports': 7.18.6 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.2) + '@babel/types': 7.23.6 + html-entities: 2.3.3 + validate-html-nesting: 1.2.2 + dev: false + /babel-plugin-module-resolver@5.0.0: resolution: {integrity: sha512-g0u+/ChLSJ5+PzYwLwP8Rp8Rcfowz58TJNCe+L/ui4rpzE/mg//JVX0EWBUYoxaextqnwuGHzfGp2hh0PPV25Q==} engines: {node: '>= 16'} @@ -12589,6 +12617,15 @@ packages: babel-plugin-jsx-dom-expressions: 0.37.11(@babel/core@7.23.7) dev: true + /babel-preset-solid@1.8.9(@babel/core@7.23.2): + resolution: {integrity: sha512-1awR1QCoryXtAdnjsrx/eVBTYz+tpHUDOdBXqG9oVV7S0ojf2MV/woR0+8BG+LMXVzIr60oKYzCZ9UZGafxmpg==} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.2 + babel-plugin-jsx-dom-expressions: 0.37.13(@babel/core@7.23.2) + dev: false + /bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} dev: false @@ -16544,7 +16581,6 @@ packages: /html-entities@2.3.3: resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==} - dev: true /html-minifier-terser@6.1.0: resolution: {integrity: sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==} @@ -24519,7 +24555,6 @@ packages: /validate-html-nesting@1.2.2: resolution: {integrity: sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==} - dev: true /validate-npm-package-license@3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} @@ -24788,6 +24823,7 @@ packages: rollup: 4.9.2 optionalDependencies: fsevents: 2.3.3 + dev: true /vite@5.0.10(less@4.2.0): resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==} @@ -24823,7 +24859,6 @@ packages: rollup: 4.9.2 optionalDependencies: fsevents: 2.3.3 - dev: true /vite@5.0.10(sass@1.69.5): resolution: {integrity: sha512-2P8J7WWgmc355HUMlFrwofacvr98DAjoE52BfdbwQtyLH06XKwaL/FMnmKM2crF0iX4MpmMKoDlNCB1ok7zHCw==}