mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 06:56:20 +00:00
React 19 modernization: forwardRef removal, Compiler, ErrorBoundary, Suspense, native <script>
Adopt React 19 idioms across the codebase. The runtime was already on
react@19.2.5 but no React 19 APIs were in use.
- forwardRef -> ref-as-prop in 7 layout/component files
(NitroInput/Button/ItemCountBadge/Card×5/InfiniteGridItem,
ToolbarItemView, AvatarEditorIcon)
- <Ctx.Provider> -> <Ctx> in 6 contexts (CatalogAdmin, FloorplanEditor,
UiSettings, GridContext, NitroCardContext, NitroCardAccordionContext)
- Native <script> hoisting for Turnstile, ExternalPluginLoader, GoogleAdsView
(React 19 dedupes by src; removes manual document.head.appendChild +
module-level promise caches)
- React Compiler enabled at build time via babel-plugin-react-compiler
in vite.config.mjs (target: '19'), plus eslint-plugin-react-compiler
in lint mode
- Global <ErrorBoundary> + <Suspense> in src/index.tsx using
react-error-boundary, with LoadingView as fallback
- BackgroundsView migrated to use(promise) as a demonstrator pattern
for Suspense-driven config loading
- ESLint react setting bumped 18.3.1 -> 19.2; legacy
@typescript-eslint/ban-types replaced with no-restricted-types
(the old rule was removed in @typescript-eslint v8)
- Refresh public/configuration/{asset-loader,bootstrap}.js to match
current write-asset-loader.mjs output
Phase 3 (login forms -> useActionState/useFormStatus) deferred:
LoginView is 1623 lines with lockout + Turnstile + heartbeat
interleaving; safer as its own PR.
https://claude.ai/code/session_01GrR87LAqnAEyKG2ZbmQt5Q
This commit is contained in:
+11
-13
@@ -1,6 +1,7 @@
|
|||||||
import typescriptEslintPlugin from "@typescript-eslint/eslint-plugin";
|
import typescriptEslintPlugin from "@typescript-eslint/eslint-plugin";
|
||||||
import typescriptEslintParser from "@typescript-eslint/parser";
|
import typescriptEslintParser from "@typescript-eslint/parser";
|
||||||
import reactPlugin from "eslint-plugin-react";
|
import reactPlugin from "eslint-plugin-react";
|
||||||
|
import reactCompilerPlugin from "eslint-plugin-react-compiler";
|
||||||
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
import reactHooksPlugin from "eslint-plugin-react-hooks";
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import { fileURLToPath } from "url";
|
import { fileURLToPath } from "url";
|
||||||
@@ -14,6 +15,7 @@ export default [
|
|||||||
plugins: {
|
plugins: {
|
||||||
react: reactPlugin,
|
react: reactPlugin,
|
||||||
"react-hooks": reactHooksPlugin,
|
"react-hooks": reactHooksPlugin,
|
||||||
|
"react-compiler": reactCompilerPlugin,
|
||||||
"@typescript-eslint": typescriptEslintPlugin,
|
"@typescript-eslint": typescriptEslintPlugin,
|
||||||
},
|
},
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
@@ -110,28 +112,24 @@ export default [
|
|||||||
'@typescript-eslint/no-unused-vars': [
|
'@typescript-eslint/no-unused-vars': [
|
||||||
'off'
|
'off'
|
||||||
],
|
],
|
||||||
'@typescript-eslint/ban-types': [
|
'@typescript-eslint/no-restricted-types': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
'types':
|
'types':
|
||||||
{
|
{
|
||||||
'String': true,
|
'String': { message: 'Use string instead', fixWith: 'string' },
|
||||||
'Boolean': true,
|
'Boolean': { message: 'Use boolean instead', fixWith: 'boolean' },
|
||||||
'Number': true,
|
'Number': { message: 'Use number instead', fixWith: 'number' },
|
||||||
'Symbol': true,
|
'Symbol': { message: 'Use symbol instead', fixWith: 'symbol' }
|
||||||
'{}': false,
|
}
|
||||||
'Object': false,
|
|
||||||
'object': false,
|
|
||||||
'Function': false
|
|
||||||
},
|
|
||||||
'extendDefaults': true
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'react/react-in-jsx-scope': 'off'
|
'react/react-in-jsx-scope': 'off',
|
||||||
|
'react-compiler/react-compiler': 'warn'
|
||||||
},
|
},
|
||||||
settings: {
|
settings: {
|
||||||
react: {
|
react: {
|
||||||
version: "18.3.1",
|
version: "19.2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -23,6 +23,7 @@
|
|||||||
"framer-motion": "^12.38.0",
|
"framer-motion": "^12.38.0",
|
||||||
"react": "^19.2.5",
|
"react": "^19.2.5",
|
||||||
"react-dom": "^19.2.5",
|
"react-dom": "^19.2.5",
|
||||||
|
"react-error-boundary": "^6.1.1",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-player": "^2.16.0",
|
"react-player": "^2.16.0",
|
||||||
"use-between": "^1.4.0"
|
"use-between": "^1.4.0"
|
||||||
@@ -36,8 +37,10 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
"@typescript-eslint/eslint-plugin": "^8.59.1",
|
||||||
"@typescript-eslint/parser": "^8.59.1",
|
"@typescript-eslint/parser": "^8.59.1",
|
||||||
"@vitejs/plugin-react": "^6.0.1",
|
"@vitejs/plugin-react": "^6.0.1",
|
||||||
|
"babel-plugin-react-compiler": "^1.0.0",
|
||||||
"eslint": "^10.2.1",
|
"eslint": "^10.2.1",
|
||||||
"eslint-plugin-react": "^7.37.5",
|
"eslint-plugin-react": "^7.37.5",
|
||||||
|
"eslint-plugin-react-compiler": "19.1.0-rc.2",
|
||||||
"eslint-plugin-react-hooks": "^7.1.1",
|
"eslint-plugin-react-hooks": "^7.1.1",
|
||||||
"postcss": "^8.5.12",
|
"postcss": "^8.5.12",
|
||||||
"postcss-nested": "^7.0.2",
|
"postcss-nested": "^7.0.2",
|
||||||
|
|||||||
@@ -44,6 +44,11 @@
|
|||||||
return new URL(".", source);
|
return new URL(".", source);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getDeployBase = () => {
|
||||||
|
try { return new URL("..", getBase()); }
|
||||||
|
catch { return new URL("/", location.href); }
|
||||||
|
};
|
||||||
|
|
||||||
const withCacheBust = (url) => {
|
const withCacheBust = (url) => {
|
||||||
url.searchParams.set("v", Date.now().toString(36));
|
url.searchParams.set("v", Date.now().toString(36));
|
||||||
return url;
|
return url;
|
||||||
@@ -71,9 +76,14 @@
|
|||||||
|
|
||||||
const resolveAssetCandidates = (path) => {
|
const resolveAssetCandidates = (path) => {
|
||||||
const base = getBase();
|
const base = getBase();
|
||||||
|
const deploy = getDeployBase();
|
||||||
const normalized = path.replace(/^\.\//, "");
|
const normalized = path.replace(/^\.\//, "");
|
||||||
const file = normalized.split("/").pop();
|
const file = normalized.split("/").pop();
|
||||||
|
const relative = normalized.replace(/^\//, "");
|
||||||
const urls = [
|
const urls = [
|
||||||
|
new URL("src/assets/" + file, deploy),
|
||||||
|
new URL("assets/" + file, deploy),
|
||||||
|
new URL(relative, deploy),
|
||||||
new URL("./src/assets/" + file, base),
|
new URL("./src/assets/" + file, base),
|
||||||
new URL("./assets/" + file, base),
|
new URL("./assets/" + file, base),
|
||||||
new URL("/src/assets/" + file, base.origin),
|
new URL("/src/assets/" + file, base.origin),
|
||||||
@@ -205,7 +215,10 @@
|
|||||||
|
|
||||||
const fetchManifest = async () => {
|
const fetchManifest = async () => {
|
||||||
const base = getBase();
|
const base = getBase();
|
||||||
|
const deploy = getDeployBase();
|
||||||
const candidates = [
|
const candidates = [
|
||||||
|
new URL(".vite/manifest.json", deploy),
|
||||||
|
new URL("manifest.json", deploy),
|
||||||
new URL(".vite/manifest.json", base.origin + "/"),
|
new URL(".vite/manifest.json", base.origin + "/"),
|
||||||
new URL("manifest.json", base.origin + "/"),
|
new URL("manifest.json", base.origin + "/"),
|
||||||
new URL(".vite/manifest.json", base),
|
new URL(".vite/manifest.json", base),
|
||||||
@@ -221,7 +234,11 @@
|
|||||||
const json = await response.json();
|
const json = await response.json();
|
||||||
if(json && typeof json === "object") {
|
if(json && typeof json === "object") {
|
||||||
debug("loader: manifest from " + candidate.href);
|
debug("loader: manifest from " + candidate.href);
|
||||||
return { manifest: json, base: new URL(".", candidate.href) };
|
let manifestBase = new URL(".", candidate.href);
|
||||||
|
if(/\/\.vite\/manifest\.json$/.test(candidate.pathname)) {
|
||||||
|
manifestBase = new URL("..", manifestBase);
|
||||||
|
}
|
||||||
|
return { manifest: json, base: manifestBase };
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch {}
|
||||||
}
|
}
|
||||||
@@ -247,18 +264,24 @@
|
|||||||
const resolveManifestPath = (manifestBase, file) => {
|
const resolveManifestPath = (manifestBase, file) => {
|
||||||
if(/^https?:\/\//i.test(file)) return file;
|
if(/^https?:\/\//i.test(file)) return file;
|
||||||
if(file.startsWith("/")) return file;
|
if(file.startsWith("/")) return file;
|
||||||
return new URL(file, manifestBase.origin + "/").pathname;
|
return new URL(file, manifestBase).pathname;
|
||||||
};
|
};
|
||||||
|
|
||||||
const isLoaderUrl = (href) => /(?:^|\/)bootstrap\.js(?:$|\?|#)/i.test(href) || /(?:^|\/)asset-loader\.js(?:$|\?|#)/i.test(href);
|
const isLoaderUrl = (href) => /(?:^|\/)bootstrap\.js(?:$|\?|#)/i.test(href) || /(?:^|\/)asset-loader\.js(?:$|\?|#)/i.test(href);
|
||||||
|
|
||||||
const fetchEntryFromIndexHtml = async () => {
|
const fetchEntryFromIndexHtml = async () => {
|
||||||
const base = getBase();
|
const base = getBase();
|
||||||
|
const deploy = getDeployBase();
|
||||||
const candidates = [
|
const candidates = [
|
||||||
|
new URL("index.html", deploy),
|
||||||
|
new URL("./", deploy),
|
||||||
new URL("/index.html", base.origin + "/"),
|
new URL("/index.html", base.origin + "/"),
|
||||||
new URL("/", base.origin + "/")
|
new URL("/", base.origin + "/")
|
||||||
];
|
];
|
||||||
|
const seen = new Set();
|
||||||
for(const candidate of candidates) {
|
for(const candidate of candidates) {
|
||||||
|
if(seen.has(candidate.href)) continue;
|
||||||
|
seen.add(candidate.href);
|
||||||
try {
|
try {
|
||||||
const response = await fetch(withCacheBust(new URL(candidate.href)), { cache: "no-store" });
|
const response = await fetch(withCacheBust(new URL(candidate.href)), { cache: "no-store" });
|
||||||
if(!response.ok) continue;
|
if(!response.ok) continue;
|
||||||
|
|||||||
Vendored
-13
@@ -1,17 +1,4 @@
|
|||||||
(() => {
|
(() => {
|
||||||
const API_BASE = "http://localhost:2096";
|
|
||||||
|
|
||||||
const ensureMobileViewport = () => {
|
|
||||||
let viewport = document.querySelector('meta[name="viewport"]');
|
|
||||||
if(!viewport) {
|
|
||||||
viewport = document.createElement("meta");
|
|
||||||
viewport.name = "viewport";
|
|
||||||
document.head.appendChild(viewport);
|
|
||||||
}
|
|
||||||
viewport.content = "width=device-width, initial-scale=1, viewport-fit=cover";
|
|
||||||
};
|
|
||||||
|
|
||||||
ensureMobileViewport();
|
|
||||||
const FALLBACK_API_BASE = "";
|
const FALLBACK_API_BASE = "";
|
||||||
|
|
||||||
const getBase = () => {
|
const getBase = () => {
|
||||||
|
|||||||
@@ -215,9 +215,9 @@ export const UiSettingsProvider: FC<PropsWithChildren> = ({ children }) =>
|
|||||||
}, [ settings ]);
|
}, [ settings ]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UiSettingsContext.Provider value={ { settings, isCustomActive, updateSettings, resetSettings, getHeaderStyle, getTabsStyle, getAccentColor } }>
|
<UiSettingsContext value={ { settings, isCustomActive, updateSettings, resetSettings, getHeaderStyle, getTabsStyle, getAccentColor } }>
|
||||||
{ children }
|
{ children }
|
||||||
</UiSettingsContext.Provider>
|
</UiSettingsContext>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContext, FC, ProviderProps, useContext } from 'react';
|
import { createContext, FC, ReactNode, useContext } from 'react';
|
||||||
|
|
||||||
export interface IGridContext
|
export interface IGridContext
|
||||||
{
|
{
|
||||||
@@ -9,9 +9,9 @@ const GridContext = createContext<IGridContext>({
|
|||||||
isCssGrid: false
|
isCssGrid: false
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GridContextProvider: FC<ProviderProps<IGridContext>> = props =>
|
export const GridContextProvider: FC<{ value: IGridContext; children?: ReactNode }> = props =>
|
||||||
{
|
{
|
||||||
return <GridContext.Provider value={ props.value }>{ props.children }</GridContext.Provider>;
|
return <GridContext value={ props.value }>{ props.children }</GridContext>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useGridContext = () => useContext(GridContext);
|
export const useGridContext = () => useContext(GridContext);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContext, FC, ProviderProps, useContext } from 'react';
|
import { createContext, FC, ReactNode, useContext } from 'react';
|
||||||
|
|
||||||
interface INitroCardContext
|
interface INitroCardContext
|
||||||
{
|
{
|
||||||
@@ -9,9 +9,9 @@ const NitroCardContext = createContext<INitroCardContext>({
|
|||||||
theme: null
|
theme: null
|
||||||
});
|
});
|
||||||
|
|
||||||
export const NitroCardContextProvider: FC<ProviderProps<INitroCardContext>> = props =>
|
export const NitroCardContextProvider: FC<{ value: INitroCardContext; children?: ReactNode }> = props =>
|
||||||
{
|
{
|
||||||
return <NitroCardContext.Provider value={ props.value }>{ props.children }</NitroCardContext.Provider>;
|
return <NitroCardContext value={ props.value }>{ props.children }</NitroCardContext>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useNitroCardContext = () => useContext(NitroCardContext);
|
export const useNitroCardContext = () => useContext(NitroCardContext);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
|
import { createContext, Dispatch, FC, ReactNode, SetStateAction, useContext } from 'react';
|
||||||
|
|
||||||
export interface INitroCardAccordionContext
|
export interface INitroCardAccordionContext
|
||||||
{
|
{
|
||||||
@@ -13,9 +13,9 @@ const NitroCardAccordionContext = createContext<INitroCardAccordionContext>({
|
|||||||
closeAll: null
|
closeAll: null
|
||||||
});
|
});
|
||||||
|
|
||||||
export const NitroCardAccordionContextProvider: FC<ProviderProps<INitroCardAccordionContext>> = props =>
|
export const NitroCardAccordionContextProvider: FC<{ value: INitroCardAccordionContext; children?: ReactNode }> = props =>
|
||||||
{
|
{
|
||||||
return <NitroCardAccordionContext.Provider { ...props } />;
|
return <NitroCardAccordionContext { ...props } />;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useNitroCardAccordionContext = () => useContext(NitroCardAccordionContext);
|
export const useNitroCardAccordionContext = () => useContext(NitroCardAccordionContext);
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ interface AdsenseConfig {
|
|||||||
fullWidthResponsive?: boolean;
|
fullWidthResponsive?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ADSENSE_SCRIPT_ID = 'google-adsense-script';
|
|
||||||
|
|
||||||
const parsePublisherIdFromAdsTxt = (text: string): string | null => {
|
const parsePublisherIdFromAdsTxt = (text: string): string | null => {
|
||||||
for (const rawLine of text.split(/\r?\n/)) {
|
for (const rawLine of text.split(/\r?\n/)) {
|
||||||
const line = rawLine.split('#')[0].trim();
|
const line = rawLine.split('#')[0].trim();
|
||||||
@@ -24,18 +22,6 @@ const parsePublisherIdFromAdsTxt = (text: string): string | null => {
|
|||||||
return null;
|
return null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const ensureAdsenseScript = (publisherId: string): void => {
|
|
||||||
if (typeof document === 'undefined') return;
|
|
||||||
if (document.getElementById(ADSENSE_SCRIPT_ID)) return;
|
|
||||||
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.id = ADSENSE_SCRIPT_ID;
|
|
||||||
script.async = true;
|
|
||||||
script.crossOrigin = 'anonymous';
|
|
||||||
script.src = `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-${ publisherId }`;
|
|
||||||
document.head.appendChild(script);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GoogleAdsView: FC<{}> = () => {
|
export const GoogleAdsView: FC<{}> = () => {
|
||||||
const adsEnabled = GetConfigurationValue<boolean>('show.google.ads', false);
|
const adsEnabled = GetConfigurationValue<boolean>('show.google.ads', false);
|
||||||
const [ isOpen, setIsOpen ] = useState(false);
|
const [ isOpen, setIsOpen ] = useState(false);
|
||||||
@@ -95,11 +81,6 @@ export const GoogleAdsView: FC<{}> = () => {
|
|||||||
return () => { cancelled = true; };
|
return () => { cancelled = true; };
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!isOpen || !publisherId || !config) return;
|
|
||||||
ensureAdsenseScript(publisherId);
|
|
||||||
}, [ isOpen, publisherId, config ]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isOpen) {
|
if (!isOpen) {
|
||||||
pushedRef.current = false;
|
pushedRef.current = false;
|
||||||
@@ -138,6 +119,11 @@ export const GoogleAdsView: FC<{}> = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<NitroCardView className="nitro-google-ads" uniqueKey="google-ads" theme="primary">
|
<NitroCardView className="nitro-google-ads" uniqueKey="google-ads" theme="primary">
|
||||||
|
{ publisherId &&
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
crossOrigin="anonymous"
|
||||||
|
src={ `https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-${ publisherId }` } /> }
|
||||||
<NitroCardHeaderView headerText="Sponsored" onCloseClick={ () => setIsOpen(false) } />
|
<NitroCardHeaderView headerText="Sponsored" onCloseClick={ () => setIsOpen(false) } />
|
||||||
<NitroCardContentView>
|
<NitroCardContentView>
|
||||||
<div className="flex items-center justify-center w-[300px] h-[250px] bg-white">
|
<div className="flex items-center justify-center w-[300px] h-[250px] bg-white">
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren, forwardRef } from 'react';
|
import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren, Ref } from 'react';
|
||||||
import { classNames } from '../../layout';
|
import { classNames } from '../../layout';
|
||||||
|
|
||||||
import arrowLeftIcon from '../../assets/images/avatareditor/arrow-left-icon.png';
|
import arrowLeftIcon from '../../assets/images/avatareditor/arrow-left-icon.png';
|
||||||
@@ -55,13 +55,14 @@ const ICON_MAP: Record<string, { normal: string; selected?: string }> = {
|
|||||||
'wa': { normal: waIcon, selected: waSelectedIcon },
|
'wa': { normal: waIcon, selected: waSelectedIcon },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const AvatarEditorIcon = forwardRef<HTMLDivElement, PropsWithChildren<{
|
type AvatarEditorIconProps = PropsWithChildren<{
|
||||||
icon: string;
|
icon: string;
|
||||||
selected?: boolean;
|
selected?: boolean;
|
||||||
}> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
ref?: Ref<HTMLDivElement>;
|
||||||
{
|
}> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
const { icon = null, selected = false, className = null, children, ...rest } = props;
|
|
||||||
|
|
||||||
|
export const AvatarEditorIcon = ({ ref, icon = null, selected = false, className = null, children, ...rest }: AvatarEditorIconProps) =>
|
||||||
|
{
|
||||||
const iconEntry = icon ? ICON_MAP[icon] : null;
|
const iconEntry = icon ? ICON_MAP[icon] : null;
|
||||||
|
|
||||||
if(!iconEntry) return null;
|
if(!iconEntry) return null;
|
||||||
@@ -77,6 +78,4 @@ export const AvatarEditorIcon = forwardRef<HTMLDivElement, PropsWithChildren<{
|
|||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
AvatarEditorIcon.displayName = 'AvatarEditorIcon';
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Dispatch, FC, SetStateAction, useCallback, useEffect, useMemo, useState } from 'react';
|
import { Dispatch, FC, SetStateAction, use, useCallback, useMemo, useState } from 'react';
|
||||||
import { Base, Grid, Flex, NitroCardView, NitroCardHeaderView, NitroCardTabsView, NitroCardTabsItemView, NitroCardContentView, Text } from '../../common';
|
import { Base, Grid, Flex, NitroCardView, NitroCardHeaderView, NitroCardTabsView, NitroCardTabsItemView, NitroCardContentView, Text } from '../../common';
|
||||||
import { useRoom } from '../../hooks';
|
import { useRoom } from '../../hooks';
|
||||||
import { GetOptionalConfigurationValue } from '../../api';
|
import { GetOptionalConfigurationValue } from '../../api';
|
||||||
@@ -25,6 +25,20 @@ type TabType = typeof TABS[number];
|
|||||||
|
|
||||||
type RemoteData = Partial<Record<'backgrounds.data' | 'stands.data' | 'overlays.data' | 'cards.data', any[]>>;
|
type RemoteData = Partial<Record<'backgrounds.data' | 'stands.data' | 'overlays.data' | 'cards.data', any[]>>;
|
||||||
|
|
||||||
|
let backgroundsDataPromise: Promise<RemoteData | null> | null = null;
|
||||||
|
|
||||||
|
const fetchBackgroundsData = (): Promise<RemoteData | null> =>
|
||||||
|
{
|
||||||
|
if(backgroundsDataPromise) return backgroundsDataPromise;
|
||||||
|
|
||||||
|
backgroundsDataPromise = fetch(configFileUrl('infostand_backgrounds.json'), { credentials: 'omit' })
|
||||||
|
.then(r => r.ok ? r.json() : null)
|
||||||
|
.then(json => (json && typeof json === 'object') ? json as RemoteData : null)
|
||||||
|
.catch(() => null);
|
||||||
|
|
||||||
|
return backgroundsDataPromise;
|
||||||
|
};
|
||||||
|
|
||||||
export const BackgroundsView: FC<BackgroundsViewProps> = ({
|
export const BackgroundsView: FC<BackgroundsViewProps> = ({
|
||||||
setIsVisible,
|
setIsVisible,
|
||||||
selectedBackground,
|
selectedBackground,
|
||||||
@@ -37,18 +51,9 @@ export const BackgroundsView: FC<BackgroundsViewProps> = ({
|
|||||||
setSelectedCardBackground
|
setSelectedCardBackground
|
||||||
}) => {
|
}) => {
|
||||||
const [activeTab, setActiveTab] = useState<TabType>('backgrounds');
|
const [activeTab, setActiveTab] = useState<TabType>('backgrounds');
|
||||||
const [remoteData, setRemoteData] = useState<RemoteData | null>(null);
|
const remoteData = use(fetchBackgroundsData());
|
||||||
const { roomSession } = useRoom();
|
const { roomSession } = useRoom();
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
let cancelled = false;
|
|
||||||
fetch(configFileUrl('infostand_backgrounds.json'), { credentials: 'omit' })
|
|
||||||
.then(r => r.ok ? r.json() : null)
|
|
||||||
.then(json => { if(!cancelled && json && typeof json === 'object') setRemoteData(json as RemoteData); })
|
|
||||||
.catch(() => {});
|
|
||||||
return () => { cancelled = true; };
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const processData = useCallback((configData: any[], idField: string): ItemData[] => {
|
const processData = useCallback((configData: any[], idField: string): ItemData[] => {
|
||||||
if (!configData?.length) return [];
|
if (!configData?.length) return [];
|
||||||
|
|
||||||
|
|||||||
@@ -280,7 +280,7 @@ export const CatalogAdminProvider: FC<{ children: ReactNode }> = ({ children })
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CatalogAdminContext.Provider value={ {
|
<CatalogAdminContext value={ {
|
||||||
adminMode, setAdminMode,
|
adminMode, setAdminMode,
|
||||||
editingOffer, setEditingOffer,
|
editingOffer, setEditingOffer,
|
||||||
editingPageData, setEditingPageData,
|
editingPageData, setEditingPageData,
|
||||||
@@ -293,6 +293,6 @@ export const CatalogAdminProvider: FC<{ children: ReactNode }> = ({ children })
|
|||||||
publishCatalog
|
publishCatalog
|
||||||
} }>
|
} }>
|
||||||
{ children }
|
{ children }
|
||||||
</CatalogAdminContext.Provider>
|
</CatalogAdminContext>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { createContext, Dispatch, FC, ProviderProps, SetStateAction, useContext } from 'react';
|
import { createContext, Dispatch, FC, SetStateAction, useContext } from 'react';
|
||||||
import { IFloorplanSettings } from '@nitrots/nitro-renderer';
|
import { IFloorplanSettings } from '@nitrots/nitro-renderer';
|
||||||
import { IVisualizationSettings } from '@nitrots/nitro-renderer';
|
import { IVisualizationSettings } from '@nitrots/nitro-renderer';
|
||||||
|
|
||||||
@@ -29,6 +29,6 @@ const FloorplanEditorContext = createContext<IFloorplanEditorContext>({
|
|||||||
areaInfo: { total: 0, walkable: 0 }
|
areaInfo: { total: 0, walkable: 0 }
|
||||||
});
|
});
|
||||||
|
|
||||||
export const FloorplanEditorContextProvider: FC<ProviderProps<IFloorplanEditorContext>> = props => <FloorplanEditorContext.Provider { ...props } />;
|
export const FloorplanEditorContextProvider: FC<{ value: IFloorplanEditorContext; children?: React.ReactNode }> = props => <FloorplanEditorContext { ...props } />;
|
||||||
|
|
||||||
export const useFloorplanEditorContext = () => useContext(FloorplanEditorContext);
|
export const useFloorplanEditorContext = () => useContext(FloorplanEditorContext);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { FC, useEffect, useRef } from 'react';
|
import { FC, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
declare global
|
declare global
|
||||||
{
|
{
|
||||||
@@ -13,41 +13,8 @@ declare global
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const SCRIPT_ID = 'cf-turnstile-script';
|
|
||||||
const SCRIPT_SRC = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
|
const SCRIPT_SRC = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
|
||||||
|
|
||||||
let scriptPromise: Promise<void> | null = null;
|
|
||||||
|
|
||||||
const loadTurnstileScript = (): Promise<void> =>
|
|
||||||
{
|
|
||||||
if(typeof window === 'undefined') return Promise.resolve();
|
|
||||||
if(window.turnstile) return Promise.resolve();
|
|
||||||
if(scriptPromise) return scriptPromise;
|
|
||||||
|
|
||||||
scriptPromise = new Promise<void>((resolve, reject) =>
|
|
||||||
{
|
|
||||||
const existing = document.getElementById(SCRIPT_ID) as HTMLScriptElement | null;
|
|
||||||
|
|
||||||
if(existing)
|
|
||||||
{
|
|
||||||
existing.addEventListener('load', () => resolve());
|
|
||||||
existing.addEventListener('error', () => reject(new Error('Turnstile failed to load')));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.id = SCRIPT_ID;
|
|
||||||
script.src = SCRIPT_SRC;
|
|
||||||
script.async = true;
|
|
||||||
script.defer = true;
|
|
||||||
script.onload = () => resolve();
|
|
||||||
script.onerror = () => reject(new Error('Turnstile failed to load'));
|
|
||||||
document.head.appendChild(script);
|
|
||||||
});
|
|
||||||
|
|
||||||
return scriptPromise;
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface TurnstileWidgetProps
|
export interface TurnstileWidgetProps
|
||||||
{
|
{
|
||||||
siteKey: string;
|
siteKey: string;
|
||||||
@@ -64,44 +31,47 @@ export const TurnstileWidget: FC<TurnstileWidgetProps> = props =>
|
|||||||
const { siteKey, theme = 'light', size = 'normal', onToken, onExpire, onError, resetSignal = 0 } = props;
|
const { siteKey, theme = 'light', size = 'normal', onToken, onExpire, onError, resetSignal = 0 } = props;
|
||||||
const containerRef = useRef<HTMLDivElement | null>(null);
|
const containerRef = useRef<HTMLDivElement | null>(null);
|
||||||
const widgetIdRef = useRef<string | null>(null);
|
const widgetIdRef = useRef<string | null>(null);
|
||||||
|
const [ scriptReady, setScriptReady ] = useState<boolean>(typeof window !== 'undefined' && !!window.turnstile);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
if(!siteKey || !containerRef.current) return;
|
if(scriptReady) return;
|
||||||
|
if(typeof window === 'undefined') return;
|
||||||
|
|
||||||
let cancelled = false;
|
const interval = window.setInterval(() =>
|
||||||
|
{
|
||||||
loadTurnstileScript()
|
if(window.turnstile)
|
||||||
.then(() =>
|
|
||||||
{
|
{
|
||||||
if(cancelled || !window.turnstile || !containerRef.current) return;
|
setScriptReady(true);
|
||||||
|
window.clearInterval(interval);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
|
||||||
widgetIdRef.current = window.turnstile.render(containerRef.current, {
|
return () => window.clearInterval(interval);
|
||||||
sitekey: siteKey,
|
}, [ scriptReady ]);
|
||||||
theme,
|
|
||||||
size,
|
useEffect(() =>
|
||||||
callback: (token: string) => onToken(token),
|
{
|
||||||
'expired-callback': () => onExpire?.(),
|
if(!scriptReady || !siteKey || !containerRef.current || !window.turnstile) return;
|
||||||
'error-callback': () => onError?.()
|
|
||||||
});
|
widgetIdRef.current = window.turnstile.render(containerRef.current, {
|
||||||
})
|
sitekey: siteKey,
|
||||||
.catch(err =>
|
theme,
|
||||||
{
|
size,
|
||||||
console.error('[Turnstile] script load failed', err);
|
callback: (token: string) => onToken(token),
|
||||||
onError?.();
|
'expired-callback': () => onExpire?.(),
|
||||||
});
|
'error-callback': () => onError?.()
|
||||||
|
});
|
||||||
|
|
||||||
return () =>
|
return () =>
|
||||||
{
|
{
|
||||||
cancelled = true;
|
|
||||||
|
|
||||||
if(widgetIdRef.current && window.turnstile)
|
if(widgetIdRef.current && window.turnstile)
|
||||||
{
|
{
|
||||||
try { window.turnstile.remove(widgetIdRef.current); } catch { }
|
try { window.turnstile.remove(widgetIdRef.current); } catch { }
|
||||||
widgetIdRef.current = null;
|
widgetIdRef.current = null;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, [ siteKey, theme, size ]);
|
}, [ scriptReady, siteKey, theme, size ]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
@@ -114,5 +84,19 @@ export const TurnstileWidget: FC<TurnstileWidgetProps> = props =>
|
|||||||
|
|
||||||
if(!siteKey) return null;
|
if(!siteKey) return null;
|
||||||
|
|
||||||
return <div ref={ containerRef } className="turnstile-slot" />;
|
return (
|
||||||
|
<>
|
||||||
|
<script
|
||||||
|
async
|
||||||
|
defer
|
||||||
|
src={ SCRIPT_SRC }
|
||||||
|
onLoad={ () => setScriptReady(true) }
|
||||||
|
onError={ () =>
|
||||||
|
{
|
||||||
|
console.error('[Turnstile] script load failed');
|
||||||
|
onError?.();
|
||||||
|
} } />
|
||||||
|
<div ref={ containerRef } className="turnstile-slot" />
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,29 +2,25 @@ import { FC, useEffect, useState } from 'react';
|
|||||||
import { GetConfigurationValue } from '../../api';
|
import { GetConfigurationValue } from '../../api';
|
||||||
import { subscribePlugins } from './NitroPluginApi';
|
import { subscribePlugins } from './NitroPluginApi';
|
||||||
|
|
||||||
// Force the global API to be initialized
|
|
||||||
import './NitroPluginApi';
|
import './NitroPluginApi';
|
||||||
|
|
||||||
export const ExternalPluginLoader: FC<{}> = () =>
|
export const ExternalPluginLoader: FC<{}> = () =>
|
||||||
{
|
{
|
||||||
const [, forceUpdate] = useState(0);
|
const [, forceUpdate] = useState(0);
|
||||||
|
const [ pluginUrls, setPluginUrls ] = useState<string[]>([]);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
return subscribePlugins(() => forceUpdate(n => n + 1));
|
return subscribePlugins(() => forceUpdate(n => n + 1));
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// MainView only renders after isReady=true in App.tsx,
|
|
||||||
// so the configuration is guaranteed to be loaded at this point.
|
|
||||||
useEffect(() =>
|
useEffect(() =>
|
||||||
{
|
{
|
||||||
const scripts: HTMLScriptElement[] = [];
|
let urls: string[] = [];
|
||||||
|
|
||||||
let pluginUrls: string[] = [];
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pluginUrls = GetConfigurationValue<string[]>('external.plugins', []);
|
urls = GetConfigurationValue<string[]>('external.plugins', []) || [];
|
||||||
}
|
}
|
||||||
catch (e)
|
catch (e)
|
||||||
{
|
{
|
||||||
@@ -32,30 +28,28 @@ export const ExternalPluginLoader: FC<{}> = () =>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!pluginUrls || pluginUrls.length === 0)
|
if (!urls.length)
|
||||||
{
|
{
|
||||||
console.log('[NitroPlugins] No external plugins configured');
|
console.log('[NitroPlugins] No external plugins configured');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[NitroPlugins] Loading external plugins:', pluginUrls);
|
console.log('[NitroPlugins] Loading external plugins:', urls);
|
||||||
|
setPluginUrls(urls);
|
||||||
for (const url of pluginUrls)
|
|
||||||
{
|
|
||||||
const script = document.createElement('script');
|
|
||||||
script.src = url;
|
|
||||||
script.async = true;
|
|
||||||
script.onload = () => console.log(`[NitroPlugins] Loaded: ${url}`);
|
|
||||||
script.onerror = () => console.warn(`[NitroPlugins] Failed to load: ${url}`);
|
|
||||||
document.head.appendChild(script);
|
|
||||||
scripts.push(script);
|
|
||||||
}
|
|
||||||
|
|
||||||
return () =>
|
|
||||||
{
|
|
||||||
scripts.forEach(s => s.remove());
|
|
||||||
};
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return null;
|
if (!pluginUrls.length) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{ pluginUrls.map(url => (
|
||||||
|
<script
|
||||||
|
key={ url }
|
||||||
|
async
|
||||||
|
src={ url }
|
||||||
|
onLoad={ () => console.log(`[NitroPlugins] Loaded: ${ url }`) }
|
||||||
|
onError={ () => console.warn(`[NitroPlugins] Failed to load: ${ url }`) } />
|
||||||
|
)) }
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react';
|
import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren, Ref } from 'react';
|
||||||
import { classNames } from '../../layout';
|
import { classNames } from '../../layout';
|
||||||
|
|
||||||
export const ToolbarItemView = forwardRef<HTMLDivElement, PropsWithChildren<{
|
type ToolbarItemViewProps = PropsWithChildren<{
|
||||||
icon: string;
|
icon: string;
|
||||||
}> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
ref?: Ref<HTMLDivElement>;
|
||||||
{
|
}> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
const { icon = null, className = null, ...rest } = props;
|
|
||||||
|
|
||||||
|
export const ToolbarItemView = ({ ref, icon = null, className = null, ...rest }: ToolbarItemViewProps) =>
|
||||||
|
{
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ ref }
|
ref={ ref }
|
||||||
@@ -17,6 +18,4 @@ export const ToolbarItemView = forwardRef<HTMLDivElement, PropsWithChildren<{
|
|||||||
) }
|
) }
|
||||||
{ ...rest } />
|
{ ...rest } />
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
ToolbarItemView.displayName = 'ToolbarItemView';
|
|
||||||
|
|||||||
+16
-1
@@ -1,5 +1,8 @@
|
|||||||
|
import { Suspense } from 'react';
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
import { ErrorBoundary } from 'react-error-boundary';
|
||||||
import { App } from './App';
|
import { App } from './App';
|
||||||
|
import { LoadingView } from './components/loading/LoadingView';
|
||||||
|
|
||||||
import './css/index.css';
|
import './css/index.css';
|
||||||
|
|
||||||
@@ -40,4 +43,16 @@ import './css/toolbar/ToolBar.css';
|
|||||||
|
|
||||||
import './css/widgets/FurnitureWidgets.css';
|
import './css/widgets/FurnitureWidgets.css';
|
||||||
|
|
||||||
createRoot(document.getElementById('root')).render(<App />);
|
createRoot(document.getElementById('root')).render(
|
||||||
|
<ErrorBoundary
|
||||||
|
fallbackRender={ ({ error }) => (
|
||||||
|
<LoadingView
|
||||||
|
isError={ true }
|
||||||
|
message={ `Something went wrong.\n${ (error as Error)?.message ?? 'Unknown error' }` }
|
||||||
|
homeUrl={ window.location.origin + '/' } />
|
||||||
|
) }>
|
||||||
|
<Suspense fallback={ <LoadingView message="Loading…" /> }>
|
||||||
|
<App />
|
||||||
|
</Suspense>
|
||||||
|
</ErrorBoundary>
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { useVirtualizer } from '@tanstack/react-virtual';
|
import { useVirtualizer } from '@tanstack/react-virtual';
|
||||||
import { DetailedHTMLProps, Fragment, HTMLAttributes, ReactElement, forwardRef, useEffect, useRef, useState } from 'react';
|
import { DetailedHTMLProps, Fragment, HTMLAttributes, ReactElement, Ref, useEffect, useRef, useState } from 'react';
|
||||||
import { classNames } from './classNames';
|
import { classNames } from './classNames';
|
||||||
import { NitroLimitedEditionStyledNumberView } from './limited-edition';
|
import { NitroLimitedEditionStyledNumberView } from './limited-edition';
|
||||||
import { styleNames } from './styleNames';
|
import { styleNames } from './styleNames';
|
||||||
@@ -150,7 +150,7 @@ const InfiniteGridRoot = <T,>(props: Props<T>) =>
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const InfiniteGridItem = forwardRef<HTMLDivElement, {
|
type InfiniteGridItemProps = {
|
||||||
itemImage?: string;
|
itemImage?: string;
|
||||||
itemColor?: string;
|
itemColor?: string;
|
||||||
itemActive?: boolean;
|
itemActive?: boolean;
|
||||||
@@ -161,9 +161,11 @@ const InfiniteGridItem = forwardRef<HTMLDivElement, {
|
|||||||
itemUnseen?: boolean;
|
itemUnseen?: boolean;
|
||||||
itemHighlight?: boolean;
|
itemHighlight?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
ref?: Ref<HTMLDivElement>;
|
||||||
|
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
|
|
||||||
|
const InfiniteGridItem = ({ ref, itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemCountMinimum = 1, itemUniqueSoldout = false, itemUniqueNumber = -2, itemUnseen = false, itemHighlight = false, disabled = false, className = null, style = {}, children = null, ...rest }: InfiniteGridItemProps) =>
|
||||||
{
|
{
|
||||||
const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemCountMinimum = 1, itemUniqueSoldout = false, itemUniqueNumber = -2, itemUnseen = false, itemHighlight = false, disabled = false, className = null, style = {}, children = null, ...rest } = props;
|
|
||||||
const [ backgroundImageUrl, setBackgroundImageUrl ] = useState<string>(null);
|
const [ backgroundImageUrl, setBackgroundImageUrl ] = useState<string>(null);
|
||||||
const disposed = useRef<boolean>(false);
|
const disposed = useRef<boolean>(false);
|
||||||
|
|
||||||
@@ -238,9 +240,7 @@ const InfiniteGridItem = forwardRef<HTMLDivElement, {
|
|||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
InfiniteGridItem.displayName = 'InfiniteGridItem';
|
|
||||||
|
|
||||||
export const InfiniteGrid = Object.assign(InfiniteGridRoot, {
|
export const InfiniteGrid = Object.assign(InfiniteGridRoot, {
|
||||||
Item: InfiniteGridItem
|
Item: InfiniteGridItem
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { ButtonHTMLAttributes, DetailedHTMLProps, forwardRef, PropsWithChildren } from 'react';
|
import { ButtonHTMLAttributes, DetailedHTMLProps, PropsWithChildren, Ref } from 'react';
|
||||||
import { classNames } from './classNames';
|
import { classNames } from './classNames';
|
||||||
|
|
||||||
const classes = {
|
const classes = {
|
||||||
@@ -17,14 +17,15 @@ const classes = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NitroButton = forwardRef<HTMLButtonElement, PropsWithChildren<{
|
type NitroButtonProps = PropsWithChildren<{
|
||||||
color?: 'default' | 'dark' | 'ghost';
|
color?: 'default' | 'dark' | 'ghost';
|
||||||
size?: 'default' | 'lg' | 'xl';
|
size?: 'default' | 'lg' | 'xl';
|
||||||
outline?: boolean;
|
outline?: boolean;
|
||||||
}> & DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>>((props, ref) =>
|
ref?: Ref<HTMLButtonElement>;
|
||||||
{
|
}> & DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>;
|
||||||
const { color = 'default', size = 'default', outline = false, disabled = false, type = 'button', className = null, ...rest } = props;
|
|
||||||
|
|
||||||
|
export const NitroButton = ({ ref, color = 'default', size = 'default', outline = false, disabled = false, type = 'button', className = null, ...rest }: NitroButtonProps) =>
|
||||||
|
{
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
ref={ ref }
|
ref={ ref }
|
||||||
@@ -39,6 +40,4 @@ export const NitroButton = forwardRef<HTMLButtonElement, PropsWithChildren<{
|
|||||||
type={ type }
|
type={ type }
|
||||||
{ ...rest } />
|
{ ...rest } />
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
NitroButton.displayName = 'NitroButton';
|
|
||||||
|
|||||||
+45
-50
@@ -1,13 +1,14 @@
|
|||||||
import { DetailedHTMLProps, forwardRef, HTMLAttributes, MouseEvent, PropsWithChildren } from 'react';
|
import { DetailedHTMLProps, HTMLAttributes, MouseEvent, PropsWithChildren, Ref } from 'react';
|
||||||
import { DraggableWindow, DraggableWindowPosition, DraggableWindowProps } from '../common';
|
import { DraggableWindow, DraggableWindowPosition, DraggableWindowProps } from '../common';
|
||||||
import { classNames } from './classNames';
|
import { classNames } from './classNames';
|
||||||
import { NitroItemCountBadge } from './NitroItemCountBadge';
|
import { NitroItemCountBadge } from './NitroItemCountBadge';
|
||||||
|
|
||||||
const NitroCardRoot = forwardRef<HTMLDivElement, PropsWithChildren<{
|
type NitroCardRootProps = PropsWithChildren<{
|
||||||
} & DraggableWindowProps> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
ref?: Ref<HTMLDivElement>;
|
||||||
{
|
} & DraggableWindowProps> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
const { uniqueKey = null, handleSelector = '.drag-handler', windowPosition = DraggableWindowPosition.CENTER, disableDrag = false, className = null, ...rest } = props;
|
|
||||||
|
|
||||||
|
const NitroCardRoot = ({ ref, uniqueKey = null, handleSelector = '.drag-handler', windowPosition = DraggableWindowPosition.CENTER, disableDrag = false, className = null, ...rest }: NitroCardRootProps) =>
|
||||||
|
{
|
||||||
return (
|
return (
|
||||||
<DraggableWindow disableDrag={ disableDrag } handleSelector={ handleSelector } uniqueKey={ uniqueKey } windowPosition={ windowPosition }>
|
<DraggableWindow disableDrag={ disableDrag } handleSelector={ handleSelector } uniqueKey={ uniqueKey } windowPosition={ windowPosition }>
|
||||||
<div
|
<div
|
||||||
@@ -19,41 +20,39 @@ const NitroCardRoot = forwardRef<HTMLDivElement, PropsWithChildren<{
|
|||||||
{ ...rest } />
|
{ ...rest } />
|
||||||
</DraggableWindow>
|
</DraggableWindow>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
NitroCardRoot.displayName = 'NitroCardRoot';
|
type NitroCardHeaderProps = {
|
||||||
|
|
||||||
const NitroCardHeader = forwardRef<HTMLDivElement, {
|
|
||||||
headerText: string;
|
headerText: string;
|
||||||
onCloseClick?: (event: MouseEvent) => void;
|
onCloseClick?: (event: MouseEvent) => void;
|
||||||
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
ref?: Ref<HTMLDivElement>;
|
||||||
{
|
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
const { headerText = '', onCloseClick = null, className = null, ...rest } = props;
|
|
||||||
|
|
||||||
const onMouseDown = (event: MouseEvent<HTMLDivElement>) =>
|
const NitroCardHeader = ({ ref, headerText = '', onCloseClick = null, className = null, ...rest }: NitroCardHeaderProps) =>
|
||||||
{
|
|
||||||
event.stopPropagation();
|
|
||||||
event.nativeEvent.stopImmediatePropagation();
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div ref={ ref } className={ classNames('nitro-card-header-shell relative flex items-center justify-center flex-col drag-handler min-h-card-header max-h-card-header', className) }>
|
|
||||||
<div className="flex items-center justify-center w-full ">
|
|
||||||
<span className="nitro-card-title text-white">{ headerText }</span>
|
|
||||||
<div className="absolute flex items-center justify-center cursor-pointer right-2 nitro-card-close-button" onClick={ onCloseClick } onMouseDownCapture={ onMouseDown } />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
NitroCardHeader.displayName = 'NitroCardHeader';
|
|
||||||
|
|
||||||
const NitroCardContent = forwardRef<HTMLDivElement, {
|
|
||||||
isLoading?: boolean;
|
|
||||||
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
|
||||||
{
|
{
|
||||||
const { isLoading = false, className = null, children = null, ...rest } = props;
|
const onMouseDown = (event: MouseEvent<HTMLDivElement>) =>
|
||||||
|
{
|
||||||
|
event.stopPropagation();
|
||||||
|
event.nativeEvent.stopImmediatePropagation();
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={ ref } className={ classNames('nitro-card-header-shell relative flex items-center justify-center flex-col drag-handler min-h-card-header max-h-card-header', className) }>
|
||||||
|
<div className="flex items-center justify-center w-full ">
|
||||||
|
<span className="nitro-card-title text-white">{ headerText }</span>
|
||||||
|
<div className="absolute flex items-center justify-center cursor-pointer right-2 nitro-card-close-button" onClick={ onCloseClick } onMouseDownCapture={ onMouseDown } />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
type NitroCardContentProps = {
|
||||||
|
isLoading?: boolean;
|
||||||
|
ref?: Ref<HTMLDivElement>;
|
||||||
|
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
|
|
||||||
|
const NitroCardContent = ({ ref, isLoading = false, className = null, children = null, ...rest }: NitroCardContentProps) =>
|
||||||
|
{
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ ref }
|
ref={ ref }
|
||||||
@@ -67,15 +66,14 @@ const NitroCardContent = forwardRef<HTMLDivElement, {
|
|||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
NitroCardContent.displayName = 'NitroCardContent';
|
type NitroCardTabsProps = {
|
||||||
|
ref?: Ref<HTMLDivElement>;
|
||||||
|
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
|
|
||||||
const NitroCardTabs = forwardRef<HTMLDivElement, {
|
const NitroCardTabs = ({ ref, className = null, ...rest }: NitroCardTabsProps) =>
|
||||||
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
|
||||||
{
|
{
|
||||||
const { className = null, ...rest } = props;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ ref }
|
ref={ ref }
|
||||||
@@ -85,17 +83,16 @@ const NitroCardTabs = forwardRef<HTMLDivElement, {
|
|||||||
}
|
}
|
||||||
{ ...rest } />
|
{ ...rest } />
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
NitroCardTabs.displayName = 'NitroCardTabs';
|
type NitroCardTabItemProps = {
|
||||||
|
|
||||||
const NitroCardTabItem = forwardRef<HTMLDivElement, {
|
|
||||||
isActive?: boolean;
|
isActive?: boolean;
|
||||||
count?: number;
|
count?: number;
|
||||||
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
ref?: Ref<HTMLDivElement>;
|
||||||
{
|
} & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
const { isActive = false, count = 0, className = null, children = null, ...rest } = props;
|
|
||||||
|
|
||||||
|
const NitroCardTabItem = ({ ref, isActive = false, count = 0, className = null, children = null, ...rest }: NitroCardTabItemProps) =>
|
||||||
|
{
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ ref }
|
ref={ ref }
|
||||||
@@ -112,9 +109,7 @@ const NitroCardTabItem = forwardRef<HTMLDivElement, {
|
|||||||
<NitroItemCountBadge count={ count } /> }
|
<NitroItemCountBadge count={ count } /> }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
NitroCardTabItem.displayName = 'NitroCardTabItem';
|
|
||||||
|
|
||||||
export const NitroCard = Object.assign(NitroCardRoot, {
|
export const NitroCard = Object.assign(NitroCardRoot, {
|
||||||
Header: NitroCardHeader,
|
Header: NitroCardHeader,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DetailedHTMLProps, forwardRef, InputHTMLAttributes, PropsWithChildren } from 'react';
|
import { DetailedHTMLProps, InputHTMLAttributes, PropsWithChildren, Ref } from 'react';
|
||||||
import { classNames } from './classNames';
|
import { classNames } from './classNames';
|
||||||
|
|
||||||
const classes = {
|
const classes = {
|
||||||
@@ -13,20 +13,19 @@ const classes = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NitroInput = forwardRef<HTMLInputElement, PropsWithChildren<{
|
type NitroInputProps = PropsWithChildren<{
|
||||||
color?: 'default' | 'dark' | 'ghost';
|
color?: 'default' | 'dark' | 'ghost';
|
||||||
inputSize?: 'xs' | 'sm' | 'default' | 'lg' | 'xl';
|
inputSize?: 'xs' | 'sm' | 'default' | 'lg' | 'xl';
|
||||||
rounded?: boolean;
|
rounded?: boolean;
|
||||||
}> & DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>>((props, ref) =>
|
ref?: Ref<HTMLInputElement>;
|
||||||
{
|
}> & DetailedHTMLProps<InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
|
||||||
const { color = 'default', inputSize = 'default', rounded = true, disabled = false, type = 'text', autoComplete = 'off', className = null, ...rest } = props;
|
|
||||||
|
|
||||||
|
export const NitroInput = ({ ref, color = 'default', inputSize = 'default', rounded = true, disabled = false, type = 'text', autoComplete = 'off', className = null, ...rest }: NitroInputProps) =>
|
||||||
|
{
|
||||||
return (
|
return (
|
||||||
<input ref={ ref } autoComplete={ autoComplete } className={ classNames( classes.base, classes.size[inputSize], rounded && classes.rounded, classes.color[color], disabled && classes.disabled, className ) }
|
<input ref={ ref } autoComplete={ autoComplete } className={ classNames( classes.base, classes.size[inputSize], rounded && classes.rounded, classes.color[color], disabled && classes.disabled, className ) }
|
||||||
disabled={ disabled }
|
disabled={ disabled }
|
||||||
type={ type }
|
type={ type }
|
||||||
{ ...rest } />
|
{ ...rest } />
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
NitroInput.displayName = 'NitroInput';
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { DetailedHTMLProps, forwardRef, HTMLAttributes, PropsWithChildren } from 'react';
|
import { DetailedHTMLProps, HTMLAttributes, PropsWithChildren, Ref } from 'react';
|
||||||
import { classNames } from './classNames';
|
import { classNames } from './classNames';
|
||||||
|
|
||||||
const classes = {
|
const classes = {
|
||||||
@@ -8,13 +8,14 @@ const classes = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const NitroItemCountBadge = forwardRef<HTMLDivElement, PropsWithChildren<{
|
type NitroItemCountBadgeProps = PropsWithChildren<{
|
||||||
theme?: 'primary';
|
theme?: 'primary';
|
||||||
count: number;
|
count: number;
|
||||||
}> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>>((props, ref) =>
|
ref?: Ref<HTMLDivElement>;
|
||||||
{
|
}> & DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
|
||||||
const { theme = 'primary', count = 0, className = null, children = null, ...rest } = props;
|
|
||||||
|
|
||||||
|
export const NitroItemCountBadge = ({ ref, theme = 'primary', count = 0, className = null, children = null, ...rest }: NitroItemCountBadgeProps) =>
|
||||||
|
{
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ ref }
|
ref={ ref }
|
||||||
@@ -28,6 +29,4 @@ export const NitroItemCountBadge = forwardRef<HTMLDivElement, PropsWithChildren<
|
|||||||
{ children }
|
{ children }
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
};
|
||||||
|
|
||||||
NitroItemCountBadge.displayName = 'NitroItemCountBadge';
|
|
||||||
|
|||||||
+13
-1
@@ -7,8 +7,20 @@ const legacyRendererRoot = resolve(__dirname, '..', 'renderer');
|
|||||||
const currentRendererRoot = resolve(__dirname, '..', 'Nitro_Render_V3');
|
const currentRendererRoot = resolve(__dirname, '..', 'Nitro_Render_V3');
|
||||||
const rendererRoot = existsSync(currentRendererRoot) ? currentRendererRoot : legacyRendererRoot;
|
const rendererRoot = existsSync(currentRendererRoot) ? currentRendererRoot : legacyRendererRoot;
|
||||||
|
|
||||||
|
const ReactCompilerConfig = {
|
||||||
|
target: '19'
|
||||||
|
};
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [ react() ],
|
plugins: [
|
||||||
|
react({
|
||||||
|
babel: {
|
||||||
|
plugins: [
|
||||||
|
[ 'babel-plugin-react-compiler', ReactCompilerConfig ]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
],
|
||||||
server: {
|
server: {
|
||||||
fs: {
|
fs: {
|
||||||
allow: [
|
allow: [
|
||||||
|
|||||||
@@ -53,6 +53,13 @@
|
|||||||
"@jridgewell/trace-mapping" "^0.3.28"
|
"@jridgewell/trace-mapping" "^0.3.28"
|
||||||
jsesc "^3.0.2"
|
jsesc "^3.0.2"
|
||||||
|
|
||||||
|
"@babel/helper-annotate-as-pure@^7.27.3":
|
||||||
|
version "7.27.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.27.3.tgz#f31fd86b915fc4daf1f3ac6976c59be7084ed9c5"
|
||||||
|
integrity sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.27.3"
|
||||||
|
|
||||||
"@babel/helper-compilation-targets@^7.28.6":
|
"@babel/helper-compilation-targets@^7.28.6":
|
||||||
version "7.28.6"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25"
|
resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25"
|
||||||
@@ -64,11 +71,32 @@
|
|||||||
lru-cache "^5.1.1"
|
lru-cache "^5.1.1"
|
||||||
semver "^6.3.1"
|
semver "^6.3.1"
|
||||||
|
|
||||||
|
"@babel/helper-create-class-features-plugin@^7.18.6":
|
||||||
|
version "7.29.3"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.3.tgz#67328947d956f06fc7b48def269bf0489155fd42"
|
||||||
|
integrity sha512-RpLYy2sb51oNLjuu1iD3bwBqCBWUzjO0ocp+iaCP/lJtb2CPLcnC2Fftw+4sAzaMELGeWTgExSKADbdo0GFVzA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-annotate-as-pure" "^7.27.3"
|
||||||
|
"@babel/helper-member-expression-to-functions" "^7.28.5"
|
||||||
|
"@babel/helper-optimise-call-expression" "^7.27.1"
|
||||||
|
"@babel/helper-replace-supers" "^7.28.6"
|
||||||
|
"@babel/helper-skip-transparent-expression-wrappers" "^7.27.1"
|
||||||
|
"@babel/traverse" "^7.29.0"
|
||||||
|
semver "^6.3.1"
|
||||||
|
|
||||||
"@babel/helper-globals@^7.28.0":
|
"@babel/helper-globals@^7.28.0":
|
||||||
version "7.28.0"
|
version "7.28.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
|
resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674"
|
||||||
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
|
integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==
|
||||||
|
|
||||||
|
"@babel/helper-member-expression-to-functions@^7.28.5":
|
||||||
|
version "7.28.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.28.5.tgz#f3e07a10be37ed7a63461c63e6929575945a6150"
|
||||||
|
integrity sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/traverse" "^7.28.5"
|
||||||
|
"@babel/types" "^7.28.5"
|
||||||
|
|
||||||
"@babel/helper-module-imports@^7.28.6":
|
"@babel/helper-module-imports@^7.28.6":
|
||||||
version "7.28.6"
|
version "7.28.6"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c"
|
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c"
|
||||||
@@ -86,6 +114,35 @@
|
|||||||
"@babel/helper-validator-identifier" "^7.28.5"
|
"@babel/helper-validator-identifier" "^7.28.5"
|
||||||
"@babel/traverse" "^7.28.6"
|
"@babel/traverse" "^7.28.6"
|
||||||
|
|
||||||
|
"@babel/helper-optimise-call-expression@^7.27.1":
|
||||||
|
version "7.27.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.27.1.tgz#c65221b61a643f3e62705e5dd2b5f115e35f9200"
|
||||||
|
integrity sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.27.1"
|
||||||
|
|
||||||
|
"@babel/helper-plugin-utils@^7.18.6":
|
||||||
|
version "7.28.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8"
|
||||||
|
integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==
|
||||||
|
|
||||||
|
"@babel/helper-replace-supers@^7.28.6":
|
||||||
|
version "7.28.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.28.6.tgz#94aa9a1d7423a00aead3f204f78834ce7d53fe44"
|
||||||
|
integrity sha512-mq8e+laIk94/yFec3DxSjCRD2Z0TAjhVbEJY3UQrlwVo15Lmt7C2wAUbK4bjnTs4APkwsYLTahXRraQXhb1WCg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-member-expression-to-functions" "^7.28.5"
|
||||||
|
"@babel/helper-optimise-call-expression" "^7.27.1"
|
||||||
|
"@babel/traverse" "^7.28.6"
|
||||||
|
|
||||||
|
"@babel/helper-skip-transparent-expression-wrappers@^7.27.1":
|
||||||
|
version "7.27.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.27.1.tgz#62bb91b3abba8c7f1fec0252d9dbea11b3ee7a56"
|
||||||
|
integrity sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==
|
||||||
|
dependencies:
|
||||||
|
"@babel/traverse" "^7.27.1"
|
||||||
|
"@babel/types" "^7.27.1"
|
||||||
|
|
||||||
"@babel/helper-string-parser@^7.27.1":
|
"@babel/helper-string-parser@^7.27.1":
|
||||||
version "7.27.1"
|
version "7.27.1"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
|
resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687"
|
||||||
@@ -116,6 +173,14 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@babel/types" "^7.29.0"
|
"@babel/types" "^7.29.0"
|
||||||
|
|
||||||
|
"@babel/plugin-proposal-private-methods@^7.18.6":
|
||||||
|
version "7.18.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea"
|
||||||
|
integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA==
|
||||||
|
dependencies:
|
||||||
|
"@babel/helper-create-class-features-plugin" "^7.18.6"
|
||||||
|
"@babel/helper-plugin-utils" "^7.18.6"
|
||||||
|
|
||||||
"@babel/runtime@^7.29.2":
|
"@babel/runtime@^7.29.2":
|
||||||
version "7.29.2"
|
version "7.29.2"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.2.tgz#9a6e2d05f4b6692e1801cd4fb176ad823930ed5e"
|
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.29.2.tgz#9a6e2d05f4b6692e1801cd4fb176ad823930ed5e"
|
||||||
@@ -130,7 +195,7 @@
|
|||||||
"@babel/parser" "^7.28.6"
|
"@babel/parser" "^7.28.6"
|
||||||
"@babel/types" "^7.28.6"
|
"@babel/types" "^7.28.6"
|
||||||
|
|
||||||
"@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0":
|
"@babel/traverse@^7.27.1", "@babel/traverse@^7.28.5", "@babel/traverse@^7.28.6", "@babel/traverse@^7.29.0":
|
||||||
version "7.29.0"
|
version "7.29.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a"
|
resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.0.tgz#f323d05001440253eead3c9c858adbe00b90310a"
|
||||||
integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==
|
integrity sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==
|
||||||
@@ -143,7 +208,7 @@
|
|||||||
"@babel/types" "^7.29.0"
|
"@babel/types" "^7.29.0"
|
||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
|
|
||||||
"@babel/types@^7.28.6", "@babel/types@^7.29.0":
|
"@babel/types@^7.26.0", "@babel/types@^7.27.1", "@babel/types@^7.27.3", "@babel/types@^7.28.5", "@babel/types@^7.28.6", "@babel/types@^7.29.0":
|
||||||
version "7.29.0"
|
version "7.29.0"
|
||||||
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7"
|
resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.0.tgz#9f5b1e838c446e72cf3cd4b918152b8c605e37c7"
|
||||||
integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==
|
integrity sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==
|
||||||
@@ -1121,6 +1186,13 @@ available-typed-arrays@^1.0.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
|
|
||||||
|
babel-plugin-react-compiler@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz#bdf7360a23a4d5ebfca090255da3893efd07425f"
|
||||||
|
integrity sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/types" "^7.26.0"
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||||
@@ -1482,6 +1554,18 @@ escape-string-regexp@^4.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34"
|
||||||
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==
|
||||||
|
|
||||||
|
eslint-plugin-react-compiler@19.1.0-rc.2:
|
||||||
|
version "19.1.0-rc.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-compiler/-/eslint-plugin-react-compiler-19.1.0-rc.2.tgz#83343e7422e00fa61e729af8e8468f0ddec37925"
|
||||||
|
integrity sha512-oKalwDGcD+RX9mf3NEO4zOoUMeLvjSvcbbEOpquzmzqEEM2MQdp7/FY/Hx9NzmUwFzH1W9SKTz5fihfMldpEYw==
|
||||||
|
dependencies:
|
||||||
|
"@babel/core" "^7.24.4"
|
||||||
|
"@babel/parser" "^7.24.4"
|
||||||
|
"@babel/plugin-proposal-private-methods" "^7.18.6"
|
||||||
|
hermes-parser "^0.25.1"
|
||||||
|
zod "^3.22.4"
|
||||||
|
zod-validation-error "^3.0.3"
|
||||||
|
|
||||||
eslint-plugin-react-hooks@^7.1.1:
|
eslint-plugin-react-hooks@^7.1.1:
|
||||||
version "7.1.1"
|
version "7.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz#e6742cad75d970c0a3f30d7d3fa80a4784f55927"
|
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.1.1.tgz#e6742cad75d970c0a3f30d7d3fa80a4784f55927"
|
||||||
@@ -2464,6 +2548,11 @@ react-dom@^19.2.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
scheduler "^0.27.0"
|
scheduler "^0.27.0"
|
||||||
|
|
||||||
|
react-error-boundary@^6.1.1:
|
||||||
|
version "6.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-error-boundary/-/react-error-boundary-6.1.1.tgz#491d655e86c32434ede852755bb649119fdddd89"
|
||||||
|
integrity sha512-BrYwPOdXi5mqkk5lw+Uvt0ThHx32rCt3BkukS4X23A2AIWDPSGX6iaWTc0y9TU/mHDA/6qOSGel+B2ERkOvD1w==
|
||||||
|
|
||||||
react-fast-compare@^3.0.1:
|
react-fast-compare@^3.0.1:
|
||||||
version "3.2.2"
|
version "3.2.2"
|
||||||
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
|
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.2.tgz#929a97a532304ce9fee4bcae44234f1ce2c21d49"
|
||||||
@@ -3041,11 +3130,21 @@ yocto-queue@^0.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
|
||||||
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==
|
||||||
|
|
||||||
|
zod-validation-error@^3.0.3:
|
||||||
|
version "3.5.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-3.5.4.tgz#9072f829e4b45b9e27317c3002408c0c4cdd2bb4"
|
||||||
|
integrity sha512-+hEiRIiPobgyuFlEojnqjJnhFvg4r/i3cqgcm67eehZf/WBaK3g6cD02YU9mtdVxZjv8CzCA9n/Rhrs3yAAvAw==
|
||||||
|
|
||||||
"zod-validation-error@^3.5.0 || ^4.0.0":
|
"zod-validation-error@^3.5.0 || ^4.0.0":
|
||||||
version "4.0.2"
|
version "4.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918"
|
resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918"
|
||||||
integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==
|
integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==
|
||||||
|
|
||||||
|
zod@^3.22.4:
|
||||||
|
version "3.25.76"
|
||||||
|
resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34"
|
||||||
|
integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==
|
||||||
|
|
||||||
"zod@^3.25.0 || ^4.0.0":
|
"zod@^3.25.0 || ^4.0.0":
|
||||||
version "4.4.3"
|
version "4.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/zod/-/zod-4.4.3.tgz#b680f172885d18bbebf21a834ea25e55a1bbf356"
|
resolved "https://registry.yarnpkg.com/zod/-/zod-4.4.3.tgz#b680f172885d18bbebf21a834ea25e55a1bbf356"
|
||||||
|
|||||||
Reference in New Issue
Block a user