hightjs 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.idea/HightJS.iml +9 -0
- package/.idea/copilot.data.migration.agent.xml +6 -0
- package/.idea/copilot.data.migration.ask.xml +6 -0
- package/.idea/copilot.data.migration.ask2agent.xml +6 -0
- package/.idea/copilot.data.migration.edit.xml +6 -0
- package/.idea/inspectionProfiles/Project_Default.xml +13 -0
- package/.idea/libraries/test_package.xml +9 -0
- package/.idea/libraries/ts_commonjs_default_export.xml +9 -0
- package/.idea/misc.xml +7 -0
- package/.idea/modules.xml +8 -0
- package/.idea/vcs.xml +6 -0
- package/LICENSE +13 -0
- package/README.md +508 -0
- package/dist/adapters/express.d.ts +7 -0
- package/dist/adapters/express.js +63 -0
- package/dist/adapters/factory.d.ts +23 -0
- package/dist/adapters/factory.js +122 -0
- package/dist/adapters/fastify.d.ts +25 -0
- package/dist/adapters/fastify.js +61 -0
- package/dist/adapters/native.d.ts +8 -0
- package/dist/adapters/native.js +203 -0
- package/dist/adapters/starters/express.d.ts +0 -0
- package/dist/adapters/starters/express.js +1 -0
- package/dist/adapters/starters/factory.d.ts +0 -0
- package/dist/adapters/starters/factory.js +1 -0
- package/dist/adapters/starters/fastify.d.ts +0 -0
- package/dist/adapters/starters/fastify.js +1 -0
- package/dist/adapters/starters/index.d.ts +0 -0
- package/dist/adapters/starters/index.js +1 -0
- package/dist/adapters/starters/native.d.ts +0 -0
- package/dist/adapters/starters/native.js +1 -0
- package/dist/api/console.d.ts +92 -0
- package/dist/api/console.js +276 -0
- package/dist/api/http.d.ts +180 -0
- package/dist/api/http.js +467 -0
- package/dist/auth/client.d.ts +14 -0
- package/dist/auth/client.js +68 -0
- package/dist/auth/components.d.ts +29 -0
- package/dist/auth/components.js +84 -0
- package/dist/auth/core.d.ts +38 -0
- package/dist/auth/core.js +124 -0
- package/dist/auth/index.d.ts +7 -0
- package/dist/auth/index.js +27 -0
- package/dist/auth/jwt.d.ts +41 -0
- package/dist/auth/jwt.js +169 -0
- package/dist/auth/providers.d.ts +5 -0
- package/dist/auth/providers.js +14 -0
- package/dist/auth/react/index.d.ts +6 -0
- package/dist/auth/react/index.js +32 -0
- package/dist/auth/react.d.ts +22 -0
- package/dist/auth/react.js +175 -0
- package/dist/auth/routes.d.ts +16 -0
- package/dist/auth/routes.js +104 -0
- package/dist/auth/types.d.ts +62 -0
- package/dist/auth/types.js +2 -0
- package/dist/bin/hightjs.d.ts +2 -0
- package/dist/bin/hightjs.js +35 -0
- package/dist/builder.d.ts +32 -0
- package/dist/builder.js +341 -0
- package/dist/client/DefaultNotFound.d.ts +1 -0
- package/dist/client/DefaultNotFound.js +53 -0
- package/dist/client/ErrorBoundary.d.ts +16 -0
- package/dist/client/ErrorBoundary.js +181 -0
- package/dist/client/clientRouter.d.ts +58 -0
- package/dist/client/clientRouter.js +116 -0
- package/dist/client/entry.client.d.ts +1 -0
- package/dist/client/entry.client.js +271 -0
- package/dist/client/routerContext.d.ts +26 -0
- package/dist/client/routerContext.js +62 -0
- package/dist/client.d.ts +3 -0
- package/dist/client.js +8 -0
- package/dist/components/Link.d.ts +7 -0
- package/dist/components/Link.js +13 -0
- package/dist/eslint/index.d.ts +32 -0
- package/dist/eslint/index.js +15 -0
- package/dist/eslint/use-client-rule.d.ts +19 -0
- package/dist/eslint/use-client-rule.js +99 -0
- package/dist/eslintSetup.d.ts +0 -0
- package/dist/eslintSetup.js +1 -0
- package/dist/example/src/web/routes/index.d.ts +3 -0
- package/dist/example/src/web/routes/index.js +15 -0
- package/dist/helpers.d.ts +18 -0
- package/dist/helpers.js +318 -0
- package/dist/hotReload.d.ts +23 -0
- package/dist/hotReload.js +292 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +480 -0
- package/dist/renderer.d.ts +14 -0
- package/dist/renderer.js +106 -0
- package/dist/router.d.ts +78 -0
- package/dist/router.js +359 -0
- package/dist/types/framework.d.ts +37 -0
- package/dist/types/framework.js +2 -0
- package/dist/types.d.ts +43 -0
- package/dist/types.js +2 -0
- package/dist/typescript/use-client-plugin.d.ts +5 -0
- package/dist/typescript/use-client-plugin.js +113 -0
- package/dist/validation.d.ts +0 -0
- package/dist/validation.js +1 -0
- package/package.json +72 -0
- package/src/adapters/express.ts +70 -0
- package/src/adapters/factory.ts +96 -0
- package/src/adapters/fastify.ts +88 -0
- package/src/adapters/native.ts +223 -0
- package/src/api/console.ts +285 -0
- package/src/api/http.ts +515 -0
- package/src/auth/client.ts +74 -0
- package/src/auth/components.tsx +109 -0
- package/src/auth/core.ts +143 -0
- package/src/auth/index.ts +9 -0
- package/src/auth/jwt.ts +194 -0
- package/src/auth/providers.ts +13 -0
- package/src/auth/react/index.ts +9 -0
- package/src/auth/react.tsx +209 -0
- package/src/auth/routes.ts +133 -0
- package/src/auth/types.ts +73 -0
- package/src/bin/hightjs.js +40 -0
- package/src/builder.js +362 -0
- package/src/client/DefaultNotFound.tsx +68 -0
- package/src/client/clientRouter.ts +137 -0
- package/src/client/entry.client.tsx +302 -0
- package/src/client.ts +8 -0
- package/src/components/Link.tsx +22 -0
- package/src/helpers.ts +316 -0
- package/src/hotReload.ts +289 -0
- package/src/index.ts +514 -0
- package/src/renderer.tsx +122 -0
- package/src/router.ts +400 -0
- package/src/types/framework.ts +42 -0
- package/src/types.ts +54 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
// Sistema de roteamento do lado do cliente para hweb-sdk
|
|
2
|
+
|
|
3
|
+
export interface RouterEvents {
|
|
4
|
+
beforeNavigate?: (url: string) => boolean | Promise<boolean>;
|
|
5
|
+
afterNavigate?: (url: string) => void;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
class Router {
|
|
9
|
+
private events: RouterEvents = {};
|
|
10
|
+
private listeners: Set<() => void> = new Set();
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Navega para uma nova rota
|
|
14
|
+
*/
|
|
15
|
+
async push(url: string): Promise<void> {
|
|
16
|
+
// Callback antes de navegar
|
|
17
|
+
if (this.events.beforeNavigate) {
|
|
18
|
+
const shouldProceed = await this.events.beforeNavigate(url);
|
|
19
|
+
if (shouldProceed === false) return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Atualiza a URL na barra de endereço
|
|
23
|
+
window.history.pushState({ path: url }, '', url);
|
|
24
|
+
|
|
25
|
+
// Dispara evento para o roteador capturar de forma assíncrona
|
|
26
|
+
setTimeout(() => this.triggerNavigation(), 0);
|
|
27
|
+
|
|
28
|
+
// Callback após navegar
|
|
29
|
+
if (this.events.afterNavigate) {
|
|
30
|
+
this.events.afterNavigate(url);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Substitui a entrada atual do histórico
|
|
36
|
+
*/
|
|
37
|
+
async replace(url: string): Promise<void> {
|
|
38
|
+
// Callback antes de navegar
|
|
39
|
+
if (this.events.beforeNavigate) {
|
|
40
|
+
const shouldProceed = await this.events.beforeNavigate(url);
|
|
41
|
+
if (shouldProceed === false) return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Substitui a URL atual no histórico
|
|
45
|
+
window.history.replaceState({ path: url }, '', url);
|
|
46
|
+
|
|
47
|
+
// Dispara evento para o roteador capturar de forma assíncrona
|
|
48
|
+
setTimeout(() => this.triggerNavigation(), 0);
|
|
49
|
+
|
|
50
|
+
// Callback após navegar
|
|
51
|
+
if (this.events.afterNavigate) {
|
|
52
|
+
this.events.afterNavigate(url);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Volta uma página no histórico
|
|
58
|
+
*/
|
|
59
|
+
back(): void {
|
|
60
|
+
window.history.back();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Avança uma página no histórico
|
|
65
|
+
*/
|
|
66
|
+
forward(): void {
|
|
67
|
+
window.history.forward();
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Recarrega a página atual (re-renderiza o componente)
|
|
72
|
+
*/
|
|
73
|
+
refresh(): void {
|
|
74
|
+
setTimeout(() => this.triggerNavigation(), 0);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Obtém a URL atual
|
|
79
|
+
*/
|
|
80
|
+
get pathname(): string {
|
|
81
|
+
return window.location.pathname;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Obtém os query parameters atuais
|
|
86
|
+
*/
|
|
87
|
+
get query(): URLSearchParams {
|
|
88
|
+
return new URLSearchParams(window.location.search);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Obtém a URL completa atual
|
|
93
|
+
*/
|
|
94
|
+
get url(): string {
|
|
95
|
+
return window.location.href;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Adiciona event listeners para eventos de roteamento
|
|
100
|
+
*/
|
|
101
|
+
on(events: RouterEvents): void {
|
|
102
|
+
this.events = { ...this.events, ...events };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Remove event listeners
|
|
107
|
+
*/
|
|
108
|
+
off(): void {
|
|
109
|
+
this.events = {};
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Adiciona um listener para mudanças de rota
|
|
114
|
+
*/
|
|
115
|
+
subscribe(listener: () => void): () => void {
|
|
116
|
+
this.listeners.add(listener);
|
|
117
|
+
return () => this.listeners.delete(listener);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Dispara evento de navegação para todos os listeners
|
|
122
|
+
*/
|
|
123
|
+
private triggerNavigation(): void {
|
|
124
|
+
// Dispara o evento nativo para o roteador do hweb capturar
|
|
125
|
+
window.dispatchEvent(new PopStateEvent('popstate'));
|
|
126
|
+
|
|
127
|
+
// Notifica todos os listeners customizados
|
|
128
|
+
this.listeners.forEach(listener => listener());
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Instância singleton do router
|
|
134
|
+
export const router = new Router();
|
|
135
|
+
|
|
136
|
+
// Para compatibilidade, também exporta como default
|
|
137
|
+
export default router;
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import React, {useState, useEffect, useCallback, useRef} from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
3
|
+
import { router } from './clientRouter';
|
|
4
|
+
|
|
5
|
+
// --- O Componente Principal do Cliente (Roteador) ---
|
|
6
|
+
|
|
7
|
+
interface AppProps {
|
|
8
|
+
componentMap: Record<string, any>;
|
|
9
|
+
routes: { pattern: string; componentPath: string }[];
|
|
10
|
+
initialComponentPath: string;
|
|
11
|
+
initialParams: any;
|
|
12
|
+
layoutComponent?: any;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function App({ componentMap, routes, initialComponentPath, initialParams, layoutComponent }: AppProps) {
|
|
16
|
+
// Estado que guarda o componente a ser renderizado atualmente
|
|
17
|
+
|
|
18
|
+
const [CurrentPageComponent, setCurrentPageComponent] = useState(() => {
|
|
19
|
+
// Se for a rota especial __404__, não busca no componentMap
|
|
20
|
+
if (initialComponentPath === '__404__') {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
return componentMap[initialComponentPath];
|
|
24
|
+
});
|
|
25
|
+
const [params, setParams] = useState(initialParams);
|
|
26
|
+
|
|
27
|
+
const findRouteForPath = useCallback((path: string) => {
|
|
28
|
+
for (const route of routes) {
|
|
29
|
+
const regexPattern = route.pattern.replace(/\[(\w+)\]/g, '(?<$1>[^/]+)');
|
|
30
|
+
const regex = new RegExp(`^${regexPattern}/?$`);
|
|
31
|
+
const match = path.match(regex);
|
|
32
|
+
if (match) {
|
|
33
|
+
return {
|
|
34
|
+
componentPath: route.componentPath,
|
|
35
|
+
params: match.groups || {}
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return null;
|
|
40
|
+
}, [routes]);
|
|
41
|
+
|
|
42
|
+
const updateRoute = useCallback(() => {
|
|
43
|
+
const currentPath = router.pathname;
|
|
44
|
+
const match = findRouteForPath(currentPath);
|
|
45
|
+
if (match) {
|
|
46
|
+
setCurrentPageComponent(() => componentMap[match.componentPath]);
|
|
47
|
+
setParams(match.params);
|
|
48
|
+
} else {
|
|
49
|
+
// Se não encontrou rota, define como null para mostrar 404
|
|
50
|
+
setCurrentPageComponent(null);
|
|
51
|
+
setParams({});
|
|
52
|
+
}
|
|
53
|
+
}, [router.pathname, findRouteForPath, componentMap]);
|
|
54
|
+
|
|
55
|
+
// Ouve os eventos de "voltar" e "avançar" do navegador
|
|
56
|
+
useEffect(() => {
|
|
57
|
+
const handlePopState = () => {
|
|
58
|
+
updateRoute();
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
window.addEventListener('popstate', handlePopState);
|
|
62
|
+
|
|
63
|
+
// Também se inscreve no router para mudanças de rota
|
|
64
|
+
const unsubscribe = router.subscribe(updateRoute);
|
|
65
|
+
|
|
66
|
+
return () => {
|
|
67
|
+
window.removeEventListener('popstate', handlePopState);
|
|
68
|
+
unsubscribe();
|
|
69
|
+
};
|
|
70
|
+
}, [updateRoute]);
|
|
71
|
+
|
|
72
|
+
// Se não há componente ou é a rota __404__, mostra página 404
|
|
73
|
+
if (!CurrentPageComponent || initialComponentPath === '__404__') {
|
|
74
|
+
// Usa o componente 404 personalizado se existir, senão usa o padrão do hweb
|
|
75
|
+
const NotFoundComponent = (window as any).__HWEB_NOT_FOUND__;
|
|
76
|
+
|
|
77
|
+
if (NotFoundComponent) {
|
|
78
|
+
// Usa o notFound.tsx personalizado do usuário
|
|
79
|
+
const NotFoundContent = <NotFoundComponent />;
|
|
80
|
+
|
|
81
|
+
// Aplica o layout se existir
|
|
82
|
+
if (layoutComponent) {
|
|
83
|
+
return React.createElement(layoutComponent, { children: NotFoundContent });
|
|
84
|
+
}
|
|
85
|
+
return NotFoundContent;
|
|
86
|
+
} else {
|
|
87
|
+
// Usa o 404 padrão do hweb que foi incluído no build
|
|
88
|
+
const DefaultNotFound = (window as any).__HWEB_DEFAULT_NOT_FOUND__;
|
|
89
|
+
const NotFoundContent = <DefaultNotFound />;
|
|
90
|
+
|
|
91
|
+
// Aplica o layout se existir
|
|
92
|
+
if (layoutComponent) {
|
|
93
|
+
return React.createElement(layoutComponent, { children: NotFoundContent });
|
|
94
|
+
}
|
|
95
|
+
return NotFoundContent;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Renderiza o componente atual (sem Context, usa o router diretamente)
|
|
100
|
+
const PageContent = <CurrentPageComponent params={params} />;
|
|
101
|
+
|
|
102
|
+
// SEMPRE usa o layout - se não existir, cria um wrapper padrão
|
|
103
|
+
const content = layoutComponent
|
|
104
|
+
? React.createElement(layoutComponent, { children: PageContent })
|
|
105
|
+
: <div>{PageContent}</div>;
|
|
106
|
+
|
|
107
|
+
// Adiciona o indicador de dev se não for produção
|
|
108
|
+
return (
|
|
109
|
+
<>
|
|
110
|
+
{content}
|
|
111
|
+
{process.env.NODE_ENV !== 'production' && <DevIndicator />}
|
|
112
|
+
</>
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
// --- Constantes de Configuração ---
|
|
119
|
+
const DEV_INDICATOR_SIZE = 48;
|
|
120
|
+
const DEV_INDICATOR_CORNERS = [
|
|
121
|
+
{ top: 16, left: 16 }, // 0: topo-esquerda
|
|
122
|
+
{ top: 16, right: 16 }, // 1: topo-direita
|
|
123
|
+
{ bottom: 16, left: 16 }, // 2: baixo-esquerda
|
|
124
|
+
{ bottom: 16, right: 16 },// 3: baixo-direita
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
function DevIndicator() {
|
|
128
|
+
const [corner, setCorner] = useState(3); // Canto atual (0-3)
|
|
129
|
+
const [isDragging, setIsDragging] = useState(false); // Estado de arrastar
|
|
130
|
+
|
|
131
|
+
// Posição visual do indicador durante o arraste
|
|
132
|
+
const [position, setPosition] = useState<{ top: number; left: number }>({ top: 0, left: 0 });
|
|
133
|
+
|
|
134
|
+
const indicatorRef = useRef<HTMLDivElement>(null);
|
|
135
|
+
const dragStartRef = useRef<{ x: number; y: number; moved: boolean } | null>(null);
|
|
136
|
+
|
|
137
|
+
// --- Estilos Dinâmicos ---
|
|
138
|
+
const getIndicatorStyle = (): React.CSSProperties => {
|
|
139
|
+
const baseStyle: React.CSSProperties = {
|
|
140
|
+
position: 'fixed',
|
|
141
|
+
zIndex: 9999,
|
|
142
|
+
width: DEV_INDICATOR_SIZE,
|
|
143
|
+
height: DEV_INDICATOR_SIZE,
|
|
144
|
+
borderRadius: '50%',
|
|
145
|
+
background: 'linear-gradient(135deg, #8e2de2, #4a00e0)', // Gradiente Roxo
|
|
146
|
+
color: 'white',
|
|
147
|
+
fontWeight: 'bold',
|
|
148
|
+
fontSize: 28,
|
|
149
|
+
boxShadow: '0 4px 15px rgba(0,0,0,0.2)',
|
|
150
|
+
display: 'flex',
|
|
151
|
+
alignItems: 'center',
|
|
152
|
+
justifyContent: 'center',
|
|
153
|
+
cursor: isDragging ? 'grabbing' : 'grab',
|
|
154
|
+
userSelect: 'none',
|
|
155
|
+
transition: isDragging ? 'none' : 'all 0.3s ease-out', // Animação suave ao soltar
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (isDragging) {
|
|
159
|
+
return {
|
|
160
|
+
...baseStyle,
|
|
161
|
+
top: position.top,
|
|
162
|
+
left: position.left,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return { ...baseStyle, ...DEV_INDICATOR_CORNERS[corner] };
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const getMenuPositionStyle = (): React.CSSProperties => {
|
|
170
|
+
// Posiciona o menu dependendo do canto
|
|
171
|
+
switch (corner) {
|
|
172
|
+
case 0: return { top: '110%', left: '0' }; // Top-Left
|
|
173
|
+
case 1: return { top: '110%', right: '0' }; // Top-Right
|
|
174
|
+
case 2: return { bottom: '110%', left: '0' }; // Bottom-Left
|
|
175
|
+
case 3: return { bottom: '110%', right: '0' }; // Bottom-Right
|
|
176
|
+
default: return {};
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// --- Lógica de Eventos ---
|
|
181
|
+
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
|
182
|
+
e.preventDefault();
|
|
183
|
+
dragStartRef.current = { x: e.clientX, y: e.clientY, moved: false };
|
|
184
|
+
if (indicatorRef.current) {
|
|
185
|
+
const rect = indicatorRef.current.getBoundingClientRect();
|
|
186
|
+
setPosition({ top: rect.top, left: rect.left });
|
|
187
|
+
}
|
|
188
|
+
setIsDragging(true);
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const handleMouseMove = useCallback((e: MouseEvent) => {
|
|
192
|
+
if (!isDragging || !dragStartRef.current) return;
|
|
193
|
+
|
|
194
|
+
const deltaX = e.clientX - dragStartRef.current.x;
|
|
195
|
+
const deltaY = e.clientY - dragStartRef.current.y;
|
|
196
|
+
|
|
197
|
+
// Diferencia clique de arrastar (threshold de 5px)
|
|
198
|
+
if (!dragStartRef.current.moved && Math.hypot(deltaX, deltaY) > 5) {
|
|
199
|
+
dragStartRef.current.moved = true;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (dragStartRef.current.moved) {
|
|
203
|
+
setPosition(prevPos => ({
|
|
204
|
+
top: prevPos.top + deltaY,
|
|
205
|
+
left: prevPos.left + deltaX,
|
|
206
|
+
}));
|
|
207
|
+
// Atualiza a referência para o próximo movimento
|
|
208
|
+
dragStartRef.current.x = e.clientX;
|
|
209
|
+
dragStartRef.current.y = e.clientY;
|
|
210
|
+
}
|
|
211
|
+
}, [isDragging]);
|
|
212
|
+
|
|
213
|
+
const handleMouseUp = useCallback((e: MouseEvent) => {
|
|
214
|
+
if (!isDragging) return;
|
|
215
|
+
setIsDragging(false);
|
|
216
|
+
|
|
217
|
+
// Se moveu, calcula o canto mais próximo
|
|
218
|
+
if (dragStartRef.current?.moved) {
|
|
219
|
+
const { clientX, clientY } = e;
|
|
220
|
+
const w = window.innerWidth;
|
|
221
|
+
const h = window.innerHeight;
|
|
222
|
+
|
|
223
|
+
const dists = [
|
|
224
|
+
Math.hypot(clientX, clientY), // TL
|
|
225
|
+
Math.hypot(w - clientX, clientY), // TR
|
|
226
|
+
Math.hypot(clientX, h - clientY), // BL
|
|
227
|
+
Math.hypot(w - clientX, h - clientY), // BR
|
|
228
|
+
];
|
|
229
|
+
setCorner(dists.indexOf(Math.min(...dists)));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
dragStartRef.current = null;
|
|
233
|
+
}, [isDragging]);
|
|
234
|
+
|
|
235
|
+
// Adiciona e remove listeners globais
|
|
236
|
+
useEffect(() => {
|
|
237
|
+
if (isDragging) {
|
|
238
|
+
window.addEventListener('mousemove', handleMouseMove);
|
|
239
|
+
window.addEventListener('mouseup', handleMouseUp);
|
|
240
|
+
}
|
|
241
|
+
return () => {
|
|
242
|
+
window.removeEventListener('mousemove', handleMouseMove);
|
|
243
|
+
window.removeEventListener('mouseup', handleMouseUp);
|
|
244
|
+
};
|
|
245
|
+
}, [isDragging, handleMouseMove, handleMouseUp]);
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
return (
|
|
249
|
+
<div ref={indicatorRef} style={getIndicatorStyle()} onMouseDown={handleMouseDown} title="Modo Dev HightJS">
|
|
250
|
+
H
|
|
251
|
+
</div>
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// --- Inicialização do Cliente (CSR - Client-Side Rendering) ---
|
|
256
|
+
|
|
257
|
+
function initializeClient() {
|
|
258
|
+
const initialData = (window as any).__HWEB_INITIAL_DATA__;
|
|
259
|
+
|
|
260
|
+
if (!initialData) {
|
|
261
|
+
console.error('[hweb] Dados iniciais não encontrados na página.');
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Cria o mapa de componentes dinamicamente a partir dos módulos carregados
|
|
266
|
+
const componentMap: Record<string, any> = {};
|
|
267
|
+
|
|
268
|
+
// Registra todos os componentes que foram importados
|
|
269
|
+
if ((window as any).__HWEB_COMPONENTS__) {
|
|
270
|
+
Object.assign(componentMap, (window as any).__HWEB_COMPONENTS__);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const container = document.getElementById('root');
|
|
274
|
+
if (!container) {
|
|
275
|
+
console.error('[hweb] Container #root não encontrado.');
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
try {
|
|
280
|
+
// Usar createRoot para render inicial (CSR)
|
|
281
|
+
const root = createRoot(container);
|
|
282
|
+
|
|
283
|
+
root.render(
|
|
284
|
+
<App
|
|
285
|
+
componentMap={componentMap}
|
|
286
|
+
routes={initialData.routes}
|
|
287
|
+
initialComponentPath={initialData.initialComponentPath}
|
|
288
|
+
initialParams={initialData.initialParams}
|
|
289
|
+
layoutComponent={(window as any).__HWEB_LAYOUT__}
|
|
290
|
+
/>
|
|
291
|
+
);
|
|
292
|
+
} catch (error) {
|
|
293
|
+
console.error('[hweb] Erro ao renderizar aplicação:', error);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Executa quando o DOM estiver pronto
|
|
298
|
+
if (document.readyState === 'loading') {
|
|
299
|
+
document.addEventListener('DOMContentLoaded', initializeClient);
|
|
300
|
+
} else {
|
|
301
|
+
initializeClient();
|
|
302
|
+
}
|
package/src/client.ts
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import React, { type AnchorHTMLAttributes, type ReactNode } from 'react';
|
|
2
|
+
import { router } from '../client/clientRouter';
|
|
3
|
+
|
|
4
|
+
interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
|
|
5
|
+
href: string;
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function Link({ href, children, ...props }: LinkProps) {
|
|
10
|
+
const handleClick = async (e: React.MouseEvent<HTMLAnchorElement>) => {
|
|
11
|
+
e.preventDefault();
|
|
12
|
+
|
|
13
|
+
// Usa o novo sistema de router
|
|
14
|
+
await router.push(href);
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<a href={href} {...props} onClick={handleClick}>
|
|
19
|
+
{children}
|
|
20
|
+
</a>
|
|
21
|
+
);
|
|
22
|
+
}
|