create-fluxstack 1.14.0 → 1.16.0

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.
Files changed (76) hide show
  1. package/LLMD/INDEX.md +4 -3
  2. package/LLMD/resources/live-binary-delta.md +507 -0
  3. package/LLMD/resources/live-components.md +208 -12
  4. package/LLMD/resources/live-rooms.md +731 -333
  5. package/app/client/.live-stubs/LiveAdminPanel.js +5 -0
  6. package/app/client/.live-stubs/LiveCounter.js +9 -0
  7. package/app/client/.live-stubs/LiveForm.js +11 -0
  8. package/app/client/.live-stubs/LiveLocalCounter.js +8 -0
  9. package/app/client/.live-stubs/LivePingPong.js +10 -0
  10. package/app/client/.live-stubs/LiveRoomChat.js +11 -0
  11. package/app/client/.live-stubs/LiveSharedCounter.js +10 -0
  12. package/app/client/.live-stubs/LiveUpload.js +15 -0
  13. package/app/client/src/App.tsx +19 -7
  14. package/app/client/src/components/AppLayout.tsx +18 -10
  15. package/app/client/src/live/PingPongDemo.tsx +199 -0
  16. package/app/client/src/live/RoomChatDemo.tsx +187 -22
  17. package/app/client/src/live/SharedCounterDemo.tsx +142 -0
  18. package/app/server/auth/DevAuthProvider.ts +2 -2
  19. package/app/server/auth/JWTAuthProvider.example.ts +2 -2
  20. package/app/server/index.ts +2 -2
  21. package/app/server/live/LiveAdminPanel.ts +1 -1
  22. package/app/server/live/LivePingPong.ts +61 -0
  23. package/app/server/live/LiveProtectedChat.ts +1 -1
  24. package/app/server/live/LiveRoomChat.ts +106 -38
  25. package/app/server/live/LiveSharedCounter.ts +73 -0
  26. package/app/server/live/rooms/ChatRoom.ts +68 -0
  27. package/app/server/live/rooms/CounterRoom.ts +51 -0
  28. package/app/server/live/rooms/DirectoryRoom.ts +42 -0
  29. package/app/server/live/rooms/PingRoom.ts +40 -0
  30. package/app/server/routes/room.routes.ts +1 -2
  31. package/core/build/live-components-generator.ts +11 -2
  32. package/core/build/vite-plugins.ts +28 -0
  33. package/core/client/hooks/useLiveUpload.ts +3 -4
  34. package/core/client/index.ts +25 -35
  35. package/core/framework/server.ts +1 -1
  36. package/core/server/index.ts +1 -2
  37. package/core/server/live/auto-generated-components.ts +5 -8
  38. package/core/server/live/index.ts +90 -21
  39. package/core/server/live/websocket-plugin.ts +54 -1079
  40. package/core/types/types.ts +76 -1025
  41. package/core/utils/version.ts +1 -1
  42. package/create-fluxstack.ts +1 -1
  43. package/package.json +100 -95
  44. package/plugins/crypto-auth/index.ts +1 -1
  45. package/plugins/crypto-auth/server/CryptoAuthLiveProvider.ts +2 -2
  46. package/tsconfig.json +4 -1
  47. package/vite.config.ts +40 -12
  48. package/app/client/src/live/ChatDemo.tsx +0 -107
  49. package/app/client/src/live/LiveDebuggerPanel.tsx +0 -779
  50. package/app/server/live/LiveChat.ts +0 -78
  51. package/core/client/LiveComponentsProvider.tsx +0 -531
  52. package/core/client/components/Live.tsx +0 -111
  53. package/core/client/components/LiveDebugger.tsx +0 -1324
  54. package/core/client/hooks/AdaptiveChunkSizer.ts +0 -215
  55. package/core/client/hooks/state-validator.ts +0 -130
  56. package/core/client/hooks/useChunkedUpload.ts +0 -359
  57. package/core/client/hooks/useLiveChunkedUpload.ts +0 -87
  58. package/core/client/hooks/useLiveComponent.ts +0 -853
  59. package/core/client/hooks/useLiveDebugger.ts +0 -392
  60. package/core/client/hooks/useRoom.ts +0 -409
  61. package/core/client/hooks/useRoomProxy.ts +0 -382
  62. package/core/server/live/ComponentRegistry.ts +0 -1128
  63. package/core/server/live/FileUploadManager.ts +0 -446
  64. package/core/server/live/LiveComponentPerformanceMonitor.ts +0 -931
  65. package/core/server/live/LiveDebugger.ts +0 -462
  66. package/core/server/live/LiveLogger.ts +0 -144
  67. package/core/server/live/LiveRoomManager.ts +0 -278
  68. package/core/server/live/RoomEventBus.ts +0 -234
  69. package/core/server/live/RoomStateManager.ts +0 -172
  70. package/core/server/live/SingleConnectionManager.ts +0 -0
  71. package/core/server/live/StateSignature.ts +0 -705
  72. package/core/server/live/WebSocketConnectionManager.ts +0 -710
  73. package/core/server/live/auth/LiveAuthContext.ts +0 -71
  74. package/core/server/live/auth/LiveAuthManager.ts +0 -304
  75. package/core/server/live/auth/index.ts +0 -19
  76. package/core/server/live/auth/types.ts +0 -179
@@ -3,4 +3,4 @@
3
3
  * Single source of truth for version number
4
4
  * Auto-synced with package.json
5
5
  */
6
- export const FLUXSTACK_VERSION = '1.14.0'
6
+ export const FLUXSTACK_VERSION = '1.16.0'
@@ -344,7 +344,7 @@ bun.lockb
344
344
 
345
345
  // Customize package.json with project name
346
346
  const packageJsonPath = join(projectPath, 'package.json')
347
- const actualProjectName = isCurrentDir ? basename(projectPath) : normalizedName
347
+ const actualProjectName = basename(projectPath)
348
348
 
349
349
  if (existsSync(packageJsonPath)) {
350
350
  const packageContent = readFileSync(packageJsonPath, 'utf-8')
package/package.json CHANGED
@@ -1,95 +1,100 @@
1
- {
2
- "name": "create-fluxstack",
3
- "version": "1.14.0",
4
- "description": "⚡ Revolutionary full-stack TypeScript framework with Declarative Config System, Elysia + React + Bun",
5
- "keywords": [
6
- "framework",
7
- "full-stack",
8
- "typescript",
9
- "elysia",
10
- "react",
11
- "bun",
12
- "vite"
13
- ],
14
- "author": "FluxStack Team",
15
- "license": "MIT",
16
- "homepage": "https://github.com/MarcosBrendonDePaula/FluxStack",
17
- "repository": {
18
- "type": "git",
19
- "url": "git+https://github.com/MarcosBrendonDePaula/FluxStack.git"
20
- },
21
- "module": "app/server/index.ts",
22
- "type": "module",
23
- "bin": {
24
- "create-fluxstack": "create-fluxstack.ts"
25
- },
26
- "scripts": {
27
- "dev": "bun run core/cli/index.ts dev",
28
- "dev:frontend": "bun run core/cli/index.ts dev --frontend-only",
29
- "dev:backend": "bun run core/cli/index.ts dev --backend-only",
30
- "build": "cross-env NODE_ENV=production bun run core/cli/index.ts build",
31
- "build:frontend": "cross-env NODE_ENV=production bun run core/cli/index.ts build --frontend-only",
32
- "build:backend": "cross-env NODE_ENV=production bun run core/cli/index.ts build --backend-only",
33
- "build:exe": "cross-env NODE_ENV=production && bun run core/cli/index.ts build && bun run core/cli/index.ts build:exe",
34
- "start": "NODE_ENV=production bun dist/index.js",
35
- "create": "bun run core/cli/index.ts create",
36
- "cli": "bun run core/cli/index.ts",
37
- "make:component": "bun run core/cli/index.ts make:component",
38
- "sync-version": "bun run core/utils/sync-version.ts",
39
- "test": "vitest",
40
- "test:ui": "vitest --ui",
41
- "test:coverage": "vitest run --coverage",
42
- "typecheck:api": "tsc --noEmit -p tsconfig.api-strict.json"
43
- },
44
- "devDependencies": {
45
- "@eslint/js": "^9.30.1",
46
- "@noble/curves": "1.2.0",
47
- "@noble/hashes": "1.3.2",
48
- "@tailwindcss/vite": "^4.1.13",
49
- "@testing-library/jest-dom": "^6.6.4",
50
- "@testing-library/react": "^16.3.0",
51
- "@testing-library/user-event": "^14.6.1",
52
- "@types/bun": "latest",
53
- "@types/node": "^24.5.2",
54
- "@types/react": "^19.1.8",
55
- "@types/react-dom": "^19.1.6",
56
- "@vitest/coverage-v8": "^3.2.4",
57
- "@vitest/ui": "^3.2.4",
58
- "cross-env": "^10.1.0",
59
- "eslint": "^9.30.1",
60
- "eslint-plugin-react-hooks": "^5.2.0",
61
- "eslint-plugin-react-refresh": "^0.4.20",
62
- "globals": "^16.3.0",
63
- "jsdom": "^26.1.0",
64
- "rollup": "4.20.0",
65
- "tailwindcss": "^4.1.13",
66
- "typescript": "^5.8.3",
67
- "typescript-eslint": "^8.35.1",
68
- "vite-plugin-checker": "^0.12.0",
69
- "vite-tsconfig-paths": "^6.0.5",
70
- "vitest": "^3.2.4"
71
- },
72
- "dependencies": {
73
- "@elysiajs/eden": "^1.3.2",
74
- "@elysiajs/swagger": "^1.3.1",
75
- "@vitejs/plugin-react": "^4.6.0",
76
- "chalk": "^5.3.0",
77
- "commander": "^12.1.0",
78
- "elysia": "^1.4.6",
79
- "lightningcss": "^1.30.1",
80
- "ora": "^8.1.0",
81
- "react": "^19.1.0",
82
- "react-dom": "^19.1.0",
83
- "react-icons": "^5.5.0",
84
- "react-router": "^7.9.3",
85
- "uuid": "^13.0.0",
86
- "vite": "^7.1.7",
87
- "winston": "^3.18.3",
88
- "winston-daily-rotate-file": "^5.0.0",
89
- "zustand": "^5.0.8"
90
- },
91
- "engines": {
92
- "bun": ">=1.2.0"
93
- },
94
- "preferredPackageManager": "bun"
95
- }
1
+ {
2
+ "name": "create-fluxstack",
3
+ "version": "1.16.0",
4
+ "description": "⚡ Revolutionary full-stack TypeScript framework with Declarative Config System, Elysia + React + Bun",
5
+ "keywords": [
6
+ "framework",
7
+ "full-stack",
8
+ "typescript",
9
+ "elysia",
10
+ "react",
11
+ "bun",
12
+ "vite"
13
+ ],
14
+ "author": "FluxStack Team",
15
+ "license": "MIT",
16
+ "homepage": "https://github.com/MarcosBrendonDePaula/FluxStack",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/MarcosBrendonDePaula/FluxStack.git"
20
+ },
21
+ "module": "app/server/index.ts",
22
+ "type": "module",
23
+ "bin": {
24
+ "create-fluxstack": "create-fluxstack.ts"
25
+ },
26
+ "scripts": {
27
+ "dev": "bun run core/cli/index.ts dev",
28
+ "dev:frontend": "bun run core/cli/index.ts dev --frontend-only",
29
+ "dev:backend": "bun run core/cli/index.ts dev --backend-only",
30
+ "build": "cross-env NODE_ENV=production bun run core/cli/index.ts build",
31
+ "build:frontend": "cross-env NODE_ENV=production bun run core/cli/index.ts build --frontend-only",
32
+ "build:backend": "cross-env NODE_ENV=production bun run core/cli/index.ts build --backend-only",
33
+ "build:exe": "cross-env NODE_ENV=production && bun run core/cli/index.ts build && bun run core/cli/index.ts build:exe",
34
+ "start": "NODE_ENV=production bun dist/index.js",
35
+ "create": "bun run core/cli/index.ts create",
36
+ "cli": "bun run core/cli/index.ts",
37
+ "make:component": "bun run core/cli/index.ts make:component",
38
+ "sync-version": "bun run core/utils/sync-version.ts",
39
+ "test": "vitest",
40
+ "test:ui": "vitest --ui",
41
+ "test:coverage": "vitest run --coverage",
42
+ "typecheck:api": "tsc --noEmit -p tsconfig.api-strict.json"
43
+ },
44
+ "devDependencies": {
45
+ "@eslint/js": "^9.30.1",
46
+ "@noble/curves": "1.2.0",
47
+ "@noble/hashes": "1.3.2",
48
+ "@tailwindcss/vite": "^4.1.13",
49
+ "@testing-library/jest-dom": "^6.6.4",
50
+ "@testing-library/react": "^16.3.0",
51
+ "@testing-library/user-event": "^14.6.1",
52
+ "@types/bun": "latest",
53
+ "@types/node": "^24.5.2",
54
+ "@types/react": "^19.1.8",
55
+ "@types/react-dom": "^19.1.6",
56
+ "@vitest/coverage-v8": "^3.2.4",
57
+ "@vitest/ui": "^3.2.4",
58
+ "baseline-browser-mapping": "^2.10.7",
59
+ "cross-env": "^10.1.0",
60
+ "eslint": "^9.30.1",
61
+ "eslint-plugin-react-hooks": "^5.2.0",
62
+ "eslint-plugin-react-refresh": "^0.4.20",
63
+ "globals": "^16.3.0",
64
+ "jsdom": "^26.1.0",
65
+ "rollup": "4.20.0",
66
+ "tailwindcss": "^4.1.13",
67
+ "typescript": "^5.8.3",
68
+ "typescript-eslint": "^8.35.1",
69
+ "vite-plugin-checker": "^0.12.0",
70
+ "vite-tsconfig-paths": "^6.0.5",
71
+ "vitest": "^3.2.4"
72
+ },
73
+ "dependencies": {
74
+ "@fluxstack/live": "^0.2.0",
75
+ "@fluxstack/live-elysia": "^0.2.0",
76
+ "@fluxstack/live-client": "^0.2.0",
77
+ "@fluxstack/live-react": "^0.2.0",
78
+ "@elysiajs/eden": "^1.3.2",
79
+ "@elysiajs/swagger": "^1.3.1",
80
+ "@vitejs/plugin-react": "^4.6.0",
81
+ "chalk": "^5.3.0",
82
+ "commander": "^12.1.0",
83
+ "elysia": "^1.4.6",
84
+ "lightningcss": "^1.30.1",
85
+ "ora": "^8.1.0",
86
+ "react": "^19.1.0",
87
+ "react-dom": "^19.1.0",
88
+ "react-icons": "^5.5.0",
89
+ "react-router": "^7.9.3",
90
+ "uuid": "^13.0.0",
91
+ "vite": "^7.1.7",
92
+ "winston": "^3.18.3",
93
+ "winston-daily-rotate-file": "^5.0.0",
94
+ "zustand": "^5.0.8"
95
+ },
96
+ "engines": {
97
+ "bun": ">=1.2.0"
98
+ },
99
+ "preferredPackageManager": "bun"
100
+ }
@@ -9,7 +9,7 @@ type Plugin = FluxStack.Plugin
9
9
  import { Elysia, t } from "elysia"
10
10
  import { CryptoAuthService, AuthMiddleware } from "./server"
11
11
  import { CryptoAuthLiveProvider } from "./server/CryptoAuthLiveProvider"
12
- import { liveAuthManager } from "@core/server/live/auth"
12
+ import { liveAuthManager } from "@core/server/live"
13
13
  import { makeProtectedRouteCommand } from "./cli/make-protected-route.command"
14
14
 
15
15
  // ✅ Plugin carrega sua própria configuração (da pasta config/ do plugin)
@@ -14,8 +14,8 @@ import type {
14
14
  LiveAuthProvider,
15
15
  LiveAuthCredentials,
16
16
  LiveAuthContext,
17
- } from '@core/server/live/auth/types'
18
- import { AuthenticatedContext, ANONYMOUS_CONTEXT } from '@core/server/live/auth/LiveAuthContext'
17
+ } from '@fluxstack/live'
18
+ import { AuthenticatedContext, ANONYMOUS_CONTEXT } from '@fluxstack/live'
19
19
 
20
20
  export class CryptoAuthLiveProvider implements LiveAuthProvider {
21
21
  readonly name = 'crypto-auth'
package/tsconfig.json CHANGED
@@ -28,7 +28,10 @@
28
28
  "@config/*": ["./config/*"],
29
29
  "@app/*": ["./app/*"],
30
30
  "@shared/*": ["./app/shared/*"],
31
- "@plugins/*": ["./plugins/*"]
31
+ "@plugins/*": ["./plugins/*"],
32
+ "@fluxstack/live": ["../fluxstack-live/packages/core/src/index.ts"],
33
+ "@fluxstack/live-client": ["../fluxstack-live/packages/client/src/index.ts"],
34
+ "@fluxstack/live-react": ["../fluxstack-live/packages/react/src/index.ts"]
32
35
  },
33
36
 
34
37
  // Best practices
package/vite.config.ts CHANGED
@@ -1,34 +1,54 @@
1
1
  import { defineConfig } from 'vite'
2
2
  import react from '@vitejs/plugin-react'
3
3
  import tailwindcss from '@tailwindcss/vite'
4
- import tsconfigPaths from 'vite-tsconfig-paths'
5
- import checker from 'vite-plugin-checker'
6
4
  import { resolve } from 'path'
5
+ import { existsSync } from 'fs'
7
6
  import { clientConfig } from './config/system/client.config'
8
- import { helpers } from './core/utils/env'
7
+ import { fluxstackVitePlugins } from './core/build/vite-plugins'
9
8
 
10
9
  // Root directory (vite.config.ts is in project root)
11
10
  const rootDir = import.meta.dirname
12
11
 
12
+ // When using bun-linked @fluxstack/live-* packages locally, point Vite at the
13
+ // TypeScript source instead of pre-built dist. This ensures a single React
14
+ // context (no dual-instance problem) and gives us HMR for the library code.
15
+ // In CI or when the sibling repo doesn't exist, resolve from node_modules.
16
+ const liveMonorepoRoot = resolve(rootDir, '../fluxstack-live/packages')
17
+ const hasLocalLiveMonorepo = existsSync(resolve(liveMonorepoRoot, 'core/src/index.ts'))
18
+
19
+ const liveAliases: Record<string, string> = hasLocalLiveMonorepo
20
+ ? {
21
+ '@fluxstack/live-react': resolve(liveMonorepoRoot, 'react/src/index.ts'),
22
+ '@fluxstack/live-client': resolve(liveMonorepoRoot, 'client/src/index.ts'),
23
+ '@fluxstack/live': resolve(liveMonorepoRoot, 'core/src/index.ts'),
24
+ }
25
+ : {}
26
+
13
27
  // https://vite.dev/config/
14
28
  export default defineConfig({
15
29
  plugins: [
30
+ // FluxStack internal plugins (live-strip, tsconfig-paths, type-checker)
31
+ ...fluxstackVitePlugins(),
16
32
  react(),
17
33
  tailwindcss(),
18
- tsconfigPaths({
19
- projects: [resolve(rootDir, 'tsconfig.json')]
20
- }),
21
- // Only run type checker in development (saves ~5+ minutes in Docker builds)
22
- helpers.isDevelopment() && checker({
23
- typescript: true,
24
- overlay: true
25
- })
26
- ].filter(Boolean),
34
+ ],
27
35
 
28
36
  root: resolve(rootDir, 'app/client'),
29
37
 
30
38
  // Aliases são lidos do tsconfig.json pelo plugin vite-tsconfig-paths
31
39
 
40
+ resolve: {
41
+ dedupe: ['react', 'react-dom', 'react/jsx-runtime'],
42
+ alias: liveAliases,
43
+ },
44
+
45
+ // Exclude linked packages from dep optimization when aliased to source
46
+ optimizeDeps: {
47
+ exclude: hasLocalLiveMonorepo
48
+ ? ['@fluxstack/live', '@fluxstack/live-client', '@fluxstack/live-react']
49
+ : [],
50
+ },
51
+
32
52
  server: {
33
53
  port: clientConfig.vite.port, // ✅ From config
34
54
  host: clientConfig.vite.host, // ✅ From config
@@ -36,6 +56,14 @@ export default defineConfig({
36
56
  open: clientConfig.vite.open, // ✅ From config
37
57
  allowedHosts: clientConfig.vite.allowedHosts, // ✅ From config (VITE_ALLOWED_HOSTS)
38
58
 
59
+ // Allow Vite to serve files outside the client root (needed for monorepo aliases)
60
+ fs: {
61
+ allow: [
62
+ rootDir,
63
+ ...(hasLocalLiveMonorepo ? [liveMonorepoRoot] : []),
64
+ ],
65
+ },
66
+
39
67
  hmr: {
40
68
  protocol: 'ws',
41
69
  host: clientConfig.vite.host,
@@ -1,107 +0,0 @@
1
- import { useEffect, useMemo, useRef, useState } from 'react'
2
- import { Live } from '@/core/client'
3
- import { LiveChat } from '@server/live/LiveChat'
4
-
5
- export function ChatDemo() {
6
- const [text, setText] = useState('')
7
- const [user, setUser] = useState('')
8
- const containerRef = useRef<HTMLDivElement | null>(null)
9
- const wasNearBottomRef = useRef(true)
10
- const defaultUser = useMemo(() => {
11
- if (typeof crypto !== 'undefined' && 'randomUUID' in crypto) {
12
- return `user-${crypto.randomUUID().slice(0, 6)}`
13
- }
14
- return `user-${Math.random().toString(36).slice(2, 8)}`
15
- }, [])
16
-
17
- const chat = Live.use(LiveChat, {
18
- room: 'global-chat',
19
- initialState: LiveChat.defaultState,
20
- persistState: false
21
- })
22
-
23
- const handleSend = async () => {
24
- if (!text.trim()) return
25
- const finalUser = user.trim() || defaultUser
26
- await chat.sendMessage({ user: finalUser, text })
27
- setText('')
28
- }
29
-
30
- useEffect(() => {
31
- const el = containerRef.current
32
- if (!el) return
33
-
34
- if (wasNearBottomRef.current) {
35
- el.scrollTop = el.scrollHeight
36
- }
37
- }, [chat.$state.messages.length])
38
-
39
- const handleScroll = () => {
40
- const el = containerRef.current
41
- if (!el) return
42
- const distance = el.scrollHeight - (el.scrollTop + el.clientHeight)
43
- wasNearBottomRef.current = distance < 80
44
- }
45
-
46
- return (
47
- <div className="bg-white/5 backdrop-blur-sm border border-white/10 rounded-2xl p-4 sm:p-6 md:p-8 w-full max-w-2xl mx-auto">
48
- <h2 className="text-2xl font-bold text-white mb-2 text-center">Chat Compartilhado</h2>
49
- <p className="text-gray-400 text-sm text-center mb-4">
50
- Sala global em tempo real. Abra em várias abas para testar.
51
- </p>
52
-
53
- <div className="flex flex-wrap items-center gap-2 mb-4 text-xs">
54
- <span className={`px-3 py-1 rounded-full ${chat.$connected ? 'bg-emerald-500/20 text-emerald-300' : 'bg-red-500/20 text-red-300'}`}>
55
- {chat.$connected ? 'Conectado' : 'Desconectado'}
56
- </span>
57
- <span className="text-gray-400">Você: {user.trim() || defaultUser}</span>
58
- </div>
59
-
60
- <div className="mb-4">
61
- <label className="block text-xs text-gray-400 mb-2">Seu nome</label>
62
- <input
63
- value={user}
64
- onChange={(e) => setUser(e.target.value)}
65
- placeholder={`Ex: ${defaultUser}`}
66
- className="w-full px-4 py-2 rounded-lg bg-white/10 border border-white/20 text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500/50"
67
- />
68
- </div>
69
-
70
- <div
71
- ref={containerRef}
72
- onScroll={handleScroll}
73
- className="bg-black/40 border border-white/10 rounded-xl p-3 sm:p-5 h-72 sm:h-96 md:h-[28rem] overflow-auto space-y-3"
74
- >
75
- {chat.$state.messages.length === 0 && (
76
- <div className="text-gray-500 text-sm text-center">Nenhuma mensagem ainda</div>
77
- )}
78
- {chat.$state.messages.map((m) => (
79
- <div key={m.id} className="text-sm">
80
- <span className="text-purple-300 font-semibold">{m.user}</span>
81
- <span className="text-gray-500 text-xs ml-2">{new Date(m.timestamp).toLocaleTimeString()}</span>
82
- <div className="text-gray-200">{m.text}</div>
83
- </div>
84
- ))}
85
- </div>
86
-
87
- <div className="mt-4 flex gap-2">
88
- <input
89
- value={text}
90
- onChange={(e) => setText(e.target.value)}
91
- onKeyDown={(e) => {
92
- if (e.key === 'Enter') void handleSend()
93
- }}
94
- placeholder="Digite uma mensagem..."
95
- className="flex-1 px-4 py-2 rounded-lg bg-white/10 border border-white/20 text-white placeholder-gray-500 focus:outline-none focus:ring-2 focus:ring-purple-500/50"
96
- />
97
- <button
98
- onClick={handleSend}
99
- disabled={!chat.$connected}
100
- className="px-4 py-2 rounded-lg bg-purple-500/20 border border-purple-500/30 text-purple-200 hover:bg-purple-500/30 transition-all disabled:opacity-50"
101
- >
102
- Enviar
103
- </button>
104
- </div>
105
- </div>
106
- )
107
- }